b06b50f4c1515c2eae51a01bf91cd0648feb15b1
[oweals/cde.git] / cde / programs / dtappbuilder / src / libAButil / istr.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /*
24  *      $XConsortium: istr.c /main/4 1995/11/06 18:50:43 rswiston $
25  *
26  * @(#)istr.c   1.25 14 Feb 1994        cde_app_builder/src/libAButil
27  *
28  *      RESTRICTED CONFIDENTIAL INFORMATION:
29  *      
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
36  *      Sun's request.
37  *
38  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
39  *
40  */
41
42
43 /*
44  * istr.c
45  * 
46  * Implements ISTRING data type.
47  *
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].
51  *
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.
55  */
56
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <assert.h>
61 #include <ab_private/istr.h>
62 #include "utilP.h"
63
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
70
71 /* #define NUMBUCKETS   211 */
72 #define NUMBUCKETS   1024
73 #define NUMBUCKETS_MASK ((unsigned)(NUMBUCKETS-1))
74 #define BUCKETSIZE 10
75 #define ARRAYSIZE  100 /* size of and freelist */
76
77 typedef struct BUCKET
78 {
79     struct BUCKET       *next;
80     int                 values[BUCKETSIZE];
81 } BucketRec, *Bucket;
82
83 /*
84  * Public data
85  */
86 STRING  Istr_null_string= "(nil)";
87 STRN    *int_array= NULL;       /* unique number array  */
88 long    num_count  = 1;         /* unique number counter */
89
90 static BucketRec        hashtable[NUMBUCKETS];
91
92 #ifdef DEBUG
93 STRN *debug_istr= NULL;         /* debugging shortcut for clients (see */
94                                 /* comment at top of this file) */
95 #endif /* DEBUG */
96
97 static long *freelist;           /* freelist for unused numbers */
98
99 static long freecount  = 0;      /* freelist count */
100 static long hash_count = 0;      /* total number that has been inserted */
101
102 static unsigned hashing(
103                     char *p
104                 );
105
106 static int      insert_array(
107                     int flag, 
108                     int val, 
109                     char *string
110                 );
111
112 static int      hash_and_lookupstr(
113                     char        *string,
114                     int         *hash_val_out_ptr
115                 );
116
117 static int      hashtable_init(void);
118
119 static int      istrP_errmsg_noexist(int istr_value);
120
121 #define check_init()            ((hash_count == 0) && (hashtable_init() >= 0))
122 #ifdef DEBUG
123 #define int_array_set(ptr)      (int_array = (ptr), debug_istr= int_array)
124 #else
125 #define int_array_set(ptr)      (int_array = (ptr))
126 #endif
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)
130
131 /*****************************************************************************/
132 /*                        EXTERNAL FUNCTIONS                                 */
133 /*****************************************************************************/
134
135 /* 
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. 
138  */
139 ISTRING 
140 istr_create (
141     STRING string
142 )
143 {
144     int hashval;
145     long str_exists;
146     Bucket      new_bucket;
147     int i;
148     Bucket      entry;
149     check_init();
150
151     if (string == NULL)
152     {
153         return NULL;
154     }
155     /* hashval = hashing(string); */
156     if ((str_exists = hash_and_lookupstr(string,&hashval )) == -1)     /* new entry */  
157     {
158         entry = &hashtable[hashval];
159         for (i=0; i< BUCKETSIZE; i++)
160         { 
161             if (entry->values[i] == -1)
162             {
163                 
164                 if(freecount == 0)
165                 {
166                     entry->values[i] = num_count;
167                     if (insert_array(1,num_count, string) == -1)
168                     {
169                         fprintf(stderr, "%s",
170                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
171                             "ISTR: error in allocating to int array\n") );
172                         return NULL;
173                     }
174                     num_count++;
175                     hash_count++;
176                     return istrP_int_to_client(num_count-1);
177                 }
178                 else
179                 {   /* take int value from freelist */
180                     if(int_array[freelist[freecount-1]].refcount != 0)
181                     {
182                         fprintf(stderr, "%s",
183                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
184                             "ISTR: error in allocating space for string\n") );
185                         return NULL;
186                     }
187                     entry->values[i] = freelist[freecount-1];
188                     if (insert_array(1,freelist[freecount-1], string) == -1)
189                     {
190                         fprintf(stderr, "%s",
191                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
192                             "ISTR: error in allocating to int array\n") );
193                         return NULL; 
194                     }
195                     freecount--;
196                     return istrP_int_to_client(freelist[freecount]);
197                 } 
198             } 
199         }
200         while(entry->next != NULL)   /* check next bucket */
201         {
202             entry = entry->next;
203             for (i=0; i< BUCKETSIZE; i++)
204             { 
205                 if (entry->values[i] == -1)
206                 {
207                     if (freecount == 0)
208                     {
209                         entry->values[i] = num_count;
210                         if (insert_array(1, num_count, string) == -1)
211                         {
212                             fprintf(stderr, "%s",
213                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
214                                 "ISTR: error in allocating to int array\n") );
215                             return NULL;
216                         }
217                         num_count++;
218                         hash_count++;
219                         return istrP_int_to_client(num_count-1);
220                     }
221                     else
222                     {
223                         if(int_array[freelist[freecount-1]].refcount != 0)
224                         {
225                             fprintf(stderr, "%s",
226                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
227                                 "ISTR: error in allocating space for string\n") );
228                             return NULL;
229                         }
230                         entry->values[i] = freelist[freecount-1];
231                         if (insert_array(1, 
232                             freelist[freecount-1], string) == -1)
233                         {
234                             fprintf(stderr, "%s",
235                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
236                                 "ISTR: error in allocating to int array\n") );
237                             return NULL;
238                         }
239                         freecount--;
240                         return istrP_int_to_client(freelist[freecount]);
241                     } 
242                 } 
243             }
244         }
245 /* if get this far, then no space is available in existing bucket, 
246    add new bucket */
247         new_bucket = (Bucket)malloc (sizeof(BucketRec));
248         if (new_bucket == NULL)
249         {
250             fprintf(stderr, "%s",
251                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
252                 "ISTR: error in allocating memory\n") );
253             return NULL ;
254         }  
255         for(i=1;i<BUCKETSIZE; i++)
256             new_bucket->values[i] = -1;
257         new_bucket->next = NULL;
258         if (freecount == 0)
259         {
260             new_bucket->values[0] = num_count;
261             entry->next = new_bucket;
262             if (insert_array(1, num_count, string) == -1)
263             {
264                 fprintf(stderr, "%s",
265                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
266                     "ISTR: error in allocating to int array\n") );
267                 return NULL;
268             }
269             num_count++;
270             hash_count++;
271             return istrP_int_to_client(num_count-1);
272         }
273         else
274         {
275             if(int_array[freelist[freecount-1]].refcount != 0)
276             {
277                 fprintf(stderr, "%s",
278                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
279                     "ISTR: error in allocating space for string\n") );
280                 return NULL;
281             }
282             new_bucket->values[0] = freelist[freecount-1];
283             entry->next = new_bucket;
284             if (insert_array(1, freelist[freecount-1], string) == -1)
285             {
286                 fprintf(stderr, "%s",
287                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
288                     "ISTR: error in allocating to int array\n") );
289                 return NULL;
290             }
291             freecount--;
292             return_istr(freelist[freecount]);
293
294         }
295     }
296     else            /* duplicate entry */
297     {
298         int_array[str_exists].refcount++;
299         return istrP_int_to_client(str_exists);
300     }
301 }
302
303 /* 
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. 
306  */
307 ISTRING 
308 istrP_create_alloced_impl(
309     STRING *string
310 )
311 {
312     int hashval;
313     long str_exists;
314     Bucket      new_bucket;
315     int i;
316     Bucket      entry;
317     check_init();
318
319     if (*string == NULL)
320     {
321         return NULL;
322     }
323
324     /* hashval = hashing(*string); */
325     if ((str_exists = hash_and_lookupstr(*string,&hashval)) == -1)     /* new entry */  
326     {     
327         entry = &hashtable[hashval];
328         for (i=0; i< BUCKETSIZE; i++)
329         { 
330             if (entry->values[i] == -1)
331             {
332                 
333                 if(freecount == 0)
334                 {
335                     entry->values[i] = num_count;
336                     if (insert_array(3,num_count, *string) == -1)
337                     {
338                         fprintf(stderr, "%s",
339                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
340                             "ISTR: error in allocating to int array\n") );
341                         return NULL;
342                     }
343                     num_count++;
344                     hash_count++;
345                     return_istr(num_count-1);
346                 }
347                 else
348                 {   /* take int value from freelist */
349                     if(int_array[freelist[freecount-1]].refcount != 0)
350                     {
351                         fprintf(stderr, "%s",
352                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
353                             "ISTR: error in allocating space for string\n") );
354                         return NULL;
355                     }
356                     entry->values[i] = freelist[freecount-1];
357                     if (insert_array(3,freelist[freecount-1], *string) == -1)
358                     {
359                         fprintf(stderr, "%s",
360                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
361                             "ISTR: error in allocating to int array\n") );
362                         return NULL;
363                     }
364                     freecount--;
365                     return_istr(freelist[freecount]);
366                 } 
367             } 
368         }
369         while(entry->next != NULL)  /* go to next bucket */
370         {
371             entry = entry->next;
372             for (i=0; i< BUCKETSIZE; i++)
373             { 
374                 if (entry->values[i] == -1)
375                 {
376                     if (freecount == 0)
377                     {
378                         entry->values[i] = num_count;
379                         if (insert_array(3, num_count, *string) == -1)
380                         {
381                             fprintf(stderr, "%s",
382                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
383                                 "ISTR: error in allocating to int array\n") );
384                             return NULL;
385                         }
386                         num_count++;
387                         hash_count++;
388                         return_istr(num_count-1);
389                     }
390                     else
391                     {
392                         if(int_array[freelist[freecount-1]].refcount != 0)
393                         {
394                             fprintf(stderr, "%s",
395                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
396                                 "ISTR: error in allocating space for string\n") );
397                             return NULL;
398                         }
399                         entry->values[i] = freelist[freecount-1];
400                         if (insert_array(3, 
401                             freelist[freecount-1], *string) == -1)
402                         {
403                             fprintf(stderr, "%s",
404                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
405                                 "ISTR: error in allocating to int array\n") );
406                             return NULL;
407                         }
408                         freecount--;
409                         return_istr(freelist[freecount]);
410                     } 
411                 } 
412             }
413         }
414 /* if get this far, then no space is available in existing bucket, 
415    add new bucket */
416         new_bucket = (Bucket)malloc (sizeof(BucketRec));
417         if (new_bucket == NULL)
418         {
419             fprintf(stderr, "%s",
420                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
421                 "ISTR: error in allocating memory\n") );
422             return NULL ;
423         }  
424         for(i=1;i<BUCKETSIZE; i++)
425             new_bucket->values[i] = -1;
426         new_bucket->next = NULL;
427         if (freecount == 0)
428         {
429             new_bucket->values[0] = num_count;
430             entry->next = new_bucket;
431             if (insert_array(3, num_count, *string) == -1)
432             {
433                 fprintf(stderr, "%s",
434                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
435                     "ISTR: error in allocating to int array\n") );
436                 return NULL;
437             }
438             num_count++;
439             hash_count++;
440             return_istr(num_count-1);
441         }
442         else
443         {
444             if(int_array[freelist[freecount-1]].refcount != 0)
445             {
446                 fprintf(stderr, "%s",
447                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
448                     "ISTR: error in allocating space for string\n") );
449                 free(new_bucket);
450                 return NULL;
451             }
452             new_bucket->values[0] = freelist[freecount-1];
453             entry->next = new_bucket;
454             if (insert_array(3, freelist[freecount-1], *string) == -1)
455             {
456                 fprintf(stderr, "%s",
457                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
458                     "ISTR: error in allocating to int array\n") );
459                 return NULL;
460             }
461             freecount--;
462             return_istr(freelist[freecount]);
463
464         }
465     }
466     else            /* duplicate entry */
467     {
468         int_array[str_exists].refcount++;
469         if ((*string != int_array[str_exists].str) &&
470            (*&string != &(int_array[str_exists].str)))
471         {
472             free(*string);
473             *string = NULL;
474         }
475         return_istr(str_exists);
476     }
477 }
478
479 /* 
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 
483  * the existing int. 
484 */
485 ISTRING 
486 istr_create_const(
487     STRING string
488 )
489 {
490     int hashval;
491     long str_exists;
492     Bucket      new_bucket;
493     int i;
494     Bucket      entry;
495     check_init();
496  
497     if (string == NULL)
498     {
499         return NULL;
500     }
501
502     /* hashval = hashing(string); */
503     if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1)     /* new entry */  
504     {     
505         entry = &hashtable[hashval];
506         for (i=0; i< BUCKETSIZE; i++)
507         { 
508             if (entry->values[i] == -1)
509             {
510                 
511                 if(freecount == 0)
512                 {         /* no numbers on freelist */
513                     entry->values[i] = num_count;
514                     if (insert_array(2, num_count, string) == -1)
515                     {
516                         fprintf(stderr, "%s",
517                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
518                             "ISTR: error in allocating to int array\n") );
519                         return NULL;
520                     }
521                     num_count++;
522                     hash_count++;
523                     return_istr(num_count-1);
524                 }
525                 else
526                 {   /* take int value from freelist */
527                     if(int_array[freelist[freecount-1]].refcount != 0)
528                     {
529                         fprintf(stderr, "%s",
530                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
531                             "ISTR: error in allocating space for string\n") );
532                         return NULL;
533                     }
534                     entry->values[i] = freelist[freecount-1];
535                     if (insert_array(2, freelist[freecount-1], string) == -1)
536                     {
537                         fprintf(stderr, "%s",
538                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
539                             "ISTR: error in allocating to int array\n") );
540                         return NULL;
541                     }
542                     freecount--;
543                     return_istr(freelist[freecount]);
544                 } 
545             } 
546         }
547         while(entry->next != NULL)
548         {                            /* check next bucket */
549             entry = entry->next;
550             for (i=0; i< BUCKETSIZE; i++)
551             { 
552                 if (entry->values[i] == -1)
553                 {
554                     if (freecount == 0)
555                     {
556                         entry->values[i] = num_count;
557                         if (insert_array(2, num_count, string) == -1)
558                         {
559                             fprintf(stderr, "%s",
560                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
561                                 "ISTR: error in allocating to int array\n") );
562                             return NULL;
563                         }
564                         num_count++;
565                         hash_count++;
566                         return_istr(num_count-1);
567                     }
568                     else
569                     {
570                         if(int_array[freelist[freecount-1]].refcount != 0)
571                         {
572                             fprintf(stderr, "%s",
573                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
574                                 "ISTR: error in allocating space for string\n") );
575                             return NULL;
576                         }
577                         entry->values[i] = freelist[freecount-1];
578                         if (insert_array(2, 
579                             freelist[freecount-1], string) == -1)
580                         {
581                             fprintf(stderr, "%s",
582                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
583                                 "ISTR: error in allocating to int array\n") );
584                             return NULL;
585                         }
586                         freecount--;
587                         return_istr(freelist[freecount]);
588                     } 
589                 } 
590             }
591         }
592 /* if get this far, then no space is available in existing bucket, 
593    add new bucket */
594         new_bucket = (Bucket)malloc (sizeof(BucketRec));
595         if (new_bucket == NULL)
596         {
597             fprintf(stderr, "%s",
598                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
599                 "ISTR: error in allocating memory\n") );
600             return NULL ;
601         }  
602         for(i=1;i<BUCKETSIZE; i++)
603         {
604             new_bucket->values[i] = -1;
605         }
606         new_bucket->next = NULL;
607         if (freecount == 0)
608         {
609             new_bucket->values[0] = num_count;
610             entry->next = new_bucket;
611             if (insert_array(2, num_count, string) == -1)
612             {
613                 fprintf(stderr, "%s",
614                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
615                     "ISTR: error in allocating to int array\n") );
616                 return NULL;
617             }
618             num_count++;
619             hash_count++;
620             return_istr(num_count-1);
621         }
622         else
623         {
624             if(int_array[freelist[freecount-1]].refcount != 0)
625             {
626                 fprintf(stderr, "%s",
627                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
628                     "ISTR: error in allocating space for string\n") );
629                 free(new_bucket);
630                 return NULL;
631             }
632             new_bucket->values[0] = freelist[freecount-1];
633             entry->next = new_bucket;
634             if (insert_array(2, freelist[freecount-1], string) == -1)
635             {
636                 fprintf(stderr, "%s",
637                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
638                     "ISTR: error in allocating to int array\n") );
639                 return NULL;
640             }
641             freecount--;
642             return_istr(freelist[freecount]);
643
644         }
645     }
646     else            /* duplicate entry */
647     {
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)))
652             {
653                 free(int_array[str_exists].str);
654                 int_array[str_exists].str = string;
655             }
656             int_array[str_exists].read_const = 1;
657         } 
658         int_array[str_exists].refcount++;
659         return_istr(str_exists);
660     }
661 }
662
663 /* 
664  * Lookup string if find it duplicate the entry and return int value,
665  * else return NULL.
666  */
667 ISTRING
668 istr_dup_existing(
669     STRING string
670 )
671 {
672     int hashval;
673     long str_exists;
674
675     if (string == NULL)
676     {
677         return NULL;
678     }
679     /* hashval = hashing(string); */
680     if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1)    
681     {                                          /* string doesn't exist */
682         return NULL;
683     }
684     else 
685     {
686         int_array[str_exists].refcount++;
687         return_istr(str_exists);
688     }
689 }
690
691 /* 
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 
695  */
696 int 
697 istrP_destroy_impl(
698     ISTRING *istringClientPtr
699 )
700 {
701     long istring = (long)(*istringClientPtr);
702     int val;                 /* hashing value */
703     int i;
704     Bucket      entry;
705     static int free_num = 0;   /* allocated space in freelist = 
706                                   free_num * ARRAYSIZE */
707
708     if(istring == 0)  
709     {
710         return 0;
711     }
712     if((istring < 0) || (istring >= num_count) || 
713        ((int_array[istring].refcount == 0) && 
714         (int_array[istring].read_const == 0)))
715     {
716         istrP_errmsg_noexist(istring);
717         return 0;
718     }
719     if (int_array[istring].read_const == 1)  /* const entry */
720     {
721         /* never let refs to const entries drop below 1 */
722         if (int_array[istring].refcount > 1)
723         {
724             int_array[istring].refcount--;
725         }
726         (*istringClientPtr) = NULL;
727         return 0;
728     }
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++)
735         {
736             if (entry->values[i] == istring)
737             {
738                 entry->values[i] = -1;
739             } 
740         } 
741         while(entry->next != NULL)
742         {
743             entry = entry->next; 
744             for (i =0; i< BUCKETSIZE; i++)
745             {
746                 if (entry->values[i] == istring)
747                 {
748                     entry->values[i] = -1;
749                 }
750             } 
751         }
752         free(int_array[istring].str);
753         int_array[istring].str = NULL;
754 /* put unused int_array location of the freelist */
755         if(free_num == 0)
756         {
757             freelist = (long *)malloc(ARRAYSIZE * sizeof(long));
758             if (freelist == NULL)
759             {
760                 fprintf(stderr, "%s",
761                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
762                     "ISTR: error in allocating memory\n") );
763                 return 0 ;
764             }  
765             free_num = 1;
766         }
767         if(freecount < (ARRAYSIZE * free_num))  /* put free int value on 
768                                                    freelist  */
769         {
770             freelist[freecount] = istring;
771             freecount++;
772         }
773         else  /* need more freelist space */
774         { 
775             free_num++;
776             freelist = (long *)realloc(freelist,
777                 (ARRAYSIZE * free_num) * sizeof(long));
778             assert(freelist != NULL);
779             if (freelist == NULL)
780             {
781                 fprintf(stderr, "%s",
782                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
783                     "ISTR: error in allocating memory\n") );
784                 return 0 ;
785             }  
786             freelist[freecount] = istring;
787             freecount++;
788         }
789     }
790
791     /*
792      * Set the client's variable to NULL
793      */
794     istring = 0;
795     (*istringClientPtr) = istrP_int_to_client(istring);
796     return 1;
797 }
798
799
800 /* 
801  * Increment the string refcounter, and return the string value.
802  * Return -1 if error 
803  */
804 ISTRING 
805 istr_dup(
806     ISTRING istringClientVal
807 )
808 {
809     long        istring= istrP_client_to_int(istringClientVal);
810
811     if(istring == 0) 
812     {
813         return 0;
814     }
815     else if((istring < 0) || (istring >= num_count) || 
816        ((int_array[istring].refcount == 0) && 
817         (int_array[istring].read_const == 0)))
818     {
819         istrP_errmsg_noexist(istring);
820         return NULL;
821     }
822     int_array[istring].refcount++;
823     return_istr(istring);
824 }
825
826 /* 
827  * Return the string name for the given int, return NULL if error 
828  *
829  * Verifies that the string is valid
830  */
831 STRING 
832 istrP_get_string_verify(
833     ISTRING istringClientVal
834 )
835 {
836     long        istring = istrP_client_to_int(istringClientVal);
837
838     if(istring == 0) 
839     {
840         return NULL;
841     }
842     if((istring < 0) || (istring >= num_count) || 
843        ((int_array[istring].refcount == 0) &&
844         (int_array[istring].read_const == 0)))
845     {
846         istrP_errmsg_noexist(istring);
847         return NULL;
848     }
849     return int_array[istring].str;
850 }
851
852 /******************************************************************************/
853 /*                       PRIVATE FUNCTIONS                                    */
854 /******************************************************************************/
855
856 /* 
857  * hash function 
858  */
859 static unsigned 
860 hashing(
861         STRING  string
862 )
863 {
864     register unsigned hash_val = 0;
865
866     for (hash_val = 0; *string; ++string)
867         hash_val = hash_val * 65599 + *string;
868     return hash_val % NUMBUCKETS;
869 }
870
871 /* 
872  * search hash table for existing strings 
873  *
874  * Returns int value for string, or -1 if not found
875  */
876 static int 
877 hash_and_lookupstr(
878     char        *string,
879     int         *hash_val_out_ptr
880 )
881 {
882 #define fast_streq(s1,s2) (((s1)[0] == (s2)[0]) && (strcmp(s1,s2) == 0))
883
884     register unsigned hash_val = 0;
885     register char       *stringPtr;
886     Bucket      entry;
887     int         *valuePtr;
888     int         *valuePtrEnd;
889     int         value;
890
891     /*
892      * Get bucket
893      */
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);
897
898     /*
899      * Find entry in bucket
900      */
901     for (entry = &hashtable[hash_val]; entry != NULL; entry = entry->next)
902     {
903         valuePtr = entry->values;
904         valuePtrEnd = valuePtr + BUCKETSIZE;
905         for (; valuePtr != valuePtrEnd; ++valuePtr)
906         {
907             value = *valuePtr;
908             if (   (value >= 0) 
909                 && (fast_streq(int_array[value].str,string)) )
910             {
911                 return value;
912             }
913         } 
914     } 
915
916     return -1;
917 #undef fast_streq
918 }
919
920 /* 
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 
924  */
925 static int 
926 insert_array(
927     int flag, 
928     int val, 
929     char *string
930 )
931 {
932     char *str;
933     static int array_num =0;
934
935     if(hash_count == 0)
936     {
937         int_array_set((STRN *)calloc(ARRAYSIZE, sizeof(STRN)));
938         if (int_array == NULL)
939         {
940             fprintf(stderr, "%s",
941                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
942                 "ISTR: error in allocating memory\n") );
943             return 0 ;
944         }  
945         array_num = 1;
946     }
947     if(val < (ARRAYSIZE * array_num)) /* insert into array */
948     {
949         int_array[val].refcount =1;
950         if (flag == 1)
951         {                   /* read only */
952            str = strdup(string);
953            int_array[val].read_const = 0;
954            int_array[val].str = str; 
955         }
956         else if (flag == 2)
957         {                  /* const */
958            int_array[val].read_const = 1;
959            int_array[val].str = string; 
960         }
961         else               /* flag == 3 */
962         {                  /* allocated */
963            int_array[val].read_const = 0;
964            int_array[val].str = string; 
965         }
966     }
967     else  /* need more array space */
968     { 
969         array_num++;
970         int_array_set((STRN *)realloc(int_array,
971             (ARRAYSIZE * array_num) * sizeof(STRN)));
972         assert(int_array != NULL);
973         if (int_array == NULL)
974         {
975             fprintf(stderr, "%s",
976                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
977                 "ISTR: error in allocating memory\n") );
978             return 0 ;
979         }  
980         int_array[val].refcount =1;
981         if (flag == 1)
982         {                   /* read only */
983            str = strdup(string);
984            int_array[val].read_const = 0;
985            int_array[val].str = str; 
986         }
987         else if(flag == 2)   /* const */
988         {
989            int_array[val].read_const = 1;
990            int_array[val].str = string; 
991         }
992         else                /*flag == 3*/  
993         {                   /* allocated */
994            int_array[val].read_const = 0;
995            int_array[val].str = string; 
996         }
997     }
998     return 1;
999 }
1000
1001
1002 static int
1003 hashtable_init(void)
1004 {
1005     int         i = 0, j = 0;
1006     
1007     for(i=0; i< NUMBUCKETS; i++)
1008     {
1009         hashtable[i].next = NULL;
1010         for (j=0; j < BUCKETSIZE; j++)
1011         {
1012             hashtable[i].values[j] = -1;
1013         }
1014     }
1015     return 0;
1016 }
1017
1018
1019 /*
1020  * Verifies the string exists and is not corrupted.
1021  */
1022 int
1023 istr_verify(ISTRING istringClientVal)
1024 {
1025     int         istring= istrP_client_to_int(istringClientVal);
1026     int         return_value = 0;
1027
1028     if (istringClientVal == (ISTRING)NULL)
1029     {
1030         return 0;       /* OK */
1031     }
1032     if((istring < 0) || (istring >= num_count) || 
1033        ((int_array[istring].refcount == 0) && 
1034         (int_array[istring].read_const == 0)))
1035     {
1036         return_value = -1;
1037     }
1038     return return_value;
1039 }
1040
1041 /*
1042  * This doesn't do anything right now, although it really should.
1043  */
1044 int
1045 istr_verify_all(void)
1046 {
1047     return 0;
1048 }
1049
1050
1051 static int
1052 istrP_errmsg_noexist(int istr_value)
1053 {
1054 #ifdef DEBUG
1055     fprintf(stderr,"ISTR: the reference string %d doesn't exist\n",
1056         istr_value);
1057
1058     if (util_get_verbosity() >= 3)
1059     {
1060         util_error("Aborting (dumping core).");
1061         abort();
1062     }
1063 #endif /* DEBUG */
1064     return 0;
1065 }
1066