1 /* nat/VMClass.c - java/lang/Class
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: Roman Obermaiser
29 Changes: Joseph Wenninger
31 $Id: VMClass.c 1516 2004-11-17 11:53:56Z twisti $
39 #include "exceptions.h"
45 #include "toolbox/logging.h"
46 #include "toolbox/memory.h"
47 #include "java_lang_Object.h"
48 #include "java_lang_Class.h"
49 #include "java_lang_ClassLoader.h"
50 #include "java_security_ProtectionDomain.h"
51 #include "java_lang_reflect_Constructor.h"
52 #include "java_lang_reflect_Field.h"
53 #include "java_lang_reflect_Method.h"
54 #include "java_lang_Throwable.h" /* needed for java_lang_VMClass.h */
55 #include "java_lang_VMClass.h"
58 /* for selecting public members */
59 #define MEMBER_PUBLIC 0
63 * Class: java_lang_VMClass
65 * Signature: (Ljava/lang/String;)Ljava/lang/Class;
67 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_forName(JNIEnv *env, jclass clazz, java_lang_String *s)
72 /* illegal argument */
76 /* create utf string in which '.' is replaced by '/' */
77 u = javastring_toutf(s, true);
79 /* create a new class, ... */
86 xclass = (*exceptionptr)->vftbl->class;
88 /* if the exception is a NoClassDefFoundError, we replace it with a
89 ClassNotFoundException, otherwise return the exception */
91 if (xclass == class_get(utf_new_char(string_java_lang_NoClassDefFoundError))) {
92 /* clear exceptionptr, because builtin_new checks for
93 ExceptionInInitializerError */
97 new_exception_javastring(string_java_lang_ClassNotFoundException, s);
107 /* ...and initialize it */
111 use_class_as_object(c);
113 return (java_lang_Class *) c;
118 * Class: java_lang_VMClass
119 * Method: getClassLoader
120 * Signature: ()Ljava/lang/ClassLoader;
122 JNIEXPORT java_lang_ClassLoader* JNICALL Java_java_lang_VMClass_getClassLoader(JNIEnv *env, jclass clazz, java_lang_Class *that)
124 return (java_lang_ClassLoader *) ((classinfo *) that)->classloader;
126 /* init_systemclassloader();
128 return SystemClassLoader;*/
133 * Class: java_lang_VMClass
134 * Method: getComponentType
135 * Signature: ()Ljava/lang/Class;
137 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_getComponentType(JNIEnv *env, jclass clazz,java_lang_Class *that)
139 classinfo *thisclass = (classinfo *) that;
141 arraydescriptor *desc;
143 if ((desc = thisclass->vftbl->arraydesc) != NULL) {
144 if (desc->arraytype == ARRAYTYPE_OBJECT)
145 c = desc->componentvftbl->class;
147 c = primitivetype_table[desc->arraytype].class_primitive;
150 use_class_as_object(c);
153 return (java_lang_Class *) c;
158 * Class: java_lang_VMClass
159 * Method: getDeclaredConstructors
160 * Signature: (Z)[Ljava/lang/reflect/Constructor;
162 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredConstructors(JNIEnv *env, jclass clazz,
163 struct java_lang_Class *that, s4 public_only)
166 classinfo *c = (classinfo *) that;
167 java_objectheader *o;
168 classinfo *class_constructor;
169 java_objectarray *array_constructor; /* result: array of Method-objects */
170 java_objectarray *exceptiontypes; /* the exceptions thrown by the method */
171 methodinfo *m; /* the current method to be represented */
172 int public_methods = 0; /* number of public methods of the class */
175 utf *utf_constr = utf_new_char("<init>");
177 /* determine number of constructors */
178 for (i = 0; i < c->methodscount; i++)
179 if (((c->methods[i].flags & ACC_PUBLIC) || !public_only) &&
180 (c->methods[i].name == utf_constr))
183 class_constructor = class_new(utf_new_char("java/lang/reflect/Constructor"));
185 if (!class_constructor->loaded)
186 class_load(class_constructor);
188 if (!class_constructor->linked)
189 class_link(class_constructor);
191 array_constructor = builtin_anewarray(public_methods, class_constructor);
193 if (!array_constructor)
196 for (i = 0; i < c->methodscount; i++)
197 if ((c->methods[i].flags & ACC_PUBLIC) || !public_only){
199 if (m->name!=utf_constr)
202 o = native_new_and_init(class_constructor);
203 array_constructor->data[pos++] = o;
205 /* array of exceptions declared to be thrown, information not available !! */
206 exceptiontypes = builtin_anewarray(0, class_java_lang_Class);
208 /* class_showconstantpool(class_constructor);*/
209 /* initialize instance fields */
210 /* ((java_lang_reflect_Constructor*)o)->flag=(m->flags & (ACC_PRIVATE | ACC_PUBLIC | ACC_PROTECTED));*/
211 setfield_critical(class_constructor,o,"clazz", "Ljava/lang/Class;", jobject, (jobject) c /*this*/);
212 setfield_critical(class_constructor,o,"slot", "I", jint, i);
213 /* setfield_critical(class_constructor,o,"flag", "I", jint, (m->flags & (ACC_PRIVATE |
214 ACC_PUBLIC | ACC_PROTECTED))); */
215 setfield_critical(class_constructor,o,"exceptionTypes", "[Ljava/lang/Class;", jobject, (jobject) exceptiontypes);
216 setfield_critical(class_constructor,o,"parameterTypes", "[Ljava/lang/Class;", jobject, (jobject) get_parametertypes(m));
219 return array_constructor;
224 * Class: java_lang_VMClass
225 * Method: getDeclaredClasses
226 * Signature: (Z)[Ljava/lang/Class;
228 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredClasses(JNIEnv *env, jclass clazz, java_lang_Class *that, s4 publicOnly)
230 #if defined(__GNUC__)
231 #warning fix the public only case
233 classinfo *c = (classinfo *) that;
234 int pos = 0; /* current declared class */
235 int declaredclasscount = 0; /* number of declared classes */
236 java_objectarray *result; /* array of declared classes */
237 int notPublicOnly = !publicOnly;
243 /*printf("PublicOnly: %d\n",publicOnly);*/
244 if (!Java_java_lang_VMClass_isPrimitive(env, clazz, (java_lang_Class *) c) && (c->name->text[0] != '[')) {
245 /* determine number of declared classes */
246 for (i = 0; i < c->innerclasscount; i++) {
247 if ( (c->innerclass[i].outer_class == c) && (notPublicOnly || (c->innerclass[i].flags & ACC_PUBLIC)))
248 /* outer class is this class */
249 declaredclasscount++;
253 /*class_showmethods(c); */
255 result = builtin_anewarray(declaredclasscount, class_java_lang_Class);
257 for (i = 0; i < c->innerclasscount; i++) {
258 classinfo *inner = c->innerclass[i].inner_class;
259 classinfo *outer = c->innerclass[i].outer_class;
261 if ((outer == c) && (notPublicOnly || (inner->flags & ACC_PUBLIC))) {
262 /* outer class is this class, store innerclass in array */
263 use_class_as_object(inner);
264 result->data[pos++] = (java_objectheader *) inner;
273 * Class: java/lang/Class
274 * Method: getDeclaringClass
275 * Signature: ()Ljava/lang/Class;
277 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_getDeclaringClass(JNIEnv *env, jclass clazz, struct java_lang_Class *that)
279 #if defined(__GNUC__)
282 classinfo *c = (classinfo *) that;
284 if (that && !Java_java_lang_VMClass_isPrimitive(env, clazz,that) && (c->name->text[0] != '[')) {
287 if (c->innerclasscount == 0) /* no innerclasses exist */
290 for (i = 0; i < c->innerclasscount; i++) {
291 classinfo *inner = c->innerclass[i].inner_class;
292 classinfo *outer = c->innerclass[i].outer_class;
295 /* innerclass is this class */
296 use_class_as_object(outer);
297 return (java_lang_Class *) outer;
302 /* return NULL for arrayclasses and primitive classes */
307 java_lang_reflect_Field* cacao_getField0(JNIEnv *env, java_lang_Class *that, java_lang_String *name, s4 public_only)
310 classinfo *fieldtype;
311 fieldinfo *f; /* the field to be represented */
312 java_lang_reflect_Field *o; /* result: field-object */
313 utf *desc; /* the fielddescriptor */
316 /* create Field object */
317 /* c = (classinfo *) loader_load(utf_new_char("java/lang/reflect/Field")); */
318 c = class_new(utf_new_char("java/lang/reflect/Field"));
319 o = (java_lang_reflect_Field *) native_new_and_init(c);
321 /* get fieldinfo entry */
322 idx = class_findfield_index_approx((classinfo *) that, javastring_toutf(name, false));
325 *exceptionptr = new_exception(string_java_lang_NoSuchFieldException);
329 f = &(((classinfo *) that)->fields[idx]);
331 if (public_only && !(f->flags & ACC_PUBLIC)) {
332 /* field is not public and public only had been requested*/
333 *exceptionptr = new_exception(string_java_lang_NoSuchFieldException);
337 desc = f->descriptor;
338 fieldtype = class_from_descriptor(desc->text, utf_end(desc), NULL, CLASSLOAD_LOAD);
342 /* initialize instance fields */
343 setfield_critical(c,o,"declaringClass", "Ljava/lang/Class;", jobject, (jobject) that /*this*/);
344 /* ((java_lang_reflect_Field*)(o))->flag=f->flags;*/
345 /* save type in slot-field for faster processing */
346 /* setfield_critical(c,o,"flag", "I", jint, (jint) f->flags); */
348 setfield_critical(c,o,"slot", "I", jint, (jint) idx);
349 setfield_critical(c,o,"name", "Ljava/lang/String;", jstring, (jstring) name);
350 /*setfield_critical(c,o,"type", "Ljava/lang/Class;", jclass, fieldtype);*/
360 * Class: java_lang_VMClass
361 * Method: getDeclaredFields
362 * Signature: (Z)[Ljava/lang/reflect/Field;
364 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredFields(JNIEnv *env, jclass clazz, java_lang_Class *that, s4 public_only)
366 classinfo *c = (classinfo *) that;
367 classinfo *class_field;
368 java_objectarray *array_field; /* result: array of field-objects */
369 int public_fields = 0; /* number of elements in field-array */
373 /* determine number of fields */
374 for (i = 0; i < c->fieldscount; i++)
375 if ((c->fields[i].flags & ACC_PUBLIC) || (!public_only))
378 /* class_field = loader_load(utf_new_char("java/lang/reflect/Field")); */
379 class_field = class_new(utf_new_char("java/lang/reflect/Field"));
384 /* create array of fields */
385 array_field = builtin_anewarray(public_fields, class_field);
387 /* creation of array failed */
391 /* get the fields and store in the array */
392 for (i = 0; i < c->fieldscount; i++)
393 if ( (c->fields[i].flags & ACC_PUBLIC) || (!public_only))
394 array_field->data[pos++] =
395 (java_objectheader *) cacao_getField0(env,
396 that, (java_lang_String *) javastring_new(c->fields[i].name),public_only);
402 * Class: java/lang/Class
403 * Method: getInterfaces
404 * Signature: ()[Ljava/lang/Class;
406 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getInterfaces(JNIEnv *env, jclass clazz, java_lang_Class *that)
408 classinfo *c = (classinfo *) that;
412 a = builtin_anewarray(c->interfacescount, class_java_lang_Class);
417 for (i = 0; i < c->interfacescount; i++) {
418 use_class_as_object(c->interfaces[i]);
420 a->data[i] = (java_objectheader *) c->interfaces[i];
427 java_lang_reflect_Method* cacao_getMethod0(JNIEnv *env, java_lang_Class *that, java_lang_String *name, java_objectarray *types, s4 which)
430 classinfo *clazz = (classinfo *) that;
431 java_lang_reflect_Method* o; /* result: Method-object */
432 java_objectarray *exceptiontypes; /* the exceptions thrown by the method */
433 methodinfo *m; /* the method to be represented */
435 /* c = (classinfo *) loader_load(utf_new_char("java/lang/reflect/Method")); */
436 c = class_new(utf_new_char("java/lang/reflect/Method"));
437 o = (java_lang_reflect_Method *) native_new_and_init(c);
439 /* find the method */
440 m = class_resolvemethod_approx(clazz,
441 javastring_toutf(name, false),
442 create_methodsig(types,0)
445 if (!m || (which == MEMBER_PUBLIC && !(m->flags & ACC_PUBLIC))) {
446 /* no apropriate method was found */
447 *exceptionptr = new_exception(string_java_lang_NoSuchMethodException);
451 /* array of exceptions declared to be thrown, information not available! */
452 exceptiontypes = builtin_anewarray(0, class_java_lang_Class);
454 /* initialize instance fields */
456 setfield_critical(c, o, "clazz", "Ljava/lang/Class;", jobject,
457 (jobject) clazz /*this*/);
459 setfield_critical(c, o, "parameterTypes", "[Ljava/lang/Class;", jobject,
462 setfield_critical(c, o, "exceptionTypes", "[Ljava/lang/Class;", jobject,
463 (jobject) exceptiontypes);
465 setfield_critical(c, o, "name", "Ljava/lang/String;", jstring,
466 (jobject) javastring_new(m->name));
468 setfield_critical(c, o, "modifiers", "I", jint,
471 setfield_critical(c, o, "slot", "I", jint,
474 setfield_critical(c, o, "returnType", "Ljava/lang/Class;", jclass,
482 * Class: java_lang_VMClass
483 * Method: getDeclaredMethods
484 * Signature: (Z)[Ljava/lang/reflect/Method;
486 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredMethods(JNIEnv *env, jclass clazz, java_lang_Class *that, s4 public_only)
488 classinfo *c = (classinfo *) that;
489 java_objectheader *o;
490 classinfo *class_method;
491 java_objectarray *array_method; /* result: array of Method-objects */
492 java_objectarray *exceptiontypes; /* the exceptions thrown by the method */
493 methodinfo *m; /* the current method to be represented */
494 int public_methods = 0; /* number of public methods of the class */
497 utf *utf_constr=utf_new_char("<init>");
498 utf *utf_clinit=utf_new_char("<clinit>");
500 /* class_method = (classinfo*) loader_load(utf_new_char ("java/lang/reflect/Method")); */
501 class_method = class_new(utf_new_char("java/lang/reflect/Method"));
506 /* JOWENN: array classes do not declare methods according to mauve test. It should be considered, if
507 we should return to my old clone method overriding instead of declaring it as a member function */
508 if (Java_java_lang_VMClass_isArray(env, clazz,that)) {
509 return builtin_anewarray(0, class_method);
513 /* determine number of methods */
514 for (i = 0; i < c->methodscount; i++)
515 if ((((c->methods[i].flags & ACC_PUBLIC)) || (!public_only)) &&
517 ((c->methods[i].name==utf_constr) ||
518 (c->methods[i].name==utf_clinit) )
522 class_showmethods(class_method);
527 array_method = builtin_anewarray(public_methods, class_method);
532 for (i = 0; i < c->methodscount; i++)
533 if (((c->methods[i].flags & ACC_PUBLIC) || (!public_only)) &&
535 ((c->methods[i].name==utf_constr) ||
536 (c->methods[i].name==utf_clinit) )
540 o = native_new_and_init(class_method);
541 array_method->data[pos++] = o;
543 /* array of exceptions declared to be thrown, information not available !! */
544 exceptiontypes = builtin_anewarray (0, class_java_lang_Class);
547 /* initialize instance fields */
548 /* ((java_lang_reflect_Method*)o)->flag=(m->flags &
549 (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_ABSTRACT | ACC_STATIC | ACC_FINAL |
550 ACC_SYNCHRONIZED | ACC_NATIVE | ACC_STRICT)
552 setfield_critical(class_method,o,"declaringClass", "Ljava/lang/Class;", jobject, (jobject) c /*this*/);
553 setfield_critical(class_method,o,"name", "Ljava/lang/String;", jstring, (jobject) javastring_new(m->name));
554 /* setfield_critical(class_method,o,"flag", "I", jint, (m->flags &
555 (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_ABSTRACT | ACC_STATIC | ACC_FINAL |
556 ACC_SYNCHRONIZED | ACC_NATIVE | ACC_STRICT)));*/
557 setfield_critical(class_method,o,"slot", "I", jint, i);
558 /* setfield_critical(class_method,o,"returnType", "Ljava/lang/Class;", jclass, get_returntype(m));
559 setfield_critical(class_method,o,"exceptionTypes", "[Ljava/lang/Class;", jobject, (jobject) exceptiontypes);
560 setfield_critical(class_method,o,"parameterTypes", "[Ljava/lang/Class;", jobject, (jobject) get_parametertypes(m));*/
568 * Class: java/lang/Class
569 * Method: getModifiers
572 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_getModifiers(JNIEnv *env, jclass clazz, java_lang_Class *that)
574 classinfo *c = (classinfo *) that;
580 * Class: java/lang/Class
582 * Signature: ()Ljava/lang/String;
584 JNIEXPORT java_lang_String* JNICALL Java_java_lang_VMClass_getName(JNIEnv *env, jclass clazz, java_lang_Class* that)
587 classinfo *c = (classinfo *) that;
588 java_lang_String *s = (java_lang_String *) javastring_new(c->name);
593 /* return string where '/' is replaced by '.' */
594 for (i = 0; i < s->value->header.size; i++) {
595 if (s->value->data[i] == '/')
596 s->value->data[i] = '.';
605 * Class: java/lang/VMClass
606 * Method: getBeautifiedName
607 * Signature: (Ljava/lang/Class;)Ljava/lang/String;
609 JNIEXPORT java_lang_String* JNICALL Java_java_lang_VMClass_getBeautifiedName(JNIEnv *env, jclass clazz, java_lang_Class *par1)
612 classinfo *c = (classinfo *) (par1);
614 char *utf__ptr = c->name->text; /* current position in utf-text */
615 char **utf_ptr = &utf__ptr;
616 char *desc_end = utf_end(c->name); /* points behind utf string */
623 log_text("Java_java_lang_VMClass_getBeautifiedName");
624 utf_display(c->name);
625 log_text("beautifying");
628 while ( *utf_ptr != desc_end ) {
629 if (utf_nextu2(utf_ptr)=='[') dimCnt++;
632 utf__ptr = (*utf_ptr) - 1;
638 utf_display(c->name);
642 if (((*utf_ptr) + 1) == desc_end) {
643 for (i = 0; i < PRIMITIVETYPE_COUNT; i++) {
644 if (primitivetype_table[i].typesig == (*utf__ptr)) {
645 len = dimCnt * 2 + strlen(primitivetype_table[i].name);
646 str = MNEW(char, len + 1);
647 strcpy(str, primitivetype_table[i].name);
655 len = dimCnt + strlen(c->name->text) - 2;
656 str = MNEW(char, len + 1);
657 strncpy(str, ++utf__ptr, len - 2 * dimCnt);
659 len = strlen(c->name->text);
660 str = MNEW(char, len + 1);
661 strncpy(str, utf__ptr, len);
666 dimCnt = len - 2 * dimCnt;
668 for (i = len - 1; i >= dimCnt; i = i - 2) {
673 s = javastring_new(utf_new_char(str));
674 MFREE(str, char, len + 1);
678 /* return string where '/' is replaced by '.' */
679 for (i = 0; i < s->value->header.size; i++) {
680 if (s->value->data[i] == '/') s->value->data[i] = '.';
689 * Class: java/lang/Class
690 * Method: getSuperclass
691 * Signature: ()Ljava/lang/Class;
693 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_getSuperclass(JNIEnv *env, jclass clazz, java_lang_Class *that)
695 classinfo *cl = (classinfo *) that;
696 classinfo *c = cl->super;
701 use_class_as_object (c);
703 return (java_lang_Class *) c;
708 * Class: java/lang/Class
712 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isArray(JNIEnv *env, jclass clazz, java_lang_Class *that)
714 classinfo *c = (classinfo *) that;
716 return c->vftbl->arraydesc != NULL;
721 * Class: java/lang/Class
722 * Method: isAssignableFrom
723 * Signature: (Ljava/lang/Class;)Z
725 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isAssignableFrom(JNIEnv *env, jclass clazz, java_lang_Class *that, java_lang_Class *sup)
727 /* log_text("Java_java_lang_VMClass_isAssignableFrom");*/
731 panic("sup->vmClass is NULL in VMClass.isAssignableFrom");
734 return (*env)->IsAssignableForm(env, (jclass) sup, (jclass) that);
739 * Class: java/lang/Class
741 * Signature: (Ljava/lang/Object;)Z
743 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isInstance(JNIEnv *env, jclass clazz, java_lang_Class *that, java_lang_Object *obj)
745 /* classinfo *clazz = (classinfo *) that; */
747 return (*env)->IsInstanceOf(env, (jobject) obj, (jclass) that);
752 * Class: java/lang/Class
753 * Method: isInterface
756 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isInterface(JNIEnv *env, jclass clazz, java_lang_Class *that)
758 classinfo *c = (classinfo *) that;
760 if (c->flags & ACC_INTERFACE)
768 * Class: java/lang/Class
769 * Method: isPrimitive
772 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isPrimitive(JNIEnv *env, jclass clazz, java_lang_Class *that)
775 classinfo *c = (classinfo *) that;
777 /* search table of primitive classes */
778 for (i = 0; i < PRIMITIVETYPE_COUNT; i++)
779 if (primitivetype_table[i].class_primitive == c)
787 * Class: java_lang_VMClass
791 JNIEXPORT void JNICALL Java_java_lang_VMClass_initialize(JNIEnv *env, jclass clazz, java_lang_Class *c)
795 ci = (classinfo *) c;
797 /* initialize class */
798 if (!ci->initialized)
799 /* No need to check return value, because class_init already sets the */
800 /* exception pointer. */
801 (void) class_init(ci);
806 * Class: java_lang_VMClass
807 * Method: loadArrayClass
808 * Signature: (Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/Class;
810 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_loadArrayClass(JNIEnv *env, jclass clazz, java_lang_String *par1, java_lang_ClassLoader* par2)
812 log_text("Java_java_lang_VMClass_loadArrayClass");
819 * Class: java/lang/VMClass
820 * Method: throwException
821 * Signature: (Ljava/lang/Throwable;)V
823 JNIEXPORT void JNICALL Java_java_lang_VMClass_throwException(JNIEnv *env, jclass clazz, java_lang_Throwable *t)
825 *exceptionptr = (java_objectheader *) t;
830 * These are local overrides for various environment variables in Emacs.
831 * Please do not remove this and leave it at the end of the file, where
832 * Emacs will automagically detect them.
833 * ---------------------------------------------------------------------
836 * indent-tabs-mode: t