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