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 1012 2004-04-06 20:30:19Z stefan $
46 #include <sys/types.h>
54 #include "threads/thread.h"
55 #include "threads/locks.h"
56 #include "toolbox/loging.h"
57 #include "toolbox/memory.h"
61 int count_utf_len = 0; /* size of utf hash */
62 int count_utf_new = 0; /* calls of utf_new */
63 int count_utf_new_found = 0; /* calls of utf_new with fast return */
65 hashtable utf_hash; /* hashtable for utf8-symbols */
66 hashtable string_hash; /* hashtable for javastrings */
67 hashtable class_hash; /* hashtable for classes */
69 /******************************************************************************
70 *********************** hashtable functions **********************************
71 ******************************************************************************/
73 /* hashsize must be power of 2 */
75 #define UTF_HASHSTART 16384 /* initial size of utf-hash */
76 #define HASHSTART 2048 /* initial size of javastring and class-hash */
79 /******************** function: init_hashtable ******************************
81 Initializes a hashtable structure and allocates memory.
82 The parameter size specifies the initial size of the hashtable.
84 *****************************************************************************/
86 void init_hashtable(hashtable *hash, u4 size)
92 hash->ptr = MNEW(void*, size);
95 for (i = 0; i < size; i++) hash->ptr[i] = NULL;
99 /*********************** function: tables_init *****************************
101 creates hashtables for symboltables
102 (called once at startup)
104 *****************************************************************************/
108 init_hashtable(&utf_hash, UTF_HASHSTART); /* hashtable for utf8-symbols */
109 init_hashtable(&string_hash, HASHSTART); /* hashtable for javastrings */
110 init_hashtable(&class_hash, HASHSTART); /* hashtable for classes */
113 count_utf_len += sizeof(utf*) * utf_hash.size;
119 /********************** function: tables_close ******************************
121 free memory for hashtables
123 *****************************************************************************/
125 void tables_close(stringdeleter del)
131 /* dispose utf symbols */
132 for (i = 0; i < utf_hash.size; i++) {
135 /* process elements in external hash chain */
136 utf *nextu = u->hashlink;
137 MFREE(u->text, u1, u->blength);
143 /* dispose javastrings */
144 for (i = 0; i < string_hash.size; i++) {
145 s = string_hash.ptr[i];
147 /* process elements in external hash chain */
148 literalstring *nexts = s->hashlink;
150 FREE(s, literalstring);
155 /* dispose hashtable structures */
156 MFREE(utf_hash.ptr, void*, utf_hash.size);
157 MFREE(string_hash.ptr, void*, string_hash.size);
158 MFREE(class_hash.ptr, void*, class_hash.size);
162 /********************* function: utf_display *********************************
164 write utf symbol to stdout (debugging purposes)
166 ******************************************************************************/
168 void utf_display(utf *u)
170 char *endpos = utf_end(u); /* points behind utf string */
171 char *utf_ptr = u->text; /* current position in utf text */
176 while (utf_ptr < endpos) {
177 /* read next unicode character */
178 u2 c = utf_nextu2(&utf_ptr);
179 if (c >= 32 && c <= 127) printf("%c", c);
187 /********************* function: utf_display *********************************
189 write utf symbol to stdout (debugging purposes)
191 ******************************************************************************/
193 void utf_display_classname(utf *u)
195 char *endpos = utf_end(u); /* points behind utf string */
196 char *utf_ptr = u->text; /* current position in utf text */
201 while (utf_ptr < endpos) {
202 /* read next unicode character */
203 u2 c = utf_nextu2(&utf_ptr);
204 if (c == '/') c = '.';
205 if (c >= 32 && c <= 127) printf("%c", c);
213 /************************* function: log_utf *********************************
217 ******************************************************************************/
221 char buf[MAXLOGTEXT];
227 /********************** function: log_plain_utf ******************************
229 log utf symbol (without printing "LOG: " and newline)
231 ******************************************************************************/
233 void log_plain_utf(utf *u)
235 char buf[MAXLOGTEXT];
237 dolog_plain("%s", buf);
241 /************************ function: utf_sprint *******************************
243 write utf symbol into c-string (debugging purposes)
245 ******************************************************************************/
247 void utf_sprint(char *buffer, utf *u)
249 char *endpos = utf_end(u); /* points behind utf string */
250 char *utf_ptr = u->text; /* current position in utf text */
251 u2 pos = 0; /* position in c-string */
253 while (utf_ptr < endpos)
254 /* copy next unicode character */
255 buffer[pos++] = utf_nextu2(&utf_ptr);
257 /* terminate string */
262 /********************* Funktion: utf_fprint **********************************
264 write utf symbol into file
266 ******************************************************************************/
268 void utf_fprint(FILE *file, utf *u)
270 char *endpos = utf_end(u); /* points behind utf string */
271 char *utf_ptr = u->text; /* current position in utf text */
276 while (utf_ptr < endpos) {
277 /* read next unicode character */
278 u2 c = utf_nextu2(&utf_ptr);
280 if (c >= 32 && c <= 127) fprintf(file, "%c", c);
281 else fprintf(file, "?");
286 /****************** internal function: utf_hashkey ***************************
288 The hashkey is computed from the utf-text by using up to 8 characters.
289 For utf-symbols longer than 15 characters 3 characters are taken from
290 the beginning and the end, 2 characters are taken from the middle.
292 ******************************************************************************/
294 #define nbs(val) ((u4) *(++text) << val) /* get next byte, left shift by val */
295 #define fbs(val) ((u4) *( text) << val) /* get first byte, left shift by val */
297 static u4 utf_hashkey(char *text, u4 length)
299 char *start_pos = text; /* pointer to utf text */
304 case 0: /* empty string */
307 case 1: return fbs(0);
308 case 2: return fbs(0) ^ nbs(3);
309 case 3: return fbs(0) ^ nbs(3) ^ nbs(5);
310 case 4: return fbs(0) ^ nbs(2) ^ nbs(4) ^ nbs(6);
311 case 5: return fbs(0) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(6);
312 case 6: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(5) ^ nbs(6);
313 case 7: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6);
314 case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7);
321 return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8);
330 return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9);
339 return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10);
351 return a ^ nbs(9) ^ nbs(10);
363 return a ^ nbs(9) ^ nbs(10);
374 return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
385 return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
387 default: /* 3 characters from beginning */
393 /* 2 characters from middle */
394 text = start_pos + (length / 2);
399 /* 3 characters from end */
400 text = start_pos + length - 4;
405 return a ^ nbs(10) ^ nbs(11);
410 /*************************** function: utf_hashkey ***************************
412 compute the hashkey of a unicode string
414 ******************************************************************************/
416 u4 unicode_hashkey(u2 *text, u2 len)
418 return utf_hashkey((char*) text, len);
422 /************************ function: utf_new **********************************
424 Creates a new utf-symbol, the text of the symbol is passed as a
425 u1-array. The function searches the utf-hashtable for a utf-symbol
426 with this text. On success the element returned, otherwise a new
427 hashtable element is created.
429 If the number of entries in the hashtable exceeds twice the size of the
430 hashtable slots a reorganization of the hashtable is done and the utf
431 symbols are copied to a new hashtable with doubled size.
433 ******************************************************************************/
435 utf *utf_new_int(char *text, u2 length)
437 u4 key; /* hashkey computed from utf-text */
438 u4 slot; /* slot in hashtable */
439 utf *u; /* hashtable element */
442 /* log_text("utf_new entered");*/
447 key = utf_hashkey(text, length);
448 slot = key & (utf_hash.size-1);
449 u = utf_hash.ptr[slot];
451 /* search external hash chain for utf-symbol */
453 if (u->blength == length) {
455 /* compare text of hashtable elements */
456 for (i = 0; i < length; i++)
457 if (text[i] != u->text[i]) goto nomatch;
460 count_utf_new_found++;
462 /* log_text("symbol found in hash table");*/
463 /* symbol found in hashtable */
474 u = u->hashlink; /* next element in external chain */
478 count_utf_len += sizeof(utf) + length;
481 /* location in hashtable found, create new utf element */
483 u->blength = length; /* length in bytes of utfstring */
484 u->hashlink = utf_hash.ptr[slot]; /* link in external hashchain */
485 u->text = mem_alloc(length/*JOWENN*/+1); /* allocate memory for utf-text */
486 memcpy(u->text,text,length); /* copy utf-text */
487 u->text[length] = '\0';/*JOWENN*/
488 utf_hash.ptr[slot] = u; /* insert symbol into table */
490 utf_hash.entries++; /* update number of entries */
492 if (utf_hash.entries > (utf_hash.size * 2)) {
494 /* reorganization of hashtable, average length of
495 the external chains is approx. 2 */
499 hashtable newhash; /* the new hashtable */
501 /* create new hashtable, double the size */
502 init_hashtable(&newhash, utf_hash.size * 2);
503 newhash.entries = utf_hash.entries;
506 count_utf_len += sizeof(utf*) * utf_hash.size;
509 /* transfer elements to new hashtable */
510 for (i = 0; i < utf_hash.size; i++) {
511 u = (utf *) utf_hash.ptr[i];
513 utf *nextu = u->hashlink;
514 u4 slot = utf_hashkey(u->text, u->blength) & (newhash.size - 1);
516 u->hashlink = (utf *) newhash.ptr[slot];
517 newhash.ptr[slot] = u;
519 /* follow link in external hash chain */
524 /* dispose old table */
525 MFREE(utf_hash.ptr, void*, utf_hash.size);
532 utf *utf_new(char *text, u2 length)
535 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
538 r = utf_new_int(text, length);
539 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
546 /********************* function: utf_new_char ********************************
548 creates a new utf symbol, the text for this symbol is passed
549 as a c-string ( = char* )
551 ******************************************************************************/
553 utf *utf_new_char(char *text)
555 return utf_new(text, strlen(text));
559 /********************* function: utf_new_char ********************************
561 creates a new utf symbol, the text for this symbol is passed
562 as a c-string ( = char* )
563 "." characters are going to be replaced by "/". since the above function is
564 used often, this is a separte function, instead of an if
566 ******************************************************************************/
568 utf *utf_new_char_classname(char *text)
570 if (strchr(text, '.')) {
571 char *txt = strdup(text);
572 char *end = txt + strlen(txt);
575 for (c = txt; c < end; c++)
576 if (*c == '.') *c = '/';
577 tmpRes = utf_new(txt, strlen(txt));
582 return utf_new(text, strlen(text));
586 /************************** Funktion: utf_show ******************************
588 writes the utf symbols in the utfhash to stdout and
589 displays the number of external hash chains grouped
590 according to the chainlength
593 *****************************************************************************/
598 #define CHAIN_LIMIT 20 /* limit for seperated enumeration */
600 u4 chain_count[CHAIN_LIMIT]; /* numbers of chains */
601 u4 max_chainlength = 0; /* maximum length of the chains */
602 u4 sum_chainlength = 0; /* sum of the chainlengths */
603 u4 beyond_limit = 0; /* number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
606 printf ("UTF-HASH:\n");
608 /* show element of utf-hashtable */
609 for (i=0; i<utf_hash.size; i++) {
610 utf *u = utf_hash.ptr[i];
612 printf ("SLOT %d: ", (int) i);
624 printf ("UTF-HASH: %d slots for %d entries\n",
625 (int) utf_hash.size, (int) utf_hash.entries );
628 if (utf_hash.entries == 0)
631 printf("chains:\n chainlength number of chains %% of utfstrings\n");
633 for (i=0;i<CHAIN_LIMIT;i++)
636 /* count numbers of hashchains according to their length */
637 for (i=0; i<utf_hash.size; i++) {
639 utf *u = (utf*) utf_hash.ptr[i];
642 /* determine chainlength */
648 /* update sum of all chainlengths */
649 sum_chainlength+=chain_length;
651 /* determine the maximum length of the chains */
652 if (chain_length>max_chainlength)
653 max_chainlength = chain_length;
655 /* update number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
656 if (chain_length>=CHAIN_LIMIT) {
657 beyond_limit+=chain_length;
658 chain_length=CHAIN_LIMIT-1;
661 /* update number of hashchains of current length */
662 chain_count[chain_length]++;
665 /* display results */
666 for (i=1;i<CHAIN_LIMIT-1;i++)
667 printf(" %2d %17d %18.2f%%\n",i,chain_count[i],(((float) chain_count[i]*i*100)/utf_hash.entries));
669 printf(" >=%2d %17d %18.2f%%\n",CHAIN_LIMIT-1,chain_count[CHAIN_LIMIT-1],((float) beyond_limit*100)/utf_hash.entries);
672 printf("max. chainlength:%5d\n",max_chainlength);
674 /* avg. chainlength = sum of chainlengths / number of chains */
675 printf("avg. chainlength:%5.2f\n",(float) sum_chainlength / (utf_hash.size-chain_count[0]));
678 /******************************************************************************
679 *********************** Misc support functions ********************************
680 ******************************************************************************/
683 /******************** Function: desc_to_type **********************************
685 Determines the corresponding Java base data type for a given type
688 ******************************************************************************/
690 u2 desc_to_type(utf *descriptor)
692 char *utf_ptr = descriptor->text; /* current position in utf text */
693 char logtext[MAXLOGTEXT];
695 if (descriptor->blength < 1) panic("Type-Descriptor is empty string");
697 switch (*utf_ptr++) {
702 case 'Z': return TYPE_INT;
703 case 'D': return TYPE_DOUBLE;
704 case 'F': return TYPE_FLOAT;
705 case 'J': return TYPE_LONG;
707 case '[': return TYPE_ADDRESS;
710 sprintf(logtext, "Invalid Type-Descriptor: ");
711 utf_sprint(logtext+strlen(logtext), descriptor);
718 /********************** Function: desc_typesize *******************************
720 Calculates the lenght in bytes needed for a data element of the type given
721 by its type descriptor.
723 ******************************************************************************/
725 u2 desc_typesize(utf *descriptor)
727 switch (desc_to_type(descriptor)) {
728 case TYPE_INT: return 4;
729 case TYPE_LONG: return 8;
730 case TYPE_FLOAT: return 4;
731 case TYPE_DOUBLE: return 8;
732 case TYPE_ADDRESS: return sizeof(voidptr);
738 /********************** function: utf_nextu2 *********************************
740 read the next unicode character from the utf string and
741 increment the utf-string pointer accordingly
743 ******************************************************************************/
745 u2 utf_nextu2(char **utf_ptr)
747 /* uncompressed unicode character */
749 /* current position in utf text */
750 unsigned char *utf = (unsigned char *) (*utf_ptr);
751 /* bytes representing the unicode character */
752 unsigned char ch1, ch2, ch3;
753 /* number of bytes used to represent the unicode character */
756 switch ((ch1 = utf[0]) >> 4) {
757 default: /* 1 byte */
761 case 0xD: /* 2 bytes */
762 if (((ch2 = utf[1]) & 0xC0) == 0x80) {
763 unsigned char high = ch1 & 0x1F;
764 unsigned char low = ch2 & 0x3F;
765 unicode_char = (high << 6) + low;
770 case 0xE: /* 2 or 3 bytes */
771 if (((ch2 = utf[1]) & 0xC0) == 0x80) {
772 if (((ch3 = utf[2]) & 0xC0) == 0x80) {
773 unsigned char low = ch3 & 0x3f;
774 unsigned char mid = ch2 & 0x3f;
775 unsigned char high = ch1 & 0x0f;
776 unicode_char = (((high << 6) + mid) << 6) + low;
784 /* update position in utf-text */
785 *utf_ptr = (char *) (utf + len);
790 /********************* function: is_valid_utf ********************************
792 return true if the given string is a valid UTF-8 string
794 utf_ptr...points to first character
795 end_pos...points after last character
797 ******************************************************************************/
799 static unsigned long min_codepoint[6] = {0,1L<<7,1L<<11,1L<<16,1L<<21,1L<<26};
802 is_valid_utf(char *utf_ptr,char *end_pos)
809 if (end_pos < utf_ptr) return false;
810 bytes = end_pos - utf_ptr;
813 /*dolog("%c %02x",c,c);*/
814 if (!c) return false; /* 0x00 is not allowed */
815 if ((c & 0x80) == 0) continue; /* ASCII */
817 if ((c & 0xe0) == 0xc0) len = 1; /* 110x xxxx */
818 else if ((c & 0xf0) == 0xe0) len = 2; /* 1110 xxxx */
819 else if ((c & 0xf8) == 0xf0) len = 3; /* 1111 0xxx */
820 else if ((c & 0xfc) == 0xf8) len = 4; /* 1111 10xx */
821 else if ((c & 0xfe) == 0xfc) len = 5; /* 1111 110x */
822 else return false; /* invalid leading byte */
824 if (len > 2) return false; /* Java limitation */
826 v = (unsigned long)c & (0x3f >> len);
828 if ((bytes -= len) < 0) return false; /* missing bytes */
830 for (i = len; i--; ) {
832 /*dolog(" %c %02x",c,c);*/
833 if ((c & 0xc0) != 0x80) /* 10xx xxxx */
835 v = (v<<6) | (c & 0x3f);
838 /* dolog("v=%d",v);*/
841 if (len != 1) return false; /* Java special */
844 /* Sun Java seems to allow overlong UTF-8 encodings */
846 if (v < min_codepoint[len]) { /* overlong UTF-8 */
848 fprintf(stderr,"WARNING: Overlong UTF-8 sequence found.\n");
849 /* XXX change this to panic? */
853 /* surrogates in UTF-8 seem to be allowed in Java classfiles */
854 /* if (v >= 0xd800 && v <= 0xdfff) return false; */ /* surrogates */
856 /* even these seem to be allowed */
857 /* if (v == 0xfffe || v == 0xffff) return false; */ /* invalid codepoints */
863 /********************* function: is_valid_name *******************************
865 return true if the given string may be used as a class/field/method name.
866 (Currently this only disallows empty strings and control characters.)
868 NOTE: The string is assumed to have passed is_valid_utf!
870 utf_ptr...points to first character
871 end_pos...points after last character
873 ******************************************************************************/
876 is_valid_name(char *utf_ptr,char *end_pos)
878 if (end_pos <= utf_ptr) return false; /* disallow empty names */
880 while (utf_ptr < end_pos) {
881 unsigned char c = *utf_ptr++;
883 if (c < 0x20) return false; /* disallow control characters */
884 if (c == 0xc0 && (unsigned char)*utf_ptr == 0x80) return false; /* disallow zero */
890 is_valid_name_utf(utf *u)
892 return is_valid_name(u->text,utf_end(u));
895 /******************** Function: class_new **************************************
897 searches for the class with the specified name in the classes hashtable,
898 if there is no such class a new classinfo structure is created and inserted
899 into the list of classes to be loaded
901 *******************************************************************************/
903 classinfo *class_new_int(utf *u)
905 classinfo *c; /* hashtable element */
906 u4 key; /* hashkey computed from classname */
907 u4 slot; /* slot in hashtable */
910 key = utf_hashkey(u->text, u->blength);
911 slot = key & (class_hash.size - 1);
912 c = class_hash.ptr[slot];
914 /* search external hash chain for the class */
916 if (c->name->blength == u->blength) {
917 for (i = 0; i < u->blength; i++)
918 if (u->text[i] != c->name->text[i]) goto nomatch;
920 /* class found in hashtable */
925 c = c->hashlink; /* next element in external chain */
928 /* location in hashtable found, create new classinfo structure */
931 count_class_infos += sizeof(classinfo);
934 c = GCNEW(classinfo, 1); /*JOWENN: NEW*/
938 c->packagename = NULL;
945 c->interfacescount = 0;
946 c->interfaces = NULL;
955 c->header.vftbl = NULL;
956 c->innerclasscount = 0;
957 c->innerclass = NULL;
959 c->initialized = false;
960 c->classvftbl = false;
963 c->classloader = NULL;
964 c->sourcefile = NULL;
966 /* prepare loading of the class */
967 list_addlast(&unloadedclasses, c);
969 /* insert class into the hashtable */
970 c->hashlink = class_hash.ptr[slot];
971 class_hash.ptr[slot] = c;
973 /* update number of hashtable-entries */
974 class_hash.entries++;
976 if (class_hash.entries > (class_hash.size * 2)) {
978 /* reorganization of hashtable, average length of
979 the external chains is approx. 2 */
983 hashtable newhash; /* the new hashtable */
985 /* create new hashtable, double the size */
986 init_hashtable(&newhash, class_hash.size * 2);
987 newhash.entries = class_hash.entries;
989 /* transfer elements to new hashtable */
990 for (i = 0; i < class_hash.size; i++) {
991 c = (classinfo*) class_hash.ptr[i];
993 classinfo *nextc = c->hashlink;
994 u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
996 c->hashlink = newhash.ptr[slot];
997 newhash.ptr[slot] = c;
1003 /* dispose old table */
1004 MFREE(class_hash.ptr, void*, class_hash.size);
1005 class_hash = newhash;
1008 /* Array classes need further initialization. */
1009 if (u->text[0] == '[') {
1011 c->packagename = array_packagename;
1014 /* Find the package name */
1015 /* Classes in the unnamed package keep packagename == NULL. */
1016 char *p = utf_end(c->name) - 1;
1017 char *start = c->name->text;
1018 for (;p > start; --p)
1020 c->packagename = utf_new(start,p-start);
1028 classinfo *class_new(utf *u)
1031 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1034 r = class_new_int(u);
1035 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1042 /******************** Function: class_get **************************************
1044 searches for the class with the specified name in the classes hashtable
1045 if there is no such class NULL is returned
1047 *******************************************************************************/
1049 classinfo *class_get(utf *u)
1051 classinfo *c; /* hashtable element */
1052 u4 key; /* hashkey computed from classname */
1053 u4 slot; /* slot in hashtable */
1056 key = utf_hashkey (u->text, u->blength);
1057 slot = key & (class_hash.size-1);
1058 c = class_hash.ptr[slot];
1061 log_text("class_get: looking for class:");
1063 /* search external hash-chain */
1065 if (c->name->blength == u->blength) {
1067 /* compare classnames */
1068 for (i=0; i<u->blength; i++)
1069 if (u->text[i] != c->name->text[i]) goto nomatch;
1071 log_text("class_get: class found");
1074 utf_display(c->name); */
1075 /* class found in hashtable */
1083 /* class not found */
1087 /***************** Function: class_array_of ***********************************
1089 Returns an array class with the given component class.
1090 The array class is dynamically created if neccessary.
1092 *******************************************************************************/
1094 classinfo *class_array_of(classinfo *component)
1099 /* Assemble the array class name */
1100 namelen = component->name->blength;
1102 if (component->name->text[0] == '[') {
1103 /* the component is itself an array */
1104 namebuf = DMNEW(char,namelen+1);
1106 memcpy(namebuf+1,component->name->text,namelen);
1110 /* the component is a non-array class */
1111 namebuf = DMNEW(char,namelen+3);
1114 memcpy(namebuf+2,component->name->text,namelen);
1115 namebuf[2+namelen] = ';';
1119 return class_new( utf_new(namebuf,namelen) );
1122 /*************** Function: class_multiarray_of ********************************
1124 Returns an array class with the given dimension and element class.
1125 The array class is dynamically created if neccessary.
1127 *******************************************************************************/
1129 classinfo *class_multiarray_of(int dim,classinfo *element)
1135 panic("Invalid array dimension requested");
1137 /* Assemble the array class name */
1138 namelen = element->name->blength;
1140 if (element->name->text[0] == '[') {
1141 /* the element is itself an array */
1142 namebuf = DMNEW(char,namelen+dim);
1143 memcpy(namebuf+dim,element->name->text,namelen);
1147 /* the element is a non-array class */
1148 namebuf = DMNEW(char,namelen+2+dim);
1150 memcpy(namebuf+dim+1,element->name->text,namelen);
1152 namebuf[namelen-1] = ';';
1154 memset(namebuf,'[',dim);
1156 return class_new( utf_new(namebuf,namelen) );
1159 /************************** function: utf_strlen ******************************
1161 determine number of unicode characters in the utf string
1163 *******************************************************************************/
1165 u4 utf_strlen(utf *u)
1167 char *endpos = utf_end(u); /* points behind utf string */
1168 char *utf_ptr = u->text; /* current position in utf text */
1169 u4 len = 0; /* number of unicode characters */
1171 while (utf_ptr < endpos) {
1173 /* next unicode character */
1174 utf_nextu2(&utf_ptr);
1177 if (utf_ptr != endpos)
1178 /* string ended abruptly */
1179 panic("illegal utf string");
1186 * These are local overrides for various environment variables in Emacs.
1187 * Please do not remove this and leave it at the end of the file, where
1188 * Emacs will automagically detect them.
1189 * ---------------------------------------------------------------------
1192 * indent-tabs-mode: t