Safety first.
[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 862 2004-01-06 23:42:01Z stefan $
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 THREADSPECIFIC 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 }
345
346
347 /*************** adds a class to the vector of loaded classes ****************/
348
349 void systemclassloader_addclass(classinfo *c)
350 {
351         methodinfo *m;
352
353         /* find method addClass of java.lang.ClassLoader */
354         m = class_resolvemethod(class_java_lang_ClassLoader,
355                                                         utf_new_char("addClass"),
356                                                         utf_new_char("(Ljava/lang/Class;)")
357                                                         );
358         
359         if (!m)
360                 panic("warning: cannot initialize classloader");
361
362         /* prepare class to be passed as argument */
363         use_class_as_object (c);
364
365         /* call 'addClass' */
366         asm_calljavafunction(m,
367                                                  (java_objectheader*) SystemClassLoader, 
368                                                  (java_objectheader*) c,
369                                                  NULL,  
370                                                  NULL
371                                                  );
372 }
373
374
375 /*************** adds a library to the vector of loaded libraries *************/
376
377 void systemclassloader_addlibrary(java_objectheader *o)
378 {
379         log_text("systemclassloader_addlibrary");
380 }
381
382
383 /*****************************************************************************
384
385         create systemclassloader object and initialize instance fields  
386
387 ******************************************************************************/
388
389 void init_systemclassloader() 
390 {
391         if (!SystemClassLoader) {
392                 native_loadclasses();
393                 log_text("Initializing new system class loader");
394                 /* create object and call initializer */
395                 SystemClassLoader = (java_lang_ClassLoader*) native_new_and_init(class_java_lang_ClassLoader);  
396
397                 /* systemclassloader has no parent */
398                 SystemClassLoader->parent      = NULL;
399                 SystemClassLoader->initialized = true;
400         }
401         log_text("leaving system class loader");
402 }
403
404
405 /********************* add loaded library name  *******************************/
406
407 void systemclassloader_addlibname(java_objectheader *o)
408 {
409         methodinfo *m;
410         jfieldID id;
411
412         m = class_resolvemethod(loader_load_sysclass(NULL, utf_new_char ("java/util/Vector")),
413                                                         utf_new_char("addElement"),
414                                                         utf_new_char("(Ljava/lang/Object;)V"));
415
416         if (!m) panic("cannot initialize classloader");
417
418         id = envTable.GetStaticFieldID(&env,
419                                                                    class_java_lang_ClassLoader,
420                                                                    "loadedLibraryNames",
421                                                                    "Ljava/util/Vector;");
422
423         if (!id) panic("can not access ClassLoader");
424
425         asm_calljavafunction(m,
426                                                  envTable.GetStaticObjectField(&env, class_java_lang_ClassLoader, id),
427                                                  o,
428                                                  NULL,  
429                                                  NULL);
430 }
431
432
433 /********************* function: native_setclasspath **************************/
434  
435 void native_setclasspath(char *path)
436 {
437         /* set searchpath for classfiles */
438         classpath = path;
439 }
440
441
442 /*********************** Function: native_findfunction *************************
443
444         Looks up a method (must have the same class name, method name, descriptor
445         and 'static'ness) and returns a function pointer to it.
446         Returns: function pointer or NULL (if there is no such method)
447
448         Remark: For faster operation, the names/descriptors are converted from C
449                 strings to Unicode the first time this function is called.
450
451 *******************************************************************************/
452
453 functionptr native_findfunction(utf *cname, utf *mname, 
454                                                                 utf *desc, bool isstatic)
455 {
456         int i;
457         /* entry of table for fast string comparison */
458         struct nativecompref *n;
459         /* for warning message if no function is found */
460         char *buffer;                   
461         int buffer_len;
462
463         isstatic = isstatic ? true : false;
464         
465         if (!nativecompdone) {
466                 for (i = 0; i < NATIVETABLESIZE; i++) {
467                         nativecomptable[i].classname  = 
468                                 utf_new_char(nativetable[i].classname);
469                         nativecomptable[i].methodname = 
470                                 utf_new_char(nativetable[i].methodname);
471                         nativecomptable[i].descriptor = 
472                                 utf_new_char(nativetable[i].descriptor);
473                         nativecomptable[i].isstatic   = 
474                                 nativetable[i].isstatic;
475                         nativecomptable[i].func       = 
476                                 nativetable[i].func;
477                 }
478                 nativecompdone = true;
479         }
480
481 #ifdef JOWENN_DEBUG
482         buffer_len = 
483                 utf_strlen(cname) + utf_strlen(mname) + utf_strlen(desc) + 64;
484         
485         buffer = MNEW(char, buffer_len);
486
487         strcpy(buffer, "searching matching function in native table:");
488         utf_sprint(buffer+strlen(buffer), mname);
489         strcpy(buffer+strlen(buffer), ": ");
490         utf_sprint(buffer+strlen(buffer), desc);
491         strcpy(buffer+strlen(buffer), " for class ");
492         utf_sprint(buffer+strlen(buffer), cname);
493
494         log_text(buffer);       
495
496         MFREE(buffer, char, buffer_len);
497 #endif
498                 
499         for (i = 0; i < NATIVETABLESIZE; i++) {
500                 n = &(nativecomptable[i]);
501
502                 if (cname == n->classname && mname == n->methodname &&
503                     desc == n->descriptor && isstatic == n->isstatic)
504                         return n->func;
505 #ifdef JOWENN_DEBUG
506                         else {
507                                 if (cname == n->classname && mname == n->methodname )  log_text("static and descriptor mismatch");
508                         
509                                 else {
510                                         buffer_len = 
511                                           utf_strlen(n->classname) + utf_strlen(n->methodname) + utf_strlen(n->descriptor) + 64;
512         
513                                         buffer = MNEW(char, buffer_len);
514
515                                         strcpy(buffer, "comparing with:");
516                                         utf_sprint(buffer+strlen(buffer), n->methodname);
517                                         strcpy (buffer+strlen(buffer), ": ");
518                                         utf_sprint(buffer+strlen(buffer), n->descriptor);
519                                         strcpy(buffer+strlen(buffer), " for class ");
520                                         utf_sprint(buffer+strlen(buffer), n->classname);
521
522                                         log_text(buffer);       
523
524                                         MFREE(buffer, char, buffer_len);
525                                 }
526                         } 
527 #endif
528         }
529
530                 
531         /* no function was found, display warning */
532
533         buffer_len = 
534                 utf_strlen(cname) + utf_strlen(mname) + utf_strlen(desc) + 64;
535
536         buffer = MNEW(char, buffer_len);
537
538         strcpy(buffer, "warning: native function ");
539         utf_sprint(buffer + strlen(buffer), mname);
540         strcpy(buffer + strlen(buffer), ": ");
541         utf_sprint(buffer + strlen(buffer), desc);
542         strcpy(buffer + strlen(buffer), " not found in class ");
543         utf_sprint(buffer + strlen(buffer), cname);
544
545         log_text(buffer);       
546
547         MFREE(buffer, char, buffer_len);
548
549         exit(1);
550
551         /* keep compiler happy */
552         return NULL;
553 }
554
555
556 /********************** function: javastring_new *******************************
557
558         creates a new object of type java/lang/String with the text of 
559         the specified utf8-string
560
561         return: pointer to the string or NULL if memory is exhausted.   
562
563 *******************************************************************************/
564
565 /*  java_objectheader *javastring_new(utf *u) */
566 java_lang_String *javastring_new(utf *u)
567 {
568         char *utf_ptr = u->text;        /* current utf character in utf string    */
569         int utflength = utf_strlen(u);  /* length of utf-string if uncompressed   */
570         java_lang_String *s;                /* result-string                          */
571         java_chararray *a;
572         s4 i;
573         
574 /*      log_text("javastring_new");*/
575         
576         s = (java_lang_String*) builtin_new(class_java_lang_String);
577         a = builtin_newarray_char(utflength);
578
579         /* javastring or character-array could not be created */
580         if ((!a) || (!s))
581                 return NULL;
582
583         /* decompress utf-string */
584         for (i = 0; i < utflength; i++)
585                 a->data[i] = utf_nextu2(&utf_ptr);
586         
587         /* set fields of the javastring-object */
588         s->value  = a;
589         s->offset = 0;
590         s->count  = utflength;
591
592 /*      return (java_objectheader*) s; */
593         return s;
594 }
595
596
597 /********************** function: javastring_new_char **************************
598
599         creates a new java/lang/String object which contains the convertet
600         C-string passed via text.
601
602         return: the object pointer or NULL if memory is exhausted.
603
604 *******************************************************************************/
605
606 /*  java_objectheader *javastring_new_char (char *text) */
607 java_lang_String *javastring_new_char (char *text)
608 {
609         s4 i;
610         s4 len = strlen(text); /* length of the string */
611         java_lang_String *s;   /* result-string */
612         java_chararray *a;
613         
614         /*log_text("javastring_new_char");*/
615         s = (java_lang_String*) builtin_new(class_java_lang_String);
616         a = builtin_newarray_char(len);
617
618         /* javastring or character-array could not be created */
619         if ((!a) || (!s))
620                 return NULL;
621
622         /* copy text */
623         for (i = 0; i < len; i++)
624                 a->data[i] = text[i];
625         
626         /* set fields of the javastring-object */
627         s->value  = a;
628         s->offset = 0;
629         s->count  = len;
630
631 /*      return (java_objectheader*) s; */
632         return s;
633 }
634
635
636 /************************* function javastring_tochar **************************
637
638         converts a Java string into a C string.
639         
640         return: pointer to C string
641         
642         Caution: every call of this function overwrites the previous string !!!
643         
644 *******************************************************************************/
645
646 static char stringbuffer[MAXSTRINGSIZE];
647
648 char *javastring_tochar (java_objectheader *so) 
649 {
650         java_lang_String *s = (java_lang_String*) so;
651         java_chararray *a;
652         s4 i;
653         
654         log_text("javastring_tochar");
655         
656         if (!s)
657                 return "";
658         a = s->value;
659         if (!a)
660                 return "";
661         if (s->count > MAXSTRINGSIZE)
662                 return "";
663         for (i = 0; i < s->count; i++)
664                 stringbuffer[i] = a->data[s->offset+i];
665         stringbuffer[i] = '\0';
666         return stringbuffer;
667 }
668
669
670 /****************** function class_findfield_approx ****************************
671         
672         searches in 'classinfo'-structure for a field with the
673         specified name
674
675 *******************************************************************************/
676  
677 fieldinfo *class_findfield_approx(classinfo *c, utf *name)
678 {
679         s4 i;
680         for (i = 0; i < c->fieldscount; i++) {
681                 /* compare field names */
682                 if ((c->fields[i].name == name))
683                         return &(c->fields[i]);
684         }
685
686         /* field was not found, raise exception */      
687         *exceptionptr = native_new_and_init(class_java_lang_NoSuchFieldException);
688
689         return NULL;
690 }
691
692 s4 class_findfield_index_approx (classinfo *c, utf *name)
693 {
694         s4 i;
695         for (i = 0; i < c->fieldscount; i++) {
696                 /* compare field names */
697                 if ((c->fields[i].name == name))
698                         return i;
699                 }
700
701         /* field was not found, raise exception */      
702         *exceptionptr = native_new_and_init(class_java_lang_NoSuchFieldException);
703         return -1;
704 }
705
706
707 /********************** function: native_new_and_init *************************
708
709         Creates a new object on the heap and calls the initializer.
710         Returns the object pointer or NULL if memory is exhausted.
711                         
712 *******************************************************************************/
713
714 java_objectheader *native_new_and_init(classinfo *c)
715 {
716         methodinfo *m;
717         java_objectheader *o;
718
719         /* if c==NULL it is probebly because loader_load failed */
720         if (!c) return *exceptionptr;
721
722         o = builtin_new(c);          /* create object          */
723         
724         /*
725         printf("native_new_and_init ");
726         utf_display(c->name);
727         printf("\n");
728         */
729         if (!o) return NULL;
730         /* printf("o!=NULL\n"); */
731         /* find initializer */
732
733         m = class_findmethod(c, utf_new_char("<init>"), utf_new_char("()V"));
734                                                       
735         if (!m) {                                       /* initializer not found  */
736                 if (verbose) {
737                         char logtext[MAXLOGTEXT];
738                         sprintf(logtext, "Warning: class has no instance-initializer: ");
739                         utf_sprint(logtext + strlen(logtext), c->name);
740                         log_text(logtext);
741                 }
742                 return o;
743         }
744
745         /* call initializer */
746
747         asm_calljavafunction(m, o, NULL, NULL, NULL);
748
749         return o;
750 }
751
752
753 java_objectheader *native_new_and_init_string(classinfo *c, java_lang_String *s)
754 {
755         methodinfo *m;
756         java_objectheader *o;
757
758         /* if c==NULL it is probebly because loader_load failed */
759         if (!c) return *exceptionptr;
760
761         o = builtin_new(c);          /* create object          */
762         
763         if (!o) return NULL;
764
765         /* find initializer */
766
767         m = class_findmethod(c,
768                                                  utf_new_char("<init>"),
769                                                  utf_new_char("(Ljava/lang/String;)V"));
770                                                       
771         if (!m) {                                       /* initializer not found  */
772                 if (verbose) {
773                         char logtext[MAXLOGTEXT];
774                         sprintf(logtext, "Warning: class has no instance-initializer: ");
775                         utf_sprint(logtext + strlen(logtext), c->name);
776                         log_text(logtext);
777                 }
778                 return o;
779         }
780
781         /* call initializer */
782
783         asm_calljavafunction(m, o, s, NULL, NULL);
784
785         return o;
786 }
787
788
789 /******************** function: stringtable_update ****************************
790
791         traverses the javastring hashtable and sets the vftbl-entries of
792         javastrings which were temporarily set to NULL, because 
793         java.lang.Object was not yet loaded
794
795 *******************************************************************************/
796  
797 void stringtable_update ()
798 {
799         java_lang_String *js;   
800         java_chararray *a;
801         literalstring *s;       /* hashtable entry */
802         int i;
803
804         for (i = 0; i < string_hash.size; i++) {
805                 s = string_hash.ptr[i];
806                 if (s) {
807                         while (s) {
808                                                                 
809                                 js = (java_lang_String *) s->string;
810                                 
811                                 if (!js || !js->value) 
812                                         /* error in hashtable found */
813                                         panic("invalid literalstring in hashtable");
814
815                                 a = js->value;
816
817                                 if (!js->header.vftbl) 
818                                         /* vftbl of javastring is NULL */ 
819                                         js->header.vftbl = class_java_lang_String -> vftbl;
820
821                                 if (!a->header.objheader.vftbl) 
822                                         /* vftbl of character-array is NULL */ 
823                                         a->header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
824
825                                 /* follow link in external hash chain */
826                                 s = s->hashlink;
827                         }       
828                 }               
829         }
830 }
831
832
833 /************************* function: u2_utflength ***************************
834
835         returns the utf length in bytes of a u2 array 
836
837 *****************************************************************************/
838
839 u4 u2_utflength(u2 *text, u4 u2_length)
840 {
841         u4 result_len =  0;  /* utf length in bytes  */
842         u2 ch;               /* current unicode character */
843         u4 len;
844         
845         for (len = 0; len < u2_length; len++) {
846                 /* next unicode character */
847                 ch = *text++;
848           
849                 /* determine bytes required to store unicode character as utf */
850                 if (ch && (ch < 0x80)) 
851                         result_len++;
852                 else if (ch < 0x800)
853                         result_len += 2;        
854                 else 
855                         result_len += 3;        
856         }
857
858     return result_len;
859 }
860
861
862 /********************* function: utf_new_u2 ***********************************
863
864         make utf symbol from u2 array, 
865         if isclassname is true '.' is replaced by '/'
866
867 *******************************************************************************/
868
869 utf *utf_new_u2(u2 *unicode_pos, u4 unicode_length, bool isclassname)
870 {
871         char *buffer; /* memory buffer for  unicode characters */
872         char *pos;    /* pointer to current position in buffer */
873         u4 left;      /* unicode characters left */
874         u4 buflength; /* utf length in bytes of the u2 array  */
875         utf *result;  /* resulting utf-string */
876         int i;          
877
878         /* determine utf length in bytes and allocate memory */
879         /* printf("utf_new_u2: unicode_length=%d\n",unicode_length);            */
880         buflength = u2_utflength(unicode_pos, unicode_length); 
881         buffer    = MNEW(char, buflength);
882  
883         /* memory allocation failed */
884         if (!buffer) {
885                 printf("length: %d\n",buflength);
886                 log_text("utf_new_u2:buffer==NULL");
887         }
888
889         left = buflength;
890         pos  = buffer;
891
892         for (i = 0; i++ < unicode_length; unicode_pos++) {
893                 /* next unicode character */
894                 u2 c = *unicode_pos;
895                 
896                 if ((c != 0) && (c < 0x80)) {
897                         /* 1 character */       
898                         left--;
899                 if ((int) left < 0) break;
900                         /* convert classname */
901                         if (isclassname && c == '.')
902                                 *pos++ = '/';
903                         else
904                                 *pos++ = (char) c;
905
906                 } else if (c < 0x800) {             
907                         /* 2 characters */                              
908                 unsigned char high = c >> 6;
909                 unsigned char low  = c & 0x3F;
910                         left = left - 2;
911                 if ((int) left < 0) break;
912                 *pos++ = high | 0xC0; 
913                 *pos++ = low  | 0x80;     
914
915                 } else {         
916                 /* 3 characters */                              
917                 char low  = c & 0x3f;
918                 char mid  = (c >> 6) & 0x3F;
919                 char high = c >> 12;
920                         left = left - 3;
921                 if ((int) left < 0) break;
922                 *pos++ = high | 0xE0; 
923                 *pos++ = mid  | 0x80;  
924                 *pos++ = low  | 0x80;   
925                 }
926         }
927         
928         /* insert utf-string into symbol-table */
929         result = utf_new(buffer,buflength);
930
931         MFREE(buffer, char, buflength);
932
933         return result;
934 }
935
936
937 /********************* function: javastring_toutf *****************************
938
939         make utf symbol from javastring
940
941 *******************************************************************************/
942
943 utf *javastring_toutf(java_lang_String *string, bool isclassname)
944 {
945         java_lang_String *str = (java_lang_String *) string;
946 /*      printf("javastring_toutf offset: %d, len %d\n",str->offset, str->count);
947         fflush(stdout);*/
948         return utf_new_u2(str->value->data + str->offset, str->count, isclassname);
949 }
950
951
952 /********************* function: literalstring_u2 *****************************
953
954     searches for the javastring with the specified u2-array in 
955     the string hashtable, if there is no such string a new one is 
956     created 
957
958     if copymode is true a copy of the u2-array is made
959
960 *******************************************************************************/
961
962 java_objectheader *literalstring_u2 (java_chararray *a, u4 length, bool copymode )
963 {
964     literalstring *s;                /* hashtable element */
965     java_lang_String *js;            /* u2-array wrapped in javastring */
966     java_chararray *stringdata;      /* copy of u2-array */      
967     u4 key;   
968     u4 slot;  
969     u2 i;
970
971 #if JOWENN_DEBUG1
972     printf("literalstring_u2: length: %d\n",length);    
973     log_text("literalstring_u2");
974 #endif
975     
976     /* find location in hashtable */
977     key  = unicode_hashkey (a->data, length);
978     slot = key & (string_hash.size-1);
979     s    = string_hash.ptr[slot];
980
981     while (s) {
982         
983       js = (java_lang_String *) s->string;
984         
985       if (js->count == length) {
986         /* compare text */
987         for (i=0; i<length; i++) 
988           if (js->value->data[i] != a->data[i]) goto nomatch;
989                                         
990         /* string already in hashtable, free memory */
991         if (!copymode)
992                 lit_mem_free(a, sizeof(java_chararray) + sizeof(u2) * (length - 1) + 10);
993
994 #ifdef JOWENN_DEBUG1
995         log_text("literalstring_u2: foundentry");
996         utf_display(javastring_toutf(js,0));
997 #endif
998         return (java_objectheader *) js;
999       }
1000
1001       nomatch:
1002       /* follow link in external hash chain */
1003       s = s->hashlink;
1004     }
1005
1006     if (copymode) {
1007       /* create copy of u2-array for new javastring */
1008       u4 arraysize = sizeof(java_chararray) + sizeof(u2)*(length-1)+10;
1009       stringdata = lit_mem_alloc ( arraysize ); 
1010       memcpy(stringdata, a, arraysize );        
1011     }  
1012     else
1013       stringdata = a;
1014
1015     /* location in hashtable found, complete arrayheader */
1016     stringdata -> header.objheader.vftbl = primitivetype_table[ARRAYTYPE_CHAR].arrayvftbl;
1017     stringdata -> header.size = length; 
1018
1019     /* create new javastring */
1020     js = LNEW (java_lang_String);
1021     js -> header.vftbl = class_java_lang_String -> vftbl;
1022     js -> value  = stringdata;
1023     js -> offset = 0;
1024     js -> count  = length;
1025
1026     /* create new literalstring */
1027     s = NEW (literalstring);
1028     s->hashlink = string_hash.ptr[slot];
1029     s->string   = (java_objectheader *) js;
1030     string_hash.ptr[slot] = s;
1031
1032     /* update numbe of hashtable entries */
1033     string_hash.entries++;
1034
1035     /* reorganization of hashtable */       
1036     if ( string_hash.entries > (string_hash.size*2)) {
1037
1038       /* reorganization of hashtable, average length of 
1039          the external chains is approx. 2                */  
1040
1041       u4 i;
1042       literalstring *s;     
1043       hashtable newhash; /* the new hashtable */
1044       
1045       /* create new hashtable, double the size */
1046       init_hashtable(&newhash, string_hash.size*2);
1047       newhash.entries=string_hash.entries;
1048       
1049       /* transfer elements to new hashtable */
1050       for (i=0; i<string_hash.size; i++) {
1051         s = string_hash.ptr[i];
1052         while (s) {
1053           literalstring *nexts = s -> hashlink;  
1054           js   = (java_lang_String*) s->string;
1055           slot = (unicode_hashkey(js->value->data,js->count)) & (newhash.size-1);
1056           
1057           s->hashlink = newhash.ptr[slot];
1058           newhash.ptr[slot] = s;
1059         
1060           /* follow link in external hash chain */  
1061           s = nexts;
1062         }
1063       }
1064         
1065       /* dispose old table */   
1066       MFREE (string_hash.ptr, void*, string_hash.size);
1067       string_hash = newhash;
1068     }
1069 #ifdef JOWENN_DEBUG1
1070         log_text("literalstring_u2: newly created");
1071 /*      utf_display(javastring_toutf(js,0));*/
1072 #endif
1073                         
1074     return (java_objectheader *) js;
1075 }
1076
1077 /******************** Function: literalstring_new *****************************
1078
1079     creates a new javastring with the text of the utf-symbol
1080     and inserts it into the string hashtable
1081
1082 *******************************************************************************/
1083
1084 java_objectheader *literalstring_new (utf *u)
1085 {
1086     char *utf_ptr = u->text;         /* pointer to current unicode character in utf string */
1087     u4 utflength  = utf_strlen(u);   /* length of utf-string if uncompressed */
1088     java_chararray *a;               /* u2-array constructed from utf string */
1089     u4 i;
1090 /*    log_text("literalstring_new"); */
1091 /*    utf_display(u);*/
1092     /*if (utflength==0) while (1) sleep(60);*/
1093 /*    log_text("------------------");    */
1094     /* allocate memory */ 
1095     a = lit_mem_alloc (sizeof(java_chararray) + sizeof(u2)*(utflength-1)+10 );  
1096     /* convert utf-string to u2-array */
1097     for (i=0; i<utflength; i++) a->data[i] = utf_nextu2(&utf_ptr);      
1098
1099     return literalstring_u2(a, utflength, false);
1100 }
1101
1102
1103 /********************** function: literalstring_free **************************
1104
1105         removes a javastring from memory                       
1106
1107 ******************************************************************************/
1108
1109 void literalstring_free (java_objectheader* sobj)
1110 {
1111         java_lang_String *s = (java_lang_String*) sobj;
1112         java_chararray *a = s->value;
1113
1114         log_text("literalstring_free called");
1115         
1116         /* dispose memory of java.lang.String object */
1117         LFREE (s, java_lang_String);
1118         /* dispose memory of java-characterarray */
1119         LFREE (a, sizeof(java_chararray) + sizeof(u2)*(a->header.size-1)); /* +10 ?? */
1120 }
1121
1122
1123
1124
1125 void copy_vftbl(vftbl **dest, vftbl *src)
1126 {
1127     *dest = src;
1128 #if 0
1129     /* XXX this kind of copying does not work (in the general
1130      * case). The interface tables would have to be copied, too. I
1131      * don't see why we should make a copy anyway. -Edwin
1132      */
1133         *dest = mem_alloc(sizeof(vftbl) + sizeof(methodptr)*(src->vftbllength-1));
1134         memcpy(*dest, src, sizeof(vftbl) - sizeof(methodptr));
1135         memcpy(&(*dest)->table, &src->table, src->vftbllength * sizeof(methodptr));
1136 #endif
1137 }
1138
1139
1140 /******************************************************************************************                                                                                                             
1141
1142         creates method signature (excluding return type) from array of 
1143         class-objects representing the parameters of the method 
1144
1145 *******************************************************************************************/
1146
1147
1148 utf *create_methodsig(java_objectarray* types, char *retType)
1149 {
1150     char *buffer;       /* buffer for building the desciptor */
1151     char *pos;          /* current position in buffer */
1152     utf *result;        /* the method signature */
1153     u4 buffer_size = 3; /* minimal size=3: room for parenthesis and returntype */
1154     u4 i, j;
1155  
1156     if (!types) return NULL;
1157
1158     /* determine required buffer-size */    
1159     for (i = 0; i < types->header.size; i++) {
1160                 classinfo *c = (classinfo *) types->data[i];
1161                 buffer_size  = buffer_size + c->name->blength + 2;
1162     }
1163
1164     if (retType) buffer_size += strlen(retType);
1165
1166     /* allocate buffer */
1167     buffer = MNEW(u1, buffer_size);
1168     pos    = buffer;
1169     
1170     /* method-desciptor starts with parenthesis */
1171     *pos++ = '(';
1172
1173     for (i = 0; i < types->header.size; i++) {
1174                 char ch;           
1175
1176                 /* current argument */
1177             classinfo *c = (classinfo *) types->data[i];
1178
1179             /* current position in utf-text */
1180             char *utf_ptr = c->name->text; 
1181             
1182             /* determine type of argument */
1183             if ((ch = utf_nextu2(&utf_ptr)) == '[') {
1184                 /* arrayclass */
1185                 for (utf_ptr--; utf_ptr < utf_end(c->name); utf_ptr++) {
1186                                 *pos++ = *utf_ptr; /* copy text */
1187                         }
1188
1189             } else {            
1190                         /* check for primitive types */
1191                         for (j = 0; j < PRIMITIVETYPE_COUNT; j++) {
1192                                 char *utf_pos   = utf_ptr - 1;
1193                                 char *primitive = primitivetype_table[j].wrapname;
1194
1195                                 /* compare text */
1196                                 while (utf_pos < utf_end(c->name)) {
1197                                         if (*utf_pos++ != *primitive++) goto nomatch;
1198                                 }
1199
1200                                 /* primitive type found */
1201                                 *pos++ = primitivetype_table[j].typesig;
1202                                 goto next_type;
1203
1204                         nomatch:
1205                         }
1206
1207                         /* no primitive type and no arrayclass, so must be object */
1208                         *pos++ = 'L';
1209
1210                         /* copy text */
1211                         for (utf_ptr--; utf_ptr < utf_end(c->name); utf_ptr++) {
1212                                 *pos++ = *utf_ptr;
1213                         }
1214
1215                         *pos++ = ';';
1216
1217                 next_type:
1218                 }  
1219     }       
1220
1221     *pos++ = ')';
1222
1223     if (retType) {
1224                 for (i = 0; i < strlen(retType); i++) {
1225                         *pos++ = retType[i];
1226                 }
1227     }
1228
1229     /* create utf-string */
1230     result = utf_new(buffer, (pos - buffer));
1231     MFREE(buffer, u1, buffer_size);
1232
1233     return result;
1234 }
1235
1236
1237 /******************************************************************************************
1238
1239         retrieve the next argument or returntype from a descriptor
1240         and return the corresponding class 
1241
1242 *******************************************************************************************/
1243
1244 classinfo *get_type(char **utf_ptr,char *desc_end, bool skip)
1245 {
1246     classinfo *c = class_from_descriptor(*utf_ptr,desc_end,utf_ptr,
1247                                          (skip) ? CLASSLOAD_SKIP : CLASSLOAD_LOAD);
1248     if (!c)
1249         /* unknown type */
1250         panic("illegal descriptor");
1251
1252     if (skip) return NULL;
1253
1254     use_class_as_object(c);
1255     return c;
1256 }
1257
1258
1259 /******************************************************************************************
1260
1261         use the descriptor of a method to generate a java/lang/Class array
1262         which contains the classes of the parametertypes of the method
1263
1264 *******************************************************************************************/
1265
1266 java_objectarray* get_parametertypes(methodinfo *m) 
1267 {
1268     utf  *descr    =  m->descriptor;    /* method-descriptor */ 
1269     char *utf_ptr  =  descr->text;      /* current position in utf-text */
1270     char *desc_end =  utf_end(descr);   /* points behind utf string     */
1271     java_objectarray* result;
1272     int parametercount = 0;
1273     int i;
1274
1275     /* skip '(' */
1276     utf_nextu2(&utf_ptr);
1277   
1278     /* determine number of parameters */
1279     while ( *utf_ptr != ')' ) {
1280         get_type(&utf_ptr,desc_end,true);
1281         parametercount++;
1282     }
1283
1284     /* create class-array */
1285     result = builtin_anewarray(parametercount, class_java_lang_Class);
1286
1287     utf_ptr  =  descr->text;
1288     utf_nextu2(&utf_ptr);
1289
1290     /* get returntype classes */
1291     for (i = 0; i < parametercount; i++)
1292             result->data[i] = (java_objectheader *) get_type(&utf_ptr,desc_end, false);
1293
1294     return result;
1295 }
1296
1297
1298
1299
1300
1301 /******************************************************************************************
1302
1303         get the exceptions which can be thrown by a method      
1304
1305 *******************************************************************************************/
1306
1307 java_objectarray* get_exceptiontypes(methodinfo *m) 
1308 {
1309 }
1310
1311
1312
1313
1314
1315 /******************************************************************************************
1316
1317         get the returntype class of a method
1318
1319 *******************************************************************************************/
1320
1321 classinfo *get_returntype(methodinfo *m) 
1322 {
1323         char *utf_ptr;   /* current position in utf-text */
1324         char *desc_end;  /* points behind utf string     */
1325         utf *desc = m->descriptor; /* method-descriptor  */
1326
1327         utf_ptr  = desc->text;
1328         desc_end = utf_end(desc);
1329
1330         /* ignore parametertypes */
1331         while ((utf_ptr<desc_end) && utf_nextu2(&utf_ptr)!=')')
1332                 /* skip */ ;
1333
1334         return get_type(&utf_ptr,desc_end, false);
1335 }
1336
1337
1338 /*****************************************************************************/
1339 /*****************************************************************************/
1340
1341
1342 /*--------------------------------------------------------*/
1343 void printNativeCall(nativeCall nc) {
1344   int i,j;
1345
1346   printf("\n%s's Native Methods call:\n",nc.classname); fflush(stdout);
1347   for (i=0; i<nc.methCnt; i++) {  
1348       printf("\tMethod=%s %s\n",nc.methods[i].methodname, nc.methods[i].descriptor);fflush(stdout);
1349
1350     for (j=0; j<nc.callCnt[i]; j++) {  
1351         printf("\t\t<%i,%i>aCalled = %s %s %s\n",i,j,
1352         nc.methods[i].methodCalls[j].classname, 
1353         nc.methods[i].methodCalls[j].methodname, 
1354         nc.methods[i].methodCalls[j].descriptor);fflush(stdout);
1355       }
1356     }
1357   printf("-+++++--------------------\n");fflush(stdout);
1358 }
1359
1360 /*--------------------------------------------------------*/
1361 void printCompNativeCall(nativeCompCall nc) {
1362   int i,j;
1363   printf("printCompNativeCall BEGIN\n");fflush(stdout); 
1364   printf("\n%s's Native Comp Methods call:\n",nc.classname->text);fflush(stdout);
1365   utf_display(nc.classname); fflush(stdout);
1366   
1367   for (i=0; i<nc.methCnt; i++) {  
1368     printf("\tMethod=%s %s\n",nc.methods[i].methodname->text,nc.methods[i].descriptor->text);fflush(stdout);
1369     utf_display(nc.methods[i].methodname); fflush(stdout);
1370     utf_display(nc.methods[i].descriptor);fflush(stdout);
1371     printf("\n");fflush(stdout);
1372
1373     for (j=0; j<nc.callCnt[i]; j++) {  
1374       printf("\t\t<%i,%i>bCalled = ",i,j);fflush(stdout);
1375         utf_display(nc.methods[i].methodCalls[j].classname);fflush(stdout);
1376         utf_display(nc.methods[i].methodCalls[j].methodname); fflush(stdout);
1377         utf_display(nc.methods[i].methodCalls[j].descriptor);fflush(stdout);
1378         printf("\n");fflush(stdout);
1379       }
1380     }
1381 printf("---------------------\n");fflush(stdout);
1382 }
1383
1384
1385 /*--------------------------------------------------------*/
1386 classMeth findNativeMethodCalls(utf *c, utf *m, utf *d ) 
1387 {
1388     int i = 0;
1389     int j = 0;
1390     int cnt = 0;
1391     classMeth mc;
1392     mc.i_class = i;
1393     mc.j_method = j;
1394     mc.methCnt = cnt;
1395
1396     return mc;
1397 }
1398
1399 /*--------------------------------------------------------*/
1400 nativeCall* findNativeClassCalls(char *aclassname ) {
1401 int i;
1402
1403 for (i=0;i<NATIVECALLSSIZE; i++) {
1404    /* convert table to utf later to speed up search */ 
1405    if (strcmp(nativeCalls[i].classname, aclassname) == 0) 
1406         return &nativeCalls[i];
1407    }
1408
1409 return NULL;
1410 }
1411 /*--------------------------------------------------------*/
1412 /*--------------------------------------------------------*/
1413 void utfNativeCall(nativeCall nc, nativeCompCall *ncc) {
1414   int i,j;
1415
1416
1417   ncc->classname = utf_new_char(nc.classname); 
1418   ncc->methCnt = nc.methCnt;
1419   
1420   for (i=0; i<nc.methCnt; i++) {  
1421     ncc->methods[i].methodname = utf_new_char(nc.methods[i].methodname);
1422     ncc->methods[i].descriptor = utf_new_char(nc.methods[i].descriptor);
1423     ncc->callCnt[i] = nc.callCnt[i];
1424
1425     for (j=0; j<nc.callCnt[i]; j++) {  
1426
1427         ncc->methods[i].methodCalls[j].classname  = utf_new_char(nc.methods[i].methodCalls[j].classname);
1428
1429         if (strcmp("", nc.methods[i].methodCalls[j].methodname) != 0) {
1430           ncc->methods[i].methodCalls[j].methodname = utf_new_char(nc.methods[i].methodCalls[j].methodname);
1431           ncc->methods[i].methodCalls[j].descriptor = utf_new_char(nc.methods[i].methodCalls[j].descriptor);
1432           }
1433         else {
1434           ncc->methods[i].methodCalls[j].methodname = NULL;
1435           ncc->methods[i].methodCalls[j].descriptor = NULL;
1436           }
1437       }
1438     }
1439 }
1440
1441
1442
1443 /*--------------------------------------------------------*/
1444
1445 bool natcall2utf(bool natcallcompdone) {
1446 int i;
1447
1448 if (natcallcompdone) 
1449         return true;
1450
1451 for (i=0;i<NATIVECALLSSIZE; i++) {
1452    utfNativeCall  (nativeCalls[i], &nativeCompCalls[i]);  
1453    }
1454
1455 return true;
1456 }
1457 /*--------------------------------------------------------*/
1458
1459
1460 /*
1461  * These are local overrides for various environment variables in Emacs.
1462  * Please do not remove this and leave it at the end of the file, where
1463  * Emacs will automagically detect them.
1464  * ---------------------------------------------------------------------
1465  * Local variables:
1466  * mode: c
1467  * indent-tabs-mode: t
1468  * c-basic-offset: 4
1469  * tab-width: 4
1470  * End:
1471  */