1 /* src/vmcore/utf8.c - utf8 string functions
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
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., 51 Franklin Street, Fifth Floor, Boston, MA
25 $Id: utf8.c 8056 2007-06-10 14:49:57Z michi $
37 #include "mm/memory.h"
39 #include "threads/lock-common.h"
41 #include "toolbox/hashtable.h"
43 #include "vm/exceptions.h"
45 #include "vmcore/options.h"
47 #if defined(ENABLE_STATISTICS)
48 # include "vmcore/statistics.h"
51 #include "vmcore/utf8.h"
54 /* global variables ***********************************************************/
56 /* hashsize must be power of 2 */
58 #define HASHTABLE_UTF_SIZE 16384 /* initial size of utf-hash */
60 hashtable *hashtable_utf; /* hashtable for utf8-symbols */
63 /* utf-symbols for pointer comparison of frequently used strings **************/
65 utf *utf_java_lang_Object;
67 utf *utf_java_lang_Class;
68 utf *utf_java_lang_ClassLoader;
69 utf *utf_java_lang_Cloneable;
70 utf *utf_java_lang_SecurityManager;
71 utf *utf_java_lang_String;
72 utf *utf_java_lang_System;
73 utf *utf_java_lang_ThreadGroup;
74 utf *utf_java_lang_ref_SoftReference;
75 utf *utf_java_lang_ref_WeakReference;
76 utf *utf_java_lang_ref_PhantomReference;
77 utf *utf_java_io_Serializable;
79 utf *utf_java_lang_Throwable;
80 utf *utf_java_lang_Error;
82 utf *utf_java_lang_AbstractMethodError;
83 utf *utf_java_lang_ClassCircularityError;
84 utf *utf_java_lang_ClassFormatError;
85 utf *utf_java_lang_ExceptionInInitializerError;
86 utf *utf_java_lang_IncompatibleClassChangeError;
87 utf *utf_java_lang_InstantiationError;
88 utf *utf_java_lang_InternalError;
89 utf *utf_java_lang_LinkageError;
90 utf *utf_java_lang_NoClassDefFoundError;
91 utf *utf_java_lang_NoSuchFieldError;
92 utf *utf_java_lang_NoSuchMethodError;
93 utf *utf_java_lang_OutOfMemoryError;
94 utf *utf_java_lang_UnsatisfiedLinkError;
95 utf *utf_java_lang_UnsupportedClassVersionError;
96 utf *utf_java_lang_VerifyError;
97 utf *utf_java_lang_VirtualMachineError;
99 #if defined(WITH_CLASSPATH_GNU)
100 utf *utf_java_lang_VMThrowable;
103 utf *utf_java_lang_Exception;
105 utf *utf_java_lang_ArithmeticException;
106 utf *utf_java_lang_ArrayIndexOutOfBoundsException;
107 utf *utf_java_lang_ArrayStoreException;
108 utf *utf_java_lang_ClassCastException;
109 utf *utf_java_lang_ClassNotFoundException;
110 utf *utf_java_lang_CloneNotSupportedException;
111 utf *utf_java_lang_IllegalAccessException;
112 utf *utf_java_lang_IllegalArgumentException;
113 utf *utf_java_lang_IllegalMonitorStateException;
114 utf *utf_java_lang_InstantiationException;
115 utf *utf_java_lang_InterruptedException;
116 utf *utf_java_lang_NegativeArraySizeException;
117 utf *utf_java_lang_NullPointerException;
118 utf *utf_java_lang_StringIndexOutOfBoundsException;
120 utf *utf_java_lang_reflect_InvocationTargetException;
122 utf *utf_java_security_PrivilegedActionException;
124 #if defined(ENABLE_JAVASE)
125 utf* utf_java_lang_Void;
128 utf* utf_java_lang_Boolean;
129 utf* utf_java_lang_Byte;
130 utf* utf_java_lang_Character;
131 utf* utf_java_lang_Short;
132 utf* utf_java_lang_Integer;
133 utf* utf_java_lang_Long;
134 utf* utf_java_lang_Float;
135 utf* utf_java_lang_Double;
137 #if defined(ENABLE_JAVASE)
138 utf *utf_java_lang_StackTraceElement;
139 utf *utf_java_lang_reflect_Constructor;
140 utf *utf_java_lang_reflect_Field;
141 utf *utf_java_lang_reflect_Method;
142 utf *utf_java_util_Vector;
145 utf *utf_InnerClasses; /* InnerClasses */
146 utf *utf_ConstantValue; /* ConstantValue */
147 utf *utf_Code; /* Code */
148 utf *utf_Exceptions; /* Exceptions */
149 utf *utf_LineNumberTable; /* LineNumberTable */
150 utf *utf_SourceFile; /* SourceFile */
152 #if defined(ENABLE_JAVASE)
153 utf *utf_EnclosingMethod;
155 utf *utf_RuntimeVisibleAnnotations;
156 utf *utf_StackMapTable;
159 utf *utf_init; /* <init> */
160 utf *utf_clinit; /* <clinit> */
161 utf *utf_clone; /* clone */
162 utf *utf_finalize; /* finalize */
163 utf *utf_run; /* run */
168 utf *utf_removeThread;
173 utf *utf_fillInStackTrace;
174 utf *utf_getSystemClassLoader;
176 utf *utf_printStackTrace;
178 utf *utf_division_by_zero;
189 utf *utf_void__void; /* ()V */
190 utf *utf_boolean__void; /* (Z)V */
191 utf *utf_byte__void; /* (B)V */
192 utf *utf_char__void; /* (C)V */
193 utf *utf_short__void; /* (S)V */
194 utf *utf_int__void; /* (I)V */
195 utf *utf_long__void; /* (J)V */
196 utf *utf_float__void; /* (F)V */
197 utf *utf_double__void; /* (D)V */
199 utf *utf_void__java_lang_ClassLoader; /* ()Ljava/lang/ClassLoader; */
200 utf *utf_void__java_lang_Object; /* ()Ljava/lang/Object; */
201 utf *utf_void__java_lang_Throwable; /* ()Ljava/lang/Throwable; */
202 utf *utf_java_lang_Exception__V; /* (Ljava/lang/Exception;)V */
203 utf *utf_java_lang_Object__java_lang_Object;
204 utf *utf_java_lang_String__void; /* (Ljava/lang/String;)V */
205 utf *utf_java_lang_String__java_lang_Class;
206 utf *utf_java_lang_Thread__V; /* (Ljava/lang/Thread;)V */
207 utf *utf_java_lang_Throwable__void; /* (Ljava/lang/Throwable;)V */
209 utf *utf_not_named_yet; /* special name for unnamed classes */
211 utf *array_packagename;
214 /* utf_init ********************************************************************
216 Initializes the utf8 subsystem.
218 *******************************************************************************/
222 /* create utf8 hashtable */
224 hashtable_utf = NEW(hashtable);
226 hashtable_create(hashtable_utf, HASHTABLE_UTF_SIZE);
228 #if defined(ENABLE_STATISTICS)
230 count_utf_len += sizeof(utf*) * hashtable_utf->size;
233 /* create utf-symbols for pointer comparison of frequently used strings */
235 utf_java_lang_Object = utf_new_char("java/lang/Object");
237 utf_java_lang_Class = utf_new_char("java/lang/Class");
238 utf_java_lang_ClassLoader = utf_new_char("java/lang/ClassLoader");
239 utf_java_lang_Cloneable = utf_new_char("java/lang/Cloneable");
240 utf_java_lang_SecurityManager = utf_new_char("java/lang/SecurityManager");
241 utf_java_lang_String = utf_new_char("java/lang/String");
242 utf_java_lang_System = utf_new_char("java/lang/System");
243 utf_java_lang_ThreadGroup = utf_new_char("java/lang/ThreadGroup");
245 utf_java_lang_ref_SoftReference =
246 utf_new_char("java/lang/ref/SoftReference");
248 utf_java_lang_ref_WeakReference =
249 utf_new_char("java/lang/ref/WeakReference");
251 utf_java_lang_ref_PhantomReference =
252 utf_new_char("java/lang/ref/PhantomReference");
254 utf_java_io_Serializable = utf_new_char("java/io/Serializable");
256 utf_java_lang_Throwable = utf_new_char("java/lang/Throwable");
257 utf_java_lang_Error = utf_new_char("java/lang/Error");
259 utf_java_lang_ClassCircularityError =
260 utf_new_char("java/lang/ClassCircularityError");
262 utf_java_lang_ClassFormatError = utf_new_char("java/lang/ClassFormatError");
264 utf_java_lang_ExceptionInInitializerError =
265 utf_new_char("java/lang/ExceptionInInitializerError");
267 utf_java_lang_IncompatibleClassChangeError =
268 utf_new_char("java/lang/IncompatibleClassChangeError");
270 utf_java_lang_InstantiationError =
271 utf_new_char("java/lang/InstantiationError");
273 utf_java_lang_InternalError = utf_new_char("java/lang/InternalError");
274 utf_java_lang_LinkageError = utf_new_char("java/lang/LinkageError");
276 utf_java_lang_NoClassDefFoundError =
277 utf_new_char("java/lang/NoClassDefFoundError");
279 utf_java_lang_OutOfMemoryError = utf_new_char("java/lang/OutOfMemoryError");
281 utf_java_lang_UnsatisfiedLinkError =
282 utf_new_char("java/lang/UnsatisfiedLinkError");
284 utf_java_lang_UnsupportedClassVersionError =
285 utf_new_char("java/lang/UnsupportedClassVersionError");
287 utf_java_lang_VerifyError = utf_new_char("java/lang/VerifyError");
289 utf_java_lang_VirtualMachineError =
290 utf_new_char("java/lang/VirtualMachineError");
292 #if defined(ENABLE_JAVASE)
293 utf_java_lang_AbstractMethodError =
294 utf_new_char("java/lang/AbstractMethodError");
296 utf_java_lang_NoSuchFieldError =
297 utf_new_char("java/lang/NoSuchFieldError");
299 utf_java_lang_NoSuchMethodError =
300 utf_new_char("java/lang/NoSuchMethodError");
303 #if defined(WITH_CLASSPATH_GNU)
304 utf_java_lang_VMThrowable = utf_new_char("java/lang/VMThrowable");
307 utf_java_lang_Exception = utf_new_char("java/lang/Exception");
309 utf_java_lang_ArithmeticException =
310 utf_new_char("java/lang/ArithmeticException");
312 utf_java_lang_ArrayIndexOutOfBoundsException =
313 utf_new_char("java/lang/ArrayIndexOutOfBoundsException");
315 utf_java_lang_ArrayStoreException =
316 utf_new_char("java/lang/ArrayStoreException");
318 utf_java_lang_ClassCastException =
319 utf_new_char("java/lang/ClassCastException");
321 utf_java_lang_ClassNotFoundException =
322 utf_new_char("java/lang/ClassNotFoundException");
324 utf_java_lang_CloneNotSupportedException =
325 utf_new_char("java/lang/CloneNotSupportedException");
327 utf_java_lang_IllegalAccessException =
328 utf_new_char("java/lang/IllegalAccessException");
330 utf_java_lang_IllegalArgumentException =
331 utf_new_char("java/lang/IllegalArgumentException");
333 utf_java_lang_IllegalMonitorStateException =
334 utf_new_char("java/lang/IllegalMonitorStateException");
336 utf_java_lang_InstantiationException =
337 utf_new_char("java/lang/InstantiationException");
339 utf_java_lang_InterruptedException =
340 utf_new_char("java/lang/InterruptedException");
342 utf_java_lang_NegativeArraySizeException =
343 utf_new_char("java/lang/NegativeArraySizeException");
345 utf_java_lang_NullPointerException =
346 utf_new_char("java/lang/NullPointerException");
348 utf_java_lang_StringIndexOutOfBoundsException =
349 utf_new_char("java/lang/StringIndexOutOfBoundsException");
351 utf_java_lang_reflect_InvocationTargetException =
352 utf_new_char("java/lang/reflect/InvocationTargetException");
354 utf_java_security_PrivilegedActionException =
355 utf_new_char("java/security/PrivilegedActionException");
357 #if defined(ENABLE_JAVASE)
358 utf_java_lang_Void = utf_new_char("java/lang/Void");
361 utf_java_lang_Boolean = utf_new_char("java/lang/Boolean");
362 utf_java_lang_Byte = utf_new_char("java/lang/Byte");
363 utf_java_lang_Character = utf_new_char("java/lang/Character");
364 utf_java_lang_Short = utf_new_char("java/lang/Short");
365 utf_java_lang_Integer = utf_new_char("java/lang/Integer");
366 utf_java_lang_Long = utf_new_char("java/lang/Long");
367 utf_java_lang_Float = utf_new_char("java/lang/Float");
368 utf_java_lang_Double = utf_new_char("java/lang/Double");
370 #if defined(ENABLE_JAVASE)
371 utf_java_lang_StackTraceElement =
372 utf_new_char("java/lang/StackTraceElement");
374 utf_java_lang_reflect_Constructor =
375 utf_new_char("java/lang/reflect/Constructor");
377 utf_java_lang_reflect_Field = utf_new_char("java/lang/reflect/Field");
378 utf_java_lang_reflect_Method = utf_new_char("java/lang/reflect/Method");
379 utf_java_util_Vector = utf_new_char("java/util/Vector");
382 utf_InnerClasses = utf_new_char("InnerClasses");
383 utf_ConstantValue = utf_new_char("ConstantValue");
384 utf_Code = utf_new_char("Code");
385 utf_Exceptions = utf_new_char("Exceptions");
386 utf_LineNumberTable = utf_new_char("LineNumberTable");
387 utf_SourceFile = utf_new_char("SourceFile");
389 #if defined(ENABLE_JAVASE)
390 utf_EnclosingMethod = utf_new_char("EnclosingMethod");
391 utf_Signature = utf_new_char("Signature");
392 utf_RuntimeVisibleAnnotations = utf_new_char("RuntimeVisibleAnnotations");
393 utf_StackMapTable = utf_new_char("StackMapTable");
396 utf_init = utf_new_char("<init>");
397 utf_clinit = utf_new_char("<clinit>");
398 utf_clone = utf_new_char("clone");
399 utf_finalize = utf_new_char("finalize");
400 utf_run = utf_new_char("run");
402 utf_add = utf_new_char("add");
403 utf_remove = utf_new_char("remove");
404 utf_addThread = utf_new_char("addThread");
405 utf_removeThread = utf_new_char("removeThread");
406 utf_put = utf_new_char("put");
407 utf_get = utf_new_char("get");
408 utf_value = utf_new_char("value");
410 utf_fillInStackTrace = utf_new_char("fillInStackTrace");
411 utf_getSystemClassLoader = utf_new_char("getSystemClassLoader");
412 utf_loadClass = utf_new_char("loadClass");
413 utf_printStackTrace = utf_new_char("printStackTrace");
415 utf_division_by_zero = utf_new_char("/ by zero");
417 utf_Z = utf_new_char("Z");
418 utf_B = utf_new_char("B");
419 utf_C = utf_new_char("C");
420 utf_S = utf_new_char("S");
421 utf_I = utf_new_char("I");
422 utf_J = utf_new_char("J");
423 utf_F = utf_new_char("F");
424 utf_D = utf_new_char("D");
426 utf_void__void = utf_new_char("()V");
427 utf_boolean__void = utf_new_char("(Z)V");
428 utf_byte__void = utf_new_char("(B)V");
429 utf_char__void = utf_new_char("(C)V");
430 utf_short__void = utf_new_char("(S)V");
431 utf_int__void = utf_new_char("(I)V");
432 utf_long__void = utf_new_char("(J)V");
433 utf_float__void = utf_new_char("(F)V");
434 utf_double__void = utf_new_char("(D)V");
435 utf_void__java_lang_Object = utf_new_char("()Ljava/lang/Object;");
436 utf_void__java_lang_Throwable = utf_new_char("()Ljava/lang/Throwable;");
438 utf_void__java_lang_ClassLoader =
439 utf_new_char("()Ljava/lang/ClassLoader;");
441 utf_java_lang_Exception__V = utf_new_char("(Ljava/lang/Exception;)V");
443 utf_java_lang_Object__java_lang_Object =
444 utf_new_char("(Ljava/lang/Object;)Ljava/lang/Object;");
446 utf_java_lang_String__void = utf_new_char("(Ljava/lang/String;)V");
448 utf_java_lang_String__java_lang_Class =
449 utf_new_char("(Ljava/lang/String;)Ljava/lang/Class;");
451 utf_java_lang_Thread__V = utf_new_char("(Ljava/lang/Thread;)V");
452 utf_java_lang_Throwable__void = utf_new_char("(Ljava/lang/Throwable;)V");
454 utf_null = utf_new_char("null");
455 utf_not_named_yet = utf_new_char("\t<not_named_yet>");
456 array_packagename = utf_new_char("\t<the array package>");
458 /* everything's ok */
464 /* utf_hashkey *****************************************************************
466 The hashkey is computed from the utf-text by using up to 8
467 characters. For utf-symbols longer than 15 characters 3 characters
468 are taken from the beginning and the end, 2 characters are taken
471 *******************************************************************************/
473 #define nbs(val) ((u4) *(++text) << val) /* get next byte, left shift by val */
474 #define fbs(val) ((u4) *( text) << val) /* get first byte, left shift by val */
476 u4 utf_hashkey(const char *text, u4 length)
478 const char *start_pos = text; /* pointer to utf text */
482 case 0: /* empty string */
485 case 1: return fbs(0);
486 case 2: return fbs(0) ^ nbs(3);
487 case 3: return fbs(0) ^ nbs(3) ^ nbs(5);
488 case 4: return fbs(0) ^ nbs(2) ^ nbs(4) ^ nbs(6);
489 case 5: return fbs(0) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(6);
490 case 6: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(5) ^ nbs(6);
491 case 7: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6);
492 case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7);
499 return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8);
508 return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9);
517 return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10);
529 return a ^ nbs(9) ^ nbs(10);
541 return a ^ nbs(9) ^ nbs(10);
552 return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
563 return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
565 default: /* 3 characters from beginning */
571 /* 2 characters from middle */
572 text = start_pos + (length / 2);
577 /* 3 characters from end */
578 text = start_pos + length - 4;
583 return a ^ nbs(10) ^ nbs(11);
587 /* utf_full_hashkey ************************************************************
589 This function computes a hash value using all bytes in the string.
591 The algorithm is the "One-at-a-time" algorithm as published
592 by Bob Jenkins on http://burtleburtle.net/bob/hash/doobs.html.
594 *******************************************************************************/
596 u4 utf_full_hashkey(const char *text, u4 length)
598 register const unsigned char *p = (const unsigned char *) text;
606 hash += (hash << 10);
610 hash ^= (hash >> 11);
611 hash += (hash << 15);
616 /* unicode_hashkey *************************************************************
618 Compute the hashkey of a unicode string.
620 *******************************************************************************/
622 u4 unicode_hashkey(u2 *text, u2 len)
624 return utf_hashkey((char *) text, len);
628 /* utf_new *********************************************************************
630 Creates a new utf-symbol, the text of the symbol is passed as a
631 u1-array. The function searches the utf-hashtable for a utf-symbol
632 with this text. On success the element returned, otherwise a new
633 hashtable element is created.
635 If the number of entries in the hashtable exceeds twice the size of
636 the hashtable slots a reorganization of the hashtable is done and
637 the utf symbols are copied to a new hashtable with doubled size.
639 *******************************************************************************/
641 utf *utf_new(const char *text, u2 length)
643 u4 key; /* hashkey computed from utf-text */
644 u4 slot; /* slot in hashtable */
645 utf *u; /* hashtable element */
648 LOCK_MONITOR_ENTER(hashtable_utf->header);
650 #if defined(ENABLE_STATISTICS)
655 key = utf_hashkey(text, length);
656 slot = key & (hashtable_utf->size - 1);
657 u = hashtable_utf->ptr[slot];
659 /* search external hash chain for utf-symbol */
662 if (u->blength == length) {
663 /* compare text of hashtable elements */
665 for (i = 0; i < length; i++)
666 if (text[i] != u->text[i])
669 #if defined(ENABLE_STATISTICS)
671 count_utf_new_found++;
674 /* symbol found in hashtable */
676 LOCK_MONITOR_EXIT(hashtable_utf->header);
682 u = u->hashlink; /* next element in external chain */
685 /* location in hashtable found, create new utf element */
689 u->blength = length; /* length in bytes of utfstring */
690 u->hashlink = hashtable_utf->ptr[slot]; /* link in external hashchain */
691 u->text = mem_alloc(length + 1);/* allocate memory for utf-text */
693 memcpy(u->text, text, length); /* copy utf-text */
694 u->text[length] = '\0';
696 #if defined(ENABLE_STATISTICS)
698 count_utf_len += sizeof(utf) + length + 1;
701 hashtable_utf->ptr[slot] = u; /* insert symbol into table */
702 hashtable_utf->entries++; /* update number of entries */
704 if (hashtable_utf->entries > (hashtable_utf->size * 2)) {
706 /* reorganization of hashtable, average length of the external
707 chains is approx. 2 */
709 hashtable *newhash; /* the new hashtable */
715 /* create new hashtable, double the size */
717 newhash = hashtable_resize(hashtable_utf, hashtable_utf->size * 2);
719 #if defined(ENABLE_STATISTICS)
721 count_utf_len += sizeof(utf*) * hashtable_utf->size;
724 /* transfer elements to new hashtable */
726 for (i = 0; i < hashtable_utf->size; i++) {
727 u = hashtable_utf->ptr[i];
731 slot = utf_hashkey(u->text, u->blength) & (newhash->size - 1);
733 u->hashlink = (utf *) newhash->ptr[slot];
734 newhash->ptr[slot] = u;
736 /* follow link in external hash chain */
742 /* dispose old table */
744 hashtable_free(hashtable_utf);
746 hashtable_utf = newhash;
749 LOCK_MONITOR_EXIT(hashtable_utf->header);
755 /* utf_new_u2 ******************************************************************
757 Make utf symbol from u2 array, if isclassname is true '.' is
760 *******************************************************************************/
762 utf *utf_new_u2(u2 *unicode_pos, u4 unicode_length, bool isclassname)
764 char *buffer; /* memory buffer for unicode characters */
765 char *pos; /* pointer to current position in buffer */
766 u4 left; /* unicode characters left */
767 u4 buflength; /* utf length in bytes of the u2 array */
768 utf *result; /* resulting utf-string */
771 /* determine utf length in bytes and allocate memory */
773 buflength = u2_utflength(unicode_pos, unicode_length);
774 buffer = MNEW(char, buflength);
779 for (i = 0; i++ < unicode_length; unicode_pos++) {
780 /* next unicode character */
783 if ((c != 0) && (c < 0x80)) {
786 if ((int) left < 0) break;
787 /* convert classname */
788 if (isclassname && c == '.')
793 } else if (c < 0x800) {
795 unsigned char high = c >> 6;
796 unsigned char low = c & 0x3F;
798 if ((int) left < 0) break;
799 *pos++ = high | 0xC0;
805 char mid = (c >> 6) & 0x3F;
808 if ((int) left < 0) break;
809 *pos++ = high | 0xE0;
815 /* insert utf-string into symbol-table */
816 result = utf_new(buffer,buflength);
818 MFREE(buffer, char, buflength);
824 /* utf_new_char ****************************************************************
826 Creates a new utf symbol, the text for this symbol is passed as a
827 c-string ( = char* ).
829 *******************************************************************************/
831 utf *utf_new_char(const char *text)
833 return utf_new(text, strlen(text));
837 /* utf_new_char_classname ******************************************************
839 Creates a new utf symbol, the text for this symbol is passed as a
840 c-string ( = char* ) "." characters are going to be replaced by
841 "/". Since the above function is used often, this is a separte
842 function, instead of an if.
844 *******************************************************************************/
846 utf *utf_new_char_classname(const char *text)
848 if (strchr(text, '.')) {
849 char *txt = strdup(text);
850 char *end = txt + strlen(txt);
854 for (c = txt; c < end; c++)
855 if (*c == '.') *c = '/';
857 tmpRes = utf_new(txt, strlen(txt));
863 return utf_new(text, strlen(text));
867 /* utf_nextu2 ******************************************************************
869 Read the next unicode character from the utf string and increment
870 the utf-string pointer accordingly.
872 CAUTION: This function is unsafe for input that was not checked
875 *******************************************************************************/
877 u2 utf_nextu2(char **utf_ptr)
879 /* uncompressed unicode character */
881 /* current position in utf text */
882 unsigned char *utf = (unsigned char *) (*utf_ptr);
883 /* bytes representing the unicode character */
884 unsigned char ch1, ch2, ch3;
885 /* number of bytes used to represent the unicode character */
888 switch ((ch1 = utf[0]) >> 4) {
889 default: /* 1 byte */
893 case 0xD: /* 2 bytes */
894 if (((ch2 = utf[1]) & 0xC0) == 0x80) {
895 unsigned char high = ch1 & 0x1F;
896 unsigned char low = ch2 & 0x3F;
897 unicode_char = (high << 6) + low;
902 case 0xE: /* 2 or 3 bytes */
903 if (((ch2 = utf[1]) & 0xC0) == 0x80) {
904 if (((ch3 = utf[2]) & 0xC0) == 0x80) {
905 unsigned char low = ch3 & 0x3f;
906 unsigned char mid = ch2 & 0x3f;
907 unsigned char high = ch1 & 0x0f;
908 unicode_char = (((high << 6) + mid) << 6) + low;
916 /* update position in utf-text */
917 *utf_ptr = (char *) (utf + len);
923 /* utf_bytes *******************************************************************
925 Determine number of bytes (aka. octets) in the utf string.
928 u............utf string
931 The number of octets of this utf string.
932 There is _no_ terminating zero included in this count.
934 *******************************************************************************/
942 /* utf_get_number_of_u2s_for_buffer ********************************************
944 Determine number of UTF-16 u2s in the given UTF-8 buffer
946 CAUTION: This function is unsafe for input that was not checked
949 CAUTION: Use this function *only* when you want to convert an UTF-8 buffer
950 to an array of u2s (UTF-16) and want to know how many of them you will get.
951 All other uses of this function are probably wrong.
954 buffer........points to first char in buffer
955 blength.......number of _bytes_ in the buffer
958 the number of u2s needed to hold this string in UTF-16 encoding.
959 There is _no_ terminating zero included in this count.
961 NOTE: Unlike utf_get_number_of_u2s, this function never throws an
964 *******************************************************************************/
966 u4 utf_get_number_of_u2s_for_buffer(const char *buffer, u4 blength)
968 const char *endpos; /* points behind utf string */
969 const char *utf_ptr; /* current position in utf text */
970 u4 len = 0; /* number of unicode characters */
973 endpos = utf_ptr + blength;
975 while (utf_ptr < endpos) {
977 /* next unicode character */
978 utf_nextu2((char **)&utf_ptr);
981 assert(utf_ptr == endpos);
987 /* utf_get_number_of_u2s *******************************************************
989 Determine number of UTF-16 u2s in the utf string.
991 CAUTION: This function is unsafe for input that was not checked
994 CAUTION: Use this function *only* when you want to convert a utf string
995 to an array of u2s and want to know how many of them you will get.
996 All other uses of this function are probably wrong.
999 u............utf string
1002 the number of u2s needed to hold this string in UTF-16 encoding.
1003 There is _no_ terminating zero included in this count.
1004 XXX 0 if a NullPointerException has been thrown (see below)
1006 *******************************************************************************/
1008 u4 utf_get_number_of_u2s(utf *u)
1010 char *endpos; /* points behind utf string */
1011 char *utf_ptr; /* current position in utf text */
1012 u4 len = 0; /* number of unicode characters */
1014 /* XXX this is probably not checked by most callers! Review this after */
1015 /* the invalid uses of this function have been eliminated */
1017 exceptions_throw_nullpointerexception();
1021 endpos = UTF_END(u);
1024 while (utf_ptr < endpos) {
1026 /* next unicode character */
1027 utf_nextu2(&utf_ptr);
1030 if (utf_ptr != endpos) {
1031 /* string ended abruptly */
1032 exceptions_throw_internalerror("Illegal utf8 string");
1040 /* utf8_safe_number_of_u2s *****************************************************
1042 Determine number of UTF-16 u2s needed for decoding the given UTF-8 string.
1043 (For invalid UTF-8 the U+fffd replacement character will be counted.)
1045 This function is safe even for invalid UTF-8 strings.
1048 text..........zero-terminated(!) UTF-8 string (may be invalid)
1050 nbytes........strlen(text). (This is needed to completely emulate
1054 the number of u2s needed to hold this string in UTF-16 encoding.
1055 There is _no_ terminating zero included in this count.
1057 *******************************************************************************/
1059 s4 utf8_safe_number_of_u2s(const char *text, s4 nbytes) {
1060 register const unsigned char *t;
1063 register const unsigned char *tlimit;
1071 assert(nbytes >= 0);
1074 t = (const unsigned char *) text;
1075 tlimit = t + nbytes;
1077 /* CAUTION: Keep this code in sync with utf8_safe_convert_to_u2s! */
1083 /* highest bit set, non-ASCII character */
1085 if ((byte & 0xe0) == 0xc0) {
1086 /* 2-byte: should be 110..... 10...... ? */
1088 if ((*t++ & 0xc0) == 0x80)
1089 ; /* valid 2-byte */
1093 else if ((byte & 0xf0) == 0xe0) {
1094 /* 3-byte: should be 1110.... 10...... 10...... */
1098 return len + 1; /* invalid, stop here */
1100 if ((*t++ & 0xc0) == 0x80) {
1101 if ((*t++ & 0xc0) == 0x80)
1102 ; /* valid 3-byte */
1109 else if ((byte & 0xf8) == 0xf0) {
1110 /* 4-byte: should be 11110... 10...... 10...... 10...... */
1114 return len + 1; /* invalid, stop here */
1116 if (((byte1 = *t++) & 0xc0) == 0x80) {
1117 if (((byte2 = *t++) & 0xc0) == 0x80) {
1118 if (((byte3 = *t++) & 0xc0) == 0x80) {
1119 /* valid 4-byte UTF-8? */
1120 value = ((byte & 0x07) << 18)
1121 | ((byte1 & 0x3f) << 12)
1122 | ((byte2 & 0x3f) << 6)
1123 | ((byte3 & 0x3f) );
1125 if (value > 0x10FFFF)
1127 else if (value > 0xFFFF)
1128 len += 1; /* we need surrogates */
1130 ; /* 16bit suffice */
1141 else if ((byte & 0xfc) == 0xf8) {
1142 /* invalid 5-byte */
1144 return len + 1; /* invalid, stop here */
1147 for (; skip && ((*t & 0xc0) == 0x80); --skip)
1150 else if ((byte & 0xfe) == 0xfc) {
1151 /* invalid 6-byte */
1153 return len + 1; /* invalid, stop here */
1156 for (; skip && ((*t & 0xc0) == 0x80); --skip)
1168 /* ASCII character, common case */
1178 /* utf8_safe_convert_to_u2s ****************************************************
1180 Convert the given UTF-8 string to UTF-16 into a pre-allocated buffer.
1181 (Invalid UTF-8 will be replaced with the U+fffd replacement character.)
1182 Use utf8_safe_number_of_u2s to determine the number of u2s to allocate.
1184 This function is safe even for invalid UTF-8 strings.
1187 text..........zero-terminated(!) UTF-8 string (may be invalid)
1189 nbytes........strlen(text). (This is needed to completely emulate
1191 buffer........a preallocated array of u2s to receive the decoded
1192 string. Use utf8_safe_number_of_u2s to get the
1193 required number of u2s for allocating this.
1195 *******************************************************************************/
1197 #define UNICODE_REPLACEMENT 0xfffd
1199 void utf8_safe_convert_to_u2s(const char *text, s4 nbytes, u2 *buffer) {
1200 register const unsigned char *t;
1202 register const unsigned char *tlimit;
1210 assert(nbytes >= 0);
1212 t = (const unsigned char *) text;
1213 tlimit = t + nbytes;
1215 /* CAUTION: Keep this code in sync with utf8_safe_number_of_u2s! */
1221 /* highest bit set, non-ASCII character */
1223 if ((byte & 0xe0) == 0xc0) {
1224 /* 2-byte: should be 110..... 10...... */
1226 if (((byte1 = *t++) & 0xc0) == 0x80) {
1227 /* valid 2-byte UTF-8 */
1228 *buffer++ = ((byte & 0x1f) << 6)
1229 | ((byte1 & 0x3f) );
1232 *buffer++ = UNICODE_REPLACEMENT;
1236 else if ((byte & 0xf0) == 0xe0) {
1237 /* 3-byte: should be 1110.... 10...... 10...... */
1239 if (t + 2 > tlimit) {
1240 *buffer++ = UNICODE_REPLACEMENT;
1244 if (((byte1 = *t++) & 0xc0) == 0x80) {
1245 if (((byte2 = *t++) & 0xc0) == 0x80) {
1246 /* valid 3-byte UTF-8 */
1247 *buffer++ = ((byte & 0x0f) << 12)
1248 | ((byte1 & 0x3f) << 6)
1249 | ((byte2 & 0x3f) );
1252 *buffer++ = UNICODE_REPLACEMENT;
1257 *buffer++ = UNICODE_REPLACEMENT;
1261 else if ((byte & 0xf8) == 0xf0) {
1262 /* 4-byte: should be 11110... 10...... 10...... 10...... */
1264 if (t + 3 > tlimit) {
1265 *buffer++ = UNICODE_REPLACEMENT;
1269 if (((byte1 = *t++) & 0xc0) == 0x80) {
1270 if (((byte2 = *t++) & 0xc0) == 0x80) {
1271 if (((byte3 = *t++) & 0xc0) == 0x80) {
1272 /* valid 4-byte UTF-8? */
1273 value = ((byte & 0x07) << 18)
1274 | ((byte1 & 0x3f) << 12)
1275 | ((byte2 & 0x3f) << 6)
1276 | ((byte3 & 0x3f) );
1278 if (value > 0x10FFFF) {
1279 *buffer++ = UNICODE_REPLACEMENT;
1281 else if (value > 0xFFFF) {
1282 /* we need surrogates */
1283 *buffer++ = 0xd800 | ((value >> 10) - 0x40);
1284 *buffer++ = 0xdc00 | (value & 0x03ff);
1287 *buffer++ = value; /* 16bit suffice */
1290 *buffer++ = UNICODE_REPLACEMENT;
1295 *buffer++ = UNICODE_REPLACEMENT;
1300 *buffer++ = UNICODE_REPLACEMENT;
1304 else if ((byte & 0xfc) == 0xf8) {
1305 if (t + 4 > tlimit) {
1306 *buffer++ = UNICODE_REPLACEMENT;
1311 for (; skip && ((*t & 0xc0) == 0x80); --skip)
1313 *buffer++ = UNICODE_REPLACEMENT;
1315 else if ((byte & 0xfe) == 0xfc) {
1316 if (t + 5 > tlimit) {
1317 *buffer++ = UNICODE_REPLACEMENT;
1322 for (; skip && ((*t & 0xc0) == 0x80); --skip)
1324 *buffer++ = UNICODE_REPLACEMENT;
1327 *buffer++ = UNICODE_REPLACEMENT;
1335 /* ASCII character, common case */
1343 /* u2_utflength ****************************************************************
1345 Returns the utf length in bytes of a u2 array.
1347 *******************************************************************************/
1349 u4 u2_utflength(u2 *text, u4 u2_length)
1351 u4 result_len = 0; /* utf length in bytes */
1352 u2 ch; /* current unicode character */
1355 for (len = 0; len < u2_length; len++) {
1356 /* next unicode character */
1359 /* determine bytes required to store unicode character as utf */
1360 if (ch && (ch < 0x80))
1362 else if (ch < 0x800)
1372 /* utf_copy ********************************************************************
1374 Copy the given utf string byte-for-byte to a buffer.
1377 buffer.......the buffer
1378 u............the utf string
1380 *******************************************************************************/
1382 void utf_copy(char *buffer, utf *u)
1384 /* our utf strings are zero-terminated (done by utf_new) */
1385 MCOPY(buffer, u->text, char, u->blength + 1);
1389 /* utf_cat *********************************************************************
1391 Append the given utf string byte-for-byte to a buffer.
1394 buffer.......the buffer
1395 u............the utf string
1397 *******************************************************************************/
1399 void utf_cat(char *buffer, utf *u)
1401 /* our utf strings are zero-terminated (done by utf_new) */
1402 MCOPY(buffer + strlen(buffer), u->text, char, u->blength + 1);
1406 /* utf_copy_classname **********************************************************
1408 Copy the given utf classname byte-for-byte to a buffer.
1409 '/' is replaced by '.'
1412 buffer.......the buffer
1413 u............the utf string
1415 *******************************************************************************/
1417 void utf_copy_classname(char *buffer, utf *u)
1426 endptr = UTF_END(u) + 1; /* utfs are zero-terminared by utf_new */
1428 while (srcptr != endptr) {
1437 /* utf_cat *********************************************************************
1439 Append the given utf classname byte-for-byte to a buffer.
1440 '/' is replaced by '.'
1443 buffer.......the buffer
1444 u............the utf string
1446 *******************************************************************************/
1448 void utf_cat_classname(char *buffer, utf *u)
1450 utf_copy_classname(buffer + strlen(buffer), u);
1453 /* utf_display_printable_ascii *************************************************
1455 Write utf symbol to stdout (for debugging purposes).
1456 Non-printable and non-ASCII characters are printed as '?'.
1458 *******************************************************************************/
1460 void utf_display_printable_ascii(utf *u)
1462 char *endpos; /* points behind utf string */
1463 char *utf_ptr; /* current position in utf text */
1471 endpos = UTF_END(u);
1474 while (utf_ptr < endpos) {
1475 /* read next unicode character */
1477 u2 c = utf_nextu2(&utf_ptr);
1479 if ((c >= 32) && (c <= 127))
1489 /* utf_display_printable_ascii_classname ***************************************
1491 Write utf symbol to stdout with `/' converted to `.' (for debugging
1493 Non-printable and non-ASCII characters are printed as '?'.
1495 *******************************************************************************/
1497 void utf_display_printable_ascii_classname(utf *u)
1499 char *endpos; /* points behind utf string */
1500 char *utf_ptr; /* current position in utf text */
1508 endpos = UTF_END(u);
1511 while (utf_ptr < endpos) {
1512 /* read next unicode character */
1514 u2 c = utf_nextu2(&utf_ptr);
1519 if ((c >= 32) && (c <= 127))
1529 /* utf_sprint_convert_to_latin1 ************************************************
1531 Write utf symbol into c-string (for debugging purposes).
1532 Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield
1535 *******************************************************************************/
1537 void utf_sprint_convert_to_latin1(char *buffer, utf *u)
1539 char *endpos; /* points behind utf string */
1540 char *utf_ptr; /* current position in utf text */
1541 u2 pos = 0; /* position in c-string */
1544 strcpy(buffer, "NULL");
1548 endpos = UTF_END(u);
1551 while (utf_ptr < endpos)
1552 /* copy next unicode character */
1553 buffer[pos++] = utf_nextu2(&utf_ptr);
1555 /* terminate string */
1560 /* utf_sprint_convert_to_latin1_classname **************************************
1562 Write utf symbol into c-string with `/' converted to `.' (for debugging
1564 Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield
1567 *******************************************************************************/
1569 void utf_sprint_convert_to_latin1_classname(char *buffer, utf *u)
1571 char *endpos; /* points behind utf string */
1572 char *utf_ptr; /* current position in utf text */
1573 u2 pos = 0; /* position in c-string */
1576 strcpy(buffer, "NULL");
1580 endpos = UTF_END(u);
1583 while (utf_ptr < endpos) {
1584 /* copy next unicode character */
1585 u2 c = utf_nextu2(&utf_ptr);
1586 if (c == '/') c = '.';
1590 /* terminate string */
1595 /* utf_strcat_convert_to_latin1 ************************************************
1597 Like libc strcat, but uses an utf8 string.
1598 Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield
1601 *******************************************************************************/
1603 void utf_strcat_convert_to_latin1(char *buffer, utf *u)
1605 utf_sprint_convert_to_latin1(buffer + strlen(buffer), u);
1609 /* utf_strcat_convert_to_latin1_classname **************************************
1611 Like libc strcat, but uses an utf8 string.
1612 Characters are converted to 8-bit Latin-1, non-Latin-1 characters yield
1615 *******************************************************************************/
1617 void utf_strcat_convert_to_latin1_classname(char *buffer, utf *u)
1619 utf_sprint_convert_to_latin1_classname(buffer + strlen(buffer), u);
1623 /* utf_fprint_printable_ascii **************************************************
1625 Write utf symbol into file.
1626 Non-printable and non-ASCII characters are printed as '?'.
1628 *******************************************************************************/
1630 void utf_fprint_printable_ascii(FILE *file, utf *u)
1632 char *endpos; /* points behind utf string */
1633 char *utf_ptr; /* current position in utf text */
1638 endpos = UTF_END(u);
1641 while (utf_ptr < endpos) {
1642 /* read next unicode character */
1643 u2 c = utf_nextu2(&utf_ptr);
1645 if (c >= 32 && c <= 127) fprintf(file, "%c", c);
1646 else fprintf(file, "?");
1651 /* utf_fprint_printable_ascii_classname ****************************************
1653 Write utf symbol into file with `/' converted to `.'.
1654 Non-printable and non-ASCII characters are printed as '?'.
1656 *******************************************************************************/
1658 void utf_fprint_printable_ascii_classname(FILE *file, utf *u)
1660 char *endpos; /* points behind utf string */
1661 char *utf_ptr; /* current position in utf text */
1666 endpos = UTF_END(u);
1669 while (utf_ptr < endpos) {
1670 /* read next unicode character */
1671 u2 c = utf_nextu2(&utf_ptr);
1672 if (c == '/') c = '.';
1674 if (c >= 32 && c <= 127) fprintf(file, "%c", c);
1675 else fprintf(file, "?");
1680 /* is_valid_utf ****************************************************************
1682 Return true if the given string is a valid UTF-8 string.
1684 utf_ptr...points to first character
1685 end_pos...points after last character
1687 *******************************************************************************/
1689 /* static unsigned long min_codepoint[6] = {0,1L<<7,1L<<11,1L<<16,1L<<21,1L<<26}; */
1691 bool is_valid_utf(char *utf_ptr, char *end_pos)
1698 if (end_pos < utf_ptr) return false;
1699 bytes = end_pos - utf_ptr;
1703 if (!c) return false; /* 0x00 is not allowed */
1704 if ((c & 0x80) == 0) continue; /* ASCII */
1706 if ((c & 0xe0) == 0xc0) len = 1; /* 110x xxxx */
1707 else if ((c & 0xf0) == 0xe0) len = 2; /* 1110 xxxx */
1708 else if ((c & 0xf8) == 0xf0) len = 3; /* 1111 0xxx */
1709 else if ((c & 0xfc) == 0xf8) len = 4; /* 1111 10xx */
1710 else if ((c & 0xfe) == 0xfc) len = 5; /* 1111 110x */
1711 else return false; /* invalid leading byte */
1713 if (len > 2) return false; /* Java limitation */
1715 v = (unsigned long)c & (0x3f >> len);
1717 if ((bytes -= len) < 0) return false; /* missing bytes */
1719 for (i = len; i--; ) {
1721 if ((c & 0xc0) != 0x80) /* 10xx xxxx */
1723 v = (v << 6) | (c & 0x3f);
1727 if (len != 1) return false; /* Java special */
1730 /* Sun Java seems to allow overlong UTF-8 encodings */
1732 /* if (v < min_codepoint[len]) */
1733 /* XXX throw exception? */
1736 /* surrogates in UTF-8 seem to be allowed in Java classfiles */
1737 /* if (v >= 0xd800 && v <= 0xdfff) return false; */ /* surrogates */
1739 /* even these seem to be allowed */
1740 /* if (v == 0xfffe || v == 0xffff) return false; */ /* invalid codepoints */
1747 /* is_valid_name ***************************************************************
1749 Return true if the given string may be used as a class/field/method
1750 name. (Currently this only disallows empty strings and control
1753 NOTE: The string is assumed to have passed is_valid_utf!
1755 utf_ptr...points to first character
1756 end_pos...points after last character
1758 *******************************************************************************/
1760 bool is_valid_name(char *utf_ptr, char *end_pos)
1762 if (end_pos <= utf_ptr) return false; /* disallow empty names */
1764 while (utf_ptr < end_pos) {
1765 unsigned char c = *utf_ptr++;
1767 if (c < 0x20) return false; /* disallow control characters */
1768 if (c == 0xc0 && (unsigned char) *utf_ptr == 0x80) /* disallow zero */
1775 bool is_valid_name_utf(utf *u)
1777 return is_valid_name(u->text, UTF_END(u));
1781 /* utf_show ********************************************************************
1783 Writes the utf symbols in the utfhash to stdout and displays the
1784 number of external hash chains grouped according to the chainlength
1785 (for debugging purposes).
1787 *******************************************************************************/
1789 #if !defined(NDEBUG)
1793 #define CHAIN_LIMIT 20 /* limit for seperated enumeration */
1795 u4 chain_count[CHAIN_LIMIT]; /* numbers of chains */
1796 u4 max_chainlength = 0; /* maximum length of the chains */
1797 u4 sum_chainlength = 0; /* sum of the chainlengths */
1798 u4 beyond_limit = 0; /* number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
1801 printf("UTF-HASH:\n");
1803 /* show element of utf-hashtable */
1805 for (i = 0; i < hashtable_utf->size; i++) {
1806 utf *u = hashtable_utf->ptr[i];
1809 printf("SLOT %d: ", (int) i);
1813 utf_display_printable_ascii(u);
1821 printf("UTF-HASH: %d slots for %d entries\n",
1822 (int) hashtable_utf->size, (int) hashtable_utf->entries );
1824 if (hashtable_utf->entries == 0)
1827 printf("chains:\n chainlength number of chains %% of utfstrings\n");
1829 for (i=0;i<CHAIN_LIMIT;i++)
1832 /* count numbers of hashchains according to their length */
1833 for (i=0; i<hashtable_utf->size; i++) {
1835 utf *u = (utf*) hashtable_utf->ptr[i];
1836 u4 chain_length = 0;
1838 /* determine chainlength */
1844 /* update sum of all chainlengths */
1845 sum_chainlength+=chain_length;
1847 /* determine the maximum length of the chains */
1848 if (chain_length>max_chainlength)
1849 max_chainlength = chain_length;
1851 /* update number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
1852 if (chain_length>=CHAIN_LIMIT) {
1853 beyond_limit+=chain_length;
1854 chain_length=CHAIN_LIMIT-1;
1857 /* update number of hashchains of current length */
1858 chain_count[chain_length]++;
1861 /* display results */
1862 for (i=1;i<CHAIN_LIMIT-1;i++)
1863 printf(" %2d %17d %18.2f%%\n",i,chain_count[i],(((float) chain_count[i]*i*100)/hashtable_utf->entries));
1865 printf(" >=%2d %17d %18.2f%%\n",CHAIN_LIMIT-1,chain_count[CHAIN_LIMIT-1],((float) beyond_limit*100)/hashtable_utf->entries);
1868 printf("max. chainlength:%5d\n",max_chainlength);
1870 /* avg. chainlength = sum of chainlengths / number of chains */
1871 printf("avg. chainlength:%5.2f\n",(float) sum_chainlength / (hashtable_utf->size-chain_count[0]));
1873 #endif /* !defined(NDEBUG) */
1877 * These are local overrides for various environment variables in Emacs.
1878 * Please do not remove this and leave it at the end of the file, where
1879 * Emacs will automagically detect them.
1880 * ---------------------------------------------------------------------
1883 * indent-tabs-mode: t
1887 * vim:noexpandtab:sw=4:ts=4: