1 /* Stem and variable manipulation functions for regutil
3 * The contents of this file are subject to the Mozilla Public License
4 * Version 1.0 (the "License"); you may not use this file except in
5 * compliance with the License. You may obtain a copy of the License at
6 * http://www.mozilla.org/MPL/
8 * Software distributed under the License is distributed on an "AS IS"
9 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
10 * License for the specific language governing rights and limitations
13 * The Original Code is regutil.
15 * The Initial Developer of the Original Code is Patrick TJ McPhee.
16 * Portions created by Patrick McPhee are Copyright © 1998, 2001
17 * Patrick TJ McPhee. All Rights Reserved.
21 * $Header: /opt/cvs/Regina/regutil/regstem.c,v 1.5 2009/11/23 23:24:35 mark Exp $
24 /* ******************************************************************** */
25 /* ************************** Stem Routines *************************** */
26 /* ******************************************************************** */
31 /* compare two strings case-sensitively */
32 static int rxstrcmp(const PRXSTRING l
, const PRXSTRING r
)
34 register int len
= min(l
->strlength
, r
->strlength
),
35 d
= l
->strlength
- r
->strlength
,
36 c
= memcmp(l
->strptr
, r
->strptr
, len
);
41 /* case-insensitive comparison of two regions of memory */
42 static int casecmp(const unsigned char * l
, const unsigned char * r
, const int len
)
45 for (i
= c
= 0; !c
&& i
< len
; i
++)
46 c
= toupper(l
[i
]) - toupper(r
[i
]);
51 /* compare two strings case-insensitively */
52 static int rxstrcasecmp(const PRXSTRING l
, const PRXSTRING r
)
54 register int len
= min(l
->strlength
, r
->strlength
),
55 d
= l
->strlength
- r
->strlength
,
56 c
= casecmp(l
->strptr
, r
->strptr
, len
);
58 return (len
&& c
) ? c
: d
;
61 static int rxstrcmpbackwards(const PRXSTRING l
, const PRXSTRING r
)
63 return rxstrcmp(r
, l
);
66 static int rxstrcasecmpbackwards(const PRXSTRING l
, const PRXSTRING r
)
68 return rxstrcasecmp(r
, l
);
71 /* either map a file into memory or allocate a buffer */
75 # ifdef HAVE_SYS_MMAN_H
76 # include <sys/mman.h>
78 # include <sys/stat.h>
81 # define MAP_FAILED ((void *)-1)
84 char * mapfile(const char * name
, int * len
)
90 if ((fd
= open(name
, O_RDONLY
)) == -1 || fstat(fd
, &st
)) {
96 s
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
106 int unmapfile(char *buf
, int size
)
111 return munmap(buf
, size
);
114 #elif defined(MAPVIEWOFFILE)
118 /* open a file and create a memory mapping to it */
119 char * mapfile(const char * s
, int *len
)
125 BY_HANDLE_FILE_INFORMATION bhfi
;
127 memset(&ofs
, 0, sizeof(ofs
));
128 fh
= OpenFile(s
, &ofs
, OF_READ
);
130 if (fh
== INVALID_HANDLE_VALUE
) {
134 GetFileInformationByHandle(fh
, &bhfi
);
135 *len
= bhfi
.nFileSizeLow
;
137 hShm
= CreateFileMapping((HANDLE
)fh
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
140 CloseHandle((HANDLE
)fh
);
144 buf
= (char *)MapViewOfFileEx(hShm
, FILE_MAP_READ
, 0, 0, 0, NULL
);
146 CloseHandle((HANDLE
)fh
);
151 int unmapfile(char *buf
, int size
)
156 return UnmapViewOfFile(buf
) - 1;
162 #include <sys/stat.h>
164 char * mapfile(const char * name
, int * len
)
170 if ((fp
= fopen(name
, "rb")) == NULL
|| fstat(fileno(fp
), &st
)) {
176 s
= malloc(st
.st_size
);
183 fread(s
, 1, st
.st_size
, fp
);
190 int unmapfile(char *buf
, int size
)
205 /* sysstemsort(stemname[, order] [,sensitivity] [,startpos,endpos] [,firstcol,lastcol]) */
209 int insensitive
= 0, backwards
= 0, start
= 0, count
= 0, first
= 0, width
= 0;
212 int (*cmpfn
)(const PRXSTRING l
, const PRXSTRING r
);
216 /* default to ascending sort, but go descending if the second arg is given
217 * and the first character is `d' */
218 if (argc
> 1 && argv
[1].strptr
&& toupper(argv
[1].strptr
[0]) == 'D')
221 /* default to case-sensitive sort, but go insensitive if the third arg is
222 * given and the first character is `i' */
223 if (argc
> 2 && argv
[2].strptr
&& toupper(argv
[2].strptr
[0]) == 'I')
226 /* one can choose to sort a sub-set of the array, from index start to index
227 * end. We must convert start from 1-based to 0-based, and we really want
228 * end to be the count of elements to sort. */
229 if (argc
> 3 && argv
[3].strptr
) {
230 rxstrdup(s
, argv
[3]);
238 if (argc
> 4 && argv
[4].strptr
) {
239 rxstrdup(s
, argv
[4]);
240 count
= atoi(s
) - start
;
246 /* finally, one can choose to compare the full data or
247 * substr(first,last-first+1) of the data. As with start and end,
248 * we want first to be 0-based, and se want a width, not a last */
249 if (argc
> 5 && argv
[5].strptr
) {
250 rxstrdup(s
, argv
[5]);
257 if (argc
> 6 && argv
[6].strptr
) {
258 rxstrdup(s
, argv
[6]);
259 width
= atoi(s
) - first
;
265 ca
= new_chararray();
274 count
= ca
->count
- start
;
279 if (insensitive
&& backwards
)
280 cmpfn
= rxstrcasecmpbackwards
;
281 else if (insensitive
)
282 cmpfn
= rxstrcasecmp
;
284 cmpfn
= rxstrcmpbackwards
;
288 if (!first
&& !width
)
289 qsort(ca
->array
+start
, count
, sizeof(*ca
->array
), (int(*)(const void *, const void *))cmpfn
);
296 aa
= malloc(sizeof(*aa
) * count
);
298 delete_chararray(ca
);
302 for (i
= 0; i
< count
; i
++) {
303 aa
[i
].orig
= ca
->array
[i
+start
];
305 aa
[i
].se
.strptr
= aa
[i
].orig
.strptr
+ first
;
307 aa
[i
].se
.strlength
= aa
[i
].orig
.strlength
- first
;
309 if (width
&& (int)aa
[i
].se
.strlength
> width
)
310 aa
[i
].se
.strlength
= width
;
312 else if ((int)aa
[i
].se
.strlength
< 0)
313 aa
[i
].se
.strlength
= 0;
316 qsort(aa
, count
, sizeof(*aa
), (int(*)(const void *, const void *))cmpfn
);
318 for (i
= 0; i
< count
; i
++) {
319 ca
->array
[i
+start
] = aa
[i
].orig
;
326 delete_chararray(ca
);
332 /* regmultistemsort(order,sensitivity,firstcol,lastcol,stemname1,stemname2[,stemname3,...]) */
333 rxfunc(regmultistemsort
)
340 chararray
* ca
, *tmpca
;
341 int insensitive
= 0, backwards
= 0, count
= 0, first
= 0, width
= 0, size
;
344 int (*cmpfn
)(const PRXSTRING l
, const PRXSTRING r
);
348 /* validate that all stems are stems and they all have the same length */
349 if ( getstemsize(&argv
[4], &count
) ) {
353 for ( i
= 5; i
< argc
; i
++ ) {
354 if ( getstemsize(&argv
[i
], &size
) ) {
358 /* check that this stem is the same size as the first */
359 if ( size
!= count
) {
365 /* default to ascending sort, but go descending if the first arg is given
366 * and the first character is `d' */
367 if (argv
[0].strptr
&& toupper(argv
[0].strptr
[0]) == 'D')
370 /* default to case-sensitive sort, but go insensitive if the second arg is
371 * given and the first character is `i' */
372 if (argv
[1].strptr
&& toupper(argv
[1].strptr
[0]) == 'I')
375 /* finally, one can choose to compare the full data or
376 * substr(first,last-first+1) of the data.
377 * We want first to be 0-based, and we want a width, not a last */
378 if (argv
[2].strptr
) {
379 rxstrdup(s
, argv
[2]);
386 if (argv
[3].strptr
) {
387 rxstrdup(s
, argv
[3]);
388 width
= atoi(s
) - first
;
395 * Allocate a new chararray for the first stem */
396 ca
= new_chararray();
403 * Copy the first stem into the chararray */
404 getastem(&argv
[4], ca
);
406 if (insensitive
&& backwards
)
407 cmpfn
= rxstrcasecmpbackwards
;
408 else if (insensitive
)
409 cmpfn
= rxstrcasecmp
;
411 cmpfn
= rxstrcmpbackwards
;
415 /* sort the first stem */
416 aa
= malloc(sizeof(*aa
) * count
);
418 delete_chararray(ca
);
422 for (i
= 0; i
< count
; i
++) {
424 aa
[i
].orig
= ca
->array
[i
];
425 aa
[i
].se
.strptr
= aa
[i
].orig
.strptr
+ first
;
426 aa
[i
].se
.strlength
= aa
[i
].orig
.strlength
- first
;
427 if (width
&& (int)aa
[i
].se
.strlength
> width
)
428 aa
[i
].se
.strlength
= width
;
429 else if ((int)aa
[i
].se
.strlength
< 0)
430 aa
[i
].se
.strlength
= 0;
433 qsort(aa
, count
, sizeof(*aa
), (int(*)(const void *, const void *))cmpfn
);
435 for (i
= 0; i
< count
; i
++) {
436 ca
->array
[i
] = aa
[i
].orig
;
438 setastem(&argv
[4], ca
);
441 * Allocate a new chararray for the first stem */
442 tmpca
= new_chararray();
448 * We have sorted the first stem, now rearrange the order of the other stems to match the sorted
449 * order of the first */
450 for ( i
= 5; i
< argc
; i
++ ) {
451 /* copy the stem to a chararray */
452 getastem(&argv
[i
], ca
);
453 /* and again to a temp chararray */
454 getastem(&argv
[i
], tmpca
);
455 for (j
= 0; j
< count
; j
++) {
456 ca
->array
[j
] = tmpca
->array
[aa
[j
].idx
];
458 setastem(&argv
[i
], ca
);
461 delete_chararray(ca
);
462 delete_chararray(tmpca
);
468 /* sysstemcopy(from, to [, fromindex, toindex, count, insertoverlay]) */
471 chararray
* ca
, *tca
;
474 int find
= 0, tind
= 0, count
= 0, insert
= 0;
478 /* as with stemsort, we want the indices to be offsets (ie, 0-based) */
479 if (argc
> 2 && argv
[2].strptr
) {
480 rxstrdup(s
, argv
[2]);
484 if (argc
> 3 && argv
[3].strptr
) {
485 rxstrdup(s
, argv
[3]);
489 /* but this time, there's a count which should be left alone */
490 if (argc
> 4 && argv
[4].strptr
) {
491 rxstrdup(s
, argv
[4]);
495 if (argc
> 5 && argv
[5].strptr
&& toupper(argv
[5].strptr
[0]) == 'I')
498 ca
= new_chararray();
502 if (!find
&& !tind
&& !count
&& !insert
) {
503 setastem(argv
+1, ca
);
505 /* I don't know why we needed to screw up this simple interface, but here
508 if (!count
|| (ca
->count
< (find
+count
))) {
509 count
= ca
->count
- find
;
513 delete_chararray(ca
);
515 /* should this be -1? */
520 tca
= new_chararray();
521 getastem(argv
+1, tca
);
524 /* make sure there's room */
525 if (tca
->ptr_alloc
< (tca
->count
+ count
+ tind
)) {
526 tca
->ptr_alloc
= tca
->count
+count
+tind
;
527 tca
->array
= realloc(tca
->array
, tca
->ptr_alloc
*sizeof(tca
->array
));
530 /* if we're extending past the end of the current array, set the
531 * intervening elements to null */
533 if (tind
> tca
->count
) {
534 for (i
= tca
->count
; i
< tind
; i
++) {
535 tca
->array
[i
].strptr
= NULL
;
536 tca
->array
[i
].strlength
= 0;
538 tca
->count
= tind
+ count
;
541 memmove(tca
->array
+tind
+count
, tca
->array
+tind
, (tca
->count
-tind
)*sizeof(*tca
->array
));
546 /* still make sure there's room */
547 if (tca
->ptr_alloc
< (count
+ tind
)) {
548 tca
->ptr_alloc
= count
+tind
;
549 tca
->array
= realloc(tca
->array
, tca
->ptr_alloc
*sizeof(tca
->array
));
552 /* if we're extending past the end of the current array, set the
553 * intervening elements to null */
555 if (tind
> tca
->count
) {
556 for (i
= tca
->count
; i
< tind
; i
++) {
557 tca
->array
[i
].strptr
= NULL
;
558 tca
->array
[i
].strlength
= 0;
560 tca
->count
= tind
+ count
;
562 else if (tca
->count
< (tind
+count
)) {
563 tca
->count
= tind
+ count
;
567 memcpy(tca
->array
+tind
, ca
->array
+find
, count
*sizeof(*ca
->array
));
569 setastem(argv
+1, tca
);
570 delete_chararray(tca
);
573 delete_chararray(ca
);
579 /* sysstemdelete(stem, index [, count]) */
580 rxfunc(sysstemdelete
)
583 char * counts
, *inds
;
584 int count
= 1, ind
, size
;
588 rxstrdup(inds
, argv
[1]);
592 rxstrdup(counts
, argv
[2]);
593 count
= atoi(counts
);
596 /* find out how many there are */
597 getstemsize(argv
, &size
);
599 if (ind
<= 0 || ind
> size
|| count
< 1 || count
> (size
- ind
+ 1)) {
600 memcpy(result
->strptr
, "-1", 2);
601 result
->strlength
= 2;
605 ca
= new_chararray();
607 /* retrieve the parts we want to keep, unless we're deleting the full
609 if ( ind
> 1 && ind
+count
> size
) {
610 /* set it with new size */
611 setstemsize(argv
, ind
-1);
612 } else if (ind
> 1 || count
< size
) {
613 /* retrieve from ind+count to the end */
614 getstemtail(argv
, ind
+count
, ca
);
616 /* and set it with new indices */
617 setstemtail(argv
, ind
, ca
);
623 delete_chararray(ca
);
629 /* syssteminsert(stem, index, value) */
630 rxfunc(syssteminsert
)
638 ca
= new_chararray();
642 rxstrdup(inds
, argv
[1]);
643 ind
= atoi(inds
) - 1; /* translate rexx index to C index */
645 if (ind
< 0 || ind
> ca
->count
) {
646 memcpy(result
->strptr
, "-1", 2);
647 result
->strlength
= 2;
651 /* add the value to the end of the array -- this is just to ensure there's space */
652 cha_adddummy(ca
, argv
[2].strptr
, argv
[2].strlength
);
654 /* if inserting at the end of the array, there's no need to screw
656 if (ind
< (ca
->count
- 1)) {
657 /* move the array over */
658 memmove(ca
->array
+ind
+1, ca
->array
+ind
, sizeof(*ca
->array
)*(ca
->count
-ind
-2));
659 /* and set the pointers again */
660 ca
->array
[ind
] = argv
[2];
664 delete_chararray(ca
);
670 /* stemread(filename, stemname) */
673 char * filname
, *fdata
, *cp
;
675 register int offs
= 0, oldoffs
= 0;
677 register int count
= 1;
681 rxstrdup(filname
, argv
[0]);
682 fdata
= mapfile(filname
, &flen
);
684 if (!fdata
|| !flen
) {
689 ca
= new_chararray();
691 /* deal with a leading newline */
692 if (fdata
[0] == '\n') {
694 cha_adddummy(ca
, fdata
, 0);
700 for (cp
= memchr(fdata
+oldoffs
, '\n', flen
- oldoffs
); cp
; cp
= memchr(fdata
+oldoffs
, '\n', flen
- oldoffs
)) {
703 /* some systems print cr-lf, not just lf */
707 cha_adddummy(ca
, fdata
+oldoffs
, offs
- oldoffs
);
708 oldoffs
= cp
- fdata
+ 1;
710 /* set 1000 elements at a time to cut down on memory allocation */
711 if (ca
->count
>= 1000) {
712 setstemtail(argv
+1, count
, ca
);
718 /* handle incomplete last lines */
719 if (flen
> 0 && fdata
[flen
-1] != '\n')
721 cha_adddummy(ca
, fdata
+oldoffs
, flen
-oldoffs
);
725 setstemtail(argv
+1, count
, ca
);
726 /* subtract 1 because count is one greater than the number of
727 * elements set before calling setstemtail */
728 setstemsize(argv
+1, count
+ca
->count
- 1);
729 delete_chararray(ca
);
730 unmapfile(fdata
, flen
);
736 /* stemwrite(filename, stemname) */
746 rxstrdup(filname
, argv
[0]);
748 fp
= fopen(filname
, "w");
754 ca
= new_chararray();
755 getastem(argv
+1, ca
);
757 for (i
= 0; i
< ca
->count
; i
++) {
758 fwrite(ca
->array
[i
].strptr
, 1, ca
->array
[i
].strlength
, fp
);
763 delete_chararray(ca
);
770 /* regstemdover(stem, variable[, outstem])
771 * returns 0 when it's finished
773 rxfunc(regstemdoover
)
775 static chararray
* ca
= NULL
;
776 static char * name
= NULL
;
777 static int len
= 0, cur
= 0;
783 rxstrdup(s
, argv
[0]);
786 /* we can only do one of these at a time */
787 if (!name
|| len
!= argv
[0].strlength
|| memcmp(name
, s
, len
)) {
792 delete_chararray(ca
);
796 len
= argv
[0].strlength
;
797 name
= malloc(len
+1);
798 memcpy(name
, s
, len
+1);
802 ca
= new_chararray();
804 sb
.shvcode
= RXSHV_NEXTV
;
807 sb
.shvvalue
.strptr
= (void *)-1;
809 while (! (sb
.shvret
& RXSHV_LVAR
)) {
810 sb
.shvvaluelen
= sb
.shvvalue
.strlength
= 0;
811 sb
.shvname
.strptr
= NULL
;
812 RexxVariablePool(&sb
);
813 if (sb
.shvname
.strptr
&& sb
.shvname
.strlength
> len
&&
814 !memcmp(sb
.shvname
.strptr
, name
, len
)) {
815 cha_addstr(ca
, sb
.shvname
.strptr
+len
, sb
.shvname
.strlength
- len
);
817 if (sb
.shvname
.strptr
)
818 REXXFREEMEMORY(sb
.shvname
.strptr
);
826 else if (cur
>= ca
->count
) {
827 delete_chararray(ca
);
835 sb
.shvcode
= RXSHV_SET
;
838 sb
.shvvalue
= ca
->array
[cur
++];
839 sb
.shvname
= argv
[1];
840 RexxVariablePool(&sb
);
848 /* compare the offsetth element of stem haystack against the match table
849 * needle. If exact is true, it must match exactly. Otherwise, it needs to
850 * be contained somewhere in there. */
851 static int stemcompare(PRXSTRING needle
, PRXSTRING haystack
,
852 int offset
, rxbool exact
, rxbool casesensitive
)
854 register int i
, offs
= 0, rc
;
857 /* get the value of offset */
858 memset(&shv
, 0, sizeof(shv
));
859 shv
.shvcode
= RXSHV_FETCH
;
860 shv
.shvvalue
.strlength
= shv
.shvvaluelen
= 1024;
861 shv
.shvvalue
.strptr
= alloca(1024);
862 shv
.shvname
.strptr
= alloca(haystack
->strlength
+ 10);
863 shv
.shvnamelen
= shv
.shvname
.strlength
=
864 sprintf(shv
.shvname
.strptr
, "%.*s%d", (int)haystack
->strlength
,
865 haystack
->strptr
, offset
);
866 RexxVariablePool(&shv
);
867 if (shv
.shvret
& RXSHV_TRUNC
) {
869 shv
.shvvalue
.strptr
= alloca(shv
.shvvaluelen
);
870 shv
.shvvalue
.strlength
= shv
.shvvaluelen
;
871 RexxVariablePool(&shv
);
874 /* can't match if it's not long enough */
875 if (shv
.shvvalue
.strlength
< needle
->strlength
) {
876 /* if performing an exact match, we may be doing a binary search and
877 * so need to know which side we're on */
880 rc
= memcmp(needle
->strptr
, shv
.shvvalue
.strptr
, shv
.shvvalue
.strlength
);
883 for (i
= 0; i
< shv
.shvvalue
.strlength
; i
++) {
884 rc
= ((int)(unsigned char)needle
->strptr
[i
]) -
885 toupper((unsigned char)shv
.shvvalue
.strptr
[i
]);
893 /* match up to the end of the haystack string, so return 1,
894 * since substrings go first */
903 /* loop until something in haystack doesn't match */
905 rc
= memcmp(needle
->strptr
, shv
.shvvalue
.strptr
+offs
, needle
->strlength
);
907 /* skip ahead quickly to the next possible match */
909 char * cp
= memchr(shv
.shvvalue
.strptr
+offs
+1, needle
->strptr
[0], shv
.shvvalue
.strlength
- offs
- 1);
911 offs
= (long)cp
- (long)shv
.shvvalue
.strptr
- 1;
914 offs
= shv
.shvvalue
.strlength
;
919 for (i
= 0; i
< needle
->strlength
; i
++) {
920 rc
= ((int)(unsigned char)needle
->strptr
[i
]) -
921 toupper((unsigned char)shv
.shvvalue
.strptr
[i
+offs
]);
927 } while (rc
&& !exact
&& (++offs
<= (shv
.shvvalue
.strlength
- needle
->strlength
)));
929 /* if this is an exact match, make sure the lengths match. We do this at
930 * the end because it only applies when needle is a substring of
932 if (exact
&& !rc
&& shv
.shvvalue
.strlength
!= needle
->strlength
) {
940 /* regstemsearch(needle, haystack, [start], [flags]) */
941 rxfunc(regstemsearch
)
943 RXSTRING needle
, haystack
;
945 register int offs
= 1;
946 rxbool casesensitive
= false, exact
= false, sorted
= false;
955 /* make sure the stem name is null terminated */
956 if (haystack
.strptr
[haystack
.strlength
-1] != '.') {
957 rxstrdup(haystack
.strptr
, haystack
);
958 haystack
.strptr
[haystack
.strlength
++] = '.';
961 getstemsize(&haystack
, &size
);
968 if (argc
> 2 && argv
[2].strptr
) {
969 rxstrdup(sstart
, argv
[2]);
974 if (memchr(argv
[3].strptr
, 'c', argv
[3].strlength
) ||
975 memchr(argv
[3].strptr
, 'C', argv
[3].strlength
))
976 casesensitive
= true;
978 if (memchr(argv
[3].strptr
, 'e', argv
[3].strlength
) ||
979 memchr(argv
[3].strptr
, 'E', argv
[3].strlength
))
982 if (memchr(argv
[3].strptr
, 's', argv
[3].strlength
) ||
983 memchr(argv
[3].strptr
, 'S', argv
[3].strlength
))
990 needle
.strlength
= argv
[0].strlength
;
991 needle
.strptr
= alloca(needle
.strlength
);
992 for (i
= 0; i
< needle
.strlength
; i
++) {
993 needle
.strptr
[i
] = toupper(argv
[0].strptr
[i
]);
997 /* bsearch and lsearch are not appropriate if we want to avoid the
998 * overhead of retrieving the values of all members of the stem */
1001 for (i
= offs
; i
<= size
; i
++) {
1002 if (!(rc
= stemcompare(&needle
, &haystack
, i
, exact
, casesensitive
)))
1008 register int l
= offs
, r
= size
;
1009 for (i
= (r
- l
) / 2 + l
; i
<= r
&& i
>= l
; i
= (r
- l
) / 2 + l
) {
1010 if ((rc
= stemcompare(&needle
, &haystack
, i
, exact
, casesensitive
)) < 0) {
1022 result
->strlength
= sprintf(result
->strptr
, "%d", i
);
1029 /* sysdumpvariables([filename])
1030 * write all variables either to file filename or to stdout
1032 rxfunc(sysdumpvariables
)
1034 static const char dumpformat
[] = "Name=%.*s, Value=\"%.*s\"\n";
1041 rxstrdup(filename
, argv
[0]);
1042 fp
= fopen(filename
, "a");
1049 memcpy(result
->strptr
, "-1", 2);
1050 result
->strlength
= 2;
1053 /* let's guess it will work from here on in */
1057 sb
.shvcode
= RXSHV_NEXTV
;
1061 while (! (sb
.shvret
& RXSHV_LVAR
)) {
1062 /* set ptrs to NULL so RexxVariablePool will allocate memory
1063 * for us -- this is slightly more expensive, but prevents
1064 * the possibility of truncation (we can't recover from
1065 * truncation when stepping through the variable pool). */
1066 sb
.shvvalue
.strptr
= NULL
;
1067 sb
.shvname
.strptr
= NULL
;
1069 RexxVariablePool(&sb
);
1071 if (sb
.shvname
.strptr
&& sb
.shvvalue
.strptr
) {
1072 fprintf(fp
, dumpformat
, (int)sb
.shvname
.strlength
, sb
.shvname
.strptr
,
1073 (int)sb
.shvvalue
.strlength
, sb
.shvvalue
.strptr
);
1074 REXXFREEMEMORY(sb
.shvname
.strptr
);
1075 REXXFREEMEMORY(sb
.shvvalue
.strptr
);