2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $XConsortium: istr.c /main/4 1995/11/06 18:50:43 rswiston $
26 * @(#)istr.c 1.25 14 Feb 1994 cde_app_builder/src/libAButil
28 * RESTRICTED CONFIDENTIAL INFORMATION:
30 * The information in this document is subject to special
31 * restrictions in a confidential disclosure agreement between
32 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
33 * document outside HP, IBM, Sun, USL, SCO, or Univel without
34 * Sun's specific written approval. This document and all copies
35 * and derivative works thereof must be returned or destroyed at
38 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
46 * Implements ISTRING data type.
48 * the istr variable is private, but is made to be used within
49 * the debugger. To get the value of an ISTRING, use
50 * print/display debug_istr[iString].
52 * Whenever setting the private variable int_array from within this
53 * ISTRING * implementation module, use int_array_set macro, as it
54 * will keep the istr variable up-to-date for debugging clients.
61 #include <ab_private/istr.h>
64 #define istrP_create_alloced_impl istrP_create_alloced_impl9726039350PrivF
65 #define istrP_destroy_impl istrP_destroy_impl518283652PrivF
66 #define istrP_get_string_verify istrP_get_string_verify4521632085PrivF
67 #define int_array istrP_int_array1809065681PrivD
68 #define num_count istrP_num_count7608925912PrivD
69 #define STRN ISTR_PRIVT_STRN
71 /* #define NUMBUCKETS 211 */
72 #define NUMBUCKETS 1024
73 #define NUMBUCKETS_MASK ((unsigned)(NUMBUCKETS-1))
75 #define ARRAYSIZE 100 /* size of and freelist */
80 int values[BUCKETSIZE];
86 STRING Istr_null_string= "(nil)";
87 STRN *int_array= NULL; /* unique number array */
88 int num_count = 1; /* unique number counter */
90 static BucketRec hashtable[NUMBUCKETS];
93 STRN *debug_istr= NULL; /* debugging shortcut for clients (see */
94 /* comment at top of this file) */
97 static int *freelist; /* freelist for unused numbers */
99 static int freecount = 0; /* freelist count */
100 static int hash_count = 0; /* total number that has been inserted */
102 static unsigned hashing(
106 static int insert_array(
112 static int hash_and_lookupstr(
114 int *hash_val_out_ptr
117 static int hashtable_init(void);
119 static int istrP_errmsg_noexist(int istr_value);
121 #define check_init() ((hash_count == 0) && (hashtable_init() >= 0))
123 #define int_array_set(ptr) (int_array = (ptr), debug_istr= int_array)
125 #define int_array_set(ptr) (int_array = (ptr))
127 #define istrP_int_to_client(intVal) ((ISTRING)(intVal))
128 #define istrP_client_to_int(istrVal) ((int)(istrVal))
129 #define return_istr(x) return istrP_int_to_client(x)
131 /*****************************************************************************/
132 /* EXTERNAL FUNCTIONS */
133 /*****************************************************************************/
136 * Allocate a new int for a given string and return the value.
137 * If the string already exists return the value for the existing int.
155 /* hashval = hashing(string); */
156 if ((str_exists = hash_and_lookupstr(string,&hashval )) == -1) /* new entry */
158 entry = &hashtable[hashval];
159 for (i=0; i< BUCKETSIZE; i++)
161 if (entry->values[i] == -1)
166 entry->values[i] = num_count;
167 if (insert_array(1,num_count, string) == -1)
170 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
171 "ISTR: error in allocating to int array\n") );
176 return istrP_int_to_client(num_count-1);
179 { /* take int value from freelist */
180 if(int_array[freelist[freecount-1]].refcount != 0)
183 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
184 "ISTR: error in allocating space for string\n") );
187 entry->values[i] = freelist[freecount-1];
188 if (insert_array(1,freelist[freecount-1], string) == -1)
191 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
192 "ISTR: error in allocating to int array\n") );
196 return istrP_int_to_client(freelist[freecount]);
200 while(entry->next != NULL) /* check next bucket */
203 for (i=0; i< BUCKETSIZE; i++)
205 if (entry->values[i] == -1)
209 entry->values[i] = num_count;
210 if (insert_array(1, num_count, string) == -1)
213 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
214 "ISTR: error in allocating to int array\n") );
219 return istrP_int_to_client(num_count-1);
223 if(int_array[freelist[freecount-1]].refcount != 0)
226 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
227 "ISTR: error in allocating space for string\n") );
230 entry->values[i] = freelist[freecount-1];
232 freelist[freecount-1], string) == -1)
235 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
236 "ISTR: error in allocating to int array\n") );
240 return istrP_int_to_client(freelist[freecount]);
245 /* if get this far, then no space is available in existing bucket,
247 new_bucket = (Bucket)malloc (sizeof(BucketRec));
248 if (new_bucket == NULL)
251 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
252 "ISTR: error in allocating memory\n") );
255 for(i=1;i<BUCKETSIZE; i++)
256 new_bucket->values[i] = -1;
257 new_bucket->next = NULL;
260 new_bucket->values[0] = num_count;
261 entry->next = new_bucket;
262 if (insert_array(1, num_count, string) == -1)
265 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
266 "ISTR: error in allocating to int array\n") );
271 return istrP_int_to_client(num_count-1);
275 if(int_array[freelist[freecount-1]].refcount != 0)
278 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
279 "ISTR: error in allocating space for string\n") );
282 new_bucket->values[0] = freelist[freecount-1];
283 entry->next = new_bucket;
284 if (insert_array(1, freelist[freecount-1], string) == -1)
287 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
288 "ISTR: error in allocating to int array\n") );
292 return_istr(freelist[freecount]);
296 else /* duplicate entry */
298 int_array[str_exists].refcount++;
299 return istrP_int_to_client(str_exists);
304 * Assign a new int for a given allocated string and return the value.
305 * If the string already exists return the value for the existing int.
308 istrP_create_alloced_impl(
324 /* hashval = hashing(*string); */
325 if ((str_exists = hash_and_lookupstr(*string,&hashval)) == -1) /* new entry */
327 entry = &hashtable[hashval];
328 for (i=0; i< BUCKETSIZE; i++)
330 if (entry->values[i] == -1)
335 entry->values[i] = num_count;
336 if (insert_array(3,num_count, *string) == -1)
339 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
340 "ISTR: error in allocating to int array\n") );
345 return_istr(num_count-1);
348 { /* take int value from freelist */
349 if(int_array[freelist[freecount-1]].refcount != 0)
352 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
353 "ISTR: error in allocating space for string\n") );
356 entry->values[i] = freelist[freecount-1];
357 if (insert_array(3,freelist[freecount-1], *string) == -1)
360 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
361 "ISTR: error in allocating to int array\n") );
365 return_istr(freelist[freecount]);
369 while(entry->next != NULL) /* go to next bucket */
372 for (i=0; i< BUCKETSIZE; i++)
374 if (entry->values[i] == -1)
378 entry->values[i] = num_count;
379 if (insert_array(3, num_count, *string) == -1)
382 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
383 "ISTR: error in allocating to int array\n") );
388 return_istr(num_count-1);
392 if(int_array[freelist[freecount-1]].refcount != 0)
395 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
396 "ISTR: error in allocating space for string\n") );
399 entry->values[i] = freelist[freecount-1];
401 freelist[freecount-1], *string) == -1)
404 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
405 "ISTR: error in allocating to int array\n") );
409 return_istr(freelist[freecount]);
414 /* if get this far, then no space is available in existing bucket,
416 new_bucket = (Bucket)malloc (sizeof(BucketRec));
417 if (new_bucket == NULL)
420 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
421 "ISTR: error in allocating memory\n") );
424 for(i=1;i<BUCKETSIZE; i++)
425 new_bucket->values[i] = -1;
426 new_bucket->next = NULL;
429 new_bucket->values[0] = num_count;
430 entry->next = new_bucket;
431 if (insert_array(3, num_count, *string) == -1)
434 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
435 "ISTR: error in allocating to int array\n") );
440 return_istr(num_count-1);
444 if(int_array[freelist[freecount-1]].refcount != 0)
447 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
448 "ISTR: error in allocating space for string\n") );
451 new_bucket->values[0] = freelist[freecount-1];
452 entry->next = new_bucket;
453 if (insert_array(3, freelist[freecount-1], *string) == -1)
456 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
457 "ISTR: error in allocating to int array\n") );
461 return_istr(freelist[freecount]);
465 else /* duplicate entry */
467 int_array[str_exists].refcount++;
468 if ((*string != int_array[str_exists].str) &&
469 (*&string != &(int_array[str_exists].str)))
474 return_istr(str_exists);
479 * Assign a new int for a given string and return the value.
480 * If the string already exists deallocate the existing string
481 * and assign the new string to the int return the value for
501 /* hashval = hashing(string); */
502 if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1) /* new entry */
504 entry = &hashtable[hashval];
505 for (i=0; i< BUCKETSIZE; i++)
507 if (entry->values[i] == -1)
511 { /* no numbers on freelist */
512 entry->values[i] = num_count;
513 if (insert_array(2, num_count, string) == -1)
516 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
517 "ISTR: error in allocating to int array\n") );
522 return_istr(num_count-1);
525 { /* take int value from freelist */
526 if(int_array[freelist[freecount-1]].refcount != 0)
529 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
530 "ISTR: error in allocating space for string\n") );
533 entry->values[i] = freelist[freecount-1];
534 if (insert_array(2, freelist[freecount-1], string) == -1)
537 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
538 "ISTR: error in allocating to int array\n") );
542 return_istr(freelist[freecount]);
546 while(entry->next != NULL)
547 { /* check next bucket */
549 for (i=0; i< BUCKETSIZE; i++)
551 if (entry->values[i] == -1)
555 entry->values[i] = num_count;
556 if (insert_array(2, num_count, string) == -1)
559 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
560 "ISTR: error in allocating to int array\n") );
565 return_istr(num_count-1);
569 if(int_array[freelist[freecount-1]].refcount != 0)
572 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
573 "ISTR: error in allocating space for string\n") );
576 entry->values[i] = freelist[freecount-1];
578 freelist[freecount-1], string) == -1)
581 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
582 "ISTR: error in allocating to int array\n") );
586 return_istr(freelist[freecount]);
591 /* if get this far, then no space is available in existing bucket,
593 new_bucket = (Bucket)malloc (sizeof(BucketRec));
594 if (new_bucket == NULL)
597 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
598 "ISTR: error in allocating memory\n") );
601 for(i=1;i<BUCKETSIZE; i++)
603 new_bucket->values[i] = -1;
605 new_bucket->next = NULL;
608 new_bucket->values[0] = num_count;
609 entry->next = new_bucket;
610 if (insert_array(2, num_count, string) == -1)
613 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
614 "ISTR: error in allocating to int array\n") );
619 return_istr(num_count-1);
623 if(int_array[freelist[freecount-1]].refcount != 0)
626 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
627 "ISTR: error in allocating space for string\n") );
630 new_bucket->values[0] = freelist[freecount-1];
631 entry->next = new_bucket;
632 if (insert_array(2, freelist[freecount-1], string) == -1)
635 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
636 "ISTR: error in allocating to int array\n") );
640 return_istr(freelist[freecount]);
644 else /* duplicate entry */
646 if(int_array[str_exists].read_const == 0)
647 { /* change read only string to const string */
648 if ((string != int_array[str_exists].str) &&
649 (&string != &(int_array[str_exists].str)))
651 free(int_array[str_exists].str);
652 int_array[str_exists].str = string;
654 int_array[str_exists].read_const = 1;
656 int_array[str_exists].refcount++;
657 return_istr(str_exists);
662 * Lookup string if find it duplicate the entry and return int value,
677 /* hashval = hashing(string); */
678 if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1)
679 { /* string doesn't exist */
684 int_array[str_exists].refcount++;
685 return_istr(str_exists);
690 * Deallocate for the string if refcount = 0, else decrement refcount.
691 * If read_const flag is set then don't deallocate.
692 * Return -1 if error, else return 1
696 ISTRING *istringClientPtr
699 int istring = (int)(*istringClientPtr);
700 int val; /* hashing value */
703 static int free_num = 0; /* allocated space in freelist =
704 free_num * ARRAYSIZE */
710 if((istring < 0) || (istring >= num_count) ||
711 ((int_array[istring].refcount == 0) &&
712 (int_array[istring].read_const == 0)))
714 istrP_errmsg_noexist(istring);
717 if (int_array[istring].read_const == 1) /* const entry */
719 /* never let refs to const entries drop below 1 */
720 if (int_array[istring].refcount > 1)
722 int_array[istring].refcount--;
724 (*istringClientPtr) = NULL;
727 int_array[istring].refcount--;
728 if(int_array[istring].refcount == 0)
729 { /* remove from hash table */
730 val = hashing(int_array[istring].str);
731 entry = &hashtable[val];
732 for (i =0; i< BUCKETSIZE; i++)
734 if (entry->values[i] == istring)
736 entry->values[i] = -1;
739 while(entry->next != NULL)
742 for (i =0; i< BUCKETSIZE; i++)
744 if (entry->values[i] == istring)
746 entry->values[i] = -1;
750 free(int_array[istring].str);
751 int_array[istring].str = NULL;
752 /* put unused int_array location of the freelist */
755 freelist = (int *)malloc(ARRAYSIZE * sizeof(int));
756 if (freelist == NULL)
759 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
760 "ISTR: error in allocating memory\n") );
765 if(freecount < (ARRAYSIZE * free_num)) /* put free int value on
768 freelist[freecount] = istring;
771 else /* need more freelist space */
774 freelist = (int *)realloc(freelist,
775 (ARRAYSIZE * free_num) * sizeof(int));
776 assert(freelist != NULL);
777 if (freelist == NULL)
780 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
781 "ISTR: error in allocating memory\n") );
784 freelist[freecount] = istring;
790 * Set the client's variable to NULL
793 (*istringClientPtr) = istrP_int_to_client(istring);
799 * Increment the string refcounter, and return the string value.
804 ISTRING istringClientVal
807 int istring= istrP_client_to_int(istringClientVal);
813 else if((istring < 0) || (istring >= num_count) ||
814 ((int_array[istring].refcount == 0) &&
815 (int_array[istring].read_const == 0)))
817 istrP_errmsg_noexist(istring);
820 int_array[istring].refcount++;
821 return_istr(istring);
825 * Return the string name for the given int, return NULL if error
827 * Verifies that the string is valid
830 istrP_get_string_verify(
831 ISTRING istringClientVal
834 int istring = istrP_client_to_int(istringClientVal);
840 if((istring < 0) || (istring >= num_count) ||
841 ((int_array[istring].refcount == 0) &&
842 (int_array[istring].read_const == 0)))
844 istrP_errmsg_noexist(istring);
847 return int_array[istring].str;
850 /******************************************************************************/
851 /* PRIVATE FUNCTIONS */
852 /******************************************************************************/
862 register unsigned hash_val = 0;
864 for (hash_val = 0; *string; ++string)
865 hash_val = hash_val * 65599 + *string;
866 return hash_val % NUMBUCKETS;
870 * search hash table for existing strings
872 * Returns int value for string, or -1 if not found
877 int *hash_val_out_ptr
880 #define fast_streq(s1,s2) (((s1)[0] == (s2)[0]) && (strcmp(s1,s2) == 0))
882 register unsigned hash_val = 0;
883 register char *stringPtr;
892 for (hash_val = 0, stringPtr = string; *stringPtr; ++stringPtr)
893 hash_val = hash_val * 65599 + *stringPtr;
894 (*hash_val_out_ptr) = (hash_val &= NUMBUCKETS_MASK);
897 * Find entry in bucket
899 for (entry = &hashtable[hash_val]; entry != NULL; entry = entry->next)
901 valuePtr = entry->values;
902 valuePtrEnd = valuePtr + BUCKETSIZE;
903 for (; valuePtr != valuePtrEnd; ++valuePtr)
907 && (fast_streq(int_array[value].str,string)) )
919 * Insert the given string into the given array location.
920 * Return 1 if successful, else return NULL if error.
921 * Note: int_array[0] unused
931 static int array_num =0;
935 int_array_set((STRN *)malloc(ARRAYSIZE * sizeof(STRN)));
936 if (int_array == NULL)
939 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
940 "ISTR: error in allocating memory\n") );
945 if(val < (ARRAYSIZE * array_num)) /* insert into array */
947 int_array[val].refcount =1;
950 str = strdup(string);
951 int_array[val].read_const = 0;
952 int_array[val].str = str;
956 int_array[val].read_const = 1;
957 int_array[val].str = string;
961 int_array[val].read_const = 0;
962 int_array[val].str = string;
965 else /* need more array space */
968 int_array_set((STRN *)realloc(int_array,
969 (ARRAYSIZE * array_num) * sizeof(STRN)));
970 assert(int_array != NULL);
971 if (int_array == NULL)
974 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
975 "ISTR: error in allocating memory\n") );
978 int_array[val].refcount =1;
981 str = strdup(string);
982 int_array[val].read_const = 0;
983 int_array[val].str = str;
985 else if(flag == 2) /* const */
987 int_array[val].read_const = 1;
988 int_array[val].str = string;
992 int_array[val].read_const = 0;
993 int_array[val].str = string;
1001 hashtable_init(void)
1005 for(i=0; i< NUMBUCKETS; i++)
1007 hashtable[i].next = NULL;
1008 for (j=0; j < BUCKETSIZE; j++)
1010 hashtable[i].values[j] = -1;
1018 * Verifies the string exists and is not corrupted.
1021 istr_verify(ISTRING istringClientVal)
1023 int istring= istrP_client_to_int(istringClientVal);
1024 int return_value = 0;
1026 if (istringClientVal == (ISTRING)NULL)
1030 if((istring < 0) || (istring >= num_count) ||
1031 ((int_array[istring].refcount == 0) &&
1032 (int_array[istring].read_const == 0)))
1036 return return_value;
1040 * This doesn't do anything right now, although it really should.
1043 istr_verify_all(void)
1050 istrP_errmsg_noexist(int istr_value)
1053 fprintf(stderr,"ISTR: the reference string %d doesn't exist\n",
1056 if (util_get_verbosity() >= 3)
1058 util_error("Aborting (dumping core).");