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 long 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 long *freelist; /* freelist for unused numbers */
99 static long freecount = 0; /* freelist count */
100 static long 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) ((long)(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)
169 fprintf(stderr, "%s",
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)
182 fprintf(stderr, "%s",
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)
190 fprintf(stderr, "%s",
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)
212 fprintf(stderr, "%s",
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)
225 fprintf(stderr, "%s",
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)
234 fprintf(stderr, "%s",
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)
250 fprintf(stderr, "%s",
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)
264 fprintf(stderr, "%s",
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)
277 fprintf(stderr, "%s",
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)
286 fprintf(stderr, "%s",
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)
338 fprintf(stderr, "%s",
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)
351 fprintf(stderr, "%s",
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)
359 fprintf(stderr, "%s",
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)
381 fprintf(stderr, "%s",
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)
394 fprintf(stderr, "%s",
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)
403 fprintf(stderr, "%s",
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)
419 fprintf(stderr, "%s",
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)
433 fprintf(stderr, "%s",
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)
446 fprintf(stderr, "%s",
447 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
448 "ISTR: error in allocating space for string\n") );
452 new_bucket->values[0] = freelist[freecount-1];
453 entry->next = new_bucket;
454 if (insert_array(3, freelist[freecount-1], *string) == -1)
456 fprintf(stderr, "%s",
457 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
458 "ISTR: error in allocating to int array\n") );
462 return_istr(freelist[freecount]);
466 else /* duplicate entry */
468 int_array[str_exists].refcount++;
469 if ((*string != int_array[str_exists].str) &&
470 (*&string != &(int_array[str_exists].str)))
475 return_istr(str_exists);
480 * Assign a new int for a given string and return the value.
481 * If the string already exists deallocate the existing string
482 * and assign the new string to the int return the value for
502 /* hashval = hashing(string); */
503 if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1) /* new entry */
505 entry = &hashtable[hashval];
506 for (i=0; i< BUCKETSIZE; i++)
508 if (entry->values[i] == -1)
512 { /* no numbers on freelist */
513 entry->values[i] = num_count;
514 if (insert_array(2, num_count, string) == -1)
516 fprintf(stderr, "%s",
517 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
518 "ISTR: error in allocating to int array\n") );
523 return_istr(num_count-1);
526 { /* take int value from freelist */
527 if(int_array[freelist[freecount-1]].refcount != 0)
529 fprintf(stderr, "%s",
530 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
531 "ISTR: error in allocating space for string\n") );
534 entry->values[i] = freelist[freecount-1];
535 if (insert_array(2, freelist[freecount-1], string) == -1)
537 fprintf(stderr, "%s",
538 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
539 "ISTR: error in allocating to int array\n") );
543 return_istr(freelist[freecount]);
547 while(entry->next != NULL)
548 { /* check next bucket */
550 for (i=0; i< BUCKETSIZE; i++)
552 if (entry->values[i] == -1)
556 entry->values[i] = num_count;
557 if (insert_array(2, num_count, string) == -1)
559 fprintf(stderr, "%s",
560 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
561 "ISTR: error in allocating to int array\n") );
566 return_istr(num_count-1);
570 if(int_array[freelist[freecount-1]].refcount != 0)
572 fprintf(stderr, "%s",
573 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
574 "ISTR: error in allocating space for string\n") );
577 entry->values[i] = freelist[freecount-1];
579 freelist[freecount-1], string) == -1)
581 fprintf(stderr, "%s",
582 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
583 "ISTR: error in allocating to int array\n") );
587 return_istr(freelist[freecount]);
592 /* if get this far, then no space is available in existing bucket,
594 new_bucket = (Bucket)malloc (sizeof(BucketRec));
595 if (new_bucket == NULL)
597 fprintf(stderr, "%s",
598 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
599 "ISTR: error in allocating memory\n") );
602 for(i=1;i<BUCKETSIZE; i++)
604 new_bucket->values[i] = -1;
606 new_bucket->next = NULL;
609 new_bucket->values[0] = num_count;
610 entry->next = new_bucket;
611 if (insert_array(2, num_count, string) == -1)
613 fprintf(stderr, "%s",
614 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
615 "ISTR: error in allocating to int array\n") );
620 return_istr(num_count-1);
624 if(int_array[freelist[freecount-1]].refcount != 0)
626 fprintf(stderr, "%s",
627 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
628 "ISTR: error in allocating space for string\n") );
632 new_bucket->values[0] = freelist[freecount-1];
633 entry->next = new_bucket;
634 if (insert_array(2, freelist[freecount-1], string) == -1)
636 fprintf(stderr, "%s",
637 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
638 "ISTR: error in allocating to int array\n") );
642 return_istr(freelist[freecount]);
646 else /* duplicate entry */
648 if(int_array[str_exists].read_const == 0)
649 { /* change read only string to const string */
650 if ((string != int_array[str_exists].str) &&
651 (&string != &(int_array[str_exists].str)))
653 free(int_array[str_exists].str);
654 int_array[str_exists].str = string;
656 int_array[str_exists].read_const = 1;
658 int_array[str_exists].refcount++;
659 return_istr(str_exists);
664 * Lookup string if find it duplicate the entry and return int value,
679 /* hashval = hashing(string); */
680 if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1)
681 { /* string doesn't exist */
686 int_array[str_exists].refcount++;
687 return_istr(str_exists);
692 * Deallocate for the string if refcount = 0, else decrement refcount.
693 * If read_const flag is set then don't deallocate.
694 * Return -1 if error, else return 1
698 ISTRING *istringClientPtr
701 long istring = (long)(*istringClientPtr);
702 int val; /* hashing value */
705 static int free_num = 0; /* allocated space in freelist =
706 free_num * ARRAYSIZE */
712 if((istring < 0) || (istring >= num_count) ||
713 ((int_array[istring].refcount == 0) &&
714 (int_array[istring].read_const == 0)))
716 istrP_errmsg_noexist(istring);
719 if (int_array[istring].read_const == 1) /* const entry */
721 /* never let refs to const entries drop below 1 */
722 if (int_array[istring].refcount > 1)
724 int_array[istring].refcount--;
726 (*istringClientPtr) = NULL;
729 int_array[istring].refcount--;
730 if(int_array[istring].refcount == 0)
731 { /* remove from hash table */
732 val = hashing(int_array[istring].str);
733 entry = &hashtable[val];
734 for (i =0; i< BUCKETSIZE; i++)
736 if (entry->values[i] == istring)
738 entry->values[i] = -1;
741 while(entry->next != NULL)
744 for (i =0; i< BUCKETSIZE; i++)
746 if (entry->values[i] == istring)
748 entry->values[i] = -1;
752 free(int_array[istring].str);
753 int_array[istring].str = NULL;
754 /* put unused int_array location of the freelist */
757 freelist = (long *)malloc(ARRAYSIZE * sizeof(long));
758 if (freelist == NULL)
760 fprintf(stderr, "%s",
761 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
762 "ISTR: error in allocating memory\n") );
767 if(freecount < (ARRAYSIZE * free_num)) /* put free int value on
770 freelist[freecount] = istring;
773 else /* need more freelist space */
776 freelist = (long *)realloc(freelist,
777 (ARRAYSIZE * free_num) * sizeof(long));
778 assert(freelist != NULL);
779 if (freelist == NULL)
781 fprintf(stderr, "%s",
782 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
783 "ISTR: error in allocating memory\n") );
786 freelist[freecount] = istring;
792 * Set the client's variable to NULL
795 (*istringClientPtr) = istrP_int_to_client(istring);
801 * Increment the string refcounter, and return the string value.
806 ISTRING istringClientVal
809 long istring= istrP_client_to_int(istringClientVal);
815 else if((istring < 0) || (istring >= num_count) ||
816 ((int_array[istring].refcount == 0) &&
817 (int_array[istring].read_const == 0)))
819 istrP_errmsg_noexist(istring);
822 int_array[istring].refcount++;
823 return_istr(istring);
827 * Return the string name for the given int, return NULL if error
829 * Verifies that the string is valid
832 istrP_get_string_verify(
833 ISTRING istringClientVal
836 long istring = istrP_client_to_int(istringClientVal);
842 if((istring < 0) || (istring >= num_count) ||
843 ((int_array[istring].refcount == 0) &&
844 (int_array[istring].read_const == 0)))
846 istrP_errmsg_noexist(istring);
849 return int_array[istring].str;
852 /******************************************************************************/
853 /* PRIVATE FUNCTIONS */
854 /******************************************************************************/
864 register unsigned hash_val = 0;
866 for (hash_val = 0; *string; ++string)
867 hash_val = hash_val * 65599 + *string;
868 return hash_val % NUMBUCKETS;
872 * search hash table for existing strings
874 * Returns int value for string, or -1 if not found
879 int *hash_val_out_ptr
882 #define fast_streq(s1,s2) (((s1)[0] == (s2)[0]) && (strcmp(s1,s2) == 0))
884 register unsigned hash_val = 0;
885 register char *stringPtr;
894 for (hash_val = 0, stringPtr = string; *stringPtr; ++stringPtr)
895 hash_val = hash_val * 65599 + *stringPtr;
896 (*hash_val_out_ptr) = (hash_val &= NUMBUCKETS_MASK);
899 * Find entry in bucket
901 for (entry = &hashtable[hash_val]; entry != NULL; entry = entry->next)
903 valuePtr = entry->values;
904 valuePtrEnd = valuePtr + BUCKETSIZE;
905 for (; valuePtr != valuePtrEnd; ++valuePtr)
909 && (fast_streq(int_array[value].str,string)) )
921 * Insert the given string into the given array location.
922 * Return 1 if successful, else return NULL if error.
923 * Note: int_array[0] unused
933 static int array_num =0;
937 int_array_set((STRN *)calloc(ARRAYSIZE, sizeof(STRN)));
938 if (int_array == NULL)
940 fprintf(stderr, "%s",
941 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
942 "ISTR: error in allocating memory\n") );
947 if(val < (ARRAYSIZE * array_num)) /* insert into array */
949 int_array[val].refcount =1;
952 str = strdup(string);
953 int_array[val].read_const = 0;
954 int_array[val].str = str;
958 int_array[val].read_const = 1;
959 int_array[val].str = string;
963 int_array[val].read_const = 0;
964 int_array[val].str = string;
967 else /* need more array space */
970 int_array_set((STRN *)realloc(int_array,
971 (ARRAYSIZE * array_num) * sizeof(STRN)));
972 assert(int_array != NULL);
973 if (int_array == NULL)
975 fprintf(stderr, "%s",
976 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
977 "ISTR: error in allocating memory\n") );
980 int_array[val].refcount =1;
983 str = strdup(string);
984 int_array[val].read_const = 0;
985 int_array[val].str = str;
987 else if(flag == 2) /* const */
989 int_array[val].read_const = 1;
990 int_array[val].str = string;
994 int_array[val].read_const = 0;
995 int_array[val].str = string;
1003 hashtable_init(void)
1007 for(i=0; i< NUMBUCKETS; i++)
1009 hashtable[i].next = NULL;
1010 for (j=0; j < BUCKETSIZE; j++)
1012 hashtable[i].values[j] = -1;
1020 * Verifies the string exists and is not corrupted.
1023 istr_verify(ISTRING istringClientVal)
1025 int istring= istrP_client_to_int(istringClientVal);
1026 int return_value = 0;
1028 if (istringClientVal == (ISTRING)NULL)
1032 if((istring < 0) || (istring >= num_count) ||
1033 ((int_array[istring].refcount == 0) &&
1034 (int_array[istring].read_const == 0)))
1038 return return_value;
1042 * This doesn't do anything right now, although it really should.
1045 istr_verify_all(void)
1052 istrP_errmsg_noexist(int istr_value)
1055 fprintf(stderr,"ISTR: the reference string %d doesn't exist\n",
1058 if (util_get_verbosity() >= 3)
1060 util_error("Aborting (dumping core).");