1 /*
2 Copyright (c) 1994 - 2010, Lawrence Livermore National Security, LLC.
3 LLNL-CODE-425250.
4 All rights reserved.
5 
6 This file is part of Silo. For details, see silo.llnl.gov.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11 
12    * Redistributions of source code must retain the above copyright
13      notice, this list of conditions and the disclaimer below.
14    * Redistributions in binary form must reproduce the above copyright
15      notice, this list of conditions and the disclaimer (as noted
16      below) in the documentation and/or other materials provided with
17      the distribution.
18    * Neither the name of the LLNS/LLNL nor the names of its
19      contributors may be used to endorse or promote products derived
20      from this software without specific prior written permission.
21 
22 THIS SOFTWARE  IS PROVIDED BY  THE COPYRIGHT HOLDERS  AND CONTRIBUTORS
23 "AS  IS" AND  ANY EXPRESS  OR IMPLIED  WARRANTIES, INCLUDING,  BUT NOT
24 LIMITED TO, THE IMPLIED  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A  PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN  NO  EVENT SHALL  LAWRENCE
26 LIVERMORE  NATIONAL SECURITY, LLC,  THE U.S.  DEPARTMENT OF  ENERGY OR
27 CONTRIBUTORS BE LIABLE FOR  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR  CONSEQUENTIAL DAMAGES  (INCLUDING, BUT NOT  LIMITED TO,
29 PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS  OF USE,  DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 LIABILITY, WHETHER  IN CONTRACT, STRICT LIABILITY,  OR TORT (INCLUDING
32 NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT  OF THE USE  OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 
35 This work was produced at Lawrence Livermore National Laboratory under
36 Contract No.  DE-AC52-07NA27344 with the DOE.
37 
38 Neither the  United States Government nor  Lawrence Livermore National
39 Security, LLC nor any of  their employees, makes any warranty, express
40 or  implied,  or  assumes  any  liability or  responsibility  for  the
41 accuracy, completeness,  or usefulness of  any information, apparatus,
42 product, or  process disclosed, or  represents that its use  would not
43 infringe privately-owned rights.
44 
45 Any reference herein to  any specific commercial products, process, or
46 services by trade name,  trademark, manufacturer or otherwise does not
47 necessarily  constitute or imply  its endorsement,  recommendation, or
48 favoring  by  the  United  States  Government  or  Lawrence  Livermore
49 National Security,  LLC. The views  and opinions of  authors expressed
50 herein do not necessarily state  or reflect those of the United States
51 Government or Lawrence Livermore National Security, LLC, and shall not
52 be used for advertising or product endorsement purposes.
53 */
54 #include "config.h" /* For HAVE_MEMMOVE test. */
55 /*
56  * SCCTLA.C - auxilliary functions for control structure package
57  *          - these should NEVER be modified for a specific application
58  *
59  * Source Version: 2.0
60  * Software Release #92-0043
61  *
62  *
63  */
64 #include "config.h"
65 #include <score.h>
66 #include <limits.h>
67 #if HAVE_STDLIB_H
68 #include <stdlib.h>
69 #endif
70 #include <string.h>
71 
72 typedef union u_mem_header mem_header;
73 typedef struct s_mem_descriptor mem_descriptor;
74 
75 #define SC_MEM_ID       0xF1E2D3C4
76 #define UNIT_SIZE_MAX   10
77 
78 /*
79  * This parameter controls wether small requests for memory go to
80  * the system memory manager or are allocated out of a larger chunks
81  * of memory which score manages.
82  */
83 #undef CACHE_SMALL_MEM_REQ
84 
85 /*
86  * The struct s_mem_descriptor will contain prev and next fields if
87  * NEED_MEM_TRACE is defined and the macros ASSIGN_BLOCK, SAVE_LINKS,
88  * REASSIGN_BLOCK, UNASSIGN_BLOCK and the function lite_SC_realloc() use
89  * these fields.  These machines need this defined: irix, linux.
90  * These machines might get away with not defining this: meiko, solaris,
91  * sun, sun-gnu.
92  */
93 #if NORMAL_SCLITE_HEADERS
94 #define NEED_MEM_TRACE
95 #endif
96 #ifdef NEED_MEM_TRACE
97 
98 /*
99  * Use the mem_header struct to force alignment to that of a double
100  * this solves all alignment problems (especially for RISC chips).
101  */
102 
103 struct s_mem_descriptor {
104    char			*name;
105    long 		id;
106    short 		ref_count;
107    short 		type;
108    long 		length;
109    mem_header 		*prev;
110    mem_header 		*next;
111 };
112 
113 union u_mem_header {
114    mem_descriptor	block;
115    double 		align[3];
116 };
117 
118 static mem_header	*_SC_latest_block ;
119 
120 #define ASSIGN_BLOCK(space, nb, name) {                                \
121       mem_descriptor *desc;                                            \
122       desc = &space->block;                                            \
123       desc->id        = SC_MEM_ID;                                     \
124       desc->ref_count = 1;                                             \
125       desc->type      = 0;                                             \
126       desc->length    = nb;                                            \
127       desc->name      = name;                                          \
128       if (_SC_latest_block != NULL) {                                  \
129 	 mem_header *prev, *next;                                      \
130 	 next = _SC_latest_block->block.next;                          \
131 	 prev = _SC_latest_block;                                      \
132 	 next->block.prev = space;                                     \
133 	 prev->block.next = space;                                     \
134 	 desc->next = next;                                            \
135 	 desc->prev = prev;                                            \
136 	 _SC_latest_block = space;                                     \
137       } else {                                                         \
138 	 _SC_latest_block             = space;                         \
139 	 _SC_latest_block->block.prev = space;                         \
140 	 _SC_latest_block->block.next = space;			       \
141       }								       \
142    }
143 
144 #define SAVE_LINKS(desc) {                                             \
145       prev = desc->prev;                                               \
146       next = desc->next;                                               \
147       if (space == _SC_latest_block) _SC_latest_block = next;          \
148    }
149 
150 #define REASSIGN_BLOCK(space) {                                        \
151        desc = &space->block;                                           \
152        desc->length = nb;                                              \
153        prev->block.next = space;                                       \
154        next->block.prev = space;				       \
155     }
156 
157 #define UNASSIGN_BLOCK(desc) {                                         \
158        mem_header *prev, *next;                                        \
159        prev = desc->prev;                                              \
160        next = desc->next;                                              \
161        if (prev == next) _SC_latest_block = NULL;                      \
162        prev->block.next = next;                                        \
163        next->block.prev = prev;                                        \
164        if (space == _SC_latest_block) _SC_latest_block = next;         \
165     }
166 
167 #else /* NEED_MEM_TRACE */
168 
169 /*
170  * Use the mem_header struct to force alignment to that of a double
171  * this solves all alignment problems (especially for RISC chips)
172  */
173 struct s_mem_descriptor {
174    short 		ref_count;
175    int                  length;
176 };
177 
178 union u_mem_header {
179    mem_descriptor 	block;
180    double 		align[1];
181 };
182 
183 #define ASSIGN_BLOCK(space, nb, name) {                                \
184       mem_descriptor *desc;                                            \
185       desc = &space->block;                                            \
186       desc->ref_count = 1;                                             \
187       desc->length    = nb;                                            \
188    }
189 
190 #define SAVE_LINKS(desc) /*void*/
191 
192 #define REASSIGN_BLOCK(space) {                                        \
193        desc = &space->block;                                           \
194        desc->length = nb;					       \
195     }
196 
197 #define UNASSIGN_BLOCK(desc) /*void*/
198 
199 #endif /* NEED_MEM_TRACE */
200 
201 #define SCORE_BLOCK_P(desc)                                            \
202     (1 == 1)
203 
204 #define BLOCK_LENGTH(desc)                                             \
205     (desc)->length
206 
207 #define REF_COUNT(desc)                                                \
208     ((desc)->ref_count)
209 
210 
211 #define EXTRA_WORD_SIZE sizeof(long)
212 #define NBITS (8*EXTRA_WORD_SIZE - 4)
213 
214 #define _SC_REALLOC (*_lite_SC_realloc_hook)
215 #define _SC_ALLOC   (*_lite_SC_alloc_hook)
216 #define _SC_FREE    (*_lite_SC_free_hook)
217 
218 #define SC_MEM_COUNT                                                   \
219     lite_SC_c_sp_diff = lite_SC_c_sp_alloc - lite_SC_c_sp_free;        \
220     lite_SC_c_sp_max  = (lite_SC_c_sp_max > lite_SC_c_sp_diff) ?       \
221                    lite_SC_c_sp_max : lite_SC_c_sp_diff
222 
223 FreeFuncType   		_lite_SC_free_hook    = (FreeFuncType) free;
224 ReallocFuncType		_lite_SC_realloc_hook = (ReallocFuncType) realloc;
225 MallocFuncType		_lite_SC_alloc_hook   = (MallocFuncType) malloc;
226 
227 
228 #ifdef CACHE_SMALL_MEM_REQ
229 static mem_descriptor	 *_SC_free_list[UNIT_SIZE_MAX];
230 static char		**_SC_major_block_list ;
231 static long		_SC_nx_major_blocks ;
232 static long	 	_SC_n_major_blocks ;
233 #endif
234 
235 static long		_SC_max_mem_blocks ;
236 static long		_SC_n_mem_blocks ;
237 static unsigned long	Sz_max = ( 1L << NBITS) - 1;        /* maximum value */
238 static unsigned long	Sz = sizeof(mem_header);  /* size in bytes of header */
239 static char		tokbuffer[MAXLINE];  /* used by firsttok and lasttok */
240 static int		_SC_zero_space = TRUE;
241 static lite_SC_byte *		_SC_prim_alloc (size_t) ;
242 static void		_SC_prim_free (lite_SC_byte*,unsigned long) ;
243 
244 
245 /*-------------------------------------------------------------------------
246  * Function:	lite_SC_alloc
247  *
248  * Purpose:	Add a layer of control over the C level mamory management
249  *		system to store the byte length of allocated spaces.
250  *		A space EXTRA_WORD_SIZE greater than requested is allocated.
251  *		The length in bytes is written into the first EXTRA_WORD_SIZE
252  *		bytes with a 4 bit marker in the high bits and a pointer
253  *		to the next byte is returned.
254  *
255  * Return:	Success:	Ptr to user memory
256  *
257  *		Failure:	NULL
258  *
259  * Programmer:	Adapted from PACT SCORE
260  *		Mar 12, 1996
261  *
262  * Modifications:
263  *
264  *-------------------------------------------------------------------------
265  */
266 lite_SC_byte *
lite_SC_alloc(long nitems,long bytepitem,char * name)267 lite_SC_alloc (long nitems, long bytepitem, char *name) {
268 
269    long nb;
270    unsigned long nbp;
271    mem_header *space;
272 
273    nb = nitems*bytepitem;
274 
275    if ((nb <= 0) || (nb > Sz_max)) return(NULL);
276 
277    nbp = (unsigned long) nb + Sz;
278    space = (mem_header *) _SC_prim_alloc((size_t) nbp);
279 
280    if (space != NULL) {
281       ASSIGN_BLOCK(space, nb, name);
282 
283       lite_SC_c_sp_alloc += nb;
284       SC_MEM_COUNT;
285 
286       _SC_max_mem_blocks++;
287       _SC_n_mem_blocks++;
288 
289       space++;
290 
291       /*
292        * Zero out the space.
293        */
294       if (_SC_zero_space) memset(space, 0, nb);
295    }
296 
297    return((lite_SC_byte *) space);
298 }
299 
300 
301 /*-------------------------------------------------------------------------
302  * Function:	lite_SC_realloc
303  *
304  * Purpose:	Add a layer of control over the C level memory management
305  *		system to store the byte length of allocated spaces.  A
306  *		space EXTRA_WORD_SIZE greater than requested is reallocated.
307  *		The length in bytes is written into the first EXTRA_WORD_SIZE
308  *		bytes with a 4 bit marker in the high bits and a pointer to
309  *		the next byte is returned.
310  *
311  * Return:	Success:	Ptr to move memory.
312  *
313  *		Failure:	If the maximum size implied by the
314  *				EXTRA_WORD_SIZE-4 is exceeded a NULL
315  *				ptr is returned.
316  *
317  * Programmer:	Adapted from PACT SCORE
318  *		Mar 12, 1996
319  *
320  * Modifications:
321  *
322  *-------------------------------------------------------------------------
323  */
324 lite_SC_byte *
lite_SC_realloc(lite_SC_byte * p,long nitems,long bytepitem)325 lite_SC_realloc (lite_SC_byte *p, long nitems, long bytepitem) {
326 
327    long nb, ob, db;
328    unsigned long nbp, obp;
329    mem_header *space, *tmp;
330    mem_descriptor *desc;
331 
332 #ifdef NEED_MEM_TRACE
333    mem_header *prev, *next;
334 #endif
335 
336    if (p == NULL) return(NULL);
337 
338    space = ((mem_header *) p) - 1;
339    desc  = &space->block;
340    if (!SCORE_BLOCK_P(desc)) return(NULL);
341 
342    nb  = nitems*bytepitem;
343    nbp = nb + Sz;
344 
345    if ((nb <= 0) || (nb > Sz_max)) return(NULL);
346 
347    ob = lite_SC_arrlen(p);
348    db = nb - ob;
349 
350    SAVE_LINKS(desc);
351 
352    tmp = (mem_header *) _SC_prim_alloc((size_t) nbp);
353    obp = ob + Sz;
354    memcpy(tmp, space, MIN(obp, nbp));
355    _SC_prim_free(space, obp);
356    space = tmp;
357 
358    if (space != NULL) {
359       REASSIGN_BLOCK(space);
360 
361       lite_SC_c_sp_alloc += db;
362       SC_MEM_COUNT;
363 
364       space++;
365 
366       /*
367        * Zero out the new space.
368        */
369       if ((db > 0) && (_SC_zero_space)) memset(((char *) space + ob), 0, db);
370    }
371 
372    return((lite_SC_byte *) space);
373 }
374 
375 
376 /*-------------------------------------------------------------------------
377  * Function:	lite_SC_free
378  *
379  * Purpose:	The complementary routine for lite_SC_alloc().  Free all
380  *		the space including the counter.
381  *
382  * Return:	Success:	TRUE
383  *
384  *		Failure:	FALSE
385  *
386  * Programmer:	Adapted from PACT SCORE
387  *		Mar 12, 1996
388  *
389  * Modifications:
390  *
391  *-------------------------------------------------------------------------
392  */
393 int
lite_SC_free(lite_SC_byte * p)394 lite_SC_free (lite_SC_byte *p) {
395 
396    mem_header *space;
397    mem_descriptor *desc;
398    unsigned long nbp;
399 
400    if (p == NULL) return(TRUE);
401 
402    space = ((mem_header *) p) - 1;
403    desc  = &space->block;
404    if (!SCORE_BLOCK_P(desc)) return(FALSE);
405 
406    if (REF_COUNT(desc) == UNCOLLECT) return(TRUE);
407 
408    if (--REF_COUNT(desc) > 0) return(TRUE);
409 
410    nbp = BLOCK_LENGTH(desc) + Sz;
411 
412    UNASSIGN_BLOCK(desc);
413 
414    lite_SC_c_sp_free += (nbp - Sz);
415    SC_MEM_COUNT;
416 
417    if (_SC_zero_space) {
418       memset(space, 0, nbp);
419    } else {
420 #ifdef NEED_MEM_TRACE
421       desc->name      = NULL;
422       desc->id        = 0L;
423       desc->type      = 0;
424 #endif
425       desc->ref_count = 0;
426       desc->length    = 0L;
427    }
428 
429    _SC_prim_free((lite_SC_byte *) space, nbp);
430    _SC_n_mem_blocks--;
431    return(TRUE);
432 }
433 
434 
435 /*-------------------------------------------------------------------------
436  * Function:	lite_SC_arrlen
437  *
438  * Purpose:	Return the length of an array which was allocated
439  *		with lite_SC_alloc().
440  *
441  * Return:	Success:	Length of array.
442  *
443  *		Failure:	-1
444  *
445  * Programmer:	Adapted from PACT SCORE
446  *		Mar 12, 1996
447  *
448  * Modifications:
449  *
450  *-------------------------------------------------------------------------
451  */
452 long
lite_SC_arrlen(lite_SC_byte * p)453 lite_SC_arrlen (lite_SC_byte *p) {
454 
455    mem_header *space;
456    mem_descriptor *desc;
457    long nb;
458 
459    if (p == NULL) return(-1);
460 
461    space = ((mem_header *) p) - 1;
462    desc  = &space->block;
463    if (!SCORE_BLOCK_P(desc)) return(-1L);
464 
465    nb = BLOCK_LENGTH(desc);
466    if (nb < 0L) return(-1L);
467    else return(nb);
468 }
469 
470 
471 /*-------------------------------------------------------------------------
472  * Function:	lite_SC_mark
473  *
474  * Purpose:	Change the reference count by N
475  *
476  * Return:	Success:	New reference count.
477  *
478  *		Failure:	-1
479  *
480  * Programmer:	Adapted from PACT SCORE
481  *		Mar 12, 1996
482  *
483  * Modifications:
484  *
485  *-------------------------------------------------------------------------
486  */
487 int
lite_SC_mark(lite_SC_byte * p,int n)488 lite_SC_mark (lite_SC_byte *p, int n) {
489 
490    mem_header *space;
491    mem_descriptor *desc;
492 
493    if (p == NULL) return(-1);
494 
495    space = ((mem_header *) p) - 1;
496    desc  = &space->block;
497    if (!SCORE_BLOCK_P(desc)) return(-1);
498 
499    if (REF_COUNT(desc) < UNCOLLECT) REF_COUNT(desc) += n;
500 
501    return(REF_COUNT(desc));
502 }
503 
504 
505 /*-------------------------------------------------------------------------
506  * Function:	lite_SC_ref_count
507  *
508  * Purpose:	Reference count.
509  *
510  * Return:	Success:	Return the reference count of the given
511  *				object.
512  *
513  *		Failure:	-1
514  *
515  * Programmer:	Adapted from PACT SCORE
516  *		Mar 12, 1996
517  *
518  * Modifications:
519  *
520  *-------------------------------------------------------------------------
521  */
522 int
lite_SC_ref_count(lite_SC_byte * p)523 lite_SC_ref_count (lite_SC_byte *p) {
524 
525    mem_header *space;
526    mem_descriptor *desc;
527 
528    if (p == NULL) return(-1);
529 
530    space = ((mem_header *) p) - 1;
531    desc  = &space->block;
532    if (!SCORE_BLOCK_P(desc)) return(-1);
533 
534    return((int) REF_COUNT(desc));
535 }
536 
537 
538 /*-------------------------------------------------------------------------
539  * Function:	_SC_prim_alloc
540  *
541  * Purpose:	Memory allocator that manages banks of small chunks
542  *		for efficiency.
543  *
544  * Return:	Success:	Ptr to user memory
545  *
546  *		Failure:	NULL
547  *
548  * Programmer:	Adapted from PACT SCORE
549  *		Mar 12, 1996
550  *
551  * Modifications:
552  *    Eric Brugger, Thu Dec 10 12:00:55 PST 1998
553  *    I made the caching of small memory chunks depend on a C preprocessor
554  *    variable.
555  *
556  *-------------------------------------------------------------------------
557  */
558 static lite_SC_byte *
_SC_prim_alloc(size_t nbp)559 _SC_prim_alloc (size_t nbp) {
560 
561    lite_SC_byte *p;
562 #ifdef CACHE_SMALL_MEM_REQ
563    char *pn;
564    mem_descriptor *md, *ths;
565    size_t tnb;
566    long nb, unsz;
567    int nu, us, ns, i;
568 #endif
569 
570    if (nbp <= 0) return(NULL);
571 
572 #ifdef CACHE_SMALL_MEM_REQ
573    nb   = nbp - Sz;
574    unsz = nb >> 3;
575    if (unsz < UNIT_SIZE_MAX) {
576       md = _SC_free_list[unsz];
577       if (md == NULL) {
578 	 us = Sz + ((unsz + 1) << 3);
579 	 nu = 4096/us;
580 	 ns = nu*us;
581 	 pn = _SC_ALLOC((size_t) ns);
582 
583 	 /*
584 	  * SC_REMEMBER would be nice but it would also be a recursive
585 	  * infinite loop.
586 	  */
587 	 if (_SC_major_block_list == NULL) {
588 	    _SC_nx_major_blocks = 10L;
589 	    _SC_n_major_blocks  = 0;
590 	    tnb = sizeof(char *)*_SC_nx_major_blocks;
591 	    _SC_major_block_list = (char **) _SC_ALLOC(tnb);
592 	 }
593 
594 	 _SC_major_block_list[_SC_n_major_blocks++] = pn;
595 
596 	 if (_SC_n_major_blocks >= _SC_nx_major_blocks) {
597 	    _SC_nx_major_blocks += 10L;
598 	    tnb = sizeof(char *)*_SC_nx_major_blocks;
599 	    _SC_major_block_list = (char **) _SC_REALLOC(_SC_major_block_list,
600 							 tnb);
601 	 }
602 
603 	 md = (mem_descriptor *) pn;
604 	 nu--;
605 	 for (i = 0; i < nu; i++, pn += us) {
606 	    ths       = (mem_descriptor *) pn;
607 #ifdef NEED_MEM_TRACE
608 	    ths->name = (char *) (pn + us);
609 #endif
610 	 }
611 	 ths       = (mem_descriptor *) pn;
612 #ifdef NEED_MEM_TRACE
613 	 ths->name = NULL;
614 #endif
615       }
616 
617 #ifdef NEED_MEM_TRACE
618 #error HOW TO UPDATE FREE LIST IF THIS CODE IS ENABLED
619       _SC_free_list[unsz] = (mem_descriptor *) (md->name);
620 #endif
621       p = (lite_SC_byte *) md;
622    } else {
623       p = _SC_ALLOC((size_t) nbp);
624    }
625 #else
626    p = _SC_ALLOC((size_t) nbp);
627 #endif
628 
629    return(p);
630 }
631 
632 
633 /*-------------------------------------------------------------------------
634  * Function:	_SC_prim_free
635  *
636  * Purpose:	Free small block counterpart to _SC_prim_alloc()
637  *		for efficiency.
638  *
639  * Return:	void
640  *
641  * Programmer:	Adapted from PACT SCORE
642  *		Mar 12, 1996
643  *
644  * Modifications:
645  *    Eric Brugger, Thu Dec 10 12:00:55 PST 1998
646  *    I made the caching of small memory chunks depend on a C preprocessor
647  *    variable.
648  *
649  *-------------------------------------------------------------------------
650  */
651 /* ARGSUSED */
652 static void
_SC_prim_free(lite_SC_byte * p,unsigned long nbp)653 _SC_prim_free (lite_SC_byte *p, unsigned long nbp) {
654 
655 #ifdef CACHE_SMALL_MEM_REQ
656    mem_descriptor *lst, *ths;
657    unsigned long nb, unsz;
658 #endif
659 
660    if (p == NULL) return;
661 
662 #ifdef CACHE_SMALL_MEM_REQ
663    nb   = nbp - Sz;
664    unsz = nb >> 3;
665    if (unsz < UNIT_SIZE_MAX) {
666       ths = (mem_descriptor *) p;
667       lst = _SC_free_list[unsz];
668 #ifdef NEED_MEM_TRACE
669       ths->name = (char *) lst;
670 #endif
671       _SC_free_list[unsz] = ths;
672    } else {
673       _SC_FREE(p);
674    }
675 #else
676    _SC_FREE(p);
677 #endif
678 }
679 
680 
681 /*-------------------------------------------------------------------------
682  * Function:	lite_SC_strsavef
683  *
684  * Purpose:	Save string S somewhere.  Remember its name.  Allocate
685  *		one extra character so that firsttok won't kill things
686  *		in the one bad case.
687  *
688  * Return:	Success:	New memory for string.
689  *
690  *		Failure:	NULL
691  *
692  * Programmer:	Adapted from PACT SCORE
693  *		Mar 12, 1996
694  *
695  * Modifications:
696  *
697  *-------------------------------------------------------------------------
698  */
699 char *
lite_SC_strsavef(char * s,char * name)700 lite_SC_strsavef (char *s, char *name) {
701 
702    char *p;
703    int sz;
704 
705    if (s == NULL) return(NULL);
706 
707    sz = strlen(s) + 2;
708    p  = FMAKE_N(char, sz, name);
709    if (p != NULL) strcpy(p, s);
710    else return(NULL);
711 
712    return(p);
713 }
714 
715 
716 /*-------------------------------------------------------------------------
717  * Function:	lite_SC_strrev
718  *
719  * Purpose:	Copy the string onto itself in reverse order.
720  *
721  * Return:	Success:	The string
722  *
723  *		Failure:	NULL
724  *
725  * Programmer:	Adapted from PACT SCORE
726  *		Mar 12, 1996
727  *
728  * Modifications:
729  *
730  *-------------------------------------------------------------------------
731  */
732 char *
lite_SC_strrev(char * s)733 lite_SC_strrev (char *s) {
734 
735    int i;
736    char *t, *p;
737 
738    p = s;
739    i = strlen(s) + 1;
740    t = MAKE_N(char, i);
741    if (t == NULL) return(NULL);
742 
743    t[--i] = '\0';
744    while (*p) t[--i] = *p++;
745 
746    strcpy(s, t);
747    SFREE(t);
748 
749    return(s);
750 }
751 
752 /*--------------------------------------------------------------------------*/
753 /*                           TOKENIZERS                                     */
754 /*--------------------------------------------------------------------------*/
755 
756 
757 /*-------------------------------------------------------------------------
758  * Function:	lite_SC_firsttok
759  *
760  * Purpose:	Returns a pointer to the first token and points
761  *		S to the next element in the string.
762  *
763  * Return:	Success:	Ptr to first token.
764  *
765  *		Failure:
766  *
767  * Programmer:	Adapted from PACT SCORE
768  *		Mar 12, 1996
769  *
770  * Modifications:
771  *
772  *-------------------------------------------------------------------------
773  */
774 char *
lite_SC_firsttok(char * s,char * delim)775 lite_SC_firsttok (char *s, char *delim) {
776 
777    char *t, *r;
778 
779    if (*s == '\0') return(NULL);
780 
781    /*
782     * T is the pointer to the token.
783     */
784    for (t = s; strchr(delim, *t) != NULL; t++) {
785       if (*t == '\0') return(NULL);
786    }
787 
788    /*
789     * R is the pointer to the remainder.
790     */
791    for (r = t; strchr(delim, *r) == NULL; r++) /*void*/ ;
792 
793    /*
794     * If we aren't at the end of the string.
795     */
796    if (*r != '\0') {
797       *r++ = '\0';
798 
799       /*
800        * Copy the token into a temporary.
801        */
802       strcpy(tokbuffer, t);
803 
804       /*
805        * Copy the remainder down into the original string
806        * GOTCHA: this should be replaced by MEMMOVE (ANSI standard C function)
807        */
808       /*strcpy(s, r);*/
809       memmove(s, r, strlen(r)+1);
810 
811       /*
812        * Copy the token in the space left over.
813        */
814       t = s + strlen(s) + 1;
815       strcpy(t, tokbuffer);
816 
817    } else {
818       /*
819        * If we are at the end of the string we may overindex the string
820        * by adding one more character (sigh).
821        */
822       strcpy(tokbuffer, t);
823       *s = '\0';
824       t = s + 1;
825       strcpy(t, tokbuffer);
826    }
827 
828    return(t);
829 }
830 
831 
832 /*-------------------------------------------------------------------------
833  * Function:	_lite_SC_pr_tok
834  *
835  * Purpose:	Returns a pointer to the first token and points S to
836  *		the next element in the string.
837  *
838  * Return:	Success:	First token in S
839  *
840  *		Failure:	NULL
841  *
842  * Programmer:	Adapted from PACT SCORE
843  *		Mar 12, 1996
844  *
845  * Modifications:
846  *
847  *-------------------------------------------------------------------------
848  */
849 char *
_lite_SC_pr_tok(char * s,char * delim)850 _lite_SC_pr_tok (char *s, char *delim) {
851 
852    int i, j;
853 
854    if (!s) return NULL;
855 
856    i = strcspn(s, delim);
857    j = strlen(s);
858    if ((i == 0) && (i != j)) {
859       s++;
860       return(lite_SC_firsttok(s, delim));
861    }
862 
863    s[i] = '\0';
864    strcpy(tokbuffer, s);
865 
866    /*
867     * Take care of last token in string.
868     */
869    if (i == j) *s = '\0';
870    else strcpy(s, s+i+1);
871 
872    s += strlen(s) + 1;
873    strcpy(s, tokbuffer);
874 
875    return(s);
876 }
877 
878 
879 /*-------------------------------------------------------------------------
880  * Function:	lite_SC_lasttok
881  *
882  * Purpose:	Find last token on a string, return it and the
883  *		preceeding string.
884  *
885  * Return:	Success:
886  *
887  *		Failure:
888  *
889  * Programmer:	Adapted from PACT SCORE
890  *		Mar 12, 1996
891  *
892  * Modifications:
893  *
894  *-------------------------------------------------------------------------
895  */
896 char *
lite_SC_lasttok(char * s,char * delim)897 lite_SC_lasttok (char *s, char *delim) {
898 
899    char *temp, *r;
900 
901    r    = lite_SC_strrev(s);
902    temp = _lite_SC_pr_tok(r, delim);
903 
904    return lite_SC_strrev (temp);
905 }
906