home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / flistfrontend / src / nameheap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-06  |  4.8 KB  |  195 lines

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: nameheap.c,v 1.7 1995/06/06 13:02:56 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    nameheap.c
  7.  * Author:    Thomas E. Dickey
  8.  * Created:    04 Dec 1984
  9.  * Last update:
  10.  *        18 Mar 1995, prototypes
  11.  *        06 Jul 1985, added 'nameheap_ref' and 'nameheap_add'.
  12.  *        04 Jul 1985, added 'nameheap_set' and 'nameheap_clr'
  13.  *                 entrypoints to support refs-mask.
  14.  *        15 Jun 1985, typed 'calloc'
  15.  *        14 Dec 1984, allow for 0-length non-null-ended strings
  16.  *        06 Dec 1984
  17.  *
  18.  * Function:    This module maintains a table of character strings.  It is
  19.  *        used by FLIST to maintain the set of filename (path, name or
  20.  *        type) strings).  The strings are stored in an alphabetically-
  21.  *        sorted (no repeats) linked list.
  22.  *
  23.  *        To make symbols identical at all levels of hierarchy, we
  24.  *        allocate space for a given unique string once, and keep it
  25.  *        until it is obsolete.  The '.refs' mask keeps track of which
  26.  *        levels of hierarchy reference a given string.  When a string
  27.  *        has no more references, we may purge it with 'nameheap_clr'.
  28.  *
  29.  * Entry points:
  30.  *    nameheap    Do allocation/lookup of strings in a heap
  31.  *    nameheap_set    Set current reference-mask level
  32.  *    nameheap_ref    Return current reference-mask
  33.  *    nameheap_clr    Deallocate entries in a heap at a given reference level
  34.  *    nameheap_add    Mask additional levels for a given string
  35.  */
  36.  
  37. #include    <stdlib.h>
  38. #include    <stddef.h>    /* 'offsetof()' */
  39. #include    <stdio.h>
  40. #include    <string.h>
  41.  
  42. #include    "nameheap.h"
  43. #include    "textlink.h"
  44.  
  45. #define    CHR(link)    link->text[0]
  46. #define    ADR(link)    &CHR(link)
  47.  
  48. static    int    last_refs = 0;
  49.  
  50. /* <nameheap>:
  51.  * Function:    Do lookup/allocation of strings in a heap.
  52.  *
  53.  * Arguments:    s_    - pointer to string to lookup/store
  54.  *        len    - length of string (if -1, assume null-ended).
  55.  *        heap    - address of pointer to list to maintain.
  56.  *
  57.  * Returns:    A pointer to the string component of the entry (the pointer
  58.  *        component will be invisible to the user).
  59.  */
  60. char    *nameheap (char *s_, int len, void **heap)
  61. {
  62.     int    cmp, cnt;
  63.     TEXTLINK *new, *old, *tmp;
  64.     char    *ref_,    *tst_;
  65.  
  66.     if (len < 0)        len = strlen (s_);
  67.     if (len <= 0)        return ("");
  68.  
  69. #ifdef    DEBUG
  70.     {
  71.         char    format[20];
  72.         sprintf (format, "'%%.%ds'\n", len);
  73.         trace (format, s_);
  74.     }
  75. #endif
  76.  
  77.     for (new = *heap, old = 0; new; old = new, new = new->next)
  78.     {
  79.         /*
  80.          * Do an inline string compare to make this run fast.  Note
  81.          * that the input string need not be ended with a null.
  82.          */
  83.         for (tst_ = s_, ref_ = ADR(new), cnt = len;
  84.             *ref_;
  85.                 tst_++, ref_++, cnt--)
  86.         {
  87.             if (cmp = ((cnt > 0) ? *tst_ : 0) - *ref_)    break;
  88.         }
  89.         if (!*ref_ && cnt)    cmp = *tst_;
  90. #ifdef    DEBUG
  91.         trace ("\t'%s' => %d (%d)\n", ADR(new), cmp, len-cnt);
  92. #endif
  93.         if (cmp == 0)        goto exit;
  94.         else if (cmp < 0)    break;
  95.     }
  96.  
  97.     tmp = calloc (1, sizeof(TEXTLINK) + len);/* Allocate pointer + text */
  98.  
  99.     if (old)    old->next = tmp;
  100.     else        *heap      = tmp;    /* Entry is first in list */
  101.  
  102.     tmp->next = new;
  103.     strncpy (ADR(tmp), s_, len);
  104.     tmp->text[len] = '\0';
  105.     new = tmp;
  106.  
  107. #ifdef    DEBUG
  108.     trace ("\t--> new\n");
  109. #endif
  110.  
  111. exit:    new->refs |= last_refs;
  112.     return (ADR(new));
  113. }
  114.  
  115. /* <nameheap_set>:
  116.  * Set the current refs-level.  We expect an integer in the range 1-8, since
  117.  * we shift it as a bit-mask ourselves.  Note that this level-mask is shared
  118.  * by all lists maintained by this module.
  119.  */
  120. void    nameheap_set (int new_refs)
  121. {
  122.     if (new_refs < 1)    new_refs = 1;
  123.     last_refs = 1 << (new_refs-1);
  124. #ifdef    DEBUG1
  125.     trace ("SET: %d => %d\n", new_refs, last_refs);
  126. #endif
  127. }
  128.  
  129. /* <nameheap_ref>:
  130.  * Return the mask to permit caller to maintain a compatible tagged list.
  131.  */
  132. int    nameheap_ref (void)
  133. {
  134.     return (last_refs);
  135. }
  136.  
  137. /* <nameheap_clr>:
  138.  * Clear the specified reference-level from all items in the linked-list.
  139.  * If a string has no more references, unlink it and deallocate the entry.
  140.  */
  141. void    nameheap_clr (int old_refs, void **heap)
  142. {
  143.     TEXTLINK *old = 0;
  144.     TEXTLINK *new = *heap;
  145.     TEXTLINK *nxt;
  146.  
  147.     if (old_refs < 1 || old_refs > 8)    return;
  148.     old_refs = ~(1 << (old_refs-1));
  149.  
  150.     while (new)
  151.     {
  152.         nxt = new->next;
  153.         if (new->refs &= old_refs)
  154.             old = new;
  155.         else
  156.         {
  157.             if (old)    old->next = nxt;
  158.             else        *heap      = nxt;
  159.             cfree (new);
  160.         }
  161.         new = nxt;
  162.     }
  163. }
  164.  
  165. /* <nameheap_add>:
  166.  * Given a string and a reference mask, OR the mask against the string's
  167.  * heap-descriptor.  This is used, for example, when renaming an object to
  168.  * ensure that higher levels will refer to all parts of the object.
  169.  */
  170. void    nameheap_add (int refs, char *text)
  171. {
  172.     TEXTLINK *P = (TEXTLINK *) 0;
  173.     void    *C = text - offsetof(TEXTLINK, text);
  174.     P = (TEXTLINK *) C;
  175.     P->refs |= refs;
  176. }
  177.  
  178. #ifdef    DEBUG1
  179. void    nameheap_dump (char *tag, void **heap)
  180. {
  181.     TEXTLINK *new = *heap;
  182.     register int    j;
  183.  
  184.     trace("Names: %s %08X\n", tag, new);
  185.     while (new)
  186.     {
  187.         for (j = 1; j < 256; j <<= 1)
  188.             trace ("%c", new->refs & j ? '*' : '-');
  189.         trace (" '%s'\n", new->text);
  190.         new = new->next;
  191.     }
  192.     trace ("----\n");
  193. }
  194. #endif    /* DEBUG1 */
  195.