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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Reinhard Grafl
32 Contains support functions for:
33 - Reading of Java class files
36 - additional support functions
38 $Id: tables.c 881 2004-01-13 19:57:08Z edwin $
44 #include <sys/types.h>
52 #include "threads/thread.h"
53 #include "threads/locks.h"
54 #include "toolbox/loging.h"
55 #include "toolbox/memory.h"
59 int count_utf_len = 0; /* size of utf hash */
60 int count_utf_new = 0; /* calls of utf_new */
61 int count_utf_new_found = 0; /* calls of utf_new with fast return */
63 hashtable utf_hash; /* hashtable for utf8-symbols */
64 hashtable string_hash; /* hashtable for javastrings */
65 hashtable class_hash; /* hashtable for classes */
67 /******************************************************************************
68 *********************** hashtable functions **********************************
69 ******************************************************************************/
71 /* hashsize must be power of 2 */
73 #define UTF_HASHSTART 16384 /* initial size of utf-hash */
74 #define HASHSTART 2048 /* initial size of javastring and class-hash */
77 /******************** function: init_hashtable ******************************
79 Initializes a hashtable structure and allocates memory.
80 The parameter size specifies the initial size of the hashtable.
82 *****************************************************************************/
84 void init_hashtable(hashtable *hash, u4 size)
90 hash->ptr = MNEW(void*, size);
93 for (i = 0; i < size; i++) hash->ptr[i] = NULL;
96 /*********************** function: tables_init *****************************
98 creates hashtables for symboltables
99 (called once at startup)
101 *****************************************************************************/
105 init_hashtable(&utf_hash, UTF_HASHSTART); /* hashtable for utf8-symbols */
106 init_hashtable(&string_hash, HASHSTART); /* hashtable for javastrings */
107 init_hashtable(&class_hash, HASHSTART); /* hashtable for classes */
110 count_utf_len += sizeof(utf*) * utf_hash.size;
115 /********************** function: tables_close ******************************
117 free memory for hashtables
119 *****************************************************************************/
121 void tables_close (stringdeleter del)
127 /* dispose utf symbols */
128 for (i=0; i<utf_hash.size; i++) {
131 /* process elements in external hash chain */
132 utf *nextu = u->hashlink;
133 MFREE (u->text, u1, u->blength);
139 /* dispose javastrings */
140 for (i=0; i<string_hash.size; i++) {
141 s = string_hash.ptr[i];
143 /* process elements in external hash chain */
144 literalstring *nexts = s->hashlink;
146 FREE(s, literalstring);
151 /* dispose hashtable structures */
152 MFREE (utf_hash.ptr, void*, utf_hash.size);
153 MFREE (string_hash.ptr, void*, string_hash.size);
154 MFREE (class_hash.ptr, void*, class_hash.size);
158 /********************* function: utf_display *********************************
160 write utf symbol to stdout (debugging purposes)
162 ******************************************************************************/
164 void utf_display(utf *u)
166 char *endpos = utf_end(u); /* points behind utf string */
167 char *utf_ptr = u->text; /* current position in utf text */
172 while (utf_ptr < endpos) {
173 /* read next unicode character */
174 u2 c = utf_nextu2(&utf_ptr);
175 if (c >= 32 && c <= 127) printf("%c", c);
183 /************************* function: log_utf *********************************
187 ******************************************************************************/
191 char buf[MAXLOGTEXT];
196 /********************** function: log_plain_utf ******************************
198 log utf symbol (without printing "LOG: " and newline)
200 ******************************************************************************/
202 void log_plain_utf(utf *u)
204 char buf[MAXLOGTEXT];
206 dolog_plain("%s",buf);
209 /************************ function: utf_sprint *******************************
211 write utf symbol into c-string (debugging purposes)
213 ******************************************************************************/
215 void utf_sprint (char *buffer, utf *u)
217 char *endpos = utf_end(u); /* points behind utf string */
218 char *utf_ptr = u->text; /* current position in utf text */
219 u2 pos = 0; /* position in c-string */
221 while (utf_ptr<endpos)
222 /* copy next unicode character */
223 buffer[pos++] = utf_nextu2(&utf_ptr);
225 /* terminate string */
230 /********************* Funktion: utf_fprint **********************************
232 write utf symbol into file
234 ******************************************************************************/
236 void utf_fprint (FILE *file, utf *u)
238 char *endpos = utf_end(u); /* points behind utf string */
239 char *utf_ptr = u->text; /* current position in utf text */
241 while (utf_ptr<endpos) {
242 /* read next unicode character */
243 u2 c = utf_nextu2(&utf_ptr);
245 if (c>=32 && c<=127) fprintf (file,"%c",c);
246 else fprintf (file,"?");
251 /****************** internal function: utf_hashkey ***************************
253 The hashkey is computed from the utf-text by using up to 8 characters.
254 For utf-symbols longer than 15 characters 3 characters are taken from
255 the beginning and the end, 2 characters are taken from the middle.
257 ******************************************************************************/
259 #define nbs(val) ((u4) *(++text) << val) /* get next byte, left shift by val */
260 #define fbs(val) ((u4) *( text) << val) /* get first byte, left shift by val */
262 static u4 utf_hashkey (char *text, u4 length)
264 char *start_pos = text; /* pointer to utf text */
269 case 0: /* empty string */
272 case 1: return fbs(0);
273 case 2: return fbs(0) ^ nbs(3);
274 case 3: return fbs(0) ^ nbs(3) ^ nbs(5);
275 case 4: return fbs(0) ^ nbs(2) ^ nbs(4) ^ nbs(6);
276 case 5: return fbs(0) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(6);
277 case 6: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(5) ^ nbs(6);
278 case 7: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6);
279 case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7);
281 case 9: a = fbs(0) ^ nbs(1) ^ nbs(2);
283 return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8);
287 a^= nbs(2) ^ nbs(3) ^ nbs(4);
289 return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9);
293 a^= nbs(2) ^ nbs(3) ^ nbs(4);
295 return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10);
301 a^= nbs(5) ^ nbs(6) ^ nbs(7);
303 return a ^ nbs(9) ^ nbs(10);
305 case 13: a = fbs(0) ^ nbs(1);
311 return a ^ nbs(9) ^ nbs(10);
319 return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
327 return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
329 default: /* 3 characters from beginning */
334 /* 2 characters from middle */
335 text = start_pos + (length / 2);
340 /* 3 characters from end */
341 text = start_pos + length - 4;
346 return a ^ nbs(10) ^ nbs(11);
351 /*************************** function: utf_hashkey ***************************
353 compute the hashkey of a unicode string
355 ******************************************************************************/
357 u4 unicode_hashkey (u2 *text, u2 len)
359 return utf_hashkey((char*) text, len);
362 /************************ function: utf_new **********************************
364 Creates a new utf-symbol, the text of the symbol is passed as a
365 u1-array. The function searches the utf-hashtable for a utf-symbol
366 with this text. On success the element returned, otherwise a new
367 hashtable element is created.
369 If the number of entries in the hashtable exceeds twice the size of the
370 hashtable slots a reorganization of the hashtable is done and the utf
371 symbols are copied to a new hashtable with doubled size.
373 ******************************************************************************/
375 utf *utf_new (char *text, u2 length)
377 u4 key; /* hashkey computed from utf-text */
378 u4 slot; /* slot in hashtable */
379 utf *u; /* hashtable element */
382 /* log_text("utf_new entered");*/
387 key = utf_hashkey (text, length);
388 slot = key & (utf_hash.size-1);
389 u = utf_hash.ptr[slot];
391 /* search external hash chain for utf-symbol */
393 if (u->blength == length) {
395 /* compare text of hashtable elements */
396 for (i=0; i<length; i++)
397 if (text[i] != u->text[i]) goto nomatch;
400 count_utf_new_found++;
402 /* log_text("symbol found in hash table");*/
403 /* symbol found in hashtable */
414 u = u->hashlink; /* next element in external chain */
418 count_utf_len += sizeof(utf) + length;
421 /* location in hashtable found, create new utf element */
423 u->blength = length; /* length in bytes of utfstring */
424 u->hashlink = utf_hash.ptr[slot]; /* link in external hashchain */
425 u->text = mem_alloc(length/*JOWENN*/+1); /* allocate memory for utf-text */
426 memcpy(u->text,text,length); /* copy utf-text */
427 u->text[length]='\0';/*JOWENN*/
428 utf_hash.ptr[slot] = u; /* insert symbol into table */
430 utf_hash.entries++; /* update number of entries */
432 if ( utf_hash.entries > (utf_hash.size*2)) {
434 /* reorganization of hashtable, average length of
435 the external chains is approx. 2 */
439 hashtable newhash; /* the new hashtable */
441 /* create new hashtable, double the size */
442 init_hashtable(&newhash, utf_hash.size*2);
443 newhash.entries=utf_hash.entries;
446 count_utf_len += sizeof(utf*) * utf_hash.size;
449 /* transfer elements to new hashtable */
450 for (i=0; i<utf_hash.size; i++) {
451 u = (utf*) utf_hash.ptr[i];
453 utf *nextu = u -> hashlink;
454 u4 slot = (utf_hashkey(u->text,u->blength)) & (newhash.size-1);
456 u->hashlink = (utf*) newhash.ptr[slot];
457 newhash.ptr[slot] = u;
459 /* follow link in external hash chain */
464 /* dispose old table */
465 MFREE (utf_hash.ptr, void*, utf_hash.size);
473 /********************* function: utf_new_char ********************************
475 creates a new utf symbol, the text for this symbol is passed
476 as a c-string ( = char* )
478 ******************************************************************************/
480 utf *utf_new_char (char *text)
482 return utf_new(text, strlen(text));
486 /********************* function: utf_new_char ********************************
488 creates a new utf symbol, the text for this symbol is passed
489 as a c-string ( = char* )
490 "." characters are going to be replaced by "/". since the above function is
491 used often, this is a separte function, instead of an if
493 ******************************************************************************/
495 utf *utf_new_char_classname (char *text)
497 if (strchr(text,'.')) {
498 char *txt=strdup(text);
499 char *end=txt+strlen(txt);
502 for (c=txt;c<end;c++)
504 tmpRes=utf_new(txt,strlen(txt));
509 return utf_new(text, strlen(text));
512 /************************** Funktion: utf_show ******************************
514 writes the utf symbols in the utfhash to stdout and
515 displays the number of external hash chains grouped
516 according to the chainlength
519 *****************************************************************************/
524 #define CHAIN_LIMIT 20 /* limit for seperated enumeration */
526 u4 chain_count[CHAIN_LIMIT]; /* numbers of chains */
527 u4 max_chainlength = 0; /* maximum length of the chains */
528 u4 sum_chainlength = 0; /* sum of the chainlengths */
529 u4 beyond_limit = 0; /* number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
532 printf ("UTF-HASH:\n");
534 /* show element of utf-hashtable */
535 for (i=0; i<utf_hash.size; i++) {
536 utf *u = utf_hash.ptr[i];
538 printf ("SLOT %d: ", (int) i);
550 printf ("UTF-HASH: %d slots for %d entries\n",
551 (int) utf_hash.size, (int) utf_hash.entries );
554 if (utf_hash.entries == 0)
557 printf("chains:\n chainlength number of chains %% of utfstrings\n");
559 for (i=0;i<CHAIN_LIMIT;i++)
562 /* count numbers of hashchains according to their length */
563 for (i=0; i<utf_hash.size; i++) {
565 utf *u = (utf*) utf_hash.ptr[i];
568 /* determine chainlength */
574 /* update sum of all chainlengths */
575 sum_chainlength+=chain_length;
577 /* determine the maximum length of the chains */
578 if (chain_length>max_chainlength)
579 max_chainlength = chain_length;
581 /* update number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
582 if (chain_length>=CHAIN_LIMIT) {
583 beyond_limit+=chain_length;
584 chain_length=CHAIN_LIMIT-1;
587 /* update number of hashchains of current length */
588 chain_count[chain_length]++;
591 /* display results */
592 for (i=1;i<CHAIN_LIMIT-1;i++)
593 printf(" %2d %17d %18.2f%%\n",i,chain_count[i],(((float) chain_count[i]*i*100)/utf_hash.entries));
595 printf(" >=%2d %17d %18.2f%%\n",CHAIN_LIMIT-1,chain_count[CHAIN_LIMIT-1],((float) beyond_limit*100)/utf_hash.entries);
598 printf("max. chainlength:%5d\n",max_chainlength);
600 /* avg. chainlength = sum of chainlengths / number of chains */
601 printf("avg. chainlength:%5.2f\n",(float) sum_chainlength / (utf_hash.size-chain_count[0]));
604 /******************************************************************************
605 *********************** Misc support functions ********************************
606 ******************************************************************************/
609 /******************** Function: desc_to_type **********************************
611 Determines the corresponding Java base data type for a given type
614 ******************************************************************************/
616 u2 desc_to_type(utf *descriptor)
618 char *utf_ptr = descriptor->text; /* current position in utf text */
619 char logtext[MAXLOGTEXT];
621 if (descriptor->blength < 1) panic("Type-Descriptor is empty string");
623 switch (*utf_ptr++) {
628 case 'Z': return TYPE_INT;
629 case 'D': return TYPE_DOUBLE;
630 case 'F': return TYPE_FLOAT;
631 case 'J': return TYPE_LONG;
633 case '[': return TYPE_ADDRESS;
636 sprintf(logtext, "Invalid Type-Descriptor: ");
637 utf_sprint(logtext+strlen(logtext), descriptor);
644 /********************** Function: desc_typesize *******************************
646 Calculates the lenght in bytes needed for a data element of the type given
647 by its type descriptor.
649 ******************************************************************************/
651 u2 desc_typesize (utf *descriptor)
653 switch (desc_to_type(descriptor)) {
654 case TYPE_INT: return 4;
655 case TYPE_LONG: return 8;
656 case TYPE_FLOAT: return 4;
657 case TYPE_DOUBLE: return 8;
658 case TYPE_ADDRESS: return sizeof(voidptr);
664 /********************** function: utf_nextu2 *********************************
666 read the next unicode character from the utf string and
667 increment the utf-string pointer accordingly
669 ******************************************************************************/
671 u2 utf_nextu2(char **utf_ptr)
673 /* uncompressed unicode character */
675 /* current position in utf text */
676 unsigned char *utf = (unsigned char *) (*utf_ptr);
677 /* bytes representing the unicode character */
678 unsigned char ch1, ch2, ch3;
679 /* number of bytes used to represent the unicode character */
682 switch ((ch1 = utf[0]) >> 4) {
683 default: /* 1 byte */
687 case 0xD: /* 2 bytes */
688 if (((ch2 = utf[1]) & 0xC0) == 0x80) {
689 unsigned char high = ch1 & 0x1F;
690 unsigned char low = ch2 & 0x3F;
691 unicode_char = (high << 6) + low;
696 case 0xE: /* 2 or 3 bytes */
697 if (((ch2 = utf[1]) & 0xC0) == 0x80) {
698 if (((ch3 = utf[2]) & 0xC0) == 0x80) {
699 unsigned char low = ch3 & 0x3f;
700 unsigned char mid = ch2 & 0x3f;
701 unsigned char high = ch1 & 0x0f;
702 unicode_char = (((high << 6) + mid) << 6) + low;
710 /* update position in utf-text */
711 *utf_ptr = (char *) (utf + len);
715 /********************* function: is_valid_utf ********************************
717 return true if the given string is a valid UTF-8 string
719 utf_ptr...points to first character
720 end_pos...points after last character
722 ******************************************************************************/
724 static unsigned long min_codepoint[6] = {0,1L<<7,1L<<11,1L<<16,1L<<21,1L<<26};
727 is_valid_utf(char *utf_ptr,char *end_pos)
734 if (end_pos < utf_ptr) return false;
735 bytes = end_pos - utf_ptr;
738 /*dolog("%c %02x",c,c);*/
739 if (!c) return false; /* 0x00 is not allowed */
740 if ((c & 0x80) == 0) continue; /* ASCII */
742 if ((c & 0xe0) == 0xc0) len = 1; /* 110x xxxx */
743 else if ((c & 0xf0) == 0xe0) len = 2; /* 1110 xxxx */
744 else if ((c & 0xf8) == 0xf0) len = 3; /* 1111 0xxx */
745 else if ((c & 0xfc) == 0xf8) len = 4; /* 1111 10xx */
746 else if ((c & 0xfe) == 0xfc) len = 5; /* 1111 110x */
747 else return false; /* invalid leading byte */
749 if (len > 2) return false; /* Java limitation */
751 v = (unsigned long)c & (0x3f >> len);
753 if ((bytes -= len) < 0) return false; /* missing bytes */
755 for (i = len; i--; ) {
757 /*dolog(" %c %02x",c,c);*/
758 if ((c & 0xc0) != 0x80) /* 10xx xxxx */
760 v = (v<<6) | (c & 0x3f);
763 /* dolog("v=%d",v);*/
766 if (len != 1) return false; /* Java special */
769 /* XXX Sun Java seems to allow overlong UTF-8 encodings */
770 /* if (v < min_codepoint[len]) return false; */ /* overlong UTF-8 */
773 /* surrogates in UTF-8 seem to be allowed in Java classfiles */
774 /* if (v >= 0xd800 && v <= 0xdfff) return false; */ /* surrogates */
776 /* even these seem to be allowed */
777 /* if (v == 0xfffe || v == 0xffff) return false; */ /* invalid codepoints */
783 /********************* function: is_valid_name *******************************
785 return true if the given string may be used as a class/field/method name.
786 (Currently this only disallows empty strings and control characters.)
788 NOTE: The string is assumed to have passed is_valid_utf!
790 utf_ptr...points to first character
791 end_pos...points after last character
793 ******************************************************************************/
796 is_valid_name(char *utf_ptr,char *end_pos)
798 if (end_pos <= utf_ptr) return false; /* disallow empty names */
800 while (utf_ptr < end_pos) {
801 unsigned char c = *utf_ptr++;
803 if (c < 0x20) return false; /* disallow control characters */
804 if (c == 0xc0 && (unsigned char)*utf_ptr == 0x80) return false; /* disallow zero */
810 is_valid_name_utf(utf *u)
812 return is_valid_name(u->text,utf_end(u));
815 /******************** Function: class_new **************************************
817 searches for the class with the specified name in the classes hashtable,
818 if there is no such class a new classinfo structure is created and inserted
819 into the list of classes to be loaded
821 *******************************************************************************/
823 classinfo *class_new(utf *u)
825 classinfo *c; /* hashtable element */
826 u4 key; /* hashkey computed from classname */
827 u4 slot; /* slot in hashtable */
830 key = utf_hashkey (u->text, u->blength);
831 slot = key & (class_hash.size-1);
832 c = class_hash.ptr[slot];
834 /* search external hash chain for the class */
836 if (c->name->blength == u->blength) {
837 for (i=0; i<u->blength; i++)
838 if (u->text[i] != c->name->text[i]) goto nomatch;
840 /* class found in hashtable */
845 c = c->hashlink; /* next element in external chain */
848 /* location in hashtable found, create new classinfo structure */
851 count_class_infos += sizeof(classinfo);
854 c = GCNEW(classinfo, 1); /*JOWENN: NEW*/
858 c->packagename = NULL;
865 c->interfacescount = 0;
866 c->interfaces = NULL;
875 c->header.vftbl = NULL;
876 c->innerclasscount = 0;
877 c->innerclass = NULL;
879 c->initialized = false;
880 c->classvftbl = false;
884 /* prepare loading of the class */
885 list_addlast(&unloadedclasses, c);
887 /* insert class into the hashtable */
888 c->hashlink = class_hash.ptr[slot];
889 class_hash.ptr[slot] = c;
891 /* update number of hashtable-entries */
892 class_hash.entries++;
894 if (class_hash.entries > (class_hash.size*2)) {
896 /* reorganization of hashtable, average length of
897 the external chains is approx. 2 */
901 hashtable newhash; /* the new hashtable */
903 /* create new hashtable, double the size */
904 init_hashtable(&newhash, class_hash.size * 2);
905 newhash.entries = class_hash.entries;
907 /* transfer elements to new hashtable */
908 for (i = 0; i < class_hash.size; i++) {
909 c = (classinfo*) class_hash.ptr[i];
911 classinfo *nextc = c->hashlink;
912 u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
914 c->hashlink = newhash.ptr[slot];
915 newhash.ptr[slot] = c;
921 /* dispose old table */
922 MFREE(class_hash.ptr, void*, class_hash.size);
923 class_hash = newhash;
926 /* Array classes need further initialization. */
927 if (u->text[0] == '[') {
929 c->packagename = array_packagename;
932 /* Find the package name */
933 /* Classes in the unnamed package keep packagename == NULL. */
934 char *p = utf_end(c->name) - 1;
935 char *start = c->name->text;
936 for (;p > start; --p)
938 c->packagename = utf_new(start,p-start);
946 /******************** Function: class_get **************************************
948 searches for the class with the specified name in the classes hashtable
949 if there is no such class NULL is returned
951 *******************************************************************************/
953 classinfo *class_get(utf *u)
955 classinfo *c; /* hashtable element */
956 u4 key; /* hashkey computed from classname */
957 u4 slot; /* slot in hashtable */
960 key = utf_hashkey (u->text, u->blength);
961 slot = key & (class_hash.size-1);
962 c = class_hash.ptr[slot];
965 log_text("class_get: looking for class:");
967 /* search external hash-chain */
969 if (c->name->blength == u->blength) {
971 /* compare classnames */
972 for (i=0; i<u->blength; i++)
973 if (u->text[i] != c->name->text[i]) goto nomatch;
975 log_text("class_get: class found");
978 utf_display(c->name); */
979 /* class found in hashtable */
987 /* class not found */
991 /***************** Function: class_array_of ***********************************
993 Returns an array class with the given component class.
994 The array class is dynamically created if neccessary.
996 *******************************************************************************/
998 classinfo *class_array_of(classinfo *component)
1003 /* Assemble the array class name */
1004 namelen = component->name->blength;
1006 if (component->name->text[0] == '[') {
1007 /* the component is itself an array */
1008 namebuf = DMNEW(char,namelen+1);
1010 memcpy(namebuf+1,component->name->text,namelen);
1014 /* the component is a non-array class */
1015 namebuf = DMNEW(char,namelen+3);
1018 memcpy(namebuf+2,component->name->text,namelen);
1019 namebuf[2+namelen] = ';';
1023 return class_new( utf_new(namebuf,namelen) );
1026 /*************** Function: class_multiarray_of ********************************
1028 Returns an array class with the given dimension and element class.
1029 The array class is dynamically created if neccessary.
1031 *******************************************************************************/
1033 classinfo *class_multiarray_of(int dim,classinfo *element)
1039 panic("Invalid array dimension requested");
1041 /* Assemble the array class name */
1042 namelen = element->name->blength;
1044 if (element->name->text[0] == '[') {
1045 /* the element is itself an array */
1046 namebuf = DMNEW(char,namelen+dim);
1047 memcpy(namebuf+dim,element->name->text,namelen);
1051 /* the element is a non-array class */
1052 namebuf = DMNEW(char,namelen+2+dim);
1054 memcpy(namebuf+dim+1,element->name->text,namelen);
1056 namebuf[namelen-1] = ';';
1058 memset(namebuf,'[',dim);
1060 return class_new( utf_new(namebuf,namelen) );
1063 /************************** function: utf_strlen ******************************
1065 determine number of unicode characters in the utf string
1067 *******************************************************************************/
1069 u4 utf_strlen(utf *u)
1071 char *endpos = utf_end(u); /* points behind utf string */
1072 char *utf_ptr = u->text; /* current position in utf text */
1073 u4 len = 0; /* number of unicode characters */
1075 while (utf_ptr<endpos) {
1077 /* next unicode character */
1078 utf_nextu2(&utf_ptr);
1081 if (utf_ptr!=endpos)
1082 /* string ended abruptly */
1083 panic("illegal utf string");
1090 * These are local overrides for various environment variables in Emacs.
1091 * Please do not remove this and leave it at the end of the file, where
1092 * Emacs will automagically detect them.
1093 * ---------------------------------------------------------------------
1096 * indent-tabs-mode: t