-+-+-+-+-+-+-+-+ START OF PART 205 -+-+-+-+-+-+-+-+ X return result; X`7D /* getnextstrid */ X X/*-------------------------------------------------------------------------- V*/ X Xstatic void freestrid(C(ptksfreeint **) freelist, C(Pint) fid) XPreANSI(ptksfreeint **freelist) XPreANSI(Pint fid) X/* X** \blurb`7BFid is placed on the freeintlist so it can be used again. `7D X** \param`7Btable`7D`7Bhashtable`7D X** \param`7Bfid`7D`7Bstring identifier to be made free`7D X** special notes: this function is used when a string has been deleted from X** the string table and it's corresponding string identifier is made X** available for a new string. X*/ X`7B X ptksfreeint *temp; X X temp = (ptksfreeint *)malloc(sizeof(ptksfreeint)); X temp->freeint = fid; X temp->next = *freelist; X *freelist = temp; X`7D /* freestrid */ X X/*-------------------------------------------------------------------------- V*/ X Xstatic Pint stringlength(C(Pchar *)str) XPreANSI(Pchar *str) X/* X** \blurb`7BReturns length of string up to first ' '(space), '\n' or '\0'`20 X** character.`7D X** \param`7Bstr`7D`7Bstring to find length of`7D X** return value: length of string. X** special notes: The hashstrings algorithm does not permit strings with X** spaces, hence the search for the first space character. The C library X** routine `60strlen' assumes there is a `60\0' character terminating the st Vring, X** however it is safer to look for a `60\n' character aswell. X*/ X`7B X ptkboolean charfound; X Pint ind; X X ind = 0; X charfound = FALSE; X while (!charfound)`20 X `7B X if (str`5Bind`5D == '\n' `7C`7C str`5Bind`5D == '\0') X charfound = TRUE; X else X ind++; X `7D X return ind; X`7D /* stringlength */ X X/*-------------------------------------------------------------------------- V*/ X Xstatic void parsestring(C(Pchar *)beforestr, C(Pchar *)afterstr,`20 X C(Pint) strlength) XPreANSI(Pchar *beforestr) XPreANSI(Pchar *afterstr) XPreANSI(Pint strlength) X/* X** \blurb`7BAll upper case characters are converted to lowercase`20 X** and a `60\0' character is put on end of the string.`7D X** \param`7Bbeforestr`7D`7Bstring to be parsed`7D X** \param`7Bstrlength`7D`7Blength of parsed string`7D X** \param`7Bafterstr`7D`7Bparsed string`7D X*/ X`7B X Pint ind; X X for (ind = 0; ind < strlength; ind++)`20 X `7B X if (isupper(beforestr`5Bind`5D)) X afterstr`5Bind`5D = beforestr`5Bind`5D - ('A' - 'a'); X else X afterstr`5Bind`5D = beforestr`5Bind`5D;`20 X `7D X afterstr`5Bind`5D = '\0'; X`7D /* parsestring */ X X/*-------------------------------------------------------------------------- V*/ X Xstatic ptkboolean addstringtotable(C(ptkshashtable *) table, C(Pchar *) str, X C(Pint *) strint) XPreANSI(ptkshashtable *table) XPreANSI(Pchar *str) XPreANSI(Pint *strint) X/* X** \blurb`7BAdds a string entry to the string table of a given X** hashtable. Reallocates the whole string table if necessary.`7D X** \param`7Btable`7D`7Bhashtable to add string to`7D X** \param`7Bstr`7D`7Bstring to add to table`7D X*/ X`7B X ptksstridentry *strentry; X Pint strlength; X ptkboolean needrealloc; X X /* allocate space for string entry */ X /* if strint < number of strings in list then no need to reallocate */ X X if (table->freeintlist->next == NULL) X needrealloc = TRUE; X else X needrealloc = FALSE; X X *strint = getnextstrid(&table->freeintlist); X if (*strint > table->maxuniqint) X `7B X fprintf(stderr, "HashStrings: Run out of integers to allocate\n"); X return FALSE; X `7D X X if (needrealloc) X `7B X table->numstrings++; X table->stridtable = (ptksstridentry *)realloc(table->stridtable, X table->numstrings * sizeof(ptksstridentry)); X `7D X X strlength = strlen(str); X strentry = (table->stridtable + (*strint - table->minuniqint)); X strentry->strdata = (Pchar *)malloc(strlength + 1); X strncpy(strentry->strdata, str, (strlength + 1)); X strentry->stringlen = strlength; X strentry->uniqint = *strint; X strentry->clashptr = NIL; X strentry->prevptr = NIL; X return TRUE; X`7D /* addstringtotable */ X X/*-------------------------------------------------------------------------- V*/ X Xstatic Pint addtabletotable(C(Pchar *) str) XPreANSI(Pchar *str) X/* X** \blurb`7BAdds a hashtable to the table of hashtables. X** Reallocates the whole table of hashtable names if necessary.`7D X** \param`7Btable`7D`7Btable of hashtables`7D X** \param`7Bstr`7D`7Bname of new hashtable`7D X*/ X`7B X ptkstableentry *tabentry; X Pint stid, strlength; X X /* allocate space for string entry */ X /* if stid < number of tables in list then no need to reallocate */ X X if (toptable.freeintlist->next == NULL) X `7B X toptable.numtables++; X toptable.tablelist = (ptkstableentry *)realloc(toptable.tablelist, X toptable.numtables * sizeof(ptkstableentry)); X `7D X stid = getnextstrid(&toptable.freeintlist); X strlength = strlen(str); X tabentry = &toptable.tablelist`5Bstid`5D; X tabentry->strdata = (Pchar *)malloc(strlength + 1); X strncpy(tabentry->strdata, str, (strlength + 1)); X tabentry->stringlen = strlength; X tabentry->clashptr = NIL; X tabentry->prevptr = NIL; X return stid; X`7D /* addtabletotable */ X X/*-------------------------------------------------------------------------- V*/ X Xstatic void ptk_hashinitialise(C(ptkshashtable *)table, C(Pint) minint,`20 X C(Pint) maxint) XPreANSI(ptkshashtable *table) XPreANSI(Pint minint) XPreANSI(Pint maxint) X/* X** \blurb`7BInitialises table structure, containing hashtable, minuniqint, X** maxuniqint, freeintlist and stridtable. X** Function checks values of minint and maxint in case X** user gets them the wrong way round.`7D X** \param`7Btable`7D`7Bhashtable`7D X** \param`7Bminint`7D`7Blower limit of string identifier range`7D X** \param`7Bmaxint`7D`7Bupper limit of string identifier range`7D X*/ X`7B X Pint ind; X X for (ind = 0; ind < sizeofhashtable; ind++) X table->hashtable`5Bind`5D = NIL; X table->stridtable = (ptksstridentry *)malloc(sizeof(ptksstridentry)); X table->numstrings = 0; X if (minint < maxint) X `7B X table->minuniqint = minint; /* minimum structure identifier */ X table->maxuniqint = maxint; /* maximum structure identifier */ X `7D X else X `7B X table->minuniqint = maxint;`20 X table->maxuniqint = minint ; X `7D X table->freeintlist = (ptksfreeint *)malloc(sizeof(ptksfreeint)); X table->freeintlist->freeint = table->minuniqint; /* first free id */ X table->freeintlist->next = NULL; X`7D /* ptk_hashinitialise */ X X/*-------------------------------------------------------------------------- V*/ X X/*function:external*/ Xextern void ptk_inithashtables(C(void)) X/* PreANSI() */ X/* X** \blurb`7BThis function initialises the table in which the details of X** hashtables created by the application are kept. This function`20 X** must be called before any other hashtable functions.`7D X*/ X`7B X Pint ind; X X for (ind = 0; ind < sizeofhashtable; ind++) X toptable.hashtable`5Bind`5D = NIL; X toptable.tablelist = (ptkstableentry *)malloc(sizeof(ptkstableentry)); X toptable.numtables = 0; X toptable.freeintlist = (ptksfreeint *)malloc(sizeof(ptksfreeint)); X toptable.freeintlist->freeint = 0; /* first free id */ X toptable.freeintlist->next = NULL; X`7D /* ptk_inithashtables */ X X/*-------------------------------------------------------------------------- V*/ X X/*function:external*/ Xextern ptkboolean ptk_hashtableused(C(Pchar *)str) XPreANSI(Pchar *str) X/* X** \parambegin X** \param`7BPchar *`7D`7Bstr`7D`7Bname of hashtable`7D`7BIN`7D X** \paramend X** \blurb`7BThis function checks if a hashtable named \pardesc`7Bstr`7D X** already exists in the table of X** hashtables, returning TRUE if the hashtable exists, otherwise FALSE.`7D X*/ X`7B X Pint hashvalue, strlength; X Pchar *newstr; X ptkboolean found; X Pint foundentry; X X strlength = stringlength(str); X newstr = (Pchar *)malloc(strlength + 1); X parsestring(str, newstr, strlength); X hashvalue = hashstring(newstr, strlength); /* calc hashvalue */ X if (toptable.hashtable`5Bhashvalue - 1`5D == NIL) X `7B `20 X /* not present */ X return FALSE; X `7D X else`20 X `7B X /* collision, so traverse clash pointers to search for occurence */ X searchfortable(newstr, toptable.hashtable`5Bhashvalue - 1`5D, X &foundentry, &found); X return found; X `7D X`7D /* ptk_hashtableused */ X X/*-------------------------------------------------------------------------- V*/ X X/*function:external*/ Xextern void ptk_createhashtable(C(Pchar *) tablestr, C(Pint) minint,`20 X C(Pint) maxint) XPreANSI(Pchar *tablestr) XPreANSI(Pint minint) XPreANSI(Pint maxint) X/* X** \parambegin X** \param`7BPchar *`7D`7Btablestr`7D`7Bhashtable name`7D`7BIN`7D X** \param`7BPint`7D`7Bminint`7D`7Blower limit of string-integer range`7D`7BI VN`7D X** \param`7BPint`7D`7Bmaxint`7D`7Bupper limit of string-integer range`7D`7BI VN`7D X** \paramend X** \blurb`7BThis function creates a new hashtable, with the name \pardesc`7B Vtablestr`7D.`20 X** \pardesc`7Bminint`7D and \pardesc`7Bmaxint`7D respectively specify the lo Vwer and`20 X** upper limits of the range of`20 X** integers to which strings hashed into the hashtable will be mapped.`7D X*/ X`7B X Pint hashvalue, stid, strlength; X Pchar *newstr; X ptkboolean found; X Pint foundentry; X`20 X /* check if string exists in top table */ X if (!ptk_hashtableused(tablestr)) X `7B X /* addstringtotable */ X `20 X strlength = stringlength(tablestr); X newstr = (Pchar *)malloc(strlength + 1); /* `60+1' for \0 character */ X parsestring(tablestr, newstr, strlength); X hashvalue = hashstring(newstr, strlength); /* calc hashvalue */ X if (toptable.hashtable`5Bhashvalue - 1`5D == NIL) X `7B `20 X /* no collision, so add string */ X stid = addtabletotable(newstr); X toptable.hashtable`5Bhashvalue - 1`5D = stid; X free(newstr); X `7D`20 X else`20 X `7B X /* collision, so traverse clash pointers to first free position */ X searchfortable(newstr, toptable.hashtable`5Bhashvalue - 1`5D, X &foundentry, &found); X X /* add into table */ X stid = addtabletotable(newstr); X toptable.hashtable`5Bhashvalue - 1`5D = stid;`20 X toptable.tablelist`5Bfoundentry`5D.clashptr = stid; X toptable.tablelist`5Bstid`5D.prevptr = foundentry; X free(newstr); X `7D /* else */ X`20 X toptable.tablelist`5Bstid`5D.tableptr =`20 X (ptkshashtable *)malloc(sizeof(ptkshashtable)); X ptk_hashinitialise(toptable.tablelist`5Bstid`5D.tableptr, minint, maxint V); X `7D X`7D /* ptk_createhashtable */ X X/*-------------------------------------------------------------------------- V*/ X Xstatic ptkshashtable * ptk_stringtotable(C(Pchar *)str) XPreANSI(Pchar *str) X/* X** \parambegin X** \param`7BPchar *`7D`7Bstr`7D`7Bname of hashtable`7D`7BIN`7D X** \paramend X** \blurb`7BReturns pointer to a hashtable.`7D X*/ X`7B X Pint hashvalue, strlength; X Pchar *newstr; X ptkboolean found; X Pint foundentry; X X strlength = stringlength(str); X newstr = (Pchar *)malloc(strlength + 1); /* `60+1' for \0 character */ X parsestring(str, newstr, strlength); X hashvalue = hashstring(newstr, strlength); /* calc hashvalue */ X if (toptable.hashtable`5Bhashvalue - 1`5D == NIL) X `7B `20 X /* no collision, so no table */ X free(newstr); X fprintf(stderr, "HashStrings: Hashtable \"%s\" doesn't exist\n", str); X return NULL; X `7D`20 X else`20 X `7B X /* collision, so traverse clash pointers to first free position */ X searchfortable(newstr, toptable.hashtable`5Bhashvalue - 1`5D, X &foundentry, &found); X free(newstr);`20 X return toptable.tablelist`5Bfoundentry`5D.tableptr; X `7D /* else */ X`7D /* ptk_stringtotable */ X X/*-------------------------------------------------------------------------- V*/ X X/*function:external*/ Xextern void ptk_inttostring(C(Pchar *) tablestr, C(Pint) stint,`20 X C(Pint) size, C(Pchar *) strbuffer,`20 X C(Pint *) buffersize) XPreANSI(Pchar *tablestr) XPreANSI(Pint stint) XPreANSI(Pint size) XPreANSI(Pchar *strbuffer) XPreANSI(Pint *buffersize) X/* X** \parambegin X** \param`7BPchar *`7D`7Btablestr`7D`7Bhashtable name`7D`7BIN`7D X** \param`7BPint`7D`7Bstint`7D`7Bstring identifier to search hashtable for`7 VD`7BIN`7D X** \param`7BPint`7D`7Bsize`7D`7Bnumber of bytes allocated by the user for th Ve string`7D`7BIN`7D X** \param`7BPchar *`7D`7Bstrbuffer`7D`7Bpointer to space allocated by the us Ver for the string`7D`7BOUT`7D X** \param`7BPint *`7D`7Bbuffersize`7D`7Bactual size of buffer required`7D`7B VOUT`7D X** \paramend X** \blurb`7BThis function returns the string in hashtable \pardesc`7Btablest Vr`7D X** which has been allocated the integer X** \pardesc`7Bstint`7D. The string is returned in the buffer \pardesc`7Bstrb Vuffer`7D, X** which must be allocated by the application. The number of bytes actually V used X** in the buffer is returned in \pardesc`7Bbuffersize`7D, as X** the length of string + 1 (for `60\\0' character), X** or 0 if no string was returned.`7D X*/`20 X`7B X ptksstridentry *strentry; X ptkshashtable *table; X Pint i; X ptkboolean found; X X if ((table = ptk_stringtotable(tablestr)) != NULL) X `7B X found = FALSE; X i = 0; X while ((i < table->numstrings) && (!found)) X `7B X strentry = &table->stridtable`5Bi`5D; X if ((strentry->uniqint == stint) && (strentry->strdata != NULL)) X found = TRUE; X else X i++; X `7D X X if (!found) X `7B `20 X /* no string allocated */ X *buffersize = 0; X return; X `7D X else X `7B X *buffersize = (strentry->stringlen + 1);`20 X `20 X /* check buffer size */ X if (size >= *buffersize) X `7B X /* copy string into buffer. X ** NB: this routine relies on the user being truthful about the X ** size of the buffer, if not errors may occur.`20 +-+-+-+-+-+-+-+- END OF PART 205 +-+-+-+-+-+-+-+-