Add GNU LGPL headers to all .c .C and .h files
[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 int     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 int *freelist;           /* freelist for unused numbers */
98
99 static int freecount  = 0;      /* freelist count */
100 static int 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)    ((int)(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     int 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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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     int 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,
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,
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,
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,
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,
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,
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,
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,
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,
447                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
448                     "ISTR: error in allocating space for string\n") );
449                 return NULL;
450             }
451             new_bucket->values[0] = freelist[freecount-1];
452             entry->next = new_bucket;
453             if (insert_array(3, freelist[freecount-1], *string) == -1)
454             {
455                 fprintf(stderr,
456                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
457                     "ISTR: error in allocating to int array\n") );
458                 return NULL;
459             }
460             freecount--;
461             return_istr(freelist[freecount]);
462
463         }
464     }
465     else            /* duplicate entry */
466     {
467         int_array[str_exists].refcount++;
468         if ((*string != int_array[str_exists].str) &&
469            (*&string != &(int_array[str_exists].str)))
470         {
471             free(*string);
472             *string = NULL;
473         }
474         return_istr(str_exists);
475     }
476 }
477
478 /* 
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 
482  * the existing int. 
483 */
484 ISTRING 
485 istr_create_const(
486     STRING string
487 )
488 {
489     int hashval;
490     int str_exists;
491     Bucket      new_bucket;
492     int i;
493     Bucket      entry;
494     check_init();
495  
496     if (string == NULL)
497     {
498         return NULL;
499     }
500
501     /* hashval = hashing(string); */
502     if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1)     /* new entry */  
503     {     
504         entry = &hashtable[hashval];
505         for (i=0; i< BUCKETSIZE; i++)
506         { 
507             if (entry->values[i] == -1)
508             {
509                 
510                 if(freecount == 0)
511                 {         /* no numbers on freelist */
512                     entry->values[i] = num_count;
513                     if (insert_array(2, num_count, string) == -1)
514                     {
515                         fprintf(stderr,
516                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
517                             "ISTR: error in allocating to int array\n") );
518                         return NULL;
519                     }
520                     num_count++;
521                     hash_count++;
522                     return_istr(num_count-1);
523                 }
524                 else
525                 {   /* take int value from freelist */
526                     if(int_array[freelist[freecount-1]].refcount != 0)
527                     {
528                         fprintf(stderr,
529                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
530                             "ISTR: error in allocating space for string\n") );
531                         return NULL;
532                     }
533                     entry->values[i] = freelist[freecount-1];
534                     if (insert_array(2, freelist[freecount-1], string) == -1)
535                     {
536                         fprintf(stderr,
537                             catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
538                             "ISTR: error in allocating to int array\n") );
539                         return NULL;
540                     }
541                     freecount--;
542                     return_istr(freelist[freecount]);
543                 } 
544             } 
545         }
546         while(entry->next != NULL)
547         {                            /* check next bucket */
548             entry = entry->next;
549             for (i=0; i< BUCKETSIZE; i++)
550             { 
551                 if (entry->values[i] == -1)
552                 {
553                     if (freecount == 0)
554                     {
555                         entry->values[i] = num_count;
556                         if (insert_array(2, num_count, string) == -1)
557                         {
558                             fprintf(stderr,
559                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
560                                 "ISTR: error in allocating to int array\n") );
561                             return NULL;
562                         }
563                         num_count++;
564                         hash_count++;
565                         return_istr(num_count-1);
566                     }
567                     else
568                     {
569                         if(int_array[freelist[freecount-1]].refcount != 0)
570                         {
571                             fprintf(stderr,
572                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
573                                 "ISTR: error in allocating space for string\n") );
574                             return NULL;
575                         }
576                         entry->values[i] = freelist[freecount-1];
577                         if (insert_array(2, 
578                             freelist[freecount-1], string) == -1)
579                         {
580                             fprintf(stderr,
581                                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
582                                 "ISTR: error in allocating to int array\n") );
583                             return NULL;
584                         }
585                         freecount--;
586                         return_istr(freelist[freecount]);
587                     } 
588                 } 
589             }
590         }
591 /* if get this far, then no space is available in existing bucket, 
592    add new bucket */
593         new_bucket = (Bucket)malloc (sizeof(BucketRec));
594         if (new_bucket == NULL)
595         {
596             fprintf(stderr,
597                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
598                 "ISTR: error in allocating memory\n") );
599             return NULL ;
600         }  
601         for(i=1;i<BUCKETSIZE; i++)
602         {
603             new_bucket->values[i] = -1;
604         }
605         new_bucket->next = NULL;
606         if (freecount == 0)
607         {
608             new_bucket->values[0] = num_count;
609             entry->next = new_bucket;
610             if (insert_array(2, num_count, string) == -1)
611             {
612                 fprintf(stderr,
613                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
614                     "ISTR: error in allocating to int array\n") );
615                 return NULL;
616             }
617             num_count++;
618             hash_count++;
619             return_istr(num_count-1);
620         }
621         else
622         {
623             if(int_array[freelist[freecount-1]].refcount != 0)
624             {
625                 fprintf(stderr,
626                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 2,
627                     "ISTR: error in allocating space for string\n") );
628                 return NULL;
629             }
630             new_bucket->values[0] = freelist[freecount-1];
631             entry->next = new_bucket;
632             if (insert_array(2, freelist[freecount-1], string) == -1)
633             {
634                 fprintf(stderr,
635                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 1,
636                     "ISTR: error in allocating to int array\n") );
637                 return NULL;
638             }
639             freecount--;
640             return_istr(freelist[freecount]);
641
642         }
643     }
644     else            /* duplicate entry */
645     {
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)))
650             {
651                 free(int_array[str_exists].str);
652                 int_array[str_exists].str = string;
653             }
654             int_array[str_exists].read_const = 1;
655         } 
656         int_array[str_exists].refcount++;
657         return_istr(str_exists);
658     }
659 }
660
661 /* 
662  * Lookup string if find it duplicate the entry and return int value,
663  * else return NULL.
664  */
665 ISTRING
666 istr_dup_existing(
667     STRING string
668 )
669 {
670     int hashval;
671     int str_exists;
672
673     if (string == NULL)
674     {
675         return NULL;
676     }
677     /* hashval = hashing(string); */
678     if ((str_exists = hash_and_lookupstr(string,&hashval)) == -1)    
679     {                                          /* string doesn't exist */
680         return NULL;
681     }
682     else 
683     {
684         int_array[str_exists].refcount++;
685         return_istr(str_exists);
686     }
687 }
688
689 /* 
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 
693  */
694 int 
695 istrP_destroy_impl(
696     ISTRING *istringClientPtr
697 )
698 {
699     int istring = (int)(*istringClientPtr);
700     int val;                 /* hashing value */
701     int i;
702     Bucket      entry;
703     static int free_num = 0;   /* allocated space in freelist = 
704                                   free_num * ARRAYSIZE */
705
706     if(istring == 0)  
707     {
708         return 0;
709     }
710     if((istring < 0) || (istring >= num_count) || 
711        ((int_array[istring].refcount == 0) && 
712         (int_array[istring].read_const == 0)))
713     {
714         istrP_errmsg_noexist(istring);
715         return NULL;
716     }
717     if (int_array[istring].read_const == 1)  /* const entry */
718     {
719         /* never let refs to const entries drop below 1 */
720         if (int_array[istring].refcount > 1)
721         {
722             int_array[istring].refcount--;
723         }
724         (*istringClientPtr) = NULL;
725         return 0;
726     }
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++)
733         {
734             if (entry->values[i] == istring)
735             {
736                 entry->values[i] = -1;
737             } 
738         } 
739         while(entry->next != NULL)
740         {
741             entry = entry->next; 
742             for (i =0; i< BUCKETSIZE; i++)
743             {
744                 if (entry->values[i] == istring)
745                 {
746                     entry->values[i] = -1;
747                 }
748             } 
749         }
750         free(int_array[istring].str);
751         int_array[istring].str = NULL;
752 /* put unused int_array location of the freelist */
753         if(free_num == 0)
754         {
755             freelist = (int *)malloc(ARRAYSIZE * sizeof(int));
756             if (freelist == NULL)
757             {
758                 fprintf(stderr,
759                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
760                     "ISTR: error in allocating memory\n") );
761                 return NULL ;
762             }  
763             free_num = 1;
764         }
765         if(freecount < (ARRAYSIZE * free_num))  /* put free int value on 
766                                                    freelist  */
767         {
768             freelist[freecount] = istring;
769             freecount++;
770         }
771         else  /* need more freelist space */
772         { 
773             free_num++;
774             freelist = (int *)realloc(freelist,
775                 (ARRAYSIZE * free_num) * sizeof(int));
776             assert(freelist != NULL);
777             if (freelist == NULL)
778             {
779                 fprintf(stderr,
780                     catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
781                     "ISTR: error in allocating memory\n") );
782                 return NULL ;
783             }  
784             freelist[freecount] = istring;
785             freecount++;
786         }
787     }
788
789     /*
790      * Set the client's variable to NULL
791      */
792     istring = NULL;
793     (*istringClientPtr) = istrP_int_to_client(istring);
794     return 1;
795 }
796
797
798 /* 
799  * Increment the string refcounter, and return the string value.
800  * Return -1 if error 
801  */
802 ISTRING 
803 istr_dup(
804     ISTRING istringClientVal
805 )
806 {
807     int         istring= istrP_client_to_int(istringClientVal);
808
809     if(istring == 0) 
810     {
811         return 0;
812     }
813     else if((istring < 0) || (istring >= num_count) || 
814        ((int_array[istring].refcount == 0) && 
815         (int_array[istring].read_const == 0)))
816     {
817         istrP_errmsg_noexist(istring);
818         return NULL;
819     }
820     int_array[istring].refcount++;
821     return_istr(istring);
822 }
823
824 /* 
825  * Return the string name for the given int, return NULL if error 
826  *
827  * Verifies that the string is valid
828  */
829 STRING 
830 istrP_get_string_verify(
831     ISTRING istringClientVal
832 )
833 {
834     int         istring = istrP_client_to_int(istringClientVal);
835
836     if(istring == 0) 
837     {
838         return NULL;
839     }
840     if((istring < 0) || (istring >= num_count) || 
841        ((int_array[istring].refcount == 0) &&
842         (int_array[istring].read_const == 0)))
843     {
844         istrP_errmsg_noexist(istring);
845         return NULL;
846     }
847     return int_array[istring].str;
848 }
849
850 /******************************************************************************/
851 /*                       PRIVATE FUNCTIONS                                    */
852 /******************************************************************************/
853
854 /* 
855  * hash function 
856  */
857 static unsigned 
858 hashing(
859         STRING  string
860 )
861 {
862     register unsigned hash_val = 0;
863
864     for (hash_val = 0; *string; ++string)
865         hash_val = hash_val * 65599 + *string;
866     return hash_val % NUMBUCKETS;
867 }
868
869 /* 
870  * search hash table for existing strings 
871  *
872  * Returns int value for string, or -1 if not found
873  */
874 static int 
875 hash_and_lookupstr(
876     char        *string,
877     int         *hash_val_out_ptr
878 )
879 {
880 #define fast_streq(s1,s2) (((s1)[0] == (s2)[0]) && (strcmp(s1,s2) == 0))
881
882     register unsigned hash_val = 0;
883     register char       *stringPtr;
884     Bucket      entry;
885     int         *valuePtr;
886     int         *valuePtrEnd;
887     int         value;
888
889     /*
890      * Get bucket
891      */
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);
895
896     /*
897      * Find entry in bucket
898      */
899     for (entry = &hashtable[hash_val]; entry != NULL; entry = entry->next)
900     {
901         valuePtr = entry->values;
902         valuePtrEnd = valuePtr + BUCKETSIZE;
903         for (; valuePtr != valuePtrEnd; ++valuePtr)
904         {
905             value = *valuePtr;
906             if (   (value >= 0) 
907                 && (fast_streq(int_array[value].str,string)) )
908             {
909                 return value;
910             }
911         } 
912     } 
913
914     return -1;
915 #undef fast_streq
916 }
917
918 /* 
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 
922  */
923 static int 
924 insert_array(
925     int flag, 
926     int val, 
927     char *string
928 )
929 {
930     char *str;
931     static int array_num =0;
932
933     if(hash_count == 0)
934     {
935         int_array_set((STRN *)malloc(ARRAYSIZE * sizeof(STRN)));
936         if (int_array == NULL)
937         {
938             fprintf(stderr,
939                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
940                 "ISTR: error in allocating memory\n") );
941             return NULL ;
942         }  
943         array_num = 1;
944     }
945     if(val < (ARRAYSIZE * array_num)) /* insert into array */
946     {
947         int_array[val].refcount =1;
948         if (flag == 1)
949         {                   /* read only */
950            str = strdup(string);
951            int_array[val].read_const = 0;
952            int_array[val].str = str; 
953         }
954         else if (flag == 2)
955         {                  /* const */
956            int_array[val].read_const = 1;
957            int_array[val].str = string; 
958         }
959         else               /* flag == 3 */
960         {                  /* allocated */
961            int_array[val].read_const = 0;
962            int_array[val].str = string; 
963         }
964     }
965     else  /* need more array space */
966     { 
967         array_num++;
968         int_array_set((STRN *)realloc(int_array,
969             (ARRAYSIZE * array_num) * sizeof(STRN)));
970         assert(int_array != NULL);
971         if (int_array == NULL)
972         {
973             fprintf(stderr,
974                 catgets(UTIL_MESSAGE_CATD, UTIL_MESSAGE_SET, 3,
975                 "ISTR: error in allocating memory\n") );
976             return NULL ;
977         }  
978         int_array[val].refcount =1;
979         if (flag == 1)
980         {                   /* read only */
981            str = strdup(string);
982            int_array[val].read_const = 0;
983            int_array[val].str = str; 
984         }
985         else if(flag == 2)   /* const */
986         {
987            int_array[val].read_const = 1;
988            int_array[val].str = string; 
989         }
990         else                /*flag == 3*/  
991         {                   /* allocated */
992            int_array[val].read_const = 0;
993            int_array[val].str = string; 
994         }
995     }
996     return 1;
997 }
998
999
1000 static int
1001 hashtable_init(void)
1002 {
1003     int         i = 0, j = 0;
1004     
1005     for(i=0; i< NUMBUCKETS; i++)
1006     {
1007         hashtable[i].next = NULL;
1008         for (j=0; j < BUCKETSIZE; j++)
1009         {
1010             hashtable[i].values[j] = -1;
1011         }
1012     }
1013     return 0;
1014 }
1015
1016
1017 /*
1018  * Verifies the string exists and is not corrupted.
1019  */
1020 int
1021 istr_verify(ISTRING istringClientVal)
1022 {
1023     int         istring= istrP_client_to_int(istringClientVal);
1024     int         return_value = 0;
1025
1026     if (istringClientVal == (ISTRING)NULL)
1027     {
1028         return 0;       /* OK */
1029     }
1030     if((istring < 0) || (istring >= num_count) || 
1031        ((int_array[istring].refcount == 0) && 
1032         (int_array[istring].read_const == 0)))
1033     {
1034         return_value = -1;
1035     }
1036     return return_value;
1037 }
1038
1039 /*
1040  * This doesn't do anything right now, although it really should.
1041  */
1042 int
1043 istr_verify_all(void)
1044 {
1045     return 0;
1046 }
1047
1048
1049 static int
1050 istrP_errmsg_noexist(int istr_value)
1051 {
1052 #ifdef DEBUG
1053     fprintf(stderr,"ISTR: the reference string %d doesn't exist\n",
1054         istr_value);
1055
1056     if (util_get_verbosity() >= 3)
1057     {
1058         util_error("Aborting (dumping core).");
1059         abort();
1060     }
1061 #endif /* DEBUG */
1062     return 0;
1063 }
1064