-/* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
-/****************************** tables.c ***************************************
+/* tables.c -
- Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+ M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+ P. Tomsich, J. Wenninger
- See file COPYRIGHT for information on usage and disclaimer of warranties
+ This file is part of CACAO.
- Enth"alt Supportfunktionen f"ur:
- - Lesen von JavaClass-Files
- - unicode-Symbole
- - den Heap
- - zus"atzliche Support-Funktionen
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
- Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at
- Changes: Mark Probst EMAIL: cacao@complang.tuwien.ac.at
- Andreas Krall EMAIL: cacao@complang.tuwien.ac.at
-
- Last Change: 1998/03/24
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
-*******************************************************************************/
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Reinhard Grafl
+
+ Changes: Mark Probst
+ Andreas Krall
+ Contains support functions for:
+ - Reading of Java class files
+ - Unicode symbols
+ - the heap
+ - additional support functions
+
+ $Id: tables.c 700 2003-12-07 15:54:28Z edwin $
+
+*/
+
+#include <string.h>
#include <assert.h>
+#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
+#include "types.h"
#include "global.h"
#include "tables.h"
#include "asmpart.h"
-#include "callargs.h"
-
-#include "threads/thread.h" /* schani */
+#include "threads/thread.h"
#include "threads/locks.h"
+#include "toolbox/loging.h"
+#include "toolbox/memory.h"
-bool runverbose = false;
/* statistics */
int count_utf_len = 0; /* size of utf hash */
hash->entries = 0;
hash->size = size;
- hash->ptr = MNEW (void*, size);
+ hash->ptr = MNEW(void*, size);
/* clear table */
- for (i=0; i<size; i++) hash->ptr[i] = NULL;
+ for (i = 0; i < size; i++) hash->ptr[i] = NULL;
}
/*********************** function: tables_init *****************************
/* dispose utf symbols */
for (i=0; i<utf_hash.size; i++) {
- u = utf_hash.ptr[i];
+ u = utf_hash.ptr[i];
while (u) {
/* process elements in external hash chain */
utf *nextu = u->hashlink;
MFREE (u->text, u1, u->blength);
FREE (u, utf);
u = nextu;
- }
- }
+ }
+ }
/* dispose javastrings */
for (i=0; i<string_hash.size; i++) {
del(s->string);
FREE(s, literalstring);
s = nexts;
- }
- }
+ }
+ }
/* dispose hashtable structures */
MFREE (utf_hash.ptr, void*, utf_hash.size);
{
char *endpos = utf_end(u); /* points behind utf string */
char *utf_ptr = u->text; /* current position in utf text */
-
+ if (u==NULL) return;
while (utf_ptr<endpos) {
/* read next unicode character */
u2 c = utf_nextu2(&utf_ptr);
if (c>=32 && c<=127) printf ("%c",c);
- else printf ("?");
+ else printf ("?");
}
fflush (stdout);
}
+/************************* function: log_utf *********************************
+
+ log utf symbol
+
+******************************************************************************/
+
+void log_utf(utf *u)
+{
+ char buf[MAXLOGTEXT];
+ utf_sprint(buf,u);
+ dolog(buf);
+}
+
+/********************** function: log_plain_utf ******************************
+
+ log utf symbol (without printing "LOG: " and newline)
+
+******************************************************************************/
+
+void log_plain_utf(utf *u)
+{
+ char buf[MAXLOGTEXT];
+ utf_sprint(buf,u);
+ dolog_plain(buf);
+}
+
/************************ function: utf_sprint *******************************
write utf symbol into c-string (debugging purposes)
{
char *endpos = utf_end(u); /* points behind utf string */
char *utf_ptr = u->text; /* current position in utf text */
+ if (u==NULL) return;
+ while (utf_ptr<endpos) {
+ /* read next unicode character */
+ u2 c = utf_nextu2(&utf_ptr);
- while (utf_ptr<endpos)
- /* write next unicode character */
- putc ( utf_nextu2(&utf_ptr), file );
+ if (c>=32 && c<=127) fprintf (file,"%c",c);
+ else fprintf (file,"?");
+ }
}
case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7);
case 9: a = fbs(0) ^ nbs(1) ^ nbs(2);
- text++;
- return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8);
+ text++;
+ return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8);
case 10: a = fbs(0);
- text++;
- a^= nbs(2) ^ nbs(3) ^ nbs(4);
- text++;
- return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9);
+ text++;
+ a^= nbs(2) ^ nbs(3) ^ nbs(4);
+ text++;
+ return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9);
case 11: a = fbs(0);
- text++;
- a^= nbs(2) ^ nbs(3) ^ nbs(4);
- text++;
- return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10);
+ text++;
+ a^= nbs(2) ^ nbs(3) ^ nbs(4);
+ text++;
+ return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10);
case 12: a = fbs(0);
- text+=2;
- a^= nbs(2) ^ nbs(3);
- text+=1;
- a^= nbs(5) ^ nbs(6) ^ nbs(7);
- text+=1;
- return a ^ nbs(9) ^ nbs(10);
+ text+=2;
+ a^= nbs(2) ^ nbs(3);
+ text+=1;
+ a^= nbs(5) ^ nbs(6) ^ nbs(7);
+ text+=1;
+ return a ^ nbs(9) ^ nbs(10);
case 13: a = fbs(0) ^ nbs(1);
- text+=1;
- a^= nbs(3) ^ nbs(4);
- text+=2;
- a^= nbs(7) ^ nbs(8);
- text+=2;
- return a ^ nbs(9) ^ nbs(10);
+ text+=1;
+ a^= nbs(3) ^ nbs(4);
+ text+=2;
+ a^= nbs(7) ^ nbs(8);
+ text+=2;
+ return a ^ nbs(9) ^ nbs(10);
case 14: a = fbs(0);
- text+=2;
- a^= nbs(3) ^ nbs(4);
- text+=2;
- a^= nbs(7) ^ nbs(8);
- text+=2;
- return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
+ text+=2;
+ a^= nbs(3) ^ nbs(4);
+ text+=2;
+ a^= nbs(7) ^ nbs(8);
+ text+=2;
+ return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
case 15: a = fbs(0);
- text+=2;
- a^= nbs(3) ^ nbs(4);
- text+=2;
- a^= nbs(7) ^ nbs(8);
- text+=2;
- return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
+ text+=2;
+ a^= nbs(3) ^ nbs(4);
+ text+=2;
+ a^= nbs(7) ^ nbs(8);
+ text+=2;
+ return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
default: /* 3 characters from beginning */
- a = fbs(0);
- text+=2;
- a^= nbs(3) ^ nbs(4);
+ a = fbs(0);
+ text+=2;
+ a^= nbs(3) ^ nbs(4);
- /* 2 characters from middle */
- text = start_pos + (length / 2);
- a^= fbs(5);
- text+=2;
- a^= nbs(6);
+ /* 2 characters from middle */
+ text = start_pos + (length / 2);
+ a^= fbs(5);
+ text+=2;
+ a^= nbs(6);
- /* 3 characters from end */
- text = start_pos + length - 4;
+ /* 3 characters from end */
+ text = start_pos + length - 4;
- a^= fbs(7);
- text+=1;
+ a^= fbs(7);
+ text+=1;
- return a ^ nbs(10) ^ nbs(11);
+ return a ^ nbs(10) ^ nbs(11);
}
}
u4 unicode_hashkey (u2 *text, u2 len)
{
- utf_hashkey((char*) text, len);
+ return utf_hashkey((char*) text, len);
}
/************************ function: utf_new **********************************
utf *u; /* hashtable element */
u2 i;
+/* log_text("utf_new entered");*/
#ifdef STATISTICS
count_utf_new++;
#endif
#ifdef STATISTICS
count_utf_new_found++;
#endif
- /* symbol found in hashtable */
+/* log_text("symbol found in hash table");*/
+ /* symbol found in hashtable */
+/* utf_display(u);
+ {
+ utf blup;
+ blup.blength=length;
+ blup.text=text;
+ utf_display(&blup);
+ }*/
return u;
}
- nomatch:
+ nomatch:
u = u->hashlink; /* next element in external chain */
}
u = NEW (utf);
u->blength = length; /* length in bytes of utfstring */
u->hashlink = utf_hash.ptr[slot]; /* link in external hashchain */
- u->text = mem_alloc(length); /* allocate memory for utf-text */
+ u->text = mem_alloc(length/*JOWENN*/+1); /* allocate memory for utf-text */
memcpy(u->text,text,length); /* copy utf-text */
+ u->text[length]='\0';/*JOWENN*/
utf_hash.ptr[slot] = u; /* insert symbol into table */
utf_hash.entries++; /* update number of entries */
/* reorganization of hashtable, average length of
the external chains is approx. 2 */
- u4 i;
- utf *u;
- hashtable newhash; /* the new hashtable */
+ u4 i;
+ utf *u;
+ hashtable newhash; /* the new hashtable */
- /* create new hashtable, double the size */
- init_hashtable(&newhash, utf_hash.size*2);
- newhash.entries=utf_hash.entries;
+ /* create new hashtable, double the size */
+ init_hashtable(&newhash, utf_hash.size*2);
+ newhash.entries=utf_hash.entries;
#ifdef STATISTICS
- count_utf_len += sizeof(utf*) * utf_hash.size;
+ count_utf_len += sizeof(utf*) * utf_hash.size;
#endif
- /* transfer elements to new hashtable */
- for (i=0; i<utf_hash.size; i++) {
- u = (utf*) utf_hash.ptr[i];
- while (u) {
- utf *nextu = u -> hashlink;
- u4 slot = (utf_hashkey(u->text,u->blength)) & (newhash.size-1);
+ /* transfer elements to new hashtable */
+ for (i=0; i<utf_hash.size; i++) {
+ u = (utf*) utf_hash.ptr[i];
+ while (u) {
+ utf *nextu = u -> hashlink;
+ u4 slot = (utf_hashkey(u->text,u->blength)) & (newhash.size-1);
- u->hashlink = (utf*) newhash.ptr[slot];
- newhash.ptr[slot] = u;
+ u->hashlink = (utf*) newhash.ptr[slot];
+ newhash.ptr[slot] = u;
- /* follow link in external hash chain */
- u = nextu;
+ /* follow link in external hash chain */
+ u = nextu;
}
}
- /* dispose old table */
- MFREE (utf_hash.ptr, void*, utf_hash.size);
- utf_hash = newhash;
+ /* dispose old table */
+ MFREE (utf_hash.ptr, void*, utf_hash.size);
+ utf_hash = newhash;
}
-
+ /*utf_display(u);*/
return u;
}
return utf_new(text, strlen(text));
}
+
+/********************* function: utf_new_char ********************************
+
+ creates a new utf symbol, the text for this symbol is passed
+ as a c-string ( = char* )
+ "." characters are going to be replaced by "/". since the above function is
+ used often, this is a separte function, instead of an if
+
+******************************************************************************/
+
+utf *utf_new_char_classname (char *text)
+{
+ if (strchr(text,'.')) {
+ char *txt=strdup(text);
+ char *end=txt+strlen(txt);
+ char *c;
+ utf *tmpRes;
+ for (c=txt;c<end;c++)
+ if (*c=='.') *c='/';
+ tmpRes=utf_new(txt,strlen(txt));
+ free(txt);
+ return tmpRes;
+ }
+ else
+ return utf_new(text, strlen(text));
+}
+
/************************** Funktion: utf_show ******************************
writes the utf symbols in the utfhash to stdout and
utf_display (u);
printf ("' ");
u = u->hashlink;
- }
+ }
printf ("\n");
- }
-
}
+
+ }
printf ("UTF-HASH: %d slots for %d entries\n",
- (int) utf_hash.size, (int) utf_hash.entries );
+ (int) utf_hash.size, (int) utf_hash.entries );
if (utf_hash.entries == 0)
while (u) {
u = u->hashlink;
chain_length++;
- }
+ }
/* update sum of all chainlengths */
sum_chainlength+=chain_length;
/* update number of hashchains of current length */
chain_count[chain_length]++;
- }
+ }
/* display results */
for (i=1;i<CHAIN_LIMIT-1;i++)
}
/******************************************************************************
-*********************** Diverse Support-Funktionen ****************************
+*********************** Misc support functions ********************************
******************************************************************************/
-/******************** Funktion: desc_to_type **********************************
+/******************** Function: desc_to_type **********************************
- Findet zu einem gegebenen Typdescriptor den entsprechenden
- Java-Grunddatentyp.
+ Determines the corresponding Java base data type for a given type
+ descriptor.
******************************************************************************/
-u2 desc_to_type (utf *descriptor)
+u2 desc_to_type(utf *descriptor)
{
char *utf_ptr = descriptor->text; /* current position in utf text */
+ char logtext[MAXLOGTEXT];
- if (descriptor->blength < 1) panic ("Type-Descriptor is empty string");
+ if (descriptor->blength < 1) panic("Type-Descriptor is empty string");
switch (*utf_ptr++) {
case 'B':
case '[': return TYPE_ADDRESS;
}
- sprintf (logtext, "Invalid Type-Descriptor: ");
- utf_sprint (logtext+strlen(logtext), descriptor);
- error ();
+ sprintf(logtext, "Invalid Type-Descriptor: ");
+ utf_sprint(logtext+strlen(logtext), descriptor);
+ error(logtext);
+
return 0;
}
-/********************** Funktion: desc_typesize *******************************
+/********************** Function: desc_typesize *******************************
- Berechnet die L"ange (in Byte) eines Datenelements gegebenen Typs,
- der durch den Typdescriptor gegeben ist.
+ Calculates the lenght in bytes needed for a data element of the type given
+ by its type descriptor.
******************************************************************************/
int len;
switch ((ch1 = utf[0]) >> 4) {
- default: /* 1 byte */
- (*utf_ptr)++;
- return ch1;
- case 0xC:
- case 0xD: /* 2 bytes */
- if (((ch2 = utf[1]) & 0xC0) == 0x80) {
- unsigned char high = ch1 & 0x1F;
- unsigned char low = ch2 & 0x3F;
- unicode_char = (high << 6) + low;
- len = 2;
- }
- break;
-
- case 0xE: /* 2 or 3 bytes */
- if (((ch2 = utf[1]) & 0xC0) == 0x80) {
- if (((ch3 = utf[2]) & 0xC0) == 0x80) {
- unsigned char low = ch3 & 0x3f;
- unsigned char mid = ch2 & 0x3f;
- unsigned char high = ch1 & 0x0f;
- unicode_char = (((high << 6) + mid) << 6) + low;
- len = 3;
- } else
- len = 2;
- }
- break;
+ default: /* 1 byte */
+ (*utf_ptr)++;
+ return ch1;
+ case 0xC:
+ case 0xD: /* 2 bytes */
+ if (((ch2 = utf[1]) & 0xC0) == 0x80) {
+ unsigned char high = ch1 & 0x1F;
+ unsigned char low = ch2 & 0x3F;
+ unicode_char = (high << 6) + low;
+ len = 2;
+ }
+ break;
+
+ case 0xE: /* 2 or 3 bytes */
+ if (((ch2 = utf[1]) & 0xC0) == 0x80) {
+ if (((ch3 = utf[2]) & 0xC0) == 0x80) {
+ unsigned char low = ch3 & 0x3f;
+ unsigned char mid = ch2 & 0x3f;
+ unsigned char high = ch1 & 0x0f;
+ unicode_char = (((high << 6) + mid) << 6) + low;
+ len = 3;
+ } else
+ len = 2;
+ }
+ break;
}
/* update position in utf-text */
*utf_ptr = (char *) (utf + len);
return unicode_char;
}
+
-/******************** Funktion: class_new **************************************
+/******************** Function: class_new **************************************
searches for the class with the specified name in the classes hashtable,
if there is no such class a new classinfo structure is created and inserted
*******************************************************************************/
-classinfo *class_new (utf *u)
+classinfo *class_new(utf *u)
{
classinfo *c; /* hashtable element */
u4 key; /* hashkey computed from classname */
for (i=0; i<u->blength; i++)
if (u->text[i] != c->name->text[i]) goto nomatch;
- /* class found in hashtable */
- return c;
- }
+ /* class found in hashtable */
+ return c;
+ }
- nomatch:
+ nomatch:
c = c->hashlink; /* next element in external chain */
- }
+ }
/* location in hashtable found, create new classinfo structure */
count_class_infos += sizeof(classinfo);
#endif
- c = NEW (classinfo);
+ c = GCNEW (classinfo,1); /*JOWENN: NEW*/
+ c -> vmClass = 0;
c -> flags = 0;
c -> name = u;
c -> cpcount = 0;
c -> methodscount = 0;
c -> methods = NULL;
c -> linked = false;
+ c -> loaded = false;
c -> index = 0;
c -> instancesize = 0;
c -> header.vftbl = NULL;
c -> innerclass = NULL;
c -> vftbl = NULL;
c -> initialized = false;
+ c -> classvftbl = false;
+ c -> classUsed = 0;
+ c -> impldBy = NULL;
/* prepare loading of the class */
- list_addlast (&unloadedclasses, c);
+ list_addlast(&unloadedclasses, c);
/* insert class into the hashtable */
c->hashlink = class_hash.ptr[slot];
/* update number of hashtable-entries */
class_hash.entries++;
- if ( class_hash.entries > (class_hash.size*2)) {
+ if (class_hash.entries > (class_hash.size*2)) {
- /* reorganization of hashtable, average length of
- the external chains is approx. 2 */
+ /* reorganization of hashtable, average length of
+ the external chains is approx. 2 */
- u4 i;
- classinfo *c;
- hashtable newhash; /* the new hashtable */
+ u4 i;
+ classinfo *c;
+ hashtable newhash; /* the new hashtable */
- /* create new hashtable, double the size */
- init_hashtable(&newhash, class_hash.size*2);
- newhash.entries = class_hash.entries;
+ /* create new hashtable, double the size */
+ init_hashtable(&newhash, class_hash.size*2);
+ newhash.entries = class_hash.entries;
- /* transfer elements to new hashtable */
- for (i=0; i<class_hash.size; i++) {
- c = (classinfo*) class_hash.ptr[i];
- while (c) {
- classinfo *nextc = c -> hashlink;
- u4 slot = (utf_hashkey(c->name->text,c->name->blength)) & (newhash.size-1);
+ /* transfer elements to new hashtable */
+ for (i = 0; i < class_hash.size; i++) {
+ c = (classinfo*) class_hash.ptr[i];
+ while (c) {
+ classinfo *nextc = c->hashlink;
+ u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
- c->hashlink = newhash.ptr[slot];
- newhash.ptr[slot] = c;
+ c->hashlink = newhash.ptr[slot];
+ newhash.ptr[slot] = c;
- c = nextc;
+ c = nextc;
}
}
- /* dispose old table */
- MFREE (class_hash.ptr, void*, class_hash.size);
- class_hash = newhash;
+ /* dispose old table */
+ MFREE(class_hash.ptr, void*, class_hash.size);
+ class_hash = newhash;
}
+ /* Array classes need further initialization. */
+ if (u->text[0] == '[')
+ class_new_array(c);
+
return c;
}
-/******************** Funktion: class_get **************************************
+/******************** Function: class_get **************************************
searches for the class with the specified name in the classes hashtable
if there is no such class NULL is returned
*******************************************************************************/
-classinfo *class_get (utf *u)
+classinfo *class_get(utf *u)
{
classinfo *c; /* hashtable element */
u4 key; /* hashkey computed from classname */
slot = key & (class_hash.size-1);
c = class_hash.ptr[slot];
+/*
+ log_text("class_get: looking for class:");
+ utf_display(u); */
/* search external hash-chain */
while (c) {
if (c->name->blength == u->blength) {
/* compare classnames */
for (i=0; i<u->blength; i++)
if (u->text[i] != c->name->text[i]) goto nomatch;
-
+/*
+ log_text("class_get: class found");
+ utf_display(u);
+ log_text("");
+ utf_display(c->name); */
/* class found in hashtable */
return c;
- }
+ }
- nomatch:
+ nomatch:
c = c->hashlink;
- }
+ }
/* class not found */
return NULL;
}
+/***************** Function: class_array_of ***********************************
+
+ Returns an array class with the given component class.
+ The array class is dynamically created if neccessary.
+
+*******************************************************************************/
+
+classinfo *class_array_of(classinfo *component)
+{
+ int namelen;
+ char *namebuf;
+
+ /* Assemble the array class name */
+ namelen = component->name->blength;
+
+ if (component->name->text[0] == '[') {
+ /* the component is itself an array */
+ namebuf = DMNEW(char,namelen+1);
+ namebuf[0] = '[';
+ memcpy(namebuf+1,component->name->text,namelen);
+ namelen++;
+ }
+ else {
+ /* the component is a non-array class */
+ namebuf = DMNEW(char,namelen+3);
+ namebuf[0] = '[';
+ namebuf[1] = 'L';
+ memcpy(namebuf+2,component->name->text,namelen);
+ namebuf[2+namelen] = ';';
+ namelen+=3;
+ }
+
+ return class_new( utf_new(namebuf,namelen) );
+}
+
+/*************** Function: class_multiarray_of ********************************
+
+ Returns an array class with the given dimension and element class.
+ The array class is dynamically created if neccessary.
+
+*******************************************************************************/
+
+classinfo *class_multiarray_of(int dim,classinfo *element)
+{
+ int namelen;
+ char *namebuf;
+
+ if (dim<1)
+ panic("Invalid array dimension requested");
+
+ /* Assemble the array class name */
+ namelen = element->name->blength;
+
+ if (element->name->text[0] == '[') {
+ /* the element is itself an array */
+ namebuf = DMNEW(char,namelen+dim);
+ memcpy(namebuf+dim,element->name->text,namelen);
+ namelen += dim;
+ }
+ else {
+ /* the element is a non-array class */
+ namebuf = DMNEW(char,namelen+2+dim);
+ namebuf[dim] = 'L';
+ memcpy(namebuf+dim+1,element->name->text,namelen);
+ namelen += (2+dim);
+ namebuf[namelen-1] = ';';
+ }
+ memset(namebuf,'[',dim);
+
+ return class_new( utf_new(namebuf,namelen) );
+}
/************************** function: utf_strlen ******************************
u4 len = 0; /* number of unicode characters */
while (utf_ptr<endpos) {
- len++;
- /* next unicode character */
- utf_nextu2(&utf_ptr);
+ len++;
+ /* next unicode character */
+ utf_nextu2(&utf_ptr);
}
if (utf_ptr!=endpos)
/* string ended abruptly */
- panic("illegal utf string");
+ panic("illegal utf string");
return len;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */