home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume18 / mcqueer-lib / strstore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-09  |  7.6 KB  |  323 lines

  1. #include <stdio.h>
  2.  
  3. /*
  4. **
  5. **    Copyright (c) 1987, Robert L. McQueer
  6. **        All Rights Reserved
  7. **
  8. ** Permission granted for use, modification and redistribution of this
  9. ** software provided that no use is made for commercial gain without the
  10. ** written consent of the author, that all copyright notices remain intact,
  11. ** and that all changes are clearly documented.  No warranty of any kind
  12. ** concerning any use which may be made of this software is offered or implied.
  13. **
  14. */
  15.  
  16. /*
  17. ** string storage routines.
  18. **
  19. **    str_store - return an allocated copy of a string
  20. **    str_free - free all the strings
  21. **    str_cnew - make a new context block for separate group of strings
  22. **    str_ccur - return the current context block
  23. **    str_cset - set the context block
  24. **    str_cfree - free a context block
  25. **    str_afail - set allocation failure routine
  26. **
  27. ** Callers who simply need to make a single group of "permanent" strings
  28. ** for the life of their process need only call str_store, without worrying
  29. ** about context pointers.  This will probably be suitable for a lot of
  30. ** applications.  The other routines may be used to create separate groups
  31. ** of strings which may be released individually.  The burden on callers
  32. ** to keep track of current context in these cases is traded off against
  33. ** the simplicity for the other case.
  34. **
  35. ** The intent of these routines is to "micro-allocate" strings into a
  36. ** large block of storage, saving malloc() headers.  If used exclusively
  37. ** to store long strings, it might be inefficient.
  38. */
  39.  
  40. char *malloc();
  41.  
  42. /* actual malloc'ed block will be CH_BLOCK + sizeof(CHAIN) */
  43. #define CH_BLOCK (4096 - sizeof(CHAIN))
  44.  
  45. #define MAGICNUM 0x525
  46.  
  47. typedef struct _chain
  48. {
  49.     struct _chain *next;
  50.     int avail;
  51.     char *store;
  52. } CHAIN;
  53.  
  54. typedef struct
  55. {
  56.     int magic;
  57.     CHAIN *flist;
  58. } CONTEXT;
  59.  
  60. static CONTEXT Cb_def[1] =
  61. {
  62.     { MAGICNUM, NULL }
  63. };
  64.  
  65. /*
  66. ** NO_PTR_INIT may be defined if the compiler barfs on attempts
  67. ** to initialize a pointer with an array name.  If defined, extra
  68. ** checks will be made at routine entry to do the initialization
  69. ** first time through
  70. */
  71. #ifdef NO_PTR_INIT
  72. static CONTEXT *Cb = NULL;
  73. #else
  74. static CONTEXT *Cb = Cb_def;
  75. #endif
  76.  
  77. static def_afail()
  78. {
  79.     fatal ("memory allocation failure in string storage");
  80. }
  81.  
  82. static int (*Afail)() = def_afail;
  83.  
  84. /*
  85. ** str_store: return an allocated copy of a string.
  86. **
  87. **    s - the string to make a copy of.  If NULL, an empty string
  88. **        will be returned.
  89. **
  90. ** NOTE: these strings may not be individually freed.  This routine
  91. ** is intended to save memory used for alloc headers by returning
  92. ** pointers into a large blocks of allocated memory.
  93. **
  94. ** Will return NULL for allocation failure if a non-fatal failure
  95. ** routine has been defined (see str_afail).  The default failure
  96. ** routine calls "fatal" with an error message.  If the failure
  97. ** routine does not return, a NULL return from this routine is
  98. ** impossible.
  99. */
  100.  
  101. char *
  102. str_store(s)
  103. char *s;
  104. {
  105.     int len, av, idx;
  106.     char *rptr;
  107.     CHAIN *fp;
  108.  
  109. #ifdef NO_PTR_INIT
  110.     if (Cb == NULL)
  111.         Cb = Cb_def;
  112. #endif
  113.  
  114.     if (s == NULL)
  115.         s = "";
  116.  
  117.     len = strlen(s) + 1;
  118.  
  119.     /* should return inside loop */
  120.     for (idx = 0; idx < 2; ++idx)
  121.     {
  122.         for (fp = Cb->flist; fp != NULL; fp = fp->next)
  123.         {
  124.             if (fp->avail >= len)
  125.             {
  126.                 strcpy ((rptr = fp->store),s);
  127.                 fp->store += len;
  128.                 fp->avail -= len;
  129.                 return (rptr);
  130.             }
  131.         }
  132.  
  133.         /* alloc new block, let it find it on next iteration */
  134.         if (len > CH_BLOCK)
  135.             av = len;
  136.         else
  137.             av = CH_BLOCK;
  138.         if ((rptr = malloc(av + sizeof(CHAIN))) == NULL)
  139.         {
  140.             (*Afail)();
  141.             return (NULL);
  142.         }
  143.         fp = (CHAIN *) rptr;
  144.         fp->next = Cb->flist;
  145.         Cb->flist = (CHAIN *) fp;
  146.         fp->store = rptr + sizeof(CHAIN);
  147.         fp->avail = av;
  148.     }
  149.  
  150.     /* we're screwed up */
  151.     fatal("str_store: BAD craziness");
  152.     return(NULL);
  153. }
  154.  
  155. /*
  156. ** str_free:
  157. **
  158. **    Free all the strings allocated with str_store.  All of those
  159. **    pointers will no longer be valid.
  160. **
  161. **    If str_cnew / str_cset have been used, this call frees the strings
  162. **    in the current context block.
  163. **
  164. **    str_store calls may still be made after this - you're simply
  165. **    starting over.
  166. */
  167. str_free()
  168. {
  169.     CHAIN *ptr;
  170.  
  171. #ifdef NO_PTR_INIT
  172.     if (Cb == NULL)
  173.         Cb = Cb_def;
  174. #endif
  175.  
  176.     for ( ; Cb->flist != NULL; Cb->flist = ptr)
  177.     {
  178.         ptr = (Cb->flist)->next;
  179.         free ((char *) Cb->flist);
  180.     }
  181. }
  182.  
  183. /*
  184. ** str_cnew:
  185. **
  186. **    Make a new context block for str_store()
  187. **
  188. **    A pointer returned from this routine or str_ccur() is the ONLY
  189. **    valid argument for str_cset.
  190. **
  191. **    In effect what you are doing is declaring a new "pool" for all
  192. **    str_store() calls, probably so you can use str_free() to release
  193. **    groups of strings selectively.
  194. **
  195. **    NOTE: you MUST call str_cset() to actually use this new pool.
  196. **
  197. **    You MUST save this pointer to be able to add more strings to
  198. **    or free the pool.  Any number of str_cnew calls may be made,
  199. **    allowing the caller to have as many "pools" of strings as
  200. **    desired.  It is up to the caller to keep track of the context
  201. **    pointers, and which context block is currently in use.
  202. **
  203. **    NULL will be returned for failure to allocate a new context block.
  204. **    This return is only possible if a non-fatal allocation failure
  205. **    routine has been defined.
  206. */
  207. char *
  208. str_cnew()
  209. {
  210.     CONTEXT *ctx;
  211.  
  212.     /*
  213.     ** this is an inefficient use of malloc, but presumably callers
  214.     ** aren't going to define large numbers of context blocks
  215.     */
  216.     if ((ctx = (CONTEXT *) malloc(sizeof(CONTEXT))) == NULL)
  217.     {
  218.         (*Afail)();
  219.         return (NULL);
  220.     }
  221.  
  222.     ctx->magic = MAGICNUM;
  223.     ctx->flist = NULL;
  224.     return ((char *) ctx);
  225. }
  226.  
  227. /*
  228. ** str_ccur:
  229. **
  230. **    return pointer to context in current use, presumably so
  231. **    you can use str_cset to switch back to it later.
  232. */
  233. char *
  234. str_ccur()
  235. {
  236. #ifdef NO_PTR_INIT
  237.     if (Cb == NULL)
  238.         Cb = Cb_def;
  239. #endif
  240.     return ((char *) Cb);
  241. }
  242.  
  243. /*
  244. ** str_cset:
  245. **
  246. **    Set str_store() to a new context block. The ONLY
  247. **    legitimate argument for this routine is an address returned
  248. **    from a previous str_cnew() or str_ccur().
  249. **
  250. **    All old strings are still valid.  Only str_free returns any
  251. **    storage.
  252. **
  253. **    You may recover the default context prior to any str_cset calls
  254. **    by setting NULL
  255. */
  256. str_cset(ptr)
  257. char *ptr;
  258. {
  259.     if (ptr == NULL)
  260.         Cb = Cb_def;
  261.     else
  262.         Cb = (CONTEXT *) ptr;
  263.     if (Cb->magic != MAGICNUM)
  264.         fatal("bad context pointer in str_cset");
  265. }
  266.  
  267. /*
  268. ** the ONLY legal argument to this routine is pointer returned from
  269. ** str_cnew.  This routine may be used to indicate that no more strings
  270. ** are to be allocated on that context block, and the pointer will no
  271. ** longer be a legal argument to str_cset.  Note that the actual
  272. ** strings are still allocated, giving you a way to close a pool
  273. ** while retaining the strings.  If you want to free BOTH the actual
  274. ** string storage and the pool, you must use str_free first, then
  275. ** switch context, so that this block is not the current context.
  276. **
  277. ** -1 returned for errors - attempts to free the current block or
  278. ** the default block.
  279. **
  280. ** Although the current implementation makes ptr a legal address for
  281. ** free(), callers should come through this routine instead, to
  282. ** allow that to change.
  283. */
  284. str_cfree(ptr)
  285. char *ptr;
  286. {
  287.     if (ptr == (char *) Cb_def || ptr == (char *) Cb)
  288.         return (-1);
  289.  
  290.     if (((CONTEXT *) ptr)->magic != MAGICNUM)
  291.         fatal("bad context pointer in str_cfree");
  292.  
  293.     /* make it illegal to use freed context block */
  294.     ((CONTEXT *) ptr)->magic = MAGICNUM + 1;
  295.  
  296.     free(ptr);
  297.     return(0);
  298. }
  299.  
  300. /*
  301. ** str_afail:
  302. **
  303. **    define the routine to be called in the event of an allocation
  304. **    failure.  By default, fatal() will be called with an error message.
  305. **    You may reset the default by using NULL.
  306. **
  307. **    Returns old failure function to allow resetting.
  308. */
  309.  
  310. typedef int (*FPTR)();    /* needed typedef for Sun compiler */
  311.  
  312. FPTR str_afail(func)
  313. int (*func)();
  314. {
  315.     int (*old)();
  316.  
  317.     old = Afail;
  318.     if (func == NULL)
  319.         Afail = def_afail;
  320.     Afail = func;
  321.     return (old);
  322. }
  323.