Tue Sep 1 00:35:30 2020 UTC ()
eat the sign, pointed out by uwe@


(christos)
diff -r1.13 -r1.14 src/external/historical/nawk/dist/tran.c

cvs diff -r1.13 -r1.14 src/external/historical/nawk/dist/tran.c (switch to unified diff)

--- src/external/historical/nawk/dist/tran.c 2020/09/01 00:21:01 1.13
+++ src/external/historical/nawk/dist/tran.c 2020/09/01 00:35:29 1.14
@@ -1,661 +1,663 @@ @@ -1,661 +1,663 @@
1/**************************************************************** 1/****************************************************************
2Copyright (C) Lucent Technologies 1997 2Copyright (C) Lucent Technologies 1997
3All Rights Reserved 3All Rights Reserved
4 4
5Permission to use, copy, modify, and distribute this software and 5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby 6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all 7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this 8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting 9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of 10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining 11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior 12to distribution of the software without specific, written prior
13permission. 13permission.
14 14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS SOFTWARE. 22THIS SOFTWARE.
23****************************************************************/ 23****************************************************************/
24 24
25#if HAVE_NBTOOL_CONFIG_H 25#if HAVE_NBTOOL_CONFIG_H
26#include "nbtool_config.h" 26#include "nbtool_config.h"
27#endif 27#endif
28 28
29#define DEBUG 29#define DEBUG
30#include <stdio.h> 30#include <stdio.h>
31#include <math.h> 31#include <math.h>
32#include <ctype.h> 32#include <ctype.h>
33#include <string.h> 33#include <string.h>
34#include <stdlib.h> 34#include <stdlib.h>
35#include "awk.h" 35#include "awk.h"
36#include "awkgram.h" 36#include "awkgram.h"
37 37
38#define FULLTAB 2 /* rehash when table gets this x full */ 38#define FULLTAB 2 /* rehash when table gets this x full */
39#define GROWTAB 4 /* grow table by this factor */ 39#define GROWTAB 4 /* grow table by this factor */
40 40
41Array *symtab; /* main symbol table */ 41Array *symtab; /* main symbol table */
42 42
43char **FS; /* initial field sep */ 43char **FS; /* initial field sep */
44char **RS; /* initial record sep */ 44char **RS; /* initial record sep */
45char **OFS; /* output field sep */ 45char **OFS; /* output field sep */
46char **ORS; /* output record sep */ 46char **ORS; /* output record sep */
47char **OFMT; /* output format for numbers */ 47char **OFMT; /* output format for numbers */
48char **CONVFMT; /* format for conversions in getsval */ 48char **CONVFMT; /* format for conversions in getsval */
49Awkfloat *NF; /* number of fields in current record */ 49Awkfloat *NF; /* number of fields in current record */
50Awkfloat *NR; /* number of current record */ 50Awkfloat *NR; /* number of current record */
51Awkfloat *FNR; /* number of current record in current file */ 51Awkfloat *FNR; /* number of current record in current file */
52char **FILENAME; /* current filename argument */ 52char **FILENAME; /* current filename argument */
53Awkfloat *ARGC; /* number of arguments from command line */ 53Awkfloat *ARGC; /* number of arguments from command line */
54char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 54char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
55Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 55Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
56Awkfloat *RLENGTH; /* length of same */ 56Awkfloat *RLENGTH; /* length of same */
57 57
58Cell *fsloc; /* FS */ 58Cell *fsloc; /* FS */
59Cell *nrloc; /* NR */ 59Cell *nrloc; /* NR */
60Cell *nfloc; /* NF */ 60Cell *nfloc; /* NF */
61Cell *fnrloc; /* FNR */ 61Cell *fnrloc; /* FNR */
62Cell *ofsloc; /* OFS */ 62Cell *ofsloc; /* OFS */
63Cell *orsloc; /* ORS */ 63Cell *orsloc; /* ORS */
64Cell *rsloc; /* RS */ 64Cell *rsloc; /* RS */
65Array *ARGVtab; /* symbol table containing ARGV[...] */ 65Array *ARGVtab; /* symbol table containing ARGV[...] */
66Array *ENVtab; /* symbol table containing ENVIRON[...] */ 66Array *ENVtab; /* symbol table containing ENVIRON[...] */
67Cell *rstartloc; /* RSTART */ 67Cell *rstartloc; /* RSTART */
68Cell *rlengthloc; /* RLENGTH */ 68Cell *rlengthloc; /* RLENGTH */
69Cell *subseploc; /* SUBSEP */ 69Cell *subseploc; /* SUBSEP */
70Cell *symtabloc; /* SYMTAB */ 70Cell *symtabloc; /* SYMTAB */
71 71
72Cell *nullloc; /* a guaranteed empty cell */ 72Cell *nullloc; /* a guaranteed empty cell */
73Node *nullnode; /* zero&null, converted into a node for comparisons */ 73Node *nullnode; /* zero&null, converted into a node for comparisons */
74Cell *literal0; 74Cell *literal0;
75 75
76extern Cell **fldtab; 76extern Cell **fldtab;
77 77
78static void 78static void
79setfree(Cell *vp) 79setfree(Cell *vp)
80{ 80{
81 if (&vp->sval == FS || &vp->sval == RS || 81 if (&vp->sval == FS || &vp->sval == RS ||
82 &vp->sval == OFS || &vp->sval == ORS || 82 &vp->sval == OFS || &vp->sval == ORS ||
83 &vp->sval == OFMT || &vp->sval == CONVFMT || 83 &vp->sval == OFMT || &vp->sval == CONVFMT ||
84 &vp->sval == FILENAME || &vp->sval == SUBSEP) 84 &vp->sval == FILENAME || &vp->sval == SUBSEP)
85 vp->tval |= DONTFREE; 85 vp->tval |= DONTFREE;
86 else 86 else
87 vp->tval &= ~DONTFREE; 87 vp->tval &= ~DONTFREE;
88} 88}
89 89
90void syminit(void) /* initialize symbol table with builtin vars */ 90void syminit(void) /* initialize symbol table with builtin vars */
91{ 91{
92 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 92 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
93 /* this is used for if(x)... tests: */ 93 /* this is used for if(x)... tests: */
94 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 94 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
95 nullnode = celltonode(nullloc, CCON); 95 nullnode = celltonode(nullloc, CCON);
96 96
97 fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 97 fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
98 FS = &fsloc->sval; 98 FS = &fsloc->sval;
99 rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab); 99 rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
100 RS = &rsloc->sval; 100 RS = &rsloc->sval;
101 ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab); 101 ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
102 OFS = &ofsloc->sval; 102 OFS = &ofsloc->sval;
103 orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab); 103 orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
104 ORS = &orsloc->sval; 104 ORS = &orsloc->sval;
105 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 105 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
106 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 106 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
107 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 107 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
108 nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 108 nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
109 NF = &nfloc->fval; 109 NF = &nfloc->fval;
110 nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 110 nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
111 NR = &nrloc->fval; 111 NR = &nrloc->fval;
112 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 112 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
113 FNR = &fnrloc->fval; 113 FNR = &fnrloc->fval;
114 subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab); 114 subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
115 SUBSEP = &subseploc->sval; 115 SUBSEP = &subseploc->sval;
116 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 116 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
117 RSTART = &rstartloc->fval; 117 RSTART = &rstartloc->fval;
118 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 118 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
119 RLENGTH = &rlengthloc->fval; 119 RLENGTH = &rlengthloc->fval;
120 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 120 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
121 free(symtabloc->sval); 121 free(symtabloc->sval);
122 symtabloc->sval = (char *) symtab; 122 symtabloc->sval = (char *) symtab;
123} 123}
124 124
125void arginit(int ac, char **av) /* set up ARGV and ARGC */ 125void arginit(int ac, char **av) /* set up ARGV and ARGC */
126{ 126{
127 Cell *cp; 127 Cell *cp;
128 int i; 128 int i;
129 char temp[50]; 129 char temp[50];
130 130
131 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 131 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
132 cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 132 cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
133 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 133 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
134 free(cp->sval); 134 free(cp->sval);
135 cp->sval = (char *) ARGVtab; 135 cp->sval = (char *) ARGVtab;
136 for (i = 0; i < ac; i++) { 136 for (i = 0; i < ac; i++) {
137 sprintf(temp, "%d", i); 137 sprintf(temp, "%d", i);
138 if (is_number(*av)) 138 if (is_number(*av))
139 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 139 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
140 else 140 else
141 setsymtab(temp, *av, 0.0, STR, ARGVtab); 141 setsymtab(temp, *av, 0.0, STR, ARGVtab);
142 av++; 142 av++;
143 } 143 }
144} 144}
145 145
146void envinit(char **envp) /* set up ENVIRON variable */ 146void envinit(char **envp) /* set up ENVIRON variable */
147{ 147{
148 Cell *cp; 148 Cell *cp;
149 char *p; 149 char *p;
150 150
151 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 151 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
152 ENVtab = makesymtab(NSYMTAB); 152 ENVtab = makesymtab(NSYMTAB);
153 free(cp->sval); 153 free(cp->sval);
154 cp->sval = (char *) ENVtab; 154 cp->sval = (char *) ENVtab;
155 for ( ; *envp; envp++) { 155 for ( ; *envp; envp++) {
156 if ((p = strchr(*envp, '=')) == NULL) 156 if ((p = strchr(*envp, '=')) == NULL)
157 continue; 157 continue;
158 if( p == *envp ) /* no left hand side name in env string */ 158 if( p == *envp ) /* no left hand side name in env string */
159 continue; 159 continue;
160 *p++ = 0; /* split into two strings at = */ 160 *p++ = 0; /* split into two strings at = */
161 if (is_number(p)) 161 if (is_number(p))
162 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 162 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
163 else 163 else
164 setsymtab(*envp, p, 0.0, STR, ENVtab); 164 setsymtab(*envp, p, 0.0, STR, ENVtab);
165 p[-1] = '='; /* restore in case env is passed down to a shell */ 165 p[-1] = '='; /* restore in case env is passed down to a shell */
166 } 166 }
167} 167}
168 168
169Array *makesymtab(int n) /* make a new symbol table */ 169Array *makesymtab(int n) /* make a new symbol table */
170{ 170{
171 Array *ap; 171 Array *ap;
172 Cell **tp; 172 Cell **tp;
173 173
174 ap = malloc(sizeof(*ap)); 174 ap = malloc(sizeof(*ap));
175 tp = calloc(n, sizeof(*tp)); 175 tp = calloc(n, sizeof(*tp));
176 if (ap == NULL || tp == NULL) 176 if (ap == NULL || tp == NULL)
177 FATAL("out of space in makesymtab"); 177 FATAL("out of space in makesymtab");
178 ap->nelem = 0; 178 ap->nelem = 0;
179 ap->size = n; 179 ap->size = n;
180 ap->tab = tp; 180 ap->tab = tp;
181 return(ap); 181 return(ap);
182} 182}
183 183
184void freesymtab(Cell *ap) /* free a symbol table */ 184void freesymtab(Cell *ap) /* free a symbol table */
185{ 185{
186 Cell *cp, *temp; 186 Cell *cp, *temp;
187 Array *tp; 187 Array *tp;
188 int i; 188 int i;
189 189
190 if (!isarr(ap)) 190 if (!isarr(ap))
191 return; 191 return;
192 tp = (Array *) ap->sval; 192 tp = (Array *) ap->sval;
193 if (tp == NULL) 193 if (tp == NULL)
194 return; 194 return;
195 for (i = 0; i < tp->size; i++) { 195 for (i = 0; i < tp->size; i++) {
196 for (cp = tp->tab[i]; cp != NULL; cp = temp) { 196 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
197 xfree(cp->nval); 197 xfree(cp->nval);
198 if (freeable(cp)) 198 if (freeable(cp))
199 xfree(cp->sval); 199 xfree(cp->sval);
200 temp = cp->cnext; /* avoids freeing then using */ 200 temp = cp->cnext; /* avoids freeing then using */
201 free(cp); 201 free(cp);
202 tp->nelem--; 202 tp->nelem--;
203 } 203 }
204 tp->tab[i] = NULL; 204 tp->tab[i] = NULL;
205 } 205 }
206 if (tp->nelem != 0) 206 if (tp->nelem != 0)
207 WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 207 WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
208 free(tp->tab); 208 free(tp->tab);
209 free(tp); 209 free(tp);
210} 210}
211 211
212void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 212void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
213{ 213{
214 Array *tp; 214 Array *tp;
215 Cell *p, *prev = NULL; 215 Cell *p, *prev = NULL;
216 int h; 216 int h;
217 217
218 tp = (Array *) ap->sval; 218 tp = (Array *) ap->sval;
219 h = hash(s, tp->size); 219 h = hash(s, tp->size);
220 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 220 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
221 if (strcmp(s, p->nval) == 0) { 221 if (strcmp(s, p->nval) == 0) {
222 if (prev == NULL) /* 1st one */ 222 if (prev == NULL) /* 1st one */
223 tp->tab[h] = p->cnext; 223 tp->tab[h] = p->cnext;
224 else /* middle somewhere */ 224 else /* middle somewhere */
225 prev->cnext = p->cnext; 225 prev->cnext = p->cnext;
226 if (freeable(p)) 226 if (freeable(p))
227 xfree(p->sval); 227 xfree(p->sval);
228 free(p->nval); 228 free(p->nval);
229 free(p); 229 free(p);
230 tp->nelem--; 230 tp->nelem--;
231 return; 231 return;
232 } 232 }
233} 233}
234 234
235Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 235Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
236{ 236{
237 int h; 237 int h;
238 Cell *p; 238 Cell *p;
239 239
240 if (n != NULL && (p = lookup(n, tp)) != NULL) { 240 if (n != NULL && (p = lookup(n, tp)) != NULL) {
241 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 241 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
242 (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 242 (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
243 return(p); 243 return(p);
244 } 244 }
245 p = malloc(sizeof(*p)); 245 p = malloc(sizeof(*p));
246 if (p == NULL) 246 if (p == NULL)
247 FATAL("out of space for symbol table at %s", n); 247 FATAL("out of space for symbol table at %s", n);
248 p->nval = tostring(n); 248 p->nval = tostring(n);
249 p->sval = s ? tostring(s) : tostring(""); 249 p->sval = s ? tostring(s) : tostring("");
250 p->fval = f; 250 p->fval = f;
251 p->tval = t; 251 p->tval = t;
252 p->csub = CUNK; 252 p->csub = CUNK;
253 p->ctype = OCELL; 253 p->ctype = OCELL;
254 tp->nelem++; 254 tp->nelem++;
255 if (tp->nelem > FULLTAB * tp->size) 255 if (tp->nelem > FULLTAB * tp->size)
256 rehash(tp); 256 rehash(tp);
257 h = hash(n, tp->size); 257 h = hash(n, tp->size);
258 p->cnext = tp->tab[h]; 258 p->cnext = tp->tab[h];
259 tp->tab[h] = p; 259 tp->tab[h] = p;
260 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 260 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
261 (void*)p, p->nval, p->sval, p->fval, p->tval) ); 261 (void*)p, p->nval, p->sval, p->fval, p->tval) );
262 return(p); 262 return(p);
263} 263}
264 264
265int hash(const char *s, int n) /* form hash value for string s */ 265int hash(const char *s, int n) /* form hash value for string s */
266{ 266{
267 unsigned hashval; 267 unsigned hashval;
268 268
269 for (hashval = 0; *s != '\0'; s++) 269 for (hashval = 0; *s != '\0'; s++)
270 hashval = (*s + 31 * hashval); 270 hashval = (*s + 31 * hashval);
271 return hashval % n; 271 return hashval % n;
272} 272}
273 273
274void rehash(Array *tp) /* rehash items in small table into big one */ 274void rehash(Array *tp) /* rehash items in small table into big one */
275{ 275{
276 int i, nh, nsz; 276 int i, nh, nsz;
277 Cell *cp, *op, **np; 277 Cell *cp, *op, **np;
278 278
279 nsz = GROWTAB * tp->size; 279 nsz = GROWTAB * tp->size;
280 np = calloc(nsz, sizeof(*np)); 280 np = calloc(nsz, sizeof(*np));
281 if (np == NULL) /* can't do it, but can keep running. */ 281 if (np == NULL) /* can't do it, but can keep running. */
282 return; /* someone else will run out later. */ 282 return; /* someone else will run out later. */
283 for (i = 0; i < tp->size; i++) { 283 for (i = 0; i < tp->size; i++) {
284 for (cp = tp->tab[i]; cp; cp = op) { 284 for (cp = tp->tab[i]; cp; cp = op) {
285 op = cp->cnext; 285 op = cp->cnext;
286 nh = hash(cp->nval, nsz); 286 nh = hash(cp->nval, nsz);
287 cp->cnext = np[nh]; 287 cp->cnext = np[nh];
288 np[nh] = cp; 288 np[nh] = cp;
289 } 289 }
290 } 290 }
291 free(tp->tab); 291 free(tp->tab);
292 tp->tab = np; 292 tp->tab = np;
293 tp->size = nsz; 293 tp->size = nsz;
294} 294}
295 295
296Cell *lookup(const char *s, Array *tp) /* look for s in tp */ 296Cell *lookup(const char *s, Array *tp) /* look for s in tp */
297{ 297{
298 Cell *p; 298 Cell *p;
299 int h; 299 int h;
300 300
301 h = hash(s, tp->size); 301 h = hash(s, tp->size);
302 for (p = tp->tab[h]; p != NULL; p = p->cnext) 302 for (p = tp->tab[h]; p != NULL; p = p->cnext)
303 if (strcmp(s, p->nval) == 0) 303 if (strcmp(s, p->nval) == 0)
304 return(p); /* found it */ 304 return(p); /* found it */
305 return(NULL); /* not found */ 305 return(NULL); /* not found */
306} 306}
307 307
308Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 308Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
309{ 309{
310 int fldno; 310 int fldno;
311 311
312 f += 0.0; /* normalise negative zero to positive zero */ 312 f += 0.0; /* normalise negative zero to positive zero */
313 if ((vp->tval & (NUM | STR)) == 0) 313 if ((vp->tval & (NUM | STR)) == 0)
314 funnyvar(vp, "assign to"); 314 funnyvar(vp, "assign to");
315 if (isfld(vp)) { 315 if (isfld(vp)) {
316 donerec = false; /* mark $0 invalid */ 316 donerec = false; /* mark $0 invalid */
317 fldno = atoi(vp->nval); 317 fldno = atoi(vp->nval);
318 if (fldno > *NF) 318 if (fldno > *NF)
319 newfld(fldno); 319 newfld(fldno);
320 dprintf( ("setting field %d to %g\n", fldno, f) ); 320 dprintf( ("setting field %d to %g\n", fldno, f) );
321 } else if (&vp->fval == NF) { 321 } else if (&vp->fval == NF) {
322 donerec = false; /* mark $0 invalid */ 322 donerec = false; /* mark $0 invalid */
323 setlastfld(f); 323 setlastfld(f);
324 dprintf( ("setting NF to %g\n", f) ); 324 dprintf( ("setting NF to %g\n", f) );
325 } else if (isrec(vp)) { 325 } else if (isrec(vp)) {
326 donefld = false; /* mark $1... invalid */ 326 donefld = false; /* mark $1... invalid */
327 donerec = true; 327 donerec = true;
328 savefs(); 328 savefs();
329 } else if (vp == ofsloc) { 329 } else if (vp == ofsloc) {
330 if (!donerec) 330 if (!donerec)
331 recbld(); 331 recbld();
332 } 332 }
333 if (freeable(vp)) 333 if (freeable(vp))
334 xfree(vp->sval); /* free any previous string */ 334 xfree(vp->sval); /* free any previous string */
335 vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ 335 vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
336 vp->fmt = NULL; 336 vp->fmt = NULL;
337 vp->tval |= NUM; /* mark number ok */ 337 vp->tval |= NUM; /* mark number ok */
338 if (f == -0) /* who would have thought this possible? */ 338 if (f == -0) /* who would have thought this possible? */
339 f = 0; 339 f = 0;
340 dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) ); 340 dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
341 return vp->fval = f; 341 return vp->fval = f;
342} 342}
343 343
344void funnyvar(Cell *vp, const char *rw) 344void funnyvar(Cell *vp, const char *rw)
345{ 345{
346 if (isarr(vp)) 346 if (isarr(vp))
347 FATAL("can't %s %s; it's an array name.", rw, vp->nval); 347 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
348 if (vp->tval & FCN) 348 if (vp->tval & FCN)
349 FATAL("can't %s %s; it's a function.", rw, vp->nval); 349 FATAL("can't %s %s; it's a function.", rw, vp->nval);
350 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 350 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
351 (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval); 351 (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
352} 352}
353 353
354char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 354char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
355{ 355{
356 char *t; 356 char *t;
357 int fldno; 357 int fldno;
358 Awkfloat f; 358 Awkfloat f;
359 359
360 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 360 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
361 (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 361 (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
362 if ((vp->tval & (NUM | STR)) == 0) 362 if ((vp->tval & (NUM | STR)) == 0)
363 funnyvar(vp, "assign to"); 363 funnyvar(vp, "assign to");
364 if (isfld(vp)) { 364 if (isfld(vp)) {
365 donerec = false; /* mark $0 invalid */ 365 donerec = false; /* mark $0 invalid */
366 fldno = atoi(vp->nval); 366 fldno = atoi(vp->nval);
367 if (fldno > *NF) 367 if (fldno > *NF)
368 newfld(fldno); 368 newfld(fldno);
369 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 369 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
370 } else if (isrec(vp)) { 370 } else if (isrec(vp)) {
371 donefld = false; /* mark $1... invalid */ 371 donefld = false; /* mark $1... invalid */
372 donerec = true; 372 donerec = true;
373 savefs(); 373 savefs();
374 } else if (vp == ofsloc) { 374 } else if (vp == ofsloc) {
375 if (!donerec) 375 if (!donerec)
376 recbld(); 376 recbld();
377 } 377 }
378 t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ 378 t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
379 if (freeable(vp)) 379 if (freeable(vp))
380 xfree(vp->sval); 380 xfree(vp->sval);
381 vp->tval &= ~(NUM|CONVC|CONVO); 381 vp->tval &= ~(NUM|CONVC|CONVO);
382 vp->tval |= STR; 382 vp->tval |= STR;
383 vp->fmt = NULL; 383 vp->fmt = NULL;
384 setfree(vp); 384 setfree(vp);
385 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 385 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
386 (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) ); 386 (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) );
387 vp->sval = t; 387 vp->sval = t;
388 if (&vp->fval == NF) { 388 if (&vp->fval == NF) {
389 donerec = false; /* mark $0 invalid */ 389 donerec = false; /* mark $0 invalid */
390 f = getfval(vp); 390 f = getfval(vp);
391 setlastfld(f); 391 setlastfld(f);
392 dprintf( ("setting NF to %g\n", f) ); 392 dprintf( ("setting NF to %g\n", f) );
393 } 393 }
394 394
395 return(vp->sval); 395 return(vp->sval);
396} 396}
397 397
398static int checkstr(const char *s, const char *v) 398static int checkstr(const char *s, const char *v)
399{ 399{
400 while (*s && tolower((unsigned char)*s) == *v) 400 while (*s && tolower((unsigned char)*s) == *v)
401 s++, v++; 401 s++, v++;
402 return !(*s || *v); 402 return !(*s || *v);
403} 403}
404 404
405static int checkinfnan(const char *s) 405static int checkinfnan(const char *s)
406{ 406{
 407 if (*s == '+' || *s == '-')
 408 s++;
407 switch (tolower((unsigned char)*s)) { 409 switch (tolower((unsigned char)*s)) {
408 case 'i': 410 case 'i':
409 return checkstr(s, "inf") || checkstr(s, "infinity"); 411 return checkstr(s, "inf") || checkstr(s, "infinity");
410 case 'n': 412 case 'n':
411 return checkstr(s, "nan"); 413 return checkstr(s, "nan");
412 default: 414 default:
413 return 1; 415 return 1;
414 } 416 }
415} 417}
416 418
417Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 419Awkfloat getfval(Cell *vp) /* get float val of a Cell */
418{ 420{
419 if ((vp->tval & (NUM | STR)) == 0) 421 if ((vp->tval & (NUM | STR)) == 0)
420 funnyvar(vp, "read value of"); 422 funnyvar(vp, "read value of");
421 if (isfld(vp) && !donefld) 423 if (isfld(vp) && !donefld)
422 fldbld(); 424 fldbld();
423 else if (isrec(vp) && !donerec) 425 else if (isrec(vp) && !donerec)
424 recbld(); 426 recbld();
425 if (!isnum(vp)) { /* not a number */ 427 if (!isnum(vp)) { /* not a number */
426 if (checkinfnan(vp->sval)) 428 if (checkinfnan(vp->sval))
427 vp->fval = atof(vp->sval); /* best guess */ 429 vp->fval = atof(vp->sval); /* best guess */
428 if (is_number(vp->sval) && !(vp->tval&CON)) { 430 if (is_number(vp->sval) && !(vp->tval&CON)) {
429 vp->tval |= NUM; /* make NUM only sparingly */ 431 vp->tval |= NUM; /* make NUM only sparingly */
430 } 432 }
431 } 433 }
432 dprintf( ("getfval %p: %s = %g, t=%o\n", 434 dprintf( ("getfval %p: %s = %g, t=%o\n",
433 (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); 435 (void*)vp, NN(vp->nval), vp->fval, vp->tval) );
434 return(vp->fval); 436 return(vp->fval);
435} 437}
436 438
437static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 439static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
438{ 440{
439 char s[256]; 441 char s[256];
440 double dtemp; 442 double dtemp;
441 443
442 if ((vp->tval & (NUM | STR)) == 0) 444 if ((vp->tval & (NUM | STR)) == 0)
443 funnyvar(vp, "read value of"); 445 funnyvar(vp, "read value of");
444 if (isfld(vp) && ! donefld) 446 if (isfld(vp) && ! donefld)
445 fldbld(); 447 fldbld();
446 else if (isrec(vp) && ! donerec) 448 else if (isrec(vp) && ! donerec)
447 recbld(); 449 recbld();
448 450
449 /* 451 /*
450 * ADR: This is complicated and more fragile than is desirable. 452 * ADR: This is complicated and more fragile than is desirable.
451 * Retrieving a string value for a number associates the string 453 * Retrieving a string value for a number associates the string
452 * value with the scalar. Previously, the string value was 454 * value with the scalar. Previously, the string value was
453 * sticky, meaning if converted via OFMT that became the value 455 * sticky, meaning if converted via OFMT that became the value
454 * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT 456 * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
455 * changed after a string value was retrieved, the original value 457 * changed after a string value was retrieved, the original value
456 * was maintained and used. Also not per POSIX. 458 * was maintained and used. Also not per POSIX.
457 * 459 *
458 * We work around this design by adding two additional flags, 460 * We work around this design by adding two additional flags,
459 * CONVC and CONVO, indicating how the string value was 461 * CONVC and CONVO, indicating how the string value was
460 * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy 462 * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
461 * of the pointer to the xFMT format string used for the 463 * of the pointer to the xFMT format string used for the
462 * conversion. This pointer is only read, **never** dereferenced. 464 * conversion. This pointer is only read, **never** dereferenced.
463 * The next time we do a conversion, if it's coming from the same 465 * The next time we do a conversion, if it's coming from the same
464 * xFMT as last time, and the pointer value is different, we 466 * xFMT as last time, and the pointer value is different, we
465 * know that the xFMT format string changed, and we need to 467 * know that the xFMT format string changed, and we need to
466 * redo the conversion. If it's the same, we don't have to. 468 * redo the conversion. If it's the same, we don't have to.
467 * 469 *
468 * There are also several cases where we don't do a conversion, 470 * There are also several cases where we don't do a conversion,
469 * such as for a field (see the checks below). 471 * such as for a field (see the checks below).
470 */ 472 */
471 473
472 /* Don't duplicate the code for actually updating the value */ 474 /* Don't duplicate the code for actually updating the value */
473#define update_str_val(vp) \ 475#define update_str_val(vp) \
474 { \ 476 { \
475 if (freeable(vp)) \ 477 if (freeable(vp)) \
476 xfree(vp->sval); \ 478 xfree(vp->sval); \
477 if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ 479 if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
478 snprintf(s, sizeof (s), "%.30g", vp->fval); \ 480 snprintf(s, sizeof (s), "%.30g", vp->fval); \
479 else \ 481 else \
480 snprintf(s, sizeof (s), *fmt, vp->fval); \ 482 snprintf(s, sizeof (s), *fmt, vp->fval); \
481 vp->sval = tostring(s); \ 483 vp->sval = tostring(s); \
482 vp->tval &= ~DONTFREE; \ 484 vp->tval &= ~DONTFREE; \
483 vp->tval |= STR; \ 485 vp->tval |= STR; \
484 } 486 }
485 487
486 if (isstr(vp) == 0) { 488 if (isstr(vp) == 0) {
487 update_str_val(vp); 489 update_str_val(vp);
488 if (fmt == OFMT) { 490 if (fmt == OFMT) {
489 vp->tval &= ~CONVC; 491 vp->tval &= ~CONVC;
490 vp->tval |= CONVO; 492 vp->tval |= CONVO;
491 } else { 493 } else {
492 /* CONVFMT */ 494 /* CONVFMT */
493 vp->tval &= ~CONVO; 495 vp->tval &= ~CONVO;
494 vp->tval |= CONVC; 496 vp->tval |= CONVC;
495 } 497 }
496 vp->fmt = *fmt; 498 vp->fmt = *fmt;
497 } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { 499 } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
498 goto done; 500 goto done;
499 } else if (isstr(vp)) { 501 } else if (isstr(vp)) {
500 if (fmt == OFMT) { 502 if (fmt == OFMT) {
501 if ((vp->tval & CONVC) != 0 503 if ((vp->tval & CONVC) != 0
502 || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { 504 || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
503 update_str_val(vp); 505 update_str_val(vp);
504 vp->tval &= ~CONVC; 506 vp->tval &= ~CONVC;
505 vp->tval |= CONVO; 507 vp->tval |= CONVO;
506 vp->fmt = *fmt; 508 vp->fmt = *fmt;
507 } 509 }
508 } else { 510 } else {
509 /* CONVFMT */ 511 /* CONVFMT */
510 if ((vp->tval & CONVO) != 0 512 if ((vp->tval & CONVO) != 0
511 || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { 513 || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
512 update_str_val(vp); 514 update_str_val(vp);
513 vp->tval &= ~CONVO; 515 vp->tval &= ~CONVO;
514 vp->tval |= CONVC; 516 vp->tval |= CONVC;
515 vp->fmt = *fmt; 517 vp->fmt = *fmt;
516 } 518 }
517 } 519 }
518 } 520 }
519done: 521done:
520 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", 522 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
521 (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); 523 (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
522 return(vp->sval); 524 return(vp->sval);
523} 525}
524 526
525char *getsval(Cell *vp) /* get string val of a Cell */ 527char *getsval(Cell *vp) /* get string val of a Cell */
526{ 528{
527 return get_str_val(vp, CONVFMT); 529 return get_str_val(vp, CONVFMT);
528} 530}
529 531
530char *getpssval(Cell *vp) /* get string val of a Cell for print */ 532char *getpssval(Cell *vp) /* get string val of a Cell for print */
531{ 533{
532 return get_str_val(vp, OFMT); 534 return get_str_val(vp, OFMT);
533} 535}
534 536
535 537
536char *tostring(const char *s) /* make a copy of string s */ 538char *tostring(const char *s) /* make a copy of string s */
537{ 539{
538 char *p = strdup(s); 540 char *p = strdup(s);
539 if (p == NULL) 541 if (p == NULL)
540 FATAL("out of space in tostring on %s", s); 542 FATAL("out of space in tostring on %s", s);
541 return(p); 543 return(p);
542} 544}
543 545
544char *tostringN(const char *s, size_t n) /* make a copy of string s */ 546char *tostringN(const char *s, size_t n) /* make a copy of string s */
545{ 547{
546 char *p; 548 char *p;
547 549
548 p = malloc(n); 550 p = malloc(n);
549 if (p == NULL) 551 if (p == NULL)
550 FATAL("out of space in tostring on %s", s); 552 FATAL("out of space in tostring on %s", s);
551 strcpy(p, s); 553 strcpy(p, s);
552 return(p); 554 return(p);
553} 555}
554 556
555Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ 557Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
556{ 558{
557 Cell *c; 559 Cell *c;
558 char *p; 560 char *p;
559 char *sa = getsval(a); 561 char *sa = getsval(a);
560 char *sb = getsval(b); 562 char *sb = getsval(b);
561 size_t l = strlen(sa) + strlen(sb) + 1; 563 size_t l = strlen(sa) + strlen(sb) + 1;
562 p = malloc(l); 564 p = malloc(l);
563 if (p == NULL) 565 if (p == NULL)
564 FATAL("out of space concatenating %s and %s", sa, sb); 566 FATAL("out of space concatenating %s and %s", sa, sb);
565 snprintf(p, l, "%s%s", sa, sb); 567 snprintf(p, l, "%s%s", sa, sb);
566 568
567 l++; // add room for ' ' 569 l++; // add room for ' '
568 char *newbuf = malloc(l); 570 char *newbuf = malloc(l);
569 if (newbuf == NULL) 571 if (newbuf == NULL)
570 FATAL("out of space concatenating %s and %s", sa, sb); 572 FATAL("out of space concatenating %s and %s", sa, sb);
571 // See string() in lex.c; a string "xx" is stored in the symbol 573 // See string() in lex.c; a string "xx" is stored in the symbol
572 // table as "xx ". 574 // table as "xx ".
573 snprintf(newbuf, l, "%s ", p); 575 snprintf(newbuf, l, "%s ", p);
574 c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); 576 c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
575 free(p); 577 free(p);
576 free(newbuf); 578 free(newbuf);
577 return c; 579 return c;
578} 580}
579 581
580char *qstring(const char *is, int delim) /* collect string up to next delim */ 582char *qstring(const char *is, int delim) /* collect string up to next delim */
581{ 583{
582 const char *os = is; 584 const char *os = is;
583 int c, n; 585 int c, n;
584 const uschar *s = (const uschar *) is; 586 const uschar *s = (const uschar *) is;
585 uschar *buf, *bp; 587 uschar *buf, *bp;
586 588
587 if ((buf = malloc(strlen(is)+3)) == NULL) 589 if ((buf = malloc(strlen(is)+3)) == NULL)
588 FATAL( "out of space in qstring(%s)", s); 590 FATAL( "out of space in qstring(%s)", s);
589 for (bp = buf; (c = *s) != delim; s++) { 591 for (bp = buf; (c = *s) != delim; s++) {
590 if (c == '\n') 592 if (c == '\n')
591 SYNTAX( "newline in string %.20s...", os ); 593 SYNTAX( "newline in string %.20s...", os );
592 else if (c != '\\') 594 else if (c != '\\')
593 *bp++ = c; 595 *bp++ = c;
594 else { /* \something */ 596 else { /* \something */
595 c = *++s; 597 c = *++s;
596 if (c == 0) { /* \ at end */ 598 if (c == 0) { /* \ at end */
597 *bp++ = '\\'; 599 *bp++ = '\\';
598 break; /* for loop */ 600 break; /* for loop */
599 } 601 }
600 switch (c) { 602 switch (c) {
601 case '\\': *bp++ = '\\'; break; 603 case '\\': *bp++ = '\\'; break;
602 case 'n': *bp++ = '\n'; break; 604 case 'n': *bp++ = '\n'; break;
603 case 't': *bp++ = '\t'; break; 605 case 't': *bp++ = '\t'; break;
604 case 'b': *bp++ = '\b'; break; 606 case 'b': *bp++ = '\b'; break;
605 case 'f': *bp++ = '\f'; break; 607 case 'f': *bp++ = '\f'; break;
606 case 'r': *bp++ = '\r'; break; 608 case 'r': *bp++ = '\r'; break;
607 case 'v': *bp++ = '\v'; break; 609 case 'v': *bp++ = '\v'; break;
608 case 'a': *bp++ = '\a'; break; 610 case 'a': *bp++ = '\a'; break;
609 default: 611 default:
610 if (!isdigit(c)) { 612 if (!isdigit(c)) {
611 *bp++ = c; 613 *bp++ = c;
612 break; 614 break;
613 } 615 }
614 n = c - '0'; 616 n = c - '0';
615 if (isdigit(s[1])) { 617 if (isdigit(s[1])) {
616 n = 8 * n + *++s - '0'; 618 n = 8 * n + *++s - '0';
617 if (isdigit(s[1])) 619 if (isdigit(s[1]))
618 n = 8 * n + *++s - '0'; 620 n = 8 * n + *++s - '0';
619 } 621 }
620 *bp++ = n; 622 *bp++ = n;
621 break; 623 break;
622 } 624 }
623 } 625 }
624 } 626 }
625 *bp++ = 0; 627 *bp++ = 0;
626 return (char *) buf; 628 return (char *) buf;
627} 629}
628 630
629const char *flags2str(int flags) 631const char *flags2str(int flags)
630{ 632{
631 static const struct ftab { 633 static const struct ftab {
632 const char *name; 634 const char *name;
633 int value; 635 int value;
634 } flagtab[] = { 636 } flagtab[] = {
635 { "NUM", NUM }, 637 { "NUM", NUM },
636 { "STR", STR }, 638 { "STR", STR },
637 { "DONTFREE", DONTFREE }, 639 { "DONTFREE", DONTFREE },
638 { "CON", CON }, 640 { "CON", CON },
639 { "ARR", ARR }, 641 { "ARR", ARR },
640 { "FCN", FCN }, 642 { "FCN", FCN },
641 { "FLD", FLD }, 643 { "FLD", FLD },
642 { "REC", REC }, 644 { "REC", REC },
643 { "CONVC", CONVC }, 645 { "CONVC", CONVC },
644 { "CONVO", CONVO }, 646 { "CONVO", CONVO },
645 { NULL, 0 } 647 { NULL, 0 }
646 }; 648 };
647 static char buf[100]; 649 static char buf[100];
648 int i; 650 int i;
649 char *cp = buf; 651 char *cp = buf;
650 652
651 for (i = 0; flagtab[i].name != NULL; i++) { 653 for (i = 0; flagtab[i].name != NULL; i++) {
652 if ((flags & flagtab[i].value) != 0) { 654 if ((flags & flagtab[i].value) != 0) {
653 if (cp > buf) 655 if (cp > buf)
654 *cp++ = '|'; 656 *cp++ = '|';
655 strcpy(cp, flagtab[i].name); 657 strcpy(cp, flagtab[i].name);
656 cp += strlen(cp); 658 cp += strlen(cp);
657 } 659 }
658 } 660 }
659 661
660 return buf; 662 return buf;
661} 663}