1 /*
2    Changes by Gunnar Ritter, Freiburg i. Br., Germany, December 2002.
3 
4    Sccsid @(#)lib.c	1.27 (gritter) 12/25/06>
5  */
6 /* UNIX(R) Regular Expression Tools
7 
8    Copyright (C) 2001 Caldera International, Inc.
9 
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to:
22        Free Software Foundation, Inc.
23        59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25 /*	copyright	"%c%"	*/
26 
27 /*	from unixsrc:usr/src/common/cmd/awk/lib.c /main/uw7_nj/1	*/
28 /*	from RCS Header: lib.c 1.2 91/06/25 	*/
29 
30 #define DEBUG
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <strings.h>
36 #include "awk.h"
37 #include "y.tab.h"
38 #include <pfmt.h>
39 #include <stdarg.h>
40 #include <wctype.h>
41 #include "asciitype.h"
42 
43 #undef	RS
44 
45 static void	eprint(void);
46 
47 #define	getfval(p)	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
48 #define	getsval(p)	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
49 
50 FILE	*infile	= NULL;
51 unsigned char	*file	= (unsigned char*) "";
52 unsigned char	*record;
53 unsigned char	*recdata;
54 int		recsize;
55 unsigned char	*fields;
56 
57 int	donefld;	/* 1 = implies rec broken into fields */
58 int	donerec;	/* 1 = record is valid (no flds have changed) */
59 
60 Cell	**fldtab;	/* room for fields */
61 
62 static Cell	dollar0 = {
63 	OCELL, CFLD, (unsigned char*) "$0", (unsigned char *)"", 0.0, REC|STR|DONTFREE
64 };
65 static Cell	FINIT = {
66 	OCELL, CFLD, NULL, (unsigned char*) "", 0.0, FLD|STR|DONTFREE
67 };
68 
69 
70 static int	MAXFLD;	/* number of allocated fields */
71 int	maxfld	= 0;	/* last used field */
72 int	argno	= 1;	/* current input argument number */
73 extern	Awkfloat *ARGC;
74 
75 static void growrec(unsigned char **, int *, int, unsigned char **, int);
76 
77 char badopen[] = ":11:Cannot open %s: %s";
78 
79 /* Dynamic field and record allocation inspired by Bell Labs awk. */
morefields(void)80 static void morefields(void)
81 {
82 	int	i;
83 	const int	n = 32;
84 
85 	fldtab = realloc(fldtab, (MAXFLD + n + 1) * sizeof *fldtab);
86 	if (fldtab == NULL)
87 		error(MM_ERROR, ":13:Record `%.20s...' has too many fields",
88 			record);
89 	recloc = fldtab[0];
90 	for (i = MAXFLD; i < MAXFLD + n; i++) {
91 		fldtab[i] = malloc(sizeof **fldtab);
92 		if (fldtab[i] == NULL)
93 			error(MM_ERROR,
94 				":13:Record `%.20s...' has too many fields",
95 				record);
96 		*fldtab[i] = FINIT;
97 	}
98 	MAXFLD += n;
99 }
100 
fldinit(void)101 void fldinit(void)
102 {
103 	record = recdata = malloc(recsize = CHUNK);
104 	fields = malloc(recsize);
105 	if (record == NULL || fields == NULL)
106 		error(MM_ERROR, outofspace, "fldinit");
107 	*record = '\0';
108 	morefields();
109 	*fldtab[0] = dollar0;
110 }
111 
initgetrec(void)112 void initgetrec(void)
113 {
114 	extern unsigned char **start_delayed, **after_delayed;
115 	unsigned char **pp;
116 	int i;
117 	unsigned char *p;
118 
119 	/* first handle delayed name=val arguments */
120 	for (pp = start_delayed; pp != after_delayed; pp++)
121 		setclvar(*pp);
122 	for (i = 1; i < *ARGC; i++) {
123 		if (!isclvar(p = getargv(i)))	/* find 1st real filename */
124 			return;
125 		setclvar(p);	/* a commandline assignment before filename */
126 		argno++;
127 	}
128 	infile = stdin;		/* no filenames, so use stdin */
129 	/* *FILENAME = file = (unsigned char*) "-"; */
130 }
131 
getrec(unsigned char ** buf,int * bufsize)132 int getrec(unsigned char **buf, int *bufsize)
133 {
134 	int c, saved;
135 	static int firsttime = 1;
136 
137 	if (firsttime) {
138 		firsttime = 0;
139 		initgetrec();
140 	}
141 	dprintf( ("RS=<%s>, FS=<%s>, ARGC=%d, FILENAME=%s\n",
142 		*RS ? *RS : tostring(""),
143 		*FS ? *FS : tostring(""),
144 		(int) *ARGC,
145 		*FILENAME ? *FILENAME : tostring("")) );
146 	donefld = 0;
147 	donerec = 1;
148 	if (*bufsize == 0) {
149 		if ((*buf = malloc(*bufsize = CHUNK)) == NULL)
150 			error(MM_ERROR, outofspace, "getrec");
151 		**buf = '\0';
152 	}
153 	saved = (*buf)[0];
154 	(*buf)[0] = 0;
155 	while (argno < *ARGC || infile == stdin) {
156 		dprintf( ("argno=%d, file=|%s|\n", argno, file) )
157 		;
158 		if (infile == NULL) {	/* have to open a new file */
159 			file = getargv(argno);
160 			if (*file == '\0') {	/* it's been zapped */
161 				argno++;
162 				continue;
163 			}
164 			if (isclvar(file)) {	/* a var=value arg */
165 				setclvar(file);
166 				argno++;
167 				continue;
168 			}
169 			*FILENAME = file;
170 			dprintf( ("opening file %s\n", file) );
171 			if (*file == '-' && *(file+1) == '\0')
172 				infile = stdin;
173 			else if ((infile = fopen((char *)file, "r")) == NULL)
174 				error(MM_ERROR, badopen, file, strerror(errno));
175 			setfval(fnrloc, 0.0);
176 		}
177 		c = readrec(buf, bufsize, infile);
178 		if (c != 0 || (*buf)[0] != '\0') {	/* normal record */
179 			if (*buf == record) {
180 				if (!(recloc->tval & DONTFREE))
181 					xfree(recloc->sval);
182 				recloc->sval = record;
183 				recloc->tval = REC | STR | DONTFREE;
184 				(void)is2number(0, recloc);
185 			}
186 			setfval(nrloc, nrloc->fval+1);
187 			setfval(fnrloc, fnrloc->fval+1);
188 			return 1;
189 		}
190 		/* EOF arrived on this file; set up next */
191 		if (infile != stdin)
192 			fclose(infile);
193 		infile = NULL;
194 		argno++;
195 	}
196 	/*
197 	* POSIX.2 requires that NF stick with its last value
198 	* at the start of the END code.  The most straightforward
199 	* way to do this is to restore the contents of record
200 	* [==buf when called from program()] so that getnf() will
201 	* recompute the same NF value unless something strange
202 	* occurs.  This has the side effect of $0...$NF *also*
203 	* having sticky values into END, but that seems to match
204 	* the spirit of POSIX.2's rule for NF.
205 	*/
206 	if (posix)
207 		(*buf)[0] = saved;
208 	return 0;	/* true end of file */
209 }
210 
readrec(unsigned char ** buf,int * bufsize,FILE * inf)211 int readrec(unsigned char **buf, int *bufsize, FILE *inf)
212 	/* read one record into buf */
213 {
214 	register int sep, c, k, m, n;
215 	unsigned char *rr;
216 	register int nrr;
217 	wchar_t wc;
218 
219 	next(wc, *RS, n);
220 	if ((sep = **RS) == 0) {
221 		sep = '\n';
222 		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
223 			;
224 		if (c != EOF)
225 			ungetc(c, inf);
226 	}
227 	if (*bufsize == 0)
228 		growrec(buf, bufsize, CHUNK, NULL, 0);
229 	for (rr = *buf, nrr = *bufsize; ; ) {
230 	cont:	for (; (c=getc(inf)) != sep && c != EOF; *rr++ = c)
231 			if (--nrr < n + 3) {
232 				growrec(buf, bufsize, *bufsize + CHUNK, &rr, 0);
233 				nrr += CHUNK;
234 			}
235 		if (c != EOF) {
236 			/*
237 			 * Note: This code does not restrict occurences of
238 			 * the multibyte sequence in RS to the start of an
239 			 * input character.
240 			 */
241 			for (m = 1; m < n; m++) {
242 				if ((c = getc(inf)) == EOF || c != (*RS)[m]) {
243 					for (k = 0; k < m; k++)
244 						*rr++ = (*RS)[k];
245 					nrr -= k;
246 					if (c == EOF)
247 						break;
248 					*rr++ = c;
249 					nrr--;
250 					goto cont;
251 				}
252 			}
253 		}
254 		if (**RS == sep || c == EOF)
255 			break;
256 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
257 			break;
258 		*rr++ = '\n';
259 		*rr++ = c;
260 	}
261 	/*if (rr > *buf + *bufsize)
262 		error(MM_ERROR, ":12:Input record `%.20s...' too long", *buf);*/
263 	*rr = 0;
264 	dprintf( ("readrec saw <%s>, returns %d\n", *buf, c == EOF
265 		&& rr == *buf ? 0 : 1) );
266 	return c == EOF && rr == *buf ? 0 : 1;
267 }
268 
getargv(int n)269 unsigned char *getargv(int n)	/* get ARGV[n] */
270 {
271 	Cell *x;
272 	unsigned char *s, temp[25];
273 	extern Array *ARGVtab;
274 
275 	snprintf((char *)temp, sizeof temp, "%d", n);
276 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
277 	s = getsval(x);
278 	dprintf( ("getargv(%d) returns |%s|\n", n, s) );
279 	return s;
280 }
281 
setclvar(unsigned char * s)282 void setclvar(unsigned char *s)	/* set var=value from s */
283 {
284 	unsigned char *p;
285 	Cell *q;
286 
287 	for (p=s; *p != '='; p++)
288 		;
289 	*p++ = 0;
290 	p = qstring(p, '\0');
291 	q = setsymtab(s, p, 0.0, STR, symtab);
292 	setsval(q, p);
293 	(void)is2number(0, q);
294 	dprintf( ("command line set %s to |%s|\n", s, p) );
295 }
296 
297 static void	cleanfld(int n1, int n2);
298 static int	refldbld(unsigned char *rec, unsigned char *fs);
299 
300 void
fldbld(void)301 fldbld(void)
302 {
303 	register unsigned char *r, *fr;
304 	Cell **p;
305 	wchar_t wc, sep;
306 	int i, n;
307 
308 	if (donefld)
309 		return;
310 	if (!(recloc->tval & STR))
311 		getsval(recloc);
312 	r = recloc->sval;	/* was record! */
313 	fr = fields;
314 	i = 0;	/* number of fields accumulated here */
315 	if ((sep = **FS) != '\0' && (next(sep, *FS, n), (*FS)[n] != '\0')) {
316 		/* it's a regular expression */
317 		i = refldbld(r, *FS);
318 	} else if (sep == ' ') {
319 		for (i = 0; ; ) {
320 			while (*r == ' ' || *r == '\t' || *r == '\n')
321 				r++;
322 			if (*r == 0)
323 				break;
324 			i++;
325 			if (i >= MAXFLD)
326 				morefields();
327 			if (!(fldtab[i]->tval & DONTFREE))
328 				xfree(fldtab[i]->sval);
329 			fldtab[i]->sval = fr;
330 			fldtab[i]->tval = FLD | STR | DONTFREE;
331 			next(wc, r, n);
332 			do {
333 				do
334 					*fr++ = *r++;
335 				while (--n);
336 				next(wc, r, n);
337 			} while (wc != ' ' && wc != '\t' && wc != '\n' &&
338 					wc != '\0');
339 			*fr++ = 0;
340 		}
341 		*fr = 0;
342 	} else if (*r != 0) {	/* if 0, it's a null field */
343 		for (;;) {
344 			i++;
345 			if (i >= MAXFLD)
346 				morefields();
347 			if (!(fldtab[i]->tval & DONTFREE))
348 				xfree(fldtab[i]->sval);
349 			fldtab[i]->sval = fr;
350 			fldtab[i]->tval = FLD | STR | DONTFREE;
351 			while (next(wc, r, n),
352 					wc != sep && wc != '\n' && wc != '\0') {
353 					/* \n always a separator */
354 				do
355 					*fr++ = *r++;
356 				while (--n);
357 			}
358 			*fr++ = '\0';
359 			if (wc == '\0')
360 				break;
361 			r += n;
362 		}
363 		*fr = 0;
364 	}
365 	/*if (i >= MAXFLD)
366 		error(MM_ERROR, ":13:Record `%.20s...' has too many fields",
367 			record);*/
368 	/* clean out junk from previous record */
369 	cleanfld(i, maxfld);
370 	maxfld = i;
371 	donefld = 1;
372 	for (p = &fldtab[1]; p <= &fldtab[0]+maxfld; p++)
373 		(void)is2number(0, *p);
374 	setfval(nfloc, (Awkfloat) maxfld);
375 	if (dbg)
376 		for (p = &fldtab[0]; p <= &fldtab[0]+maxfld; p++)
377 			pfmt(stdout, MM_INFO, ":14:field %d: |%s|\n", p-&fldtab[0],
378 				(*p)->sval);
379 }
380 
cleanfld(int n1,int n2)381 static void cleanfld(int n1, int n2)	/* clean out fields n1..n2 inclusive */
382 {
383 	static unsigned char *nullstat = (unsigned char *) "";
384 	register Cell **p, **q;
385 
386 	for (p = &fldtab[n2], q = &fldtab[n1]; p > q; p--) {
387 		if (!((*p)->tval & DONTFREE))
388 			xfree((*p)->sval);
389 		(*p)->tval = FLD | STR | DONTFREE;
390 		(*p)->sval = nullstat;
391 	}
392 }
393 
newfld(int n)394 void newfld(int n)	/* add field n (after end) */
395 {
396 	/*if (n >= MAXFLD)
397 		error(MM_ERROR, ":15:Creating too many fields", record);*/
398 	while (n >= MAXFLD)
399 		morefields();
400 	cleanfld(maxfld, n);
401 	maxfld = n;
402 	setfval(nfloc, (Awkfloat) n);
403 }
404 
refldbld(unsigned char * rec,unsigned char * fs)405 static int refldbld(unsigned char *rec,
406 		unsigned char *fs)	/* build fields from reg expr in FS */
407 {
408 	unsigned char *fr;
409 	int i;
410 	fa *pfa;
411 
412 	fr = fields;
413 	*fr = '\0';
414 	if (*rec == '\0')
415 		return 0;
416 	pfa = makedfa(fs, 1);
417 	dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec,
418 		fs) );
419 	pfa->notbol = 0;
420 	for (i = 1; ; i++) {
421 		if (i >= MAXFLD)
422 			morefields();
423 		if (!(fldtab[i]->tval & DONTFREE))
424 			xfree(fldtab[i]->sval);
425 		fldtab[i]->tval = FLD | STR | DONTFREE;
426 		fldtab[i]->sval = fr;
427 		dprintf( ("refldbld: i=%d\n", i) );
428 		if (nematch(pfa, rec)) {
429 			pfa->notbol = REG_NOTBOL;
430 			dprintf( ("match %s (%d chars\n",
431 				patbeg, patlen) );
432 			strncpy((char*) fr, (char*) rec, patbeg-rec);
433 			fr += patbeg - rec + 1;
434 			*(fr-1) = '\0';
435 			rec = patbeg + patlen;
436 		} else {
437 			dprintf( ("no match %s\n", rec) );
438 			strcpy((char*) fr, (char*) rec);
439 			pfa->notbol = 0;
440 			break;
441 		}
442 	}
443 	return i;
444 }
445 
recbld(void)446 void recbld(void)
447 {
448 	int i;
449 	unsigned char *r, *p;
450 
451 	if (donerec == 1)
452 		return;
453 	r = recdata;
454 	for (i = 1; i <= *NF; i++) {
455 		p = getsval(fldtab[i]);
456 		while ((*r = *p++)) {
457 			if (++r >= &recdata[recsize]) {
458 				recsize += CHUNK;
459 				growrec(&recdata, &recsize, recsize, &r, 1);
460 			}
461 		}
462 		if (i < *NF)
463 			for ((p = *OFS); (*r = *p++); ) {
464 				if (++r >= &recdata[recsize]) {
465 					recsize += CHUNK;
466 					growrec(&recdata, &recsize,
467 							recsize, &r, 1);
468 				}
469 			}
470 	}
471 	*r = '\0';
472 	dprintf( ("in recbld FS=%o, recloc=%lo\n", **FS,
473 		(long)recloc) );
474 	recloc->tval = REC | STR | DONTFREE;
475 	recloc->sval = record = recdata;
476 	dprintf( ("in recbld FS=%o, recloc=%lo\n", **FS,
477 		(long)recloc) );
478 	dprintf( ("recbld = |%s|\n", record) );
479 	donerec = 1;
480 }
481 
fieldadr(int n)482 Cell *fieldadr(int n)
483 {
484 	if (n < 0)
485 		error(MM_ERROR, ":17:Trying to access field %d", n);
486 	while (n >= MAXFLD)
487 		morefields();
488 	return(fldtab[n]);
489 }
490 
491 int	errorflag	= 0;
492 char	errbuf[200];
493 
494 static int been_here = 0;
495 static char
496 	atline[] = ":18: at source line %d",
497 	infunc[] = ":19: in function %s";
498 
499 void
vyyerror(const char * msg,...)500 vyyerror(const char *msg, ...)
501 {
502 	extern unsigned char *curfname;
503 	va_list args;
504 
505 	if (been_here++ > 2)
506 		return;
507 	va_start(args, msg);
508 	vpfmt(stderr, MM_ERROR, msg, args);
509 	pfmt(stderr, MM_NOSTD, atline, lineno);
510 	if (curfname != NULL)
511 		pfmt(stderr, MM_NOSTD, infunc, curfname);
512 	fprintf(stderr, "\n");
513 	errorflag = 2;
514 	eprint();
515 
516 	va_end(args);
517 }
518 
519 void
yyerror(char * s)520 yyerror(char *s)
521 {
522 	extern unsigned char /**cmdname,*/ *curfname;
523 	static int been_here = 0;
524 
525 	if (been_here++ > 2)
526 		return;
527 	pfmt(stderr, (MM_ERROR | MM_NOGET), "%s", s);
528 	pfmt(stderr, MM_NOSTD, atline, lineno);
529 	if (curfname != NULL)
530 		pfmt(stderr, MM_NOSTD, infunc, curfname);
531 	fprintf(stderr, "\n");
532 	errorflag = 2;
533 	eprint();
534 }
535 
536 /*ARGSUSED*/
fpecatch(int signo)537 void fpecatch(int signo)
538 {
539 	error(MM_ERROR, ":20:Floating point exception");
540 }
541 
542 extern int bracecnt, brackcnt, parencnt;
543 static void bcheck2(int n, int c1, int c2);
544 
bracecheck(void)545 void bracecheck(void)
546 {
547 	int c;
548 	static int beenhere = 0;
549 
550 	if (beenhere++)
551 		return;
552 	while ((c = awk_input()) != EOF && c != '\0')
553 		bclass(c);
554 	bcheck2(bracecnt, '{', '}');
555 	bcheck2(brackcnt, '[', ']');
556 	bcheck2(parencnt, '(', ')');
557 }
558 
bcheck2(int n,int c1,int c2)559 static void bcheck2(int n, int c1, int c2)
560 {
561 	if (n == 1)
562 		pfmt(stderr, MM_ERROR, ":21:Missing %c\n", c2);
563 	else if (n > 1)
564 		pfmt(stderr, MM_ERROR, ":22:%d missing %c's\n", n, c2);
565 	else if (n == -1)
566 		pfmt(stderr, MM_ERROR, ":23:Extra %c\n", c2);
567 	else if (n < -1)
568 		pfmt(stderr, MM_ERROR, ":24:%d extra %c's\n", -n, c2);
569 }
570 
571 void
error(int flag,const char * msg,...)572 error(int flag, const char *msg, ...)
573 {
574 	int errline;
575 	extern Node *curnode;
576 	/*extern unsigned char *cmdname;*/
577 	va_list args;
578 
579 	fflush(stdout);
580 	va_start(args, msg);
581 	vpfmt(stderr, flag, msg, args);
582 	putc('\n', stderr);
583 
584 	if (compile_time != 2 && NR && *NR > 0) {
585 		pfmt(stderr, MM_INFO,
586 			":25:Input record number %g", *FNR);
587 		if (strcmp((char*) *FILENAME, "-") != 0)
588 			pfmt(stderr, MM_NOSTD,
589 				":26:, file %s", *FILENAME);
590 		fprintf(stderr, "\n");
591 	}
592 	errline = 0;
593 	if (compile_time != 2 && curnode)
594 		errline = curnode->lineno;
595 	else if (compile_time != 2 && lineno)
596 		errline = lineno;
597 	if (errline)
598 		pfmt(stderr, MM_INFO, ":27:Source line number %d\n", errline);
599 	eprint();
600 	if (flag == MM_ERROR) {
601 		if (dbg)
602 			abort();
603 		exit(2);
604 	}
605 	va_end(args);
606 }
607 
eprint(void)608 static void eprint(void)	/* try to print context around error */
609 {
610 	unsigned char *p, *q, *r;
611 	int c, episnul;
612 	static int been_here = 0;
613 	extern unsigned char ebuf[300], *ep;
614 
615 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
616 		return;
617 	episnul = ep > ebuf && ep[-1] == '\0';
618 	p = ep - 1 - episnul;
619 	if (p > ebuf && *p == '\n')
620 		p--;
621 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
622 		;
623 	while (*p == '\n')
624 		p++;
625 	if (0 /* posix */)
626 		pfmt(stderr, MM_INFO, ":28:Context is\n\t");
627 	else
628 		pfmt(stderr, MM_INFO|MM_NOSTD, ":2228: context is\n\t");
629 	for (q=ep-1-episnul; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
630 		;
631 	for (r = q; r < ep; r++) {
632 		if (*r != ' ' && *r != '\t' && *r != '\n') {
633 			for ( ; p < q; p++)
634 				if (*p)
635 					putc(*p, stderr);
636 			break;
637 		}
638 	}
639 	fprintf(stderr, " >>> ");
640 	for ( ; p < ep; p++)
641 		if (*p)
642 			putc(*p, stderr);
643 	fprintf(stderr, " <<< ");
644 	if (*ep)
645 		while ((c = awk_input()) != '\n' && c != '\0' && c != EOF) {
646 			putc(c, stderr);
647 			bclass(c);
648 		}
649 	putc('\n', stderr);
650 	ep = ebuf;
651 }
652 
bclass(int c)653 void bclass(int c)
654 {
655 	switch (c) {
656 	case '{': bracecnt++; break;
657 	case '}': bracecnt--; break;
658 	case '[': brackcnt++; break;
659 	case ']': brackcnt--; break;
660 	case '(': parencnt++; break;
661 	case ')': parencnt--; break;
662 	}
663 }
664 
errcheck(double x,unsigned char * s)665 double errcheck(double x, unsigned char *s)
666 {
667 	if (errno == EDOM) {
668 		errno = 0;
669 		error(MM_WARNING, ":29:%s argument out of domain", s);
670 		x = 1;
671 	} else if (errno == ERANGE) {
672 		errno = 0;
673 		error(MM_WARNING, ":30:%s result out of range", s);
674 		x = 1;
675 	}
676 	return x;
677 }
678 
PUTS(unsigned char * s)679 void PUTS(unsigned char *s) {
680 	dprintf( ("%s\n", s) );
681 }
682 
isclvar(unsigned char * s)683 int isclvar(unsigned char *s)	/* is s of form var=something? */
684 {
685 	unsigned char *os = s;
686 
687 	for ( ; *s; s++)
688 		if (!(alnumchar(*s) || *s == '_'))
689 			break;
690 	return *s == '=' && s > os && *(s+1) != '=' && !digitchar(*os);
691 }
692 
is2number(register unsigned char * s,Cell * p)693 int is2number(register unsigned char *s, Cell *p)
694 {
695 	unsigned char *after;
696 	Awkfloat val;
697 
698 	/*
699 	* POSIX.2 says leading <blank>s are skipped and that
700 	* <blank> is at least ' ' and '\t' and can include other
701 	* characters, but not in the "POSIX" (aka "C") locale.
702 	*
703 	* The historic code skipped those two and newline.  So,
704 	* unless it's noticed by some test suite, we choose to
705 	* keep things compatible.  To be safe, reject the string
706 	* if it starts with other white space characters since
707 	* strtod() skips any form of white space.
708 	*
709 	* Permit similarly spelled trailing white space for
710 	* compatibility.
711 	*/
712 	if (p != 0)
713 		s = p->sval;
714 	while (*s == ' ' || *s == '\t' || *s == '\n')
715 		s++;
716 	if (isspace(*s))
717 		return 0;
718 	/*
719 	 * Reject hexadecimal numbers, infinity and NaN strings which
720 	 * are recognized by C99 strtod() implementations.
721 	 */
722 	switch (*s) {
723 	case '0':
724 		if (s[1] == 'x' || s[1] == 'X')
725 			return 0;
726 		break;
727 	case 'i':
728 	case 'I':
729 		if (strncasecmp((char *)s, "inf", 3) == 0)
730 			return 0;
731 		break;
732 	case 'n':
733 	case 'N':
734 		if (strncasecmp((char *)s, "NaN", 3) == 0)
735 			return 0;
736 		break;
737 	}
738 	val = strtod((char *)s, (char **)&after);
739 	for (s = after; *s == ' ' || *s == '\t' || *s == '\n'; s++)
740 		;
741 	if (*s != '\0')
742 		return 0;
743 	if (p != 0) {
744 		p->fval = val;
745 		p->tval |= NUM;
746 	}
747 	return 1;
748 }
749 
750 double
awk_atof(const char * s)751 awk_atof(const char *s)
752 {
753 	wchar_t	wc;
754 	int	n;
755 
756 	while (*s) {
757 		next(wc, s, n);
758 		if (!(mb_cur_max > 1 ? iswspace(wc) : isspace(wc)))
759 			break;
760 		s += n;
761 	}
762 	/*
763 	 * Return 0 for hexadecimal numbers, infinity and NaN strings which
764 	 * are recognized by C99 atof() implementations.
765 	 */
766 	switch (*s) {
767 	case '0':
768 		if (s[1] == 'x' || s[1] == 'X')
769 			return 0;
770 		break;
771 	case 'i':
772 	case 'I':
773 		if (strncasecmp(s, "inf", 3) == 0)
774 			return 0;
775 		break;
776 	case 'n':
777 	case 'N':
778 		if (strncasecmp(s, "NaN", 3) == 0)
779 			return 0;
780 		break;
781 	}
782 	return atof(s);
783 }
784 
makerec(const unsigned char * data,int size)785 unsigned char *makerec(const unsigned char *data, int size)
786 {
787 	if (!(recloc->tval & DONTFREE))
788 		xfree(recloc->sval);
789 	if (recsize < size)
790 		growrec(&recdata, &recsize, size, NULL, 0);
791 	record = recdata;
792 	strcpy((char*)record, (char*)data);
793 	recloc->sval = record;
794 	recloc->tval = REC | STR | DONTFREE;
795 	donerec = 1; donefld = 0;
796 	return record;
797 }
798 
growrec(unsigned char ** buf,int * bufsize,int newsize,unsigned char ** ptr,int bld)799 static void growrec(unsigned char **buf, int *bufsize, int newsize,
800 		unsigned char **ptr, int bld)
801 {
802 	unsigned char	*np, *op;
803 
804 	op = *buf;
805 	if ((np = realloc(op, *bufsize = newsize)) == 0) {
806 		oflo:	if (bld)
807 				error(MM_ERROR,
808 					":16:Built giant record `%.20s...'",
809 					*buf);
810 			else
811 				error(MM_ERROR,
812 					":12:Input record `%.20s...' too long",
813 					*buf);
814 	}
815 	if (ptr && *ptr)
816 		*ptr = &np[*ptr - op];
817 	if (record == op)
818 		record = np;
819 	if (recdata == op) {
820 		recdata = np;
821 		recsize = *bufsize;
822 		if ((fields = realloc(fields, recsize)) == NULL)
823 			goto oflo;
824 	}
825 	if (fldtab[0]->sval == op)
826 		fldtab[0]->sval = np;
827 	if (recloc->sval == op)
828 		recloc->sval = np;
829 	*buf = np;
830 }
831 
832 int
vpfmt(FILE * stream,long flags,const char * fmt,va_list ap)833 vpfmt(FILE *stream, long flags, const char *fmt, va_list ap)
834 {
835 	extern char	*pfmt_label__;
836 	int	n = 0;
837 
838 	if ((flags & MM_NOGET) == 0) {
839 		if (*fmt == ':') {
840 			do
841 				fmt++;
842 			while (*fmt != ':');
843 			fmt++;
844 		}
845 	}
846 	if ((flags & MM_NOSTD) == 0)
847 		n += fprintf(stream, "%s: ", pfmt_label__);
848 	if ((flags & MM_ACTION) == 0 && isupper(*fmt&0377))
849 		n += fprintf(stream, "%c", tolower(*fmt++&0377));
850 	n += vfprintf(stream, fmt, ap);
851 	return n;
852 }
853