- moved compiler switches into main
[cacao.git] / native.c
1 /* native.c - table of native functions
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6    P. Tomsich, J. Wenninger
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Reinhard Grafl
28             Roman Obermaisser
29             Andreas Krall
30
31    The .hh files created with the header file generator are all
32    included here as are the C functions implementing these methods.
33
34    $Id: native.c 833 2004-01-04 22:10:24Z jowenn $
35
36 */
37
38
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <time.h>
42 #include <math.h>
43 #include <string.h>
44 #include <assert.h>
45 #include <sys/time.h>
46 #include <utime.h>
47
48 #include "config.h"
49 #include "global.h"
50 #include "jni.h"
51 #include "native.h"
52 #include "nativetypes.hh"
53 #include "builtin.h"
54 #include "asmpart.h"
55 #include "tables.h"
56 #include "loader.h"
57 #include "jni.h"
58 #include "toolbox/loging.h"
59 #include "toolbox/memory.h"
60 #include "threads/thread.h"
61 #include "threads/threadio.h"
62 #include "threads/locks.h"
63
64 /* Include files for IO functions */
65
66 #include <fcntl.h>
67 #include <dirent.h>
68 #include <sys/types.h>
69 #ifdef _OSF_SOURCE 
70 #include <sys/mode.h>
71 #endif
72 #include <sys/stat.h>
73
74 #include "threads/threadio.h"
75
76 /* searchpath for classfiles */
77 char *classpath;
78
79 /* for java-string to char conversion */
80 #define MAXSTRINGSIZE 1000                          
81
82 /******************** systemclasses required for native methods ***************/
83
84 classinfo *class_java_lang_Class;
85 classinfo *class_java_lang_VMClass;
86 methodinfo *method_vmclass_init;
87 /* static classinfo *class_java_lang_Cloneable=0; */ /* now in global.h */
88 classinfo *class_java_lang_CloneNotSupportedException;
89 classinfo *class_java_lang_System;
90 classinfo *class_java_lang_ClassLoader;
91 classinfo *class_java_lang_NoClassDefFoundError;
92 classinfo *class_java_lang_ClassNotFoundException;
93 classinfo *class_java_lang_LinkageError;
94 classinfo *class_java_lang_InstantiationException;
95 classinfo *class_java_lang_NoSuchMethodError;   
96 classinfo *class_java_lang_NoSuchFieldError;
97 classinfo *class_java_lang_ClassFormatError;
98 classinfo *class_java_lang_IllegalArgumentException;
99 classinfo *class_java_lang_ArrayIndexOutOfBoundsException;
100 classinfo *class_java_lang_NoSuchFieldException;
101 classinfo *class_java_io_SyncFailedException;
102 classinfo *class_java_io_IOException;
103 classinfo *class_java_io_FileNotFoundException;
104 classinfo *class_java_io_UnixFileSystem;
105 classinfo *class_java_security_PrivilegedActionException;
106 classinfo *class_java_net_UnknownHostException;
107 classinfo *class_java_net_SocketException;
108 classinfo *class_java_lang_NoSuchMethodException;
109 classinfo *class_java_lang_Double;
110 classinfo *class_java_lang_Float;
111 classinfo *class_java_lang_Long;
112 classinfo *class_java_lang_Byte;
113 classinfo *class_java_lang_Short;
114 classinfo *class_java_lang_Boolean;
115 classinfo *class_java_lang_Void;
116 classinfo *class_java_lang_Character;
117 classinfo *class_java_lang_Integer;
118
119 /* the system classloader object */
120 struct java_lang_ClassLoader *SystemClassLoader = NULL;
121
122 /* for raising exceptions from native methods */
123 java_objectheader* exceptionptr = NULL;
124
125 /************* use classinfo structure as java.lang.Class object **************/
126
127 void use_class_as_object(classinfo *c) 
128 {
129         vftbl *vt;
130 /*      vftbl *newtbl; */
131
132         if (!class_java_lang_Class)
133                 class_java_lang_Class = class_new(utf_new_char ("java/lang/Class"));
134
135         vt = class_java_lang_Class->vftbl;
136
137
138         if (!c->classvftbl) {
139                 c->classvftbl = true;
140
141                 /*                copy_vftbl(&newtbl, vt);
142                                                   newtbl->class = c->header.vftbl->class;
143                                                   newtbl->baseval = c->header.vftbl->baseval;
144                                                   newtbl->diffval = c->header.vftbl->diffval;
145                                                   c->header.vftbl = newtbl;*/
146                 
147                 c->header.vftbl = class_java_lang_Class->vftbl;
148         
149                 if (!class_java_lang_VMClass) {
150                         loader_load_sysclass(&class_java_lang_VMClass,
151                                                                  utf_new_char("java/lang/VMClass"));
152
153                         method_vmclass_init =
154                                 class_findmethod(class_java_lang_VMClass,
155                                                                  utf_new_char("<init>"),
156                                                                  utf_new_char("(Lgnu/classpath/RawData;)V"));
157
158                         if (method_vmclass_init == 0) {
159                                 class_showmethods(class_java_lang_VMClass);
160                                 panic("Needed class initializer for VMClass could not be found");
161                         }
162                 }
163                 {     
164                         java_objectheader *vmo = builtin_new(class_java_lang_VMClass);
165
166                         if (!vmo) panic("Error while creating instance of java/lang/VMClass");
167                         asm_calljavafunction(method_vmclass_init, vmo, c, NULL, NULL);
168                         c->vmClass = (java_lang_VMClass *) vmo;
169                         /*log_text("VMCLASS has been attached");*/
170                 }
171         }
172 }
173
174
175 /*************************** include native methods ***************************/ 
176
177 #ifdef USE_GTK 
178 #include "nat/GdkGraphics.c"
179 #include "nat/GtkComponentPeer.c"
180 #include "nat/GdkPixbufDecoder.c"
181 #include "nat/GtkScrollPanePeer.c"
182 #include "nat/GtkFileDialogPeer.c"
183 #include "nat/GtkLabelPeer.c"
184 #endif
185
186
187 /************************** tables for methods ********************************/
188
189 #undef JOWENN_DEBUG
190 #undef JOWENN_DEBUG1
191
192 /* table for locating native methods */
193 static struct nativeref {
194         char *classname;
195         char *methodname;
196         char *descriptor;
197         bool isstatic;
198         functionptr func;
199 } nativetable [] = {
200
201 #include "nativetable.hh"
202
203 };
204
205
206 #define NATIVETABLESIZE  (sizeof(nativetable)/sizeof(struct nativeref))
207
208 /* table for fast string comparison */
209 static struct nativecompref {
210         utf *classname;
211         utf *methodname;
212         utf *descriptor;
213         bool isstatic;
214         functionptr func;
215 } nativecomptable [NATIVETABLESIZE];
216
217 /* string comparsion table initialized */
218 static bool nativecompdone = false;
219
220
221 /******************************************************************************/
222 /******************************************************************************/
223 #include "natcalls.h"
224
225 /* string call comparison table initialized */
226
227 /******************************************************************************/
228 /******************************************************************************/
229
230 /*--------------- native method calls & classes used -------------------------*/
231
232
233
234 /* throw some loader exceptions */
235
236 void throw_noclassdeffounderror_message(utf* classname)
237 {
238         if (!class_java_lang_NoClassDefFoundError) {
239                 panic("java.lang.NoClassDefFoundError not found. Maybe wrong classpath?");
240         }
241
242         /* throws a NoClassDefFoundError with message */
243         exceptionptr = native_new_and_init_string(class_java_lang_NoClassDefFoundError,
244                                                                                           javastring_new(classname));
245 }
246
247
248 void throw_linkageerror_message(utf* classname)
249 {
250         if (!class_java_lang_LinkageError) {
251                 panic("java.lang.LinkageError not found. Maybe wrong classpath?");
252         }
253
254         /* throws a LinkageError with message */
255         exceptionptr = native_new_and_init_string(class_java_lang_LinkageError,
256                                                                                           javastring_new(classname));
257 }
258
259
260 /*********************** function: native_loadclasses **************************
261
262         load classes required for native methods        
263
264 *******************************************************************************/
265
266 void native_loadclasses()
267 {
268         static int classesLoaded=0; /*temporary hack JoWenn*/
269         if (classesLoaded) return;
270         classesLoaded = 1;
271 /*      log_text("loadclasses entered");*/
272
273
274         /*class_java_lang_System =*/
275         (void) class_new(utf_new_char("java/lang/VMClass"));/*JoWenn*/
276         (void) class_new(utf_new_char("java/lang/Class"));/*JoWenn*/
277
278         /* class_new adds the class to the list of classes to be loaded */
279         if (!class_java_lang_Cloneable)
280                 class_java_lang_Cloneable = 
281                         class_new(utf_new_char("java/lang/Cloneable"));
282 /*      log_text("loadclasses: class_java_lang_Cloneable has been initialized");*/
283         class_java_lang_CloneNotSupportedException = 
284                 class_new(utf_new_char("java/lang/CloneNotSupportedException"));
285         if (!class_java_lang_Class)
286                 class_java_lang_Class =
287                         class_new(utf_new_char("java/lang/Class"));
288         class_java_io_IOException = 
289                 class_new(utf_new_char("java/io/IOException"));
290         class_java_io_FileNotFoundException = 
291                 class_new(utf_new_char("java/io/FileNotFoundException"));
292         class_java_lang_NoClassDefFoundError =
293                 class_new(utf_new_char("java/lang/NoClassDefFoundError"));
294         class_java_lang_ClassNotFoundException =
295                 class_new(utf_new_char("java/lang/ClassNotFoundException"));
296         class_java_lang_LinkageError =
297                 class_new(utf_new_char("java/lang/LinkageError"));
298         class_java_lang_InstantiationException =
299                 class_new(utf_new_char("java/lang/InstantiationException"));
300         class_java_lang_NoSuchMethodError =
301                 class_new(utf_new_char("java/lang/NoSuchMethodError"));
302         class_java_lang_NoSuchFieldError =
303                 class_new(utf_new_char("java/lang/NoSuchFieldError"));  
304         class_java_lang_ClassFormatError =
305                 class_new(utf_new_char("java/lang/ClassFormatError"));  
306         class_java_io_SyncFailedException =
307                 class_new(utf_new_char("java/io/SyncFailedException"));
308                 
309 /*      log_text("native_loadclasses: class_new(\"java/lang/ClassLoader\")");           */
310         class_java_lang_ClassLoader =
311                 class_new(utf_new_char("java/lang/ClassLoader"));       
312 /*      log_text("native_loadclasses: class_new(\"java/security/PrivilegedActionException\")");         */
313         class_java_security_PrivilegedActionException =
314                 class_new(utf_new_char("java/security/PrivilegedActionException"));
315
316         loader_load_sysclass(&class_java_net_UnknownHostException,
317                                                  utf_new_char("java/net/UnknownHostException"));
318         loader_load_sysclass(&class_java_net_SocketException,
319                                                  utf_new_char("java/net/SocketException"));
320
321         class_java_lang_IllegalArgumentException =
322                 class_new(utf_new_char("java/lang/IllegalArgumentException"));
323         class_java_lang_ArrayIndexOutOfBoundsException =
324                 class_new(utf_new_char("java/lang/ArrayIndexOutOfBoundsException"));
325         class_java_lang_NoSuchFieldException =
326                 class_new(utf_new_char("java/lang/NoSuchFieldException"));
327         class_java_lang_NoSuchMethodException = 
328                 class_new(utf_new_char("java/lang/NoSuchMethodException"));
329
330         /* load classes for wrapping primitive types */
331         class_java_lang_Double    = class_new(utf_new_char("java/lang/Double"));
332         class_init(class_java_lang_Double);
333
334         class_java_lang_Float     = class_new(utf_new_char("java/lang/Float"));
335         class_java_lang_Character =     class_new(utf_new_char("java/lang/Character"));
336         class_java_lang_Integer   = class_new(utf_new_char("java/lang/Integer"));
337         class_java_lang_Long      = class_new(utf_new_char("java/lang/Long"));
338         class_java_lang_Byte      = class_new(utf_new_char("java/lang/Byte"));
339         class_java_lang_Short     = class_new(utf_new_char("java/lang/Short"));
340         class_java_lang_Boolean   = class_new(utf_new_char("java/lang/Boolean"));
341         class_java_lang_Void      = class_new(utf_new_char("java/lang/Void"));
342
343         classesLoaded = 1;
344         log_text("native_loadclasses finished");
345 }
346
347
348 /*************** adds a class to the vector of loaded classes ****************/
349
350 void systemclassloader_addclass(classinfo *c)
351 {
352         methodinfo *m;
353
354         /* find method addClass of java.lang.ClassLoader */
355         m = class_resolvemethod(
356                                                         class_java_lang_ClassLoader, 
357                                                         utf_new_char("addClass"),
358                                                         utf_new_char("(Ljava/lang/Class;)")
359                                                         );
360         
361         if (!m) panic("warning: cannot initialize classloader");
362
363         /* prepare class to be passed as argument */
364         use_class_as_object (c);
365
366         /* call 'addClass' */
367         asm_calljavafunction(m,
368                                            (java_objectheader*) SystemClassLoader, 
369                                            (java_objectheader*) c,
370                                            NULL,  
371                                            NULL
372                                            );
373 }
374
375
376 /*************** adds a library to the vector of loaded libraries *************/
377
378 void systemclassloader_addlibrary(java_objectheader *o)
379 {
380         log_text("systemclassloader_addlibrary");
381 }
382
383
384 /*****************************************************************************
385
386         create systemclassloader object and initialize instance fields  
387
388 ******************************************************************************/
389
390 void init_systemclassloader() 
391 {
392         if (!SystemClassLoader) {
393                 native_loadclasses();
394                 log_text("Initializing new system class loader");
395                 /* create object and call initializer */
396                 SystemClassLoader = (java_lang_ClassLoader*) native_new_and_init(class_java_lang_ClassLoader);  
397
398                 /* systemclassloader has no parent */
399                 SystemClassLoader->parent      = NULL;
400                 SystemClassLoader->initialized = true;
401         }
402         log_text("leaving system class loader");
403 }
404
405
406 /********************* add loaded library name  *******************************/
407
408 void systemclassloader_addlibname(java_objectheader *o)
409 {
410         methodinfo *m;
411         jfieldID id;
412
413         m = class_resolvemethod(loader_load_sysclass(NULL, utf_new_char ("java/util/Vector")),
414                                                         utf_new_char("addElement"),
415                                                         utf_new_char("(Ljava/lang/Object;)V"));
416
417         if (!m) panic("cannot initialize classloader");
418
419         id = envTable.GetStaticFieldID(&env,
420                                                                    class_java_lang_ClassLoader,
421                                                                    "loadedLibraryNames",
422                                                                    "Ljava/util/Vector;");
423
424         if (!id) panic("can not access ClassLoader");
425
426         asm_calljavafunction(m,
427                                                  envTable.GetStaticObjectField(&env, class_java_lang_ClassLoader, id),
428                                                  o,
429                                                  NULL,  
430                                                  NULL);
431 }
432
433
434 /********************* function: native_setclasspath **************************/
435  
436 void native_setclasspath(char *path)
437 {
438         /* set searchpath for classfiles */
439         classpath = path;
440 }
441
442
443 /*********************** Function: native_findfunction *************************
444
445         Looks up a method (must have the same class name, method name, descriptor
446         and 'static'ness) and returns a function pointer to it.
447         Returns: function pointer or NULL (if there is no such method)
448
449         Remark: For faster operation, the names/descriptors are converted from C
450                 strings to Unicode the first time this function is called.
451
452 *******************************************************************************/
453
454 functionptr native_findfunction(utf *cname, utf *mname, 
455                                                                 utf *desc, bool isstatic)
456 {
457         int i;
458         /* entry of table for fast string comparison */
459         struct nativecompref *n;
460         /* for warning message if no function is found */
461         char *buffer;                   
462         int buffer_len;
463
464         isstatic = isstatic ? true : false;
465         
466         if (!nativecompdone) {
467                 for (i = 0; i < NATIVETABLESIZE; i++) {
468                         nativecomptable[i].classname  = 
469                                 utf_new_char(nativetable[i].classname);
470                         nativecomptable[i].methodname = 
471                                 utf_new_char(nativetable[i].methodname);
472                         nativecomptable[i].descriptor = 
473                                 utf_new_char(nativetable[i].descriptor);
474                         nativecomptable[i].isstatic   = 
475                                 nativetable[i].isstatic;
476                         nativecomptable[i].func       = 
477                                 nativetable[i].func;
478                 }
479                 nativecompdone = true;
480         }
481
482 #ifdef JOWENN_DEBUG
483         buffer_len = 
484                 utf_strlen(cname) + utf_strlen(mname) + utf_strlen(desc) + 64;
485         
486         buffer = MNEW(char, buffer_len);
487
488         strcpy(buffer, "searching matching function in native table:");
489         utf_sprint(buffer+strlen(buffer), mname);
490         strcpy(buffer+strlen(buffer), ": ");
491         utf_sprint(buffer+strlen(buffer), desc);
492         strcpy(buffer+strlen(buffer), " for class ");
493         utf_sprint(buffer+strlen(buffer), cname);
494
495         log_text(buffer);       
496
497         MFREE(buffer, char, buffer_len);
498 #endif
499                 
500         for (i = 0; i < NATIVETABLESIZE; i++) {
501                 n = &(nativecomptable[i]);
502
503                 if (cname == n->classname && mname == n->methodname &&
504                     desc == n->descriptor && isstatic == n->isstatic)
505                         return n->func;
506 #ifdef JOWENN_DEBUG
507                         else {
508                                 if (cname == n->classname && mname == n->methodname )  log_text("static and descriptor mismatch");
509                         
510                                 else {
511                                         buffer_len = 
512                                           utf_strlen(n->classname) + utf_strlen(n->methodname) + utf_strlen(n->descriptor) + 64;
513         
514                                         buffer = MNEW(char, buffer_len);
515
516                                         strcpy(buffer, "comparing with:");
517                                         utf_sprint(buffer+strlen(buffer), n->methodname);
518                                         strcpy (buffer+strlen(buffer), ": ");
519                                         utf_sprint(buffer+strlen(buffer), n->descriptor);
520                                         strcpy(buffer+strlen(buffer), " for class ");
521                                         utf_sprint(buffer+strlen(buffer), n->classname);
522
523                                         log_text(buffer);       
524
525                                         MFREE(buffer, char, buffer_len);
526                                 }
527                         } 
528 #endif
529         }
530
531                 
532         /* no function was found, display warning */
533
534         buffer_len = 
535                 utf_strlen(cname) + utf_strlen(mname) + utf_strlen(desc) + 64;
536
537         buffer = MNEW(char, buffer_len);
538
539         strcpy(buffer, "warning: native function ");
540         utf_sprint(buffer + strlen(buffer), mname);
541         strcpy(buffer + strlen(buffer), ": ");
542         utf_sprint(buffer + strlen(buffer), desc);
543         strcpy(buffer + strlen(buffer), " not found in class ");
544         utf_sprint(buffer + strlen(buffer), cname);
545
546         log_text(buffer);       
547
548         MFREE(buffer, char, buffer_len);
549
550         exit(1);
551
552         /* keep compiler happy */
553         return NULL;
554 }
555
556
557 /********************** function: javastring_new *******************************
558
559         creates a new object of type java/lang/String with the text of 
560         the specified utf8-string
561
562         return: pointer to the string or NULL if memory is exhausted.   
563
564 *******************************************************************************/
565
566 /*  java_objectheader *javastring_new(utf *u) */
567 java_lang_String *javastring_new(utf *u)
568 {
569         char *utf_ptr = u->text;        /* current utf character in utf string    */
570         int utflength = utf_strlen(u);  /* length of utf-string if uncompressed   */
571         java_lang_String *s;                /* result-string                          */
572         java_chararray *a;
573         s4 i;
574         
575 /*      log_text("javastring_new");*/
576         
577         s = (java_lang_String*) builtin_new(class_java_lang_String);
578         a = builtin_newarray_char(utflength);
579
580         /* javastring or character-array could not be created */
581         if ((!a) || (!s))
582                 return NULL;
583
584         /* decompress utf-string */
585         for (i = 0; i < utflength; i++)
586                 a->data[i] = utf_nextu2(&utf_ptr);
587         
588         /* set fields of the javastring-object */
589         s->value  = a;
590         s->offset = 0;
591         s->count  = utflength;
592
593 /*      return (java_objectheader*) s; */
594         return s;
595 }
596
597
598 /********************** function: javastring_new_char **************************
599
600         creates a new java/lang/String object which contains the convertet
601         C-string passed via text.
602
603         return: the object pointer or NULL if memory is exhausted.
604
605 *******************************************************************************/
606
607 /*  java_objectheader *javastring_new_char (char *text) */
608 java_lang_String *javastring_new_char (char *text)
609 {
610         s4 i;
611         s4 len = strlen(text); /* length of the string */
612         java_lang_String *s;   /* result-string */
613         java_chararray *a;
614         
615         /*log_text("javastring_new_char");*/
616         s = (java_lang_String*) builtin_new(class_java_lang_String);
617         a = builtin_newarray_char(len);
618
619         /* javastring or character-array could not be created */
620         if ((!a) || (!s))
621                 return NULL;
622
623         /* copy text */
624         for (i = 0; i < len; i++)
625                 a->data[i] = text[i];
626         
627         /* set fields of the javastring-object */
628         s->value  = a;
629         s->offset = 0;
630         s->count  = len;
631
632 /*      return (java_objectheader*) s; */
633         return s;
634 }
635
636
637 /************************* function javastring_tochar **************************
638
639         converts a Java string into a C string.
640         
641         return: pointer to C string
642         
643         Caution: every call of this function overwrites the previous string !!!
644         
645 *******************************************************************************/
646
647 static char stringbuffer[MAXSTRINGSIZE];
648
649 char *javastring_tochar (java_objectheader *so) 
650 {
651         java_lang_String *s = (java_lang_String*) so;
652         java_chararray *a;
653         s4 i;
654         
655         log_text("javastring_tochar");
656         
657         if (!s)
658                 return "";
659         a = s->value;
660         if (!a)
661                 return "";
662         if (s->count > MAXSTRINGSIZE)
663                 return "";
664         for (i = 0; i < s->count; i++)
665                 stringbuffer[i] = a->data[s->offset+i];
666         stringbuffer[i] = '\0';
667         return stringbuffer;
668 }
669
670
671 /****************** function class_findfield_approx ****************************
672         
673         searches in 'classinfo'-structure for a field with the
674         specified name
675
676 *******************************************************************************/
677  
678 fieldinfo *class_findfield_approx(classinfo *c, utf *name)
679 {
680         s4 i;
681         for (i = 0; i < c->fieldscount; i++) {
682                 /* compare field names */
683                 if ((c->fields[i].name == name))
684                         return &(c->fields[i]);
685         }
686
687         /* field was not found, raise exception */      
688         exceptionptr = native_new_and_init(class_java_lang_NoSuchFieldException);
689
690         return NULL;
691 }
692
693 s4 class_findfield_index_approx (classinfo *c, utf *name)
694 {
695         s4 i;
696         for (i = 0; i < c->fieldscount; i++) {
697                 /* compare field names */
698                 if ((c->fields[i].name == name))
699                         return i;
700                 }
701
702         /* field was not found, raise exception */      
703         exceptionptr = native_new_and_init(class_java_lang_NoSuchFieldException);
704         return -1;
705 }
706
707
708 /********************** function: native_new_and_init *************************
709
710         Creates a new object on the heap and calls the initializer.
711         Returns the object pointer or NULL if memory is exhausted.
712                         
713 *******************************************************************************/
714
715 java_objectheader *native_new_and_init(classinfo *c)
716 {
717         methodinfo *m;
718         java_objectheader *o;
719
720         /* if c==NULL it is probebly because loader_load failed */
721         if (!c) return exceptionptr;
722
723         o = builtin_new(c);          /* create object          */
724         
725         /*
726         printf("native_new_and_init ");
727         utf_display(c->name);
728         printf("\n");
729         */
730         if (!o) return NULL;
731         /* printf("o!=NULL\n"); */
732         /* find initializer */
733
734         m = class_findmethod(c, utf_new_char("<init>"), utf_new_char("()V"));
735                                                       
736         if (!m) {                                       /* initializer not found  */
737                 if (verbose) {
738                         char logtext[MAXLOGTEXT];
739                         sprintf(logtext, "Warning: class has no instance-initializer: ");
740                         utf_sprint(logtext + strlen(logtext), c->name);
741                         log_text(logtext);
742                 }
743                 return o;
744         }
745
746         /* call initializer */
747
748         asm_calljavafunction(m, o, NULL, NULL, NULL);
749
750         return o;
751 }
752
753
754 java_objectheader *native_new_and_init_string(classinfo *c, java_lang_String *s)
755 {
756         methodinfo *m;
757         java_objectheader *o;
758
759         /* if c==NULL it is probebly because loader_load failed */
760         if (!c) return exceptionptr;
761
762         o = builtin_new(c);          /* create object          */
763         
764         if (!o) return NULL;
765
766         /* find initializer */
767
768         m = class_findmethod(c,
769                                                  utf_new_char("<init>"),
770                                                  utf_new_char("(Ljava/lang/String;)V"));
771                                                       
772         if (!m) {                                       /* initializer not found  */
773                 if (verbose) {
774                         char logtext[MAXLOGTEXT];
775                         sprintf(logtext, "Warning: class has no instance-initializer: ");
776                         utf_sprint(logtext + strlen(logtext), c->name);
777                         log_text(logtext);
778                 }
779                 return o;
780         }
781
782         /* call initializer */
783
784         asm_calljavafunction(m, o, s, NULL, NULL);
785
786         return o;
787 }
788
789
790 /******************** function: stringtable_update ****************************
791
792         traverses the javastring hashtable and sets the vftbl-entries of
793         javastrings which were temporarily set to NULL, because 
794         java.lang.Object was not yet loaded
795
796 *******************************************************************************/
797  
798 void stringtable_update ()
799 {
800         java_lang_String *js;   
801         java_chararray *a;
802         literalstring *s;       /* hashtable entry */
803         int i;
804
805         for (i = 0; i < string_hash.size; i++) {
806                 s = string_hash.ptr[i];
807                 if (s) {
808                         while (s) {
809                                                                 
810                                 js = (java_lang_String *) s->string;
811                                 
812                                 if (!js || !js->value) 
813                                         /* error in hashtable found */
814                                         panic("invalid literalstring in hashtable");
815
816                                 a = js->value;
817
818                                 if (!js->header.vftbl) 
819                                         /* vftbl of javastring is NULL */ 
820                                         js->header.vftbl = class_java_lang_String -> vftbl;
821
822                                 if (!a->header.objheader.vftbl) 
823                                         /* vftbl of character-array is NULL */ 
824                                         a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
825
826                                 /* follow link in external hash chain */
827                                 s = s->hashlink;
828                         }       
829                 }               
830         }
831 }
832
833
834 /************************* function: u2_utflength ***************************
835
836         returns the utf length in bytes of a u2 array 
837
838 *****************************************************************************/
839
840 u4 u2_utflength(u2 *text, u4 u2_length)
841 {
842         u4 result_len =  0;  /* utf length in bytes  */
843         u2 ch;               /* current unicode character */
844         u4 len;
845         
846         for (len = 0; len < u2_length; len++) {
847                 /* next unicode character */
848                 ch = *text++;
849           
850                 /* determine bytes required to store unicode character as utf */
851                 if (ch && (ch < 0x80)) 
852                         result_len++;
853                 else if (ch < 0x800)
854                         result_len += 2;        
855                 else 
856                         result_len += 3;        
857         }
858
859     return result_len;
860 }
861
862
863 /********************* function: utf_new_u2 ***********************************
864
865         make utf symbol from u2 array, 
866         if isclassname is true '.' is replaced by '/'
867
868 *******************************************************************************/
869
870 utf *utf_new_u2(u2 *unicode_pos, u4 unicode_length, bool isclassname)
871 {
872         char *buffer; /* memory buffer for  unicode characters */
873         char *pos;    /* pointer to current position in buffer */
874         u4 left;      /* unicode characters left */
875         u4 buflength; /* utf length in bytes of the u2 array  */
876         utf *result;  /* resulting utf-string */
877         int i;          
878
879         /* determine utf length in bytes and allocate memory */
880         /* printf("utf_new_u2: unicode_length=%d\n",unicode_length);            */
881         buflength = u2_utflength(unicode_pos, unicode_length); 
882         buffer    = MNEW(char, buflength);
883  
884         /* memory allocation failed */
885         if (!buffer) {
886                 printf("length: %d\n",buflength);
887                 log_text("utf_new_u2:buffer==NULL");
888         }
889
890         left = buflength;
891         pos  = buffer;
892
893         for (i = 0; i++ < unicode_length; unicode_pos++) {
894                 /* next unicode character */
895                 u2 c = *unicode_pos;
896                 
897                 if ((c != 0) && (c < 0x80)) {
898                         /* 1 character */       
899                         left--;
900                 if ((int) left < 0) break;
901                         /* convert classname */
902                         if (isclassname && c == '.')
903                                 *pos++ = '/';
904                         else
905                                 *pos++ = (char) c;
906
907                 } else if (c < 0x800) {             
908                         /* 2 characters */                              
909                 unsigned char high = c >> 6;
910                 unsigned char low  = c & 0x3F;
911                         left = left - 2;
912                 if ((int) left < 0) break;
913                 *pos++ = high | 0xC0; 
914                 *pos++ = low  | 0x80;     
915
916                 } else {         
917                 /* 3 characters */                              
918                 char low  = c & 0x3f;
919                 char mid  = (c >> 6) & 0x3F;
920                 char high = c >> 12;
921                         left = left - 3;
922                 if ((int) left < 0) break;
923                 *pos++ = high | 0xE0; 
924                 *pos++ = mid  | 0x80;  
925                 *pos++ = low  | 0x80;   
926                 }
927         }
928         
929         /* insert utf-string into symbol-table */
930         result = utf_new(buffer,buflength);
931
932         MFREE(buffer, char, buflength);
933
934         return result;
935 }
936
937
938 /********************* function: javastring_toutf *****************************
939
940         make utf symbol from javastring
941
942 *******************************************************************************/
943
944 utf *javastring_toutf(java_lang_String *string, bool isclassname)
945 {
946         java_lang_String *str = (java_lang_String *) string;
947 /*      printf("javastring_toutf offset: %d, len %d\n",str->offset, str->count);
948         fflush(stdout);*/
949         return utf_new_u2(str->value->data + str->offset, str->count, isclassname);
950 }
951
952
953 /********************* function: literalstring_u2 *****************************
954
955     searches for the javastring with the specified u2-array in 
956     the string hashtable, if there is no such string a new one is 
957     created 
958
959     if copymode is true a copy of the u2-array is made
960
961 *******************************************************************************/
962
963 java_objectheader *literalstring_u2 (java_chararray *a, u4 length, bool copymode )
964 {
965     literalstring *s;                /* hashtable element */
966     java_lang_String *js;            /* u2-array wrapped in javastring */
967     java_chararray *stringdata;      /* copy of u2-array */      
968     u4 key;   
969     u4 slot;  
970     u2 i;
971
972 #if JOWENN_DEBUG1
973     printf("literalstring_u2: length: %d\n",length);    
974     log_text("literalstring_u2");
975 #endif
976     
977     /* find location in hashtable */
978     key  = unicode_hashkey (a->data, length);
979     slot = key & (string_hash.size-1);
980     s    = string_hash.ptr[slot];
981
982     while (s) {
983         
984       js = (java_lang_String *) s->string;
985         
986       if (js->count == length) {
987         /* compare text */
988         for (i=0; i<length; i++) 
989           if (js->value->data[i] != a->data[i]) goto nomatch;
990                                         
991         /* string already in hashtable, free memory */
992         if (!copymode)
993                 lit_mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
994
995 #ifdef JOWENN_DEBUG1
996         log_text("literalstring_u2: foundentry");
997         utf_display(javastring_toutf(js,0));
998 #endif
999         return (java_objectheader *) js;
1000       }
1001
1002       nomatch:
1003       /* follow link in external hash chain */
1004       s = s->hashlink;
1005     }
1006
1007     if (copymode) {
1008       /* create copy of u2-array for new javastring */
1009       u4 arraysize = sizeof(java_chararray) + sizeof(u2)*(length-1)+10;
1010       stringdata = lit_mem_alloc ( arraysize ); 
1011       memcpy(stringdata, a, arraysize );        
1012     }  
1013     else
1014       stringdata = a;
1015
1016     /* location in hashtable found, complete arrayheader */
1017     stringdata -> header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
1018     stringdata -> header.size = length; 
1019
1020     /* create new javastring */
1021     js = LNEW (java_lang_String);
1022     js -> header.vftbl = class_java_lang_String -> vftbl;
1023     js -> value  = stringdata;
1024     js -> offset = 0;
1025     js -> count  = length;
1026
1027     /* create new literalstring */
1028     s = NEW (literalstring);
1029     s->hashlink = string_hash.ptr[slot];
1030     s->string   = (java_objectheader *) js;
1031     string_hash.ptr[slot] = s;
1032
1033     /* update numbe of hashtable entries */
1034     string_hash.entries++;
1035
1036     /* reorganization of hashtable */       
1037     if ( string_hash.entries > (string_hash.size*2)) {
1038
1039       /* reorganization of hashtable, average length of 
1040          the external chains is approx. 2                */  
1041
1042       u4 i;
1043       literalstring *s;     
1044       hashtable newhash; /* the new hashtable */
1045       
1046       /* create new hashtable, double the size */
1047       init_hashtable(&newhash, string_hash.size*2);
1048       newhash.entries=string_hash.entries;
1049       
1050       /* transfer elements to new hashtable */
1051       for (i=0; i<string_hash.size; i++) {
1052         s = string_hash.ptr[i];
1053         while (s) {
1054           literalstring *nexts = s -> hashlink;  
1055           js   = (java_lang_String*) s->string;
1056           slot = (unicode_hashkey(js->value->data,js->count)) & (newhash.size-1);
1057           
1058           s->hashlink = newhash.ptr[slot];
1059           newhash.ptr[slot] = s;
1060         
1061           /* follow link in external hash chain */  
1062           s = nexts;
1063         }
1064       }
1065         
1066       /* dispose old table */   
1067       MFREE (string_hash.ptr, void*, string_hash.size);
1068       string_hash = newhash;
1069     }
1070 #ifdef JOWENN_DEBUG1
1071         log_text("literalstring_u2: newly created");
1072 /*      utf_display(javastring_toutf(js,0));*/
1073 #endif
1074                         
1075     return (java_objectheader *) js;
1076 }
1077
1078 /******************** Function: literalstring_new *****************************
1079
1080     creates a new javastring with the text of the utf-symbol
1081     and inserts it into the string hashtable
1082
1083 *******************************************************************************/
1084
1085 java_objectheader *literalstring_new (utf *u)
1086 {
1087     char *utf_ptr = u->text;         /* pointer to current unicode character in utf string */
1088     u4 utflength  = utf_strlen(u);   /* length of utf-string if uncompressed */
1089     java_chararray *a;               /* u2-array constructed from utf string */
1090     u4 i;
1091 /*    log_text("literalstring_new"); */
1092 /*    utf_display(u);*/
1093     /*if (utflength==0) while (1) sleep(60);*/
1094 /*    log_text("------------------");    */
1095     /* allocate memory */ 
1096     a = lit_mem_alloc (sizeof(java_chararray) + sizeof(u2)*(utflength-1)+10 );  
1097     /* convert utf-string to u2-array */
1098     for (i=0; i<utflength; i++) a->data[i] = utf_nextu2(&utf_ptr);      
1099
1100     return literalstring_u2(a, utflength, false);
1101 }
1102
1103
1104 /********************** function: literalstring_free **************************
1105
1106         removes a javastring from memory                       
1107
1108 ******************************************************************************/
1109
1110 void literalstring_free (java_objectheader* sobj)
1111 {
1112         java_lang_String *s = (java_lang_String*) sobj;
1113         java_chararray *a = s->value;
1114
1115         log_text("literalstring_free called");
1116         
1117         /* dispose memory of java.lang.String object */
1118         LFREE (s, java_lang_String);
1119         /* dispose memory of java-characterarray */
1120         LFREE (a, sizeof(java_chararray) + sizeof(u2)*(a->header.size-1)); /* +10 ?? */
1121 }
1122
1123
1124
1125
1126 void copy_vftbl(vftbl **dest, vftbl *src)
1127 {
1128     *dest = src;
1129 #if 0
1130     /* XXX this kind of copying does not work (in the general
1131      * case). The interface tables would have to be copied, too. I
1132      * don't see why we should make a copy anyway. -Edwin
1133      */
1134         *dest = mem_alloc(sizeof(vftbl) + sizeof(methodptr)*(src->vftbllength-1));
1135         memcpy(*dest, src, sizeof(vftbl) - sizeof(methodptr));
1136         memcpy(&(*dest)->table, &src->table, src->vftbllength * sizeof(methodptr));
1137 #endif
1138 }
1139
1140
1141 /******************************************************************************************                                                                                                             
1142
1143         creates method signature (excluding return type) from array of 
1144         class-objects representing the parameters of the method 
1145
1146 *******************************************************************************************/
1147
1148
1149 utf *create_methodsig(java_objectarray* types, char *retType)
1150 {
1151     char *buffer;       /* buffer for building the desciptor */
1152     char *pos;          /* current position in buffer */
1153     utf *result;        /* the method signature */
1154     u4 buffer_size = 3; /* minimal size=3: room for parenthesis and returntype */
1155     u4 i, j;
1156  
1157     if (!types) return NULL;
1158
1159     /* determine required buffer-size */    
1160     for (i = 0; i < types->header.size; i++) {
1161                 classinfo *c = (classinfo *) types->data[i];
1162                 buffer_size  = buffer_size + c->name->blength + 2;
1163     }
1164
1165     if (retType) buffer_size += strlen(retType);
1166
1167     /* allocate buffer */
1168     buffer = MNEW(u1, buffer_size);
1169     pos    = buffer;
1170     
1171     /* method-desciptor starts with parenthesis */
1172     *pos++ = '(';
1173
1174     for (i = 0; i < types->header.size; i++) {
1175                 char ch;           
1176
1177                 /* current argument */
1178             classinfo *c = (classinfo *) types->data[i];
1179
1180             /* current position in utf-text */
1181             char *utf_ptr = c->name->text; 
1182             
1183             /* determine type of argument */
1184             if ((ch = utf_nextu2(&utf_ptr)) == '[') {
1185                 /* arrayclass */
1186                 for (utf_ptr--; utf_ptr < utf_end(c->name); utf_ptr++) {
1187                                 *pos++ = *utf_ptr; /* copy text */
1188                         }
1189
1190             } else {            
1191                         /* check for primitive types */
1192                         for (j = 0; j < PRIMITIVETYPE_COUNT; j++) {
1193                                 char *utf_pos   = utf_ptr - 1;
1194                                 char *primitive = primitivetype_table[j].wrapname;
1195
1196                                 /* compare text */
1197                                 while (utf_pos < utf_end(c->name)) {
1198                                         if (*utf_pos++ != *primitive++) goto nomatch;
1199                                 }
1200
1201                                 /* primitive type found */
1202                                 *pos++ = primitivetype_table[j].typesig;
1203                                 goto next_type;
1204
1205                         nomatch:
1206                         }
1207
1208                         /* no primitive type and no arrayclass, so must be object */
1209                         *pos++ = 'L';
1210
1211                         /* copy text */
1212                         for (utf_ptr--; utf_ptr < utf_end(c->name); utf_ptr++) {
1213                                 *pos++ = *utf_ptr;
1214                         }
1215
1216                         *pos++ = ';';
1217
1218                 next_type:
1219                 }  
1220     }       
1221
1222     *pos++ = ')';
1223
1224     if (retType) {
1225                 for (i = 0; i < strlen(retType); i++) {
1226                         *pos++ = retType[i];
1227                 }
1228     }
1229
1230     /* create utf-string */
1231     result = utf_new(buffer, (pos - buffer));
1232     MFREE(buffer, u1, buffer_size);
1233
1234     return result;
1235 }
1236
1237
1238 /******************************************************************************************
1239
1240         retrieve the next argument or returntype from a descriptor
1241         and return the corresponding class 
1242
1243 *******************************************************************************************/
1244
1245 classinfo *get_type(char **utf_ptr,char *desc_end, bool skip)
1246 {
1247     classinfo *c = class_from_descriptor(*utf_ptr,desc_end,utf_ptr,
1248                                          (skip) ? CLASSLOAD_SKIP : CLASSLOAD_LOAD);
1249     if (!c)
1250         /* unknown type */
1251         panic("illegal descriptor");
1252
1253     if (skip) return NULL;
1254
1255     use_class_as_object(c);
1256     return c;
1257 }
1258
1259
1260 /******************************************************************************************
1261
1262         use the descriptor of a method to generate a java/lang/Class array
1263         which contains the classes of the parametertypes of the method
1264
1265 *******************************************************************************************/
1266
1267 java_objectarray* get_parametertypes(methodinfo *m) 
1268 {
1269     utf  *descr    =  m->descriptor;    /* method-descriptor */ 
1270     char *utf_ptr  =  descr->text;      /* current position in utf-text */
1271     char *desc_end =  utf_end(descr);   /* points behind utf string     */
1272     java_objectarray* result;
1273     int parametercount = 0;
1274     int i;
1275
1276     /* skip '(' */
1277     utf_nextu2(&utf_ptr);
1278   
1279     /* determine number of parameters */
1280     while ( *utf_ptr != ')' ) {
1281         get_type(&utf_ptr,desc_end,true);
1282         parametercount++;
1283     }
1284
1285     /* create class-array */
1286     result = builtin_anewarray(parametercount, class_java_lang_Class);
1287
1288     utf_ptr  =  descr->text;
1289     utf_nextu2(&utf_ptr);
1290
1291     /* get returntype classes */
1292     for (i = 0; i < parametercount; i++)
1293             result->data[i] = (java_objectheader *) get_type(&utf_ptr,desc_end, false);
1294
1295     return result;
1296 }
1297
1298
1299
1300
1301
1302 /******************************************************************************************
1303
1304         get the exceptions which can be thrown by a method      
1305
1306 *******************************************************************************************/
1307
1308 java_objectarray* get_exceptiontypes(methodinfo *m) 
1309 {
1310 }
1311
1312
1313
1314
1315
1316 /******************************************************************************************
1317
1318         get the returntype class of a method
1319
1320 *******************************************************************************************/
1321
1322 classinfo *get_returntype(methodinfo *m) 
1323 {
1324         char *utf_ptr;   /* current position in utf-text */
1325         char *desc_end;  /* points behind utf string     */
1326         utf *desc = m->descriptor; /* method-descriptor  */
1327
1328         utf_ptr  = desc->text;
1329         desc_end = utf_end(desc);
1330
1331         /* ignore parametertypes */
1332         while ((utf_ptr<desc_end) && utf_nextu2(&utf_ptr)!=')')
1333                 /* skip */ ;
1334
1335         return get_type(&utf_ptr,desc_end, false);
1336 }
1337
1338
1339 /*****************************************************************************/
1340 /*****************************************************************************/
1341
1342
1343 /*--------------------------------------------------------*/
1344 void printNativeCall(nativeCall nc) {
1345   int i,j;
1346
1347   printf("\n%s's Native Methods call:\n",nc.classname); fflush(stdout);
1348   for (i=0; i<nc.methCnt; i++) {  
1349       printf("\tMethod=%s %s\n",nc.methods[i].methodname, nc.methods[i].descriptor);fflush(stdout);
1350
1351     for (j=0; j<nc.callCnt[i]; j++) {  
1352         printf("\t\t<%i,%i>aCalled = %s %s %s\n",i,j,
1353         nc.methods[i].methodCalls[j].classname, 
1354         nc.methods[i].methodCalls[j].methodname, 
1355         nc.methods[i].methodCalls[j].descriptor);fflush(stdout);
1356       }
1357     }
1358   printf("-+++++--------------------\n");fflush(stdout);
1359 }
1360
1361 /*--------------------------------------------------------*/
1362 void printCompNativeCall(nativeCompCall nc) {
1363   int i,j;
1364   printf("printCompNativeCall BEGIN\n");fflush(stdout); 
1365   printf("\n%s's Native Comp Methods call:\n",nc.classname->text);fflush(stdout);
1366   utf_display(nc.classname); fflush(stdout);
1367   
1368   for (i=0; i<nc.methCnt; i++) {  
1369     printf("\tMethod=%s %s\n",nc.methods[i].methodname->text,nc.methods[i].descriptor->text);fflush(stdout);
1370     utf_display(nc.methods[i].methodname); fflush(stdout);
1371     utf_display(nc.methods[i].descriptor);fflush(stdout);
1372     printf("\n");fflush(stdout);
1373
1374     for (j=0; j<nc.callCnt[i]; j++) {  
1375       printf("\t\t<%i,%i>bCalled = ",i,j);fflush(stdout);
1376         utf_display(nc.methods[i].methodCalls[j].classname);fflush(stdout);
1377         utf_display(nc.methods[i].methodCalls[j].methodname); fflush(stdout);
1378         utf_display(nc.methods[i].methodCalls[j].descriptor);fflush(stdout);
1379         printf("\n");fflush(stdout);
1380       }
1381     }
1382 printf("---------------------\n");fflush(stdout);
1383 }
1384
1385
1386 /*--------------------------------------------------------*/
1387 classMeth findNativeMethodCalls(utf *c, utf *m, utf *d ) 
1388 {
1389     int i = 0;
1390     int j = 0;
1391     int cnt = 0;
1392     classMeth mc;
1393     mc.i_class = i;
1394     mc.j_method = j;
1395     mc.methCnt = cnt;
1396
1397     return mc;
1398 }
1399
1400 /*--------------------------------------------------------*/
1401 nativeCall* findNativeClassCalls(char *aclassname ) {
1402 int i;
1403
1404 for (i=0;i<NATIVECALLSSIZE; i++) {
1405    /* convert table to utf later to speed up search */ 
1406    if (strcmp(nativeCalls[i].classname, aclassname) == 0) 
1407         return &nativeCalls[i];
1408    }
1409
1410 return NULL;
1411 }
1412 /*--------------------------------------------------------*/
1413 /*--------------------------------------------------------*/
1414 void utfNativeCall(nativeCall nc, nativeCompCall *ncc) {
1415   int i,j;
1416
1417
1418   ncc->classname = utf_new_char(nc.classname); 
1419   ncc->methCnt = nc.methCnt;
1420   
1421   for (i=0; i<nc.methCnt; i++) {  
1422     ncc->methods[i].methodname = utf_new_char(nc.methods[i].methodname);
1423     ncc->methods[i].descriptor = utf_new_char(nc.methods[i].descriptor);
1424     ncc->callCnt[i] = nc.callCnt[i];
1425
1426     for (j=0; j<nc.callCnt[i]; j++) {  
1427
1428         ncc->methods[i].methodCalls[j].classname  = utf_new_char(nc.methods[i].methodCalls[j].classname);
1429
1430         if (strcmp("", nc.methods[i].methodCalls[j].methodname) != 0) {
1431           ncc->methods[i].methodCalls[j].methodname = utf_new_char(nc.methods[i].methodCalls[j].methodname);
1432           ncc->methods[i].methodCalls[j].descriptor = utf_new_char(nc.methods[i].methodCalls[j].descriptor);
1433           }
1434         else {
1435           ncc->methods[i].methodCalls[j].methodname = NULL;
1436           ncc->methods[i].methodCalls[j].descriptor = NULL;
1437           }
1438       }
1439     }
1440 }
1441
1442
1443
1444 /*--------------------------------------------------------*/
1445
1446 bool natcall2utf(bool natcallcompdone) {
1447 int i;
1448
1449 if (natcallcompdone) 
1450         return true;
1451
1452 for (i=0;i<NATIVECALLSSIZE; i++) {
1453    utfNativeCall  (nativeCalls[i], &nativeCompCalls[i]);  
1454    }
1455
1456 return true;
1457 }
1458 /*--------------------------------------------------------*/
1459
1460
1461 /*
1462  * These are local overrides for various environment variables in Emacs.
1463  * Please do not remove this and leave it at the end of the file, where
1464  * Emacs will automagically detect them.
1465  * ---------------------------------------------------------------------
1466  * Local variables:
1467  * mode: c
1468  * indent-tabs-mode: t
1469  * c-basic-offset: 4
1470  * tab-width: 4
1471  * End:
1472  */