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