CDE has relied upon catgets() implementations following a relaxed interpretation of the XPG internationalization standard that ignored -1, the standard error value returned by catopen, as the catalog argument. However, this same behavior causes segmentation faults with the musl C library. This patch: - Centralizes (with the exception of ToolTalk) all calls to catopen(), catgets(), and catclose() through MsgCat within the DtSvc library. - Prevents calls to catgets() and catclose() that rely upon undefined behavior. - Eliminates a number of bespoke catgets() wrappers, including multiple redundant caching implementations designed to work around a design peculiarity in HP/UX. - Eases building CDE without XPG internationalization support by providing the appropriate macros.
1067 lines
31 KiB
C
1067 lines
31 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*
|
|
* $XConsortium: istr.c /main/4 1995/11/06 18:50:43 rswiston $
|
|
*
|
|
* @(#)istr.c 1.25 14 Feb 1994 cde_app_builder/src/libAButil
|
|
*
|
|
* RESTRICTED CONFIDENTIAL INFORMATION:
|
|
*
|
|
* The information in this document is subject to special
|
|
* restrictions in a confidential disclosure agreement between
|
|
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
|
|
* document outside HP, IBM, Sun, USL, SCO, or Univel without
|
|
* Sun's specific written approval. This document and all copies
|
|
* and derivative works thereof must be returned or destroyed at
|
|
* Sun's request.
|
|
*
|
|
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* istr.c
|
|
*
|
|
* Implements ISTRING data type.
|
|
*
|
|
* the istr variable is private, but is made to be used within
|
|
* the debugger. To get the value of an ISTRING, use
|
|
* print/display debug_istr[iString].
|
|
*
|
|
* Whenever setting the private variable int_array from within this
|
|
* ISTRING * implementation module, use int_array_set macro, as it
|
|
* will keep the istr variable up-to-date for debugging clients.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <ab_private/istr.h>
|
|
#include "utilP.h"
|
|
|
|
#define istrP_create_alloced_impl istrP_create_alloced_impl9726039350PrivF
|
|
#define istrP_destroy_impl istrP_destroy_impl518283652PrivF
|
|
#define istrP_get_string_verify istrP_get_string_verify4521632085PrivF
|
|
#define int_array istrP_int_array1809065681PrivD
|
|
#define num_count istrP_num_count7608925912PrivD
|
|
#define STRN ISTR_PRIVT_STRN
|
|
|
|
/* #define NUMBUCKETS 211 */
|
|
#define NUMBUCKETS 1024
|
|
#define NUMBUCKETS_MASK ((unsigned)(NUMBUCKETS-1))
|
|
#define BUCKETSIZE 10
|
|
#define ARRAYSIZE 100 /* size of and freelist */
|
|
|
|
typedef struct BUCKET
|
|
{
|
|
struct BUCKET *next;
|
|
int values[BUCKETSIZE];
|
|
} BucketRec, *Bucket;
|
|
|
|
/*
|
|
* Public data
|
|
*/
|
|
STRING Istr_null_string= "(nil)";
|
|
STRN *int_array= NULL; /* unique number array */
|
|
long num_count = 1; /* unique number counter */
|
|
|
|
static BucketRec hashtable[NUMBUCKETS];
|
|
|
|
#ifdef DEBUG
|
|
STRN *debug_istr= NULL; /* debugging shortcut for clients (see */
|
|
/* comment at top of this file) */
|
|
#endif /* DEBUG */
|
|
|
|
static long *freelist; /* freelist for unused numbers */
|
|
|
|
static long freecount = 0; /* freelist count */
|
|
static long hash_count = 0; /* total number that has been inserted */
|
|
|
|
static unsigned hashing(
|
|
char *p
|
|
);
|
|
|
|
static int insert_array(
|
|
int flag,
|
|
int val,
|
|
char *string
|
|
);
|
|
|
|
static int hash_and_lookupstr(
|
|
char *string,
|
|
int *hash_val_out_ptr
|
|
);
|
|
|
|
static int hashtable_init(void);
|
|
|
|
static int istrP_errmsg_noexist(int istr_value);
|
|
|
|
#define check_init() ((hash_count == 0) && (hashtable_init() >= 0))
|
|
#ifdef DEBUG
|
|
#define int_array_set(ptr) (int_array = (ptr), debug_istr= int_array)
|
|
#else
|
|
#define int_array_set(ptr) (int_array = (ptr))
|
|
#endif
|
|
#define istrP_int_to_client(intVal) ((ISTRING)(intVal))
|
|
#define istrP_client_to_int(istrVal) ((long)(istrVal))
|
|
#define return_istr(x) return istrP_int_to_client(x)
|
|
|
|
/*****************************************************************************/
|
|
/* EXTERNAL FUNCTIONS */
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Allocate a new int for a given string and return the value.
|
|
* If the string already exists return the value for the existing int.
|
|
*/
|
|
ISTRING
|
|
istr_create (
|
|
STRING string
|
|
)
|
|
{
|
|
int hashval;
|
|
long str_exists;
|
|
Bucket new_bucket;
|
|
int i;
|
|
Bucket entry;
|
|
check_init();
|
|
|
|
if (string == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
/* hashval = hashing(string); */
|
|
if ((str_exists = hash_and_lookupstr(string,&hashval )) == -1) /* new entry */
|
|
{
|
|
entry = &hashtable[hashval];
|
|
for (i=0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == -1)
|
|
{
|
|
|
|
if(freecount == 0)
|
|
{
|
|
entry->values[i] = num_count;
|
|
if (insert_array(1,num_count, string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return istrP_int_to_client(num_count-1);
|
|
}
|
|
else
|
|
{ /* take int value from freelist */
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
return NULL;
|
|
}
|
|
entry->values[i] = freelist[freecount-1];
|
|
if (insert_array(1,freelist[freecount-1], string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return istrP_int_to_client(freelist[freecount]);
|
|
}
|
|
}
|
|
}
|
|
while(entry->next != NULL) /* check next bucket */
|
|
{
|
|
entry = entry->next;
|
|
for (i=0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == -1)
|
|
{
|
|
if (freecount == 0)
|
|
{
|
|
entry->values[i] = num_count;
|
|
if (insert_array(1, num_count, string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return istrP_int_to_client(num_count-1);
|
|
}
|
|
else
|
|
{
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
return NULL;
|
|
}
|
|
entry->values[i] = freelist[freecount-1];
|
|
if (insert_array(1,
|
|
freelist[freecount-1], string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return istrP_int_to_client(freelist[freecount]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* if get this far, then no space is available in existing bucket,
|
|
add new bucket */
|
|
new_bucket = (Bucket)malloc (sizeof(BucketRec));
|
|
if (new_bucket == NULL)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
|
|
"ISTR: error in allocating memory\n") );
|
|
return NULL ;
|
|
}
|
|
for(i=1;i<BUCKETSIZE; i++)
|
|
new_bucket->values[i] = -1;
|
|
new_bucket->next = NULL;
|
|
if (freecount == 0)
|
|
{
|
|
new_bucket->values[0] = num_count;
|
|
entry->next = new_bucket;
|
|
if (insert_array(1, num_count, string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return istrP_int_to_client(num_count-1);
|
|
}
|
|
else
|
|
{
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
return NULL;
|
|
}
|
|
new_bucket->values[0] = freelist[freecount-1];
|
|
entry->next = new_bucket;
|
|
if (insert_array(1, freelist[freecount-1], string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return_istr(freelist[freecount]);
|
|
|
|
}
|
|
}
|
|
else /* duplicate entry */
|
|
{
|
|
int_array[str_exists].refcount++;
|
|
return istrP_int_to_client(str_exists);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Assign a new int for a given allocated string and return the value.
|
|
* If the string already exists return the value for the existing int.
|
|
*/
|
|
ISTRING
|
|
istrP_create_alloced_impl(
|
|
STRING *string
|
|
)
|
|
{
|
|
int hashval;
|
|
long str_exists;
|
|
Bucket new_bucket;
|
|
int i;
|
|
Bucket entry;
|
|
check_init();
|
|
|
|
if (*string == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* hashval = hashing(*string); */
|
|
if ((str_exists = hash_and_lookupstr(*string,&hashval)) == -1) /* new entry */
|
|
{
|
|
entry = &hashtable[hashval];
|
|
for (i=0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == -1)
|
|
{
|
|
|
|
if(freecount == 0)
|
|
{
|
|
entry->values[i] = num_count;
|
|
if (insert_array(3,num_count, *string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return_istr(num_count-1);
|
|
}
|
|
else
|
|
{ /* take int value from freelist */
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
return NULL;
|
|
}
|
|
entry->values[i] = freelist[freecount-1];
|
|
if (insert_array(3,freelist[freecount-1], *string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return_istr(freelist[freecount]);
|
|
}
|
|
}
|
|
}
|
|
while(entry->next != NULL) /* go to next bucket */
|
|
{
|
|
entry = entry->next;
|
|
for (i=0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == -1)
|
|
{
|
|
if (freecount == 0)
|
|
{
|
|
entry->values[i] = num_count;
|
|
if (insert_array(3, num_count, *string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return_istr(num_count-1);
|
|
}
|
|
else
|
|
{
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
return NULL;
|
|
}
|
|
entry->values[i] = freelist[freecount-1];
|
|
if (insert_array(3,
|
|
freelist[freecount-1], *string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return_istr(freelist[freecount]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* if get this far, then no space is available in existing bucket,
|
|
add new bucket */
|
|
new_bucket = (Bucket)malloc (sizeof(BucketRec));
|
|
if (new_bucket == NULL)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
|
|
"ISTR: error in allocating memory\n") );
|
|
return NULL ;
|
|
}
|
|
for(i=1;i<BUCKETSIZE; i++)
|
|
new_bucket->values[i] = -1;
|
|
new_bucket->next = NULL;
|
|
if (freecount == 0)
|
|
{
|
|
new_bucket->values[0] = num_count;
|
|
entry->next = new_bucket;
|
|
if (insert_array(3, num_count, *string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return_istr(num_count-1);
|
|
}
|
|
else
|
|
{
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
free(new_bucket);
|
|
return NULL;
|
|
}
|
|
new_bucket->values[0] = freelist[freecount-1];
|
|
entry->next = new_bucket;
|
|
if (insert_array(3, freelist[freecount-1], *string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return_istr(freelist[freecount]);
|
|
|
|
}
|
|
}
|
|
else /* duplicate entry */
|
|
{
|
|
int_array[str_exists].refcount++;
|
|
if ((*string != int_array[str_exists].str) &&
|
|
(*&string != &(int_array[str_exists].str)))
|
|
{
|
|
free(*string);
|
|
*string = NULL;
|
|
}
|
|
return_istr(str_exists);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Assign a new int for a given string and return the value.
|
|
* If the string already exists deallocate the existing string
|
|
* and assign the new string to the int return the value for
|
|
* the existing int.
|
|
*/
|
|
ISTRING
|
|
istr_create_const(
|
|
STRING string
|
|
)
|
|
{
|
|
int hashval;
|
|
long str_exists;
|
|
Bucket new_bucket;
|
|
int i;
|
|
Bucket entry;
|
|
check_init();
|
|
|
|
if (string == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* hashval = hashing(string); */
|
|
if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1) /* new entry */
|
|
{
|
|
entry = &hashtable[hashval];
|
|
for (i=0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == -1)
|
|
{
|
|
|
|
if(freecount == 0)
|
|
{ /* no numbers on freelist */
|
|
entry->values[i] = num_count;
|
|
if (insert_array(2, num_count, string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return_istr(num_count-1);
|
|
}
|
|
else
|
|
{ /* take int value from freelist */
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
return NULL;
|
|
}
|
|
entry->values[i] = freelist[freecount-1];
|
|
if (insert_array(2, freelist[freecount-1], string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return_istr(freelist[freecount]);
|
|
}
|
|
}
|
|
}
|
|
while(entry->next != NULL)
|
|
{ /* check next bucket */
|
|
entry = entry->next;
|
|
for (i=0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == -1)
|
|
{
|
|
if (freecount == 0)
|
|
{
|
|
entry->values[i] = num_count;
|
|
if (insert_array(2, num_count, string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return_istr(num_count-1);
|
|
}
|
|
else
|
|
{
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
return NULL;
|
|
}
|
|
entry->values[i] = freelist[freecount-1];
|
|
if (insert_array(2,
|
|
freelist[freecount-1], string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return_istr(freelist[freecount]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* if get this far, then no space is available in existing bucket,
|
|
add new bucket */
|
|
new_bucket = (Bucket)malloc (sizeof(BucketRec));
|
|
if (new_bucket == NULL)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
|
|
"ISTR: error in allocating memory\n") );
|
|
return NULL ;
|
|
}
|
|
for(i=1;i<BUCKETSIZE; i++)
|
|
{
|
|
new_bucket->values[i] = -1;
|
|
}
|
|
new_bucket->next = NULL;
|
|
if (freecount == 0)
|
|
{
|
|
new_bucket->values[0] = num_count;
|
|
entry->next = new_bucket;
|
|
if (insert_array(2, num_count, string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
num_count++;
|
|
hash_count++;
|
|
return_istr(num_count-1);
|
|
}
|
|
else
|
|
{
|
|
if(int_array[freelist[freecount-1]].refcount != 0)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
|
|
"ISTR: error in allocating space for string\n") );
|
|
free(new_bucket);
|
|
return NULL;
|
|
}
|
|
new_bucket->values[0] = freelist[freecount-1];
|
|
entry->next = new_bucket;
|
|
if (insert_array(2, freelist[freecount-1], string) == -1)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
|
|
"ISTR: error in allocating to int array\n") );
|
|
return NULL;
|
|
}
|
|
freecount--;
|
|
return_istr(freelist[freecount]);
|
|
|
|
}
|
|
}
|
|
else /* duplicate entry */
|
|
{
|
|
if(int_array[str_exists].read_const == 0)
|
|
{ /* change read only string to const string */
|
|
if ((string != int_array[str_exists].str) &&
|
|
(&string != &(int_array[str_exists].str)))
|
|
{
|
|
free(int_array[str_exists].str);
|
|
int_array[str_exists].str = string;
|
|
}
|
|
int_array[str_exists].read_const = 1;
|
|
}
|
|
int_array[str_exists].refcount++;
|
|
return_istr(str_exists);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Lookup string if find it duplicate the entry and return int value,
|
|
* else return NULL.
|
|
*/
|
|
ISTRING
|
|
istr_dup_existing(
|
|
STRING string
|
|
)
|
|
{
|
|
int hashval;
|
|
long str_exists;
|
|
|
|
if (string == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
/* hashval = hashing(string); */
|
|
if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1)
|
|
{ /* string doesn't exist */
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
int_array[str_exists].refcount++;
|
|
return_istr(str_exists);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deallocate for the string if refcount = 0, else decrement refcount.
|
|
* If read_const flag is set then don't deallocate.
|
|
* Return -1 if error, else return 1
|
|
*/
|
|
int
|
|
istrP_destroy_impl(
|
|
ISTRING *istringClientPtr
|
|
)
|
|
{
|
|
long istring = (long)(*istringClientPtr);
|
|
int val; /* hashing value */
|
|
int i;
|
|
Bucket entry;
|
|
static int free_num = 0; /* allocated space in freelist =
|
|
free_num * ARRAYSIZE */
|
|
|
|
if(istring == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if((istring < 0) || (istring >= num_count) ||
|
|
((int_array[istring].refcount == 0) &&
|
|
(int_array[istring].read_const == 0)))
|
|
{
|
|
istrP_errmsg_noexist(istring);
|
|
return 0;
|
|
}
|
|
if (int_array[istring].read_const == 1) /* const entry */
|
|
{
|
|
/* never let refs to const entries drop below 1 */
|
|
if (int_array[istring].refcount > 1)
|
|
{
|
|
int_array[istring].refcount--;
|
|
}
|
|
(*istringClientPtr) = NULL;
|
|
return 0;
|
|
}
|
|
int_array[istring].refcount--;
|
|
if(int_array[istring].refcount == 0)
|
|
{ /* remove from hash table */
|
|
val = hashing(int_array[istring].str);
|
|
entry = &hashtable[val];
|
|
for (i =0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == istring)
|
|
{
|
|
entry->values[i] = -1;
|
|
}
|
|
}
|
|
while(entry->next != NULL)
|
|
{
|
|
entry = entry->next;
|
|
for (i =0; i< BUCKETSIZE; i++)
|
|
{
|
|
if (entry->values[i] == istring)
|
|
{
|
|
entry->values[i] = -1;
|
|
}
|
|
}
|
|
}
|
|
free(int_array[istring].str);
|
|
int_array[istring].str = NULL;
|
|
/* put unused int_array location of the freelist */
|
|
if(free_num == 0)
|
|
{
|
|
freelist = (long *)malloc(ARRAYSIZE * sizeof(long));
|
|
if (freelist == NULL)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
|
|
"ISTR: error in allocating memory\n") );
|
|
return 0 ;
|
|
}
|
|
free_num = 1;
|
|
}
|
|
if(freecount < (ARRAYSIZE * free_num)) /* put free int value on
|
|
freelist */
|
|
{
|
|
freelist[freecount] = istring;
|
|
freecount++;
|
|
}
|
|
else /* need more freelist space */
|
|
{
|
|
free_num++;
|
|
freelist = (long *)realloc(freelist,
|
|
(ARRAYSIZE * free_num) * sizeof(long));
|
|
assert(freelist != NULL);
|
|
if (freelist == NULL)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
|
|
"ISTR: error in allocating memory\n") );
|
|
return 0 ;
|
|
}
|
|
freelist[freecount] = istring;
|
|
freecount++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the client's variable to NULL
|
|
*/
|
|
istring = 0;
|
|
(*istringClientPtr) = istrP_int_to_client(istring);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Increment the string refcounter, and return the string value.
|
|
* Return -1 if error
|
|
*/
|
|
ISTRING
|
|
istr_dup(
|
|
ISTRING istringClientVal
|
|
)
|
|
{
|
|
long istring= istrP_client_to_int(istringClientVal);
|
|
|
|
if(istring == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else if((istring < 0) || (istring >= num_count) ||
|
|
((int_array[istring].refcount == 0) &&
|
|
(int_array[istring].read_const == 0)))
|
|
{
|
|
istrP_errmsg_noexist(istring);
|
|
return NULL;
|
|
}
|
|
int_array[istring].refcount++;
|
|
return_istr(istring);
|
|
}
|
|
|
|
/*
|
|
* Return the string name for the given int, return NULL if error
|
|
*
|
|
* Verifies that the string is valid
|
|
*/
|
|
STRING
|
|
istrP_get_string_verify(
|
|
ISTRING istringClientVal
|
|
)
|
|
{
|
|
long istring = istrP_client_to_int(istringClientVal);
|
|
|
|
if(istring == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
if((istring < 0) || (istring >= num_count) ||
|
|
((int_array[istring].refcount == 0) &&
|
|
(int_array[istring].read_const == 0)))
|
|
{
|
|
istrP_errmsg_noexist(istring);
|
|
return NULL;
|
|
}
|
|
return int_array[istring].str;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/* PRIVATE FUNCTIONS */
|
|
/******************************************************************************/
|
|
|
|
/*
|
|
* hash function
|
|
*/
|
|
static unsigned
|
|
hashing(
|
|
STRING string
|
|
)
|
|
{
|
|
unsigned hash_val = 0;
|
|
|
|
for (hash_val = 0; *string; ++string)
|
|
hash_val = hash_val * 65599 + *string;
|
|
return hash_val % NUMBUCKETS;
|
|
}
|
|
|
|
/*
|
|
* search hash table for existing strings
|
|
*
|
|
* Returns int value for string, or -1 if not found
|
|
*/
|
|
static int
|
|
hash_and_lookupstr(
|
|
char *string,
|
|
int *hash_val_out_ptr
|
|
)
|
|
{
|
|
#define fast_streq(s1,s2) (((s1)[0] == (s2)[0]) && (strcmp(s1,s2) == 0))
|
|
|
|
unsigned hash_val = 0;
|
|
char *stringPtr;
|
|
Bucket entry;
|
|
int *valuePtr;
|
|
int *valuePtrEnd;
|
|
int value;
|
|
|
|
/*
|
|
* Get bucket
|
|
*/
|
|
for (hash_val = 0, stringPtr = string; *stringPtr; ++stringPtr)
|
|
hash_val = hash_val * 65599 + *stringPtr;
|
|
(*hash_val_out_ptr) = (hash_val &= NUMBUCKETS_MASK);
|
|
|
|
/*
|
|
* Find entry in bucket
|
|
*/
|
|
for (entry = &hashtable[hash_val]; entry != NULL; entry = entry->next)
|
|
{
|
|
valuePtr = entry->values;
|
|
valuePtrEnd = valuePtr + BUCKETSIZE;
|
|
for (; valuePtr != valuePtrEnd; ++valuePtr)
|
|
{
|
|
value = *valuePtr;
|
|
if ( (value >= 0)
|
|
&& (fast_streq(int_array[value].str,string)) )
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
#undef fast_streq
|
|
}
|
|
|
|
/*
|
|
* Insert the given string into the given array location.
|
|
* Return 1 if successful, else return NULL if error.
|
|
* Note: int_array[0] unused
|
|
*/
|
|
static int
|
|
insert_array(
|
|
int flag,
|
|
int val,
|
|
char *string
|
|
)
|
|
{
|
|
char *str;
|
|
static int array_num =0;
|
|
|
|
if(hash_count == 0)
|
|
{
|
|
int_array_set((STRN *)calloc(ARRAYSIZE, sizeof(STRN)));
|
|
if (int_array == NULL)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
|
|
"ISTR: error in allocating memory\n") );
|
|
return 0 ;
|
|
}
|
|
array_num = 1;
|
|
}
|
|
if(val < (ARRAYSIZE * array_num)) /* insert into array */
|
|
{
|
|
int_array[val].refcount =1;
|
|
if (flag == 1)
|
|
{ /* read only */
|
|
str = strdup(string);
|
|
int_array[val].read_const = 0;
|
|
int_array[val].str = str;
|
|
}
|
|
else if (flag == 2)
|
|
{ /* const */
|
|
int_array[val].read_const = 1;
|
|
int_array[val].str = string;
|
|
}
|
|
else /* flag == 3 */
|
|
{ /* allocated */
|
|
int_array[val].read_const = 0;
|
|
int_array[val].str = string;
|
|
}
|
|
}
|
|
else /* need more array space */
|
|
{
|
|
array_num++;
|
|
int_array_set((STRN *)realloc(int_array,
|
|
(ARRAYSIZE * array_num) * sizeof(STRN)));
|
|
assert(int_array != NULL);
|
|
if (int_array == NULL)
|
|
{
|
|
fprintf(stderr, "%s",
|
|
CATGETS(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
|
|
"ISTR: error in allocating memory\n") );
|
|
return 0 ;
|
|
}
|
|
int_array[val].refcount =1;
|
|
if (flag == 1)
|
|
{ /* read only */
|
|
str = strdup(string);
|
|
int_array[val].read_const = 0;
|
|
int_array[val].str = str;
|
|
}
|
|
else if(flag == 2) /* const */
|
|
{
|
|
int_array[val].read_const = 1;
|
|
int_array[val].str = string;
|
|
}
|
|
else /*flag == 3*/
|
|
{ /* allocated */
|
|
int_array[val].read_const = 0;
|
|
int_array[val].str = string;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
hashtable_init(void)
|
|
{
|
|
int i = 0, j = 0;
|
|
|
|
for(i=0; i< NUMBUCKETS; i++)
|
|
{
|
|
hashtable[i].next = NULL;
|
|
for (j=0; j < BUCKETSIZE; j++)
|
|
{
|
|
hashtable[i].values[j] = -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Verifies the string exists and is not corrupted.
|
|
*/
|
|
int
|
|
istr_verify(ISTRING istringClientVal)
|
|
{
|
|
int istring= istrP_client_to_int(istringClientVal);
|
|
int return_value = 0;
|
|
|
|
if (istringClientVal == (ISTRING)NULL)
|
|
{
|
|
return 0; /* OK */
|
|
}
|
|
if((istring < 0) || (istring >= num_count) ||
|
|
((int_array[istring].refcount == 0) &&
|
|
(int_array[istring].read_const == 0)))
|
|
{
|
|
return_value = -1;
|
|
}
|
|
return return_value;
|
|
}
|
|
|
|
/*
|
|
* This doesn't do anything right now, although it really should.
|
|
*/
|
|
int
|
|
istr_verify_all(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
istrP_errmsg_noexist(int istr_value)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"ISTR: the reference string %d doesn't exist\n",
|
|
istr_value);
|
|
|
|
if (util_get_verbosity() >= 3)
|
|
{
|
|
util_error("Aborting (dumping core).");
|
|
abort();
|
|
}
|
|
#endif /* DEBUG */
|
|
return 0;
|
|
}
|
|
|