Also check for printing floats correctly (fp test)
[cacao.git] / tables.c
1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
2 /****************************** tables.c ***************************************
3
4         Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
5
6         See file COPYRIGHT for information on usage and disclaimer of warranties
7
8         Contains support functions for:
9                 - Reading of Java class files
10                 - Unicode symbols
11                 - the heap
12                 - additional support functions
13
14         Authors: Reinhard Grafl      EMAIL: cacao@complang.tuwien.ac.at
15         Changes: Mark Probst         EMAIL: cacao@complang.tuwien.ac.at
16                  Andreas  Krall      EMAIL: cacao@complang.tuwien.ac.at
17                         
18         Last Change: 1998/03/24
19
20 *******************************************************************************/
21
22 #include <assert.h>
23 #include <sys/types.h>
24 #include <sys/mman.h>
25 #include <unistd.h>
26 #include "global.h"
27 #include "tables.h"
28 #include "asmpart.h"
29 #include "callargs.h"
30
31 #include "threads/thread.h"                  /* schani */
32 #include "threads/locks.h"
33
34 bool runverbose = false;
35
36 /* statistics */
37 int count_utf_len = 0;         /* size of utf hash                  */
38 int count_utf_new = 0;         /* calls of utf_new                  */
39 int count_utf_new_found  = 0;  /* calls of utf_new with fast return */
40
41 hashtable utf_hash;     /* hashtable for utf8-symbols */
42 hashtable string_hash;  /* hashtable for javastrings  */
43 hashtable class_hash;   /* hashtable for classes      */
44
45 /******************************************************************************
46  *********************** hashtable functions **********************************
47  ******************************************************************************/
48
49 /* hashsize must be power of 2 */
50
51 #define UTF_HASHSTART   16384   /* initial size of utf-hash */    
52 #define HASHSTART        2048   /* initial size of javastring and class-hash */
53
54
55 /******************** function: init_hashtable ******************************
56
57     Initializes a hashtable structure and allocates memory.
58     The parameter size specifies the initial size of the hashtable.
59         
60 *****************************************************************************/
61
62 void init_hashtable(hashtable *hash, u4 size)
63 {
64         u4 i;
65
66         hash->entries = 0;
67         hash->size    = size;
68         hash->ptr     = MNEW (void*, size);
69
70         /* clear table */
71         for (i=0; i<size; i++) hash->ptr[i] = NULL;
72 }
73
74 /*********************** function: tables_init  *****************************
75
76     creates hashtables for symboltables 
77         (called once at startup)                         
78         
79 *****************************************************************************/
80
81 void tables_init ()
82 {
83         init_hashtable(&utf_hash,    UTF_HASHSTART);  /* hashtable for utf8-symbols */
84         init_hashtable(&string_hash, HASHSTART);      /* hashtable for javastrings */
85         init_hashtable(&class_hash,  HASHSTART);      /* hashtable for classes */ 
86         
87 #ifdef STATISTICS
88         count_utf_len += sizeof(utf*) * utf_hash.size;
89 #endif
90
91 }
92
93 /********************** function: tables_close ******************************
94
95         free memory for hashtables                    
96         
97 *****************************************************************************/
98
99 void tables_close (stringdeleter del)
100 {
101         utf *u; 
102         literalstring *s;
103         u4 i;
104         
105         /* dispose utf symbols */
106         for (i=0; i<utf_hash.size; i++) {
107         u = utf_hash.ptr[i];
108                 while (u) {
109                         /* process elements in external hash chain */
110                         utf *nextu = u->hashlink;
111                         MFREE (u->text, u1, u->blength);
112                         FREE (u, utf);
113                         u = nextu;
114                         }       
115                 }
116
117         /* dispose javastrings */
118         for (i=0; i<string_hash.size; i++) {
119                 s = string_hash.ptr[i];
120                 while (u) {
121                         /* process elements in external hash chain */
122                         literalstring *nexts = s->hashlink;
123                         del(s->string);
124                         FREE(s, literalstring);
125                         s = nexts;
126                         }       
127                 }
128
129         /* dispose hashtable structures */
130         MFREE (utf_hash.ptr,    void*, utf_hash.size);
131         MFREE (string_hash.ptr, void*, string_hash.size);
132         MFREE (class_hash.ptr,  void*, class_hash.size);
133 }
134
135 /********************* function: utf_display *********************************
136
137         write utf symbol to stdout (debugging purposes)
138
139 ******************************************************************************/
140
141 void utf_display (utf *u)
142 {
143     char *endpos  = utf_end(u);  /* points behind utf string       */
144     char *utf_ptr = u->text;     /* current position in utf text   */
145         if (u==NULL) return;
146     while (utf_ptr<endpos) {
147
148                 /* read next unicode character */                
149                 u2 c = utf_nextu2(&utf_ptr);                            
150                 if (c>=32 && c<=127) printf ("%c",c);
151                                 else printf ("?");
152         }
153
154         fflush (stdout);
155 }
156
157 /************************ function: utf_sprint *******************************
158         
159     write utf symbol into c-string (debugging purposes)                                          
160
161 ******************************************************************************/ 
162
163 void utf_sprint (char *buffer, utf *u)
164 {
165     char *endpos  = utf_end(u);  /* points behind utf string       */
166     char *utf_ptr = u->text;     /* current position in utf text   */ 
167     u2 pos = 0;                  /* position in c-string           */
168
169     while (utf_ptr<endpos) 
170                 /* copy next unicode character */       
171                 buffer[pos++] = utf_nextu2(&utf_ptr);
172
173     /* terminate string */
174     buffer[pos] = '\0';
175 }
176
177
178 /********************* Funktion: utf_fprint **********************************
179         
180     write utf symbol into file          
181
182 ******************************************************************************/ 
183
184 void utf_fprint (FILE *file, utf *u)
185 {
186     char *endpos  = utf_end(u);  /* points behind utf string       */
187     char *utf_ptr = u->text;     /* current position in utf text   */ 
188     if (u==NULL) return;
189     while (utf_ptr<endpos) { 
190                 /* read next unicode character */                
191                 u2 c = utf_nextu2(&utf_ptr);                            
192
193                 if (c>=32 && c<=127) fprintf (file,"%c",c);
194                                 else fprintf (file,"?");
195                 }
196
197
198
199 /****************** internal function: utf_hashkey ***************************
200
201         The hashkey is computed from the utf-text by using up to 8 characters.
202         For utf-symbols longer than 15 characters 3 characters are taken from
203         the beginning and the end, 2 characters are taken from the middle.
204
205 ******************************************************************************/ 
206
207 #define nbs(val) ((u4) *(++text) << val) /* get next byte, left shift by val  */
208 #define fbs(val) ((u4) *(  text) << val) /* get first byte, left shift by val */
209
210 static u4 utf_hashkey (char *text, u4 length)
211 {
212         char *start_pos = text; /* pointer to utf text */
213         u4 a;
214
215         switch (length) {               
216                 
217         case 0: /* empty string */
218                 return 0;
219
220         case 1: return fbs(0);
221         case 2: return fbs(0) ^ nbs(3);
222         case 3: return fbs(0) ^ nbs(3) ^ nbs(5);
223         case 4: return fbs(0) ^ nbs(2) ^ nbs(4) ^ nbs(6);
224         case 5: return fbs(0) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(6);
225         case 6: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(5) ^ nbs(6);
226         case 7: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6);
227         case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7);
228
229         case 9: a = fbs(0) ^ nbs(1) ^ nbs(2);                
230                 text++; 
231                 return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8);
232
233         case 10: a = fbs(0);
234                  text++;
235                  a^= nbs(2) ^ nbs(3) ^ nbs(4);
236                  text++;
237                  return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9);
238
239         case 11: a = fbs(0);
240                  text++;
241                  a^= nbs(2) ^ nbs(3) ^ nbs(4);
242                  text++;
243                  return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10);
244
245         case 12: a = fbs(0);
246                  text+=2;
247                  a^= nbs(2) ^ nbs(3);
248                  text+=1;
249                  a^= nbs(5) ^ nbs(6) ^ nbs(7);
250                  text+=1;
251                  return a ^ nbs(9) ^ nbs(10);      
252
253         case 13: a = fbs(0) ^ nbs(1);
254                  text+=1;       
255                  a^= nbs(3) ^ nbs(4);
256                  text+=2;       
257                  a^= nbs(7) ^ nbs(8);
258                  text+=2;
259                  return a ^ nbs(9) ^ nbs(10);
260
261         case 14: a = fbs(0);
262                  text+=2;       
263                  a^= nbs(3) ^ nbs(4);
264                  text+=2;       
265                  a^= nbs(7) ^ nbs(8);
266                  text+=2;
267                  return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
268
269         case 15: a = fbs(0);
270                  text+=2;       
271                  a^= nbs(3) ^ nbs(4);
272                  text+=2;       
273                  a^= nbs(7) ^ nbs(8);
274                  text+=2;
275                  return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
276
277         default:  /* 3 characters from beginning */
278                   a = fbs(0);
279                   text+=2;
280                   a^= nbs(3) ^ nbs(4);
281
282                   /* 2 characters from middle */
283                   text = start_pos + (length / 2);
284                   a^= fbs(5);
285                   text+=2;
286                   a^= nbs(6);   
287
288                   /* 3 characters from end */
289                   text = start_pos + length - 4;
290
291                   a^= fbs(7);
292                   text+=1;
293
294                   return a ^ nbs(10) ^ nbs(11);
295     }
296 }
297
298
299 /*************************** function: utf_hashkey ***************************
300
301     compute the hashkey of a unicode string
302
303 ******************************************************************************/ 
304
305 u4 unicode_hashkey (u2 *text, u2 len)
306 {
307         return utf_hashkey((char*) text, len);
308 }
309
310 /************************ function: utf_new **********************************
311
312         Creates a new utf-symbol, the text of the symbol is passed as a 
313         u1-array. The function searches the utf-hashtable for a utf-symbol 
314         with this text. On success the element returned, otherwise a new 
315         hashtable element is created.
316
317         If the number of entries in the hashtable exceeds twice the size of the
318         hashtable slots a reorganization of the hashtable is done and the utf 
319         symbols are copied to a new hashtable with doubled size.
320
321 ******************************************************************************/
322
323 utf *utf_new (char *text, u2 length)
324 {
325         u4 key;            /* hashkey computed from utf-text */
326         u4 slot;           /* slot in hashtable */
327         utf *u;            /* hashtable element */
328         u2 i;
329         
330 #ifdef STATISTICS
331         count_utf_new++;
332 #endif
333
334         key  = utf_hashkey (text, length);
335         slot = key & (utf_hash.size-1);
336         u    = utf_hash.ptr[slot];
337
338         /* search external hash chain for utf-symbol */
339         while (u) {
340                 if (u->blength == length) {
341
342                         /* compare text of hashtable elements */
343                         for (i=0; i<length; i++)
344                                 if (text[i] != u->text[i]) goto nomatch;
345                         
346 #ifdef STATISTICS
347                         count_utf_new_found++;
348 #endif
349                         /* symbol found in hashtable */                                 
350                         return u;
351                 }
352                 nomatch:
353                 u = u->hashlink; /* next element in external chain */
354         }
355
356 #ifdef STATISTICS
357         count_utf_len += sizeof(utf) + length;
358 #endif
359
360         /* location in hashtable found, create new utf element */
361         u = NEW (utf);
362         u->blength  = length;             /* length in bytes of utfstring */
363         u->hashlink = utf_hash.ptr[slot]; /* link in external hashchain   */            
364         u->text     = mem_alloc(length);  /* allocate memory for utf-text */
365         memcpy(u->text,text,length);      /* copy utf-text                */
366         utf_hash.ptr[slot] = u;           /* insert symbol into table     */ 
367
368         utf_hash.entries++;               /* update number of entries     */
369
370         if ( utf_hash.entries > (utf_hash.size*2)) { 
371
372         /* reorganization of hashtable, average length of 
373            the external chains is approx. 2                */  
374
375           u4 i;
376           utf *u;
377           hashtable newhash; /* the new hashtable */
378
379           /* create new hashtable, double the size */
380           init_hashtable(&newhash, utf_hash.size*2);
381           newhash.entries=utf_hash.entries;
382
383 #ifdef STATISTICS
384           count_utf_len += sizeof(utf*) * utf_hash.size;
385 #endif
386
387           /* transfer elements to new hashtable */
388           for (i=0; i<utf_hash.size; i++) {
389                 u = (utf*) utf_hash.ptr[i];
390                 while (u) {
391                         utf *nextu = u -> hashlink;
392                         u4 slot = (utf_hashkey(u->text,u->blength)) & (newhash.size-1);
393                                                 
394                         u->hashlink = (utf*) newhash.ptr[slot];
395                         newhash.ptr[slot] = u;
396
397                         /* follow link in external hash chain */
398                         u = nextu;
399                         }
400                 }
401         
402           /* dispose old table */
403           MFREE (utf_hash.ptr, void*, utf_hash.size);
404           utf_hash = newhash;
405         }
406         
407         return u;
408 }
409
410
411 /********************* function: utf_new_char ********************************
412
413     creates a new utf symbol, the text for this symbol is passed
414     as a c-string ( = char* )
415
416 ******************************************************************************/
417
418 utf *utf_new_char (char *text)
419 {
420         return utf_new(text, strlen(text));
421 }
422
423 /************************** Funktion: utf_show ******************************
424
425     writes the utf symbols in the utfhash to stdout and
426     displays the number of external hash chains grouped 
427     according to the chainlength
428     (debugging purposes)
429
430 *****************************************************************************/
431
432 void utf_show ()
433 {
434
435 #define CHAIN_LIMIT 20               /* limit for seperated enumeration */
436
437         u4 chain_count[CHAIN_LIMIT]; /* numbers of chains */
438         u4 max_chainlength = 0;      /* maximum length of the chains */
439         u4 sum_chainlength = 0;      /* sum of the chainlengths */
440         u4 beyond_limit = 0;         /* number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
441         u4 i;
442
443         printf ("UTF-HASH:\n");
444
445         /* show element of utf-hashtable */
446         for (i=0; i<utf_hash.size; i++) {
447                 utf *u = utf_hash.ptr[i];
448                 if (u) {
449                         printf ("SLOT %d: ", (int) i);
450                         while (u) {
451                                 printf ("'");
452                                 utf_display (u);
453                                 printf ("' ");
454                                 u = u->hashlink;
455                                 }       
456                         printf ("\n");
457                         }
458                 
459                 }
460
461         printf ("UTF-HASH: %d slots for %d entries\n", 
462                  (int) utf_hash.size, (int) utf_hash.entries );
463
464
465         if (utf_hash.entries == 0)
466                 return;
467
468         printf("chains:\n  chainlength    number of chains    %% of utfstrings\n");
469
470         for (i=0;i<CHAIN_LIMIT;i++)
471                 chain_count[i]=0;
472
473         /* count numbers of hashchains according to their length */
474         for (i=0; i<utf_hash.size; i++) {
475                   
476                 utf *u = (utf*) utf_hash.ptr[i];
477                 u4 chain_length = 0;
478
479                 /* determine chainlength */
480                 while (u) {
481                         u = u->hashlink;
482                         chain_length++;
483                         }
484
485                 /* update sum of all chainlengths */
486                 sum_chainlength+=chain_length;
487
488                 /* determine the maximum length of the chains */
489                 if (chain_length>max_chainlength)
490                         max_chainlength = chain_length;
491
492                 /* update number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
493                 if (chain_length>=CHAIN_LIMIT) {
494                         beyond_limit+=chain_length;
495                         chain_length=CHAIN_LIMIT-1;
496                 }
497
498                 /* update number of hashchains of current length */
499                 chain_count[chain_length]++;
500                 }
501
502         /* display results */  
503         for (i=1;i<CHAIN_LIMIT-1;i++) 
504                 printf("       %2d %17d %18.2f%%\n",i,chain_count[i],(((float) chain_count[i]*i*100)/utf_hash.entries));
505           
506         printf("     >=%2d %17d %18.2f%%\n",CHAIN_LIMIT-1,chain_count[CHAIN_LIMIT-1],((float) beyond_limit*100)/utf_hash.entries);
507
508
509         printf("max. chainlength:%5d\n",max_chainlength);
510
511         /* avg. chainlength = sum of chainlengths / number of chains */
512         printf("avg. chainlength:%5.2f\n",(float) sum_chainlength / (utf_hash.size-chain_count[0]));
513 }
514
515 /******************************************************************************
516 *********************** Misc support functions ********************************
517 ******************************************************************************/
518
519
520 /******************** Function: desc_to_type **********************************
521    
522         Determines the corresponding Java base data type for a given type
523         descriptor.
524         
525 ******************************************************************************/
526
527 u2 desc_to_type (utf *descriptor)
528 {
529         char *utf_ptr = descriptor->text;  /* current position in utf text */
530
531         if (descriptor->blength < 1) panic ("Type-Descriptor is empty string");
532         
533         switch (*utf_ptr++) {
534         case 'B': 
535         case 'C':
536         case 'I':
537         case 'S':  
538         case 'Z':  return TYPE_INT;
539         case 'D':  return TYPE_DOUBLE;
540         case 'F':  return TYPE_FLOAT;
541         case 'J':  return TYPE_LONG;
542         case 'L':
543         case '[':  return TYPE_ADDRESS;
544         }
545                         
546         sprintf (logtext, "Invalid Type-Descriptor: "); 
547         utf_sprint (logtext+strlen(logtext), descriptor);
548         error (); 
549         return 0;
550 }
551
552
553 /********************** Function: desc_typesize *******************************
554
555         Calculates the lenght in bytes needed for a data element of the type given
556         by its type descriptor.
557         
558 ******************************************************************************/
559
560 u2 desc_typesize (utf *descriptor)
561 {
562         switch (desc_to_type(descriptor)) {
563         case TYPE_INT:     return 4;
564         case TYPE_LONG:    return 8;
565         case TYPE_FLOAT:   return 4;
566         case TYPE_DOUBLE:  return 8;
567         case TYPE_ADDRESS: return sizeof(voidptr);
568         default:           return 0;
569         }
570 }
571
572
573 /********************** function: utf_nextu2 *********************************
574
575     read the next unicode character from the utf string and
576     increment the utf-string pointer accordingly
577
578 ******************************************************************************/
579
580 u2 utf_nextu2(char **utf_ptr) 
581 {
582     /* uncompressed unicode character */
583     u2 unicode_char;    
584     /* current position in utf text */  
585     unsigned char *utf = (unsigned char *) (*utf_ptr);  
586     /* bytes representing the unicode character */
587     unsigned char ch1, ch2, ch3;
588     /* number of bytes used to represent the unicode character */
589     int len;            
590         
591     switch ((ch1 = utf[0]) >> 4) {
592       default: /* 1 byte */
593                (*utf_ptr)++;
594                return ch1;
595        case 0xC: 
596        case 0xD: /* 2 bytes */
597                  if (((ch2 = utf[1]) & 0xC0) == 0x80) {
598                    unsigned char high = ch1 & 0x1F;
599                    unsigned char low  = ch2 & 0x3F;
600                    unicode_char = (high << 6) + low;
601                    len = 2;
602                  } 
603                  break;
604
605        case 0xE: /* 2 or 3 bytes */
606                  if (((ch2 = utf[1]) & 0xC0) == 0x80) {
607                     if (((ch3 = utf[2]) & 0xC0) == 0x80) {
608                        unsigned char low  = ch3 & 0x3f;
609                        unsigned char mid  = ch2 & 0x3f;
610                        unsigned char high = ch1 & 0x0f;
611                        unicode_char = (((high << 6) + mid) << 6) + low;
612                        len = 3;
613                     } else
614                        len = 2;                                    
615                  }
616                  break;
617     }
618
619     /* update position in utf-text */
620     *utf_ptr = (char *) (utf + len);
621     return unicode_char;
622 }
623  
624 /******************** Function: class_new **************************************
625
626     searches for the class with the specified name in the classes hashtable,
627     if there is no such class a new classinfo structure is created and inserted
628     into the list of classes to be loaded
629
630 *******************************************************************************/
631
632 classinfo *class_new (utf *u)
633 {
634         classinfo *c;     /* hashtable element */ 
635         u4 key;           /* hashkey computed from classname */   
636         u4 slot;          /* slot in hashtable */
637         u2 i;
638
639         key  = utf_hashkey (u->text, u->blength);
640         slot = key & (class_hash.size-1);
641         c    = class_hash.ptr[slot];
642
643         /* search external hash chain for the class */
644         while (c) {
645                 if (c->name->blength == u->blength) {
646                         for (i=0; i<u->blength; i++) 
647                                 if (u->text[i] != c->name->text[i]) goto nomatch;
648                                                 
649                                 /* class found in hashtable */                                                                  
650                                 return c;
651                         }
652                         
653                 nomatch:
654                 c = c->hashlink; /* next element in external chain */
655                 }
656
657         /* location in hashtable found, create new classinfo structure */
658
659 #ifdef STATISTICS
660         count_class_infos += sizeof(classinfo);
661 #endif
662
663         c = NEW (classinfo);
664         c -> flags = 0;
665         c -> name = u;
666         c -> cpcount = 0;
667         c -> cptags = NULL;
668         c -> cpinfos = NULL;
669         c -> super = NULL;
670         c -> sub = NULL;
671         c -> nextsub = NULL;
672         c -> interfacescount = 0;
673         c -> interfaces = NULL;
674         c -> fieldscount = 0;
675         c -> fields = NULL;
676         c -> methodscount = 0;
677         c -> methods = NULL;
678         c -> linked = false;
679         c -> index = 0;
680         c -> instancesize = 0;
681         c -> header.vftbl = NULL;
682         c -> innerclasscount = 0;
683         c -> innerclass = NULL;
684         c -> vftbl = NULL;
685         c -> initialized = false;
686         c -> classvftbl = false;
687         
688         /* prepare loading of the class */
689         list_addlast (&unloadedclasses, c);
690
691         /* insert class into the hashtable */
692         c->hashlink = class_hash.ptr[slot];
693         class_hash.ptr[slot] = c;
694
695         /* update number of hashtable-entries */
696         class_hash.entries++;
697
698         if ( class_hash.entries > (class_hash.size*2)) {  
699
700           /* reorganization of hashtable, average length of 
701              the external chains is approx. 2                */  
702
703           u4 i;
704           classinfo *c;
705           hashtable newhash;  /* the new hashtable */
706
707           /* create new hashtable, double the size */
708           init_hashtable(&newhash, class_hash.size*2);
709           newhash.entries = class_hash.entries;
710
711           /* transfer elements to new hashtable */
712           for (i=0; i<class_hash.size; i++) {
713                 c = (classinfo*) class_hash.ptr[i];
714                 while (c) {
715                         classinfo *nextc = c -> hashlink;
716                         u4 slot = (utf_hashkey(c->name->text,c->name->blength)) & (newhash.size-1);
717                                                 
718                         c->hashlink = newhash.ptr[slot];
719                         newhash.ptr[slot] = c;
720
721                         c = nextc;
722                         }
723                 }
724         
725           /* dispose old table */       
726           MFREE (class_hash.ptr, void*, class_hash.size);
727           class_hash = newhash;
728         }
729                         
730         return c;
731 }
732
733 /******************** Function: class_get **************************************
734
735     searches for the class with the specified name in the classes hashtable
736     if there is no such class NULL is returned
737
738 *******************************************************************************/
739
740 classinfo *class_get (utf *u)
741 {
742         classinfo *c;  /* hashtable element */ 
743         u4 key;        /* hashkey computed from classname */   
744         u4 slot;       /* slot in hashtable */
745         u2 i;  
746
747         key  = utf_hashkey (u->text, u->blength);
748         slot = key & (class_hash.size-1);
749         c    = class_hash.ptr[slot];
750
751         /* search external hash-chain */
752         while (c) {
753                 if (c->name->blength == u->blength) {
754                         
755                         /* compare classnames */
756                         for (i=0; i<u->blength; i++) 
757                                 if (u->text[i] != c->name->text[i]) goto nomatch;
758
759                         /* class found in hashtable */                          
760                         return c;
761                         }
762                         
763                 nomatch:
764                 c = c->hashlink;
765                 }
766
767         /* class not found */
768         return NULL;
769 }
770
771
772 /************************** function: utf_strlen ******************************
773
774     determine number of unicode characters in the utf string
775
776 *******************************************************************************/
777
778 u4 utf_strlen(utf *u) 
779 {
780     char *endpos  = utf_end(u);  /* points behind utf string       */
781     char *utf_ptr = u->text;     /* current position in utf text   */
782     u4 len = 0;                  /* number of unicode characters   */
783
784     while (utf_ptr<endpos) {
785       len++;
786       /* next unicode character */
787       utf_nextu2(&utf_ptr);
788     }
789
790     if (utf_ptr!=endpos)
791         /* string ended abruptly */
792         panic("illegal utf string"); 
793
794     return len;
795 }
796
797
798
799
800
801
802
803  
804
805  
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821