Import NetBSD nawk
This commit is contained in:
		
							parent
							
								
									a23f4844ba
								
							
						
					
					
						commit
						5ea9e707be
					
				@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
.include <bsd.own.mk>
 | 
			
		||||
 | 
			
		||||
SUBDIR=	add_route arp ash at awk \
 | 
			
		||||
SUBDIR=	add_route arp ash at \
 | 
			
		||||
	backup badblocks banner basename \
 | 
			
		||||
	btrace cal \
 | 
			
		||||
	cawf cd  cdprobe checkhier cpp \
 | 
			
		||||
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
.include <bsd.own.mk>
 | 
			
		||||
 | 
			
		||||
PROG=	awk
 | 
			
		||||
SRCS=	awkgram.y b.c lex.c lib.c main.c parse.c proctab.c run.c tran.c
 | 
			
		||||
LDADD= -lm
 | 
			
		||||
DEPEND+= ${LIBM}
 | 
			
		||||
YHEADER=	yes
 | 
			
		||||
QUIET_YACC=	yes
 | 
			
		||||
 | 
			
		||||
CPPFLAGS+= -I. -I${.CURDIR}
 | 
			
		||||
 | 
			
		||||
build-tools: maketab
 | 
			
		||||
 | 
			
		||||
proctab.c: maketab
 | 
			
		||||
	./maketab > proctab.c
 | 
			
		||||
 | 
			
		||||
maketab.lo: awkgram.h
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
maketab: maketab.lo
 | 
			
		||||
	${HOST_LINK.c} maketab.lo -o $@
 | 
			
		||||
 | 
			
		||||
CLEANFILES= maketab proctab.c maketab.lo
 | 
			
		||||
 | 
			
		||||
.include <bsd.prog.mk>
 | 
			
		||||
							
								
								
									
										2
									
								
								external/Makefile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								external/Makefile
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,3 @@
 | 
			
		||||
SUBDIR=bsd
 | 
			
		||||
SUBDIR=bsd historical
 | 
			
		||||
 | 
			
		||||
.include <bsd.subdir.mk>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								external/historical/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								external/historical/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
#	$NetBSD: Makefile,v 1.1 2010/08/26 14:57:15 christos Exp $
 | 
			
		||||
 | 
			
		||||
.include <bsd.own.mk>
 | 
			
		||||
 | 
			
		||||
SUBDIR+= nawk
 | 
			
		||||
 | 
			
		||||
.include <bsd.subdir.mk>
 | 
			
		||||
							
								
								
									
										5
									
								
								external/historical/nawk/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								external/historical/nawk/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
#	$NetBSD: Makefile,v 1.1 2010/08/26 14:57:16 christos Exp $
 | 
			
		||||
 | 
			
		||||
SUBDIR+= bin
 | 
			
		||||
 | 
			
		||||
.include <bsd.subdir.mk>
 | 
			
		||||
							
								
								
									
										41
									
								
								external/historical/nawk/bin/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								external/historical/nawk/bin/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#	$NetBSD: Makefile,v 1.8 2011/08/16 10:45:37 christos Exp $
 | 
			
		||||
 | 
			
		||||
WARNS?= 4
 | 
			
		||||
CWARNFLAGS.clang+=	-Wno-self-assign
 | 
			
		||||
 | 
			
		||||
.include <bsd.own.mk>
 | 
			
		||||
 | 
			
		||||
BINDIR?= /usr/bin
 | 
			
		||||
DIST=	${.CURDIR}/../dist
 | 
			
		||||
.PATH:	${DIST}
 | 
			
		||||
 | 
			
		||||
PROG=	awk
 | 
			
		||||
SRCS=	awkgram.y b.c lex.c lib.c main.c parse.c proctab.c run.c tran.c
 | 
			
		||||
CPPFLAGS+=	-I${DIST} -I.
 | 
			
		||||
LDADD+=	-lm
 | 
			
		||||
.if !defined(HOSTPROG)
 | 
			
		||||
DPADD+=	${LIBM}
 | 
			
		||||
.endif
 | 
			
		||||
YHEADER=	yes
 | 
			
		||||
.if defined(HAVE_GCC) || defined(HAVE_PCC)
 | 
			
		||||
COPTS+=	-Wno-pointer-sign
 | 
			
		||||
.endif
 | 
			
		||||
COPTS.run.c += -Wno-format-nonliteral
 | 
			
		||||
COPTS.tran.c += -Wno-format-nonliteral
 | 
			
		||||
 | 
			
		||||
# info file originally from GNU awk 3.1.3, adjusted for nawk slightly
 | 
			
		||||
# Don't install on Minix, we don't have it.
 | 
			
		||||
#.PATH:	${NETBSDSRCDIR}/external/gpl2/gawk/dist
 | 
			
		||||
#TEXINFO=        awk.info
 | 
			
		||||
 | 
			
		||||
# During the tools build (from src/tools/awk/Makefile),
 | 
			
		||||
# src/tools/Makefile.host changes .CURDIR back and forth between
 | 
			
		||||
# src/tools/awk and src/usr.bin/awk.  For some unknown reason, including
 | 
			
		||||
# bsd.info.mk here leads to the obj dir being created at the wrong time,
 | 
			
		||||
# while .CURDIR is src/usr.bin/awk.  Work around the problem by not
 | 
			
		||||
# including bsd.info.mk when MKINFO=no.
 | 
			
		||||
.if ${MKINFO} != "no"
 | 
			
		||||
.include <bsd.info.mk>
 | 
			
		||||
.endif
 | 
			
		||||
 | 
			
		||||
.include <bsd.prog.mk>
 | 
			
		||||
							
								
								
									
										22
									
								
								external/historical/nawk/bin/TODO
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								external/historical/nawk/bin/TODO
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
$NetBSD: TODO,v 1.1 2010/08/26 14:57:16 christos Exp $
 | 
			
		||||
 | 
			
		||||
Besides general regression testing to ensure everything still works
 | 
			
		||||
with nawk instead of gawk, following GNU awk extensions should be implemented
 | 
			
		||||
or handled somehow (the list is probably incomplete, please add entries 
 | 
			
		||||
if anything is missing):
 | 
			
		||||
 | 
			
		||||
* String functions: gensub() (partly done, finish backref. support)
 | 
			
		||||
* (done) Time functions: strftime(), systime()
 | 
			
		||||
* --posix flag, which would switch off nawk extensions over POSIX awk (?)
 | 
			
		||||
* special file names: /dev/pid, /dev/ppid, /dev/pgrpid, /dev/user,
 | 
			
		||||
	/dev/stdin, /dev/stdout, /dev/stderr, /dev/fd/X
 | 
			
		||||
* special variables: ARGIND, ERRNO, FIELDWIDTHS, IGNORECASE, RT
 | 
			
		||||
 | 
			
		||||
Also, the manpage should be improved to be generally more helpful
 | 
			
		||||
and document extensions over what POSIX says about awk.
 | 
			
		||||
 | 
			
		||||
Other misc:
 | 
			
		||||
* run.c: don't limit files[] to FOPEN_MAX (which is ridiculously low),
 | 
			
		||||
  make the limit the current process open file limit
 | 
			
		||||
* nawk doesn't permit empty RE, like
 | 
			
		||||
// { do_something; }
 | 
			
		||||
							
								
								
									
										732
									
								
								external/historical/nawk/bin/awk.1
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										732
									
								
								external/historical/nawk/bin/awk.1
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,732 @@
 | 
			
		||||
.\"	$NetBSD: awk.1,v 1.2 2011/04/20 10:10:32 drochner Exp $
 | 
			
		||||
.\"
 | 
			
		||||
.\" Copyright (C) Lucent Technologies 1997
 | 
			
		||||
.\" All Rights Reserved
 | 
			
		||||
.\"
 | 
			
		||||
.\" Permission to use, copy, modify, and distribute this software and
 | 
			
		||||
.\" its documentation for any purpose and without fee is hereby
 | 
			
		||||
.\" granted, provided that the above copyright notice appear in all
 | 
			
		||||
.\" copies and that both that the copyright notice and this
 | 
			
		||||
.\" permission notice and warranty disclaimer appear in supporting
 | 
			
		||||
.\" documentation, and that the name Lucent Technologies or any of
 | 
			
		||||
.\" its entities not be used in advertising or publicity pertaining
 | 
			
		||||
.\" to distribution of the software without specific, written prior
 | 
			
		||||
.\" permission.
 | 
			
		||||
.\"
 | 
			
		||||
.\" LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
			
		||||
.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
 | 
			
		||||
.\" IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
 | 
			
		||||
.\" SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 | 
			
		||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 | 
			
		||||
.\" ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 | 
			
		||||
.\" THIS SOFTWARE.
 | 
			
		||||
.\"
 | 
			
		||||
.Dd May 25, 2008
 | 
			
		||||
.Dt AWK 1
 | 
			
		||||
.Os
 | 
			
		||||
.Sh NAME
 | 
			
		||||
.Nm awk
 | 
			
		||||
.Nd pattern-directed scanning and processing language
 | 
			
		||||
.Sh SYNOPSIS
 | 
			
		||||
.Nm
 | 
			
		||||
.Op Fl F Ar fs
 | 
			
		||||
.Op Fl v Ar var=value
 | 
			
		||||
.Op Fl safe
 | 
			
		||||
.Op Fl d Ns Op Ar N
 | 
			
		||||
.Op Ar prog | Fl f Ar filename
 | 
			
		||||
.Ar
 | 
			
		||||
.Nm
 | 
			
		||||
.Fl version
 | 
			
		||||
.Sh DESCRIPTION
 | 
			
		||||
.Nm
 | 
			
		||||
is the Bell Labs' implementation of the AWK programming language as
 | 
			
		||||
described in the
 | 
			
		||||
.Em The AWK Programming Language
 | 
			
		||||
by
 | 
			
		||||
A. V. Aho, B. W. Kernighan, and P. J. Weinberger.
 | 
			
		||||
.Pp
 | 
			
		||||
.Nm
 | 
			
		||||
scans each input
 | 
			
		||||
.Ar file
 | 
			
		||||
for lines that match any of a set of patterns specified literally in
 | 
			
		||||
.Ar prog
 | 
			
		||||
or in one or more files
 | 
			
		||||
specified as
 | 
			
		||||
.Fl f Ar filename .
 | 
			
		||||
With each pattern
 | 
			
		||||
there can be an associated action that will be performed
 | 
			
		||||
when a line of a
 | 
			
		||||
.Ar file
 | 
			
		||||
matches the pattern.
 | 
			
		||||
Each line is matched against the
 | 
			
		||||
pattern portion of every pattern-action statement;
 | 
			
		||||
the associated action is performed for each matched pattern.
 | 
			
		||||
The file name
 | 
			
		||||
.Ar -
 | 
			
		||||
means the standard input.
 | 
			
		||||
Any
 | 
			
		||||
.Ar file
 | 
			
		||||
of the form
 | 
			
		||||
.Ar var=value
 | 
			
		||||
is treated as an assignment, not a filename,
 | 
			
		||||
and is executed at the time it would have been opened if it were a filename.
 | 
			
		||||
.Pp
 | 
			
		||||
The options are as follows:
 | 
			
		||||
.Bl -tag -width indent
 | 
			
		||||
.It Fl d Ns Op Ar N
 | 
			
		||||
Set debug level to specified number
 | 
			
		||||
.Ar N .
 | 
			
		||||
If the number is omitted, debug level is set to 1.
 | 
			
		||||
.It Fl f Ar filename
 | 
			
		||||
Read the AWK program source from specified file
 | 
			
		||||
.Ar filename ,
 | 
			
		||||
instead of the first command line argument.
 | 
			
		||||
Multiple
 | 
			
		||||
.Fl f
 | 
			
		||||
options may be specified.
 | 
			
		||||
.It Fl F Ar fs
 | 
			
		||||
Set the input field separator
 | 
			
		||||
.Va FS
 | 
			
		||||
to the regular expression
 | 
			
		||||
.Ar fs .
 | 
			
		||||
.It Fl mr Ar NNN , Fl mf Ar NNN
 | 
			
		||||
Obsolete, no longer needed options.
 | 
			
		||||
Set limit on maximum record or
 | 
			
		||||
fields number.
 | 
			
		||||
.It Fl safe
 | 
			
		||||
Potentially unsafe functions such as
 | 
			
		||||
.Fn system
 | 
			
		||||
make the program abort (with a warning message).
 | 
			
		||||
.It Fl v Ar var Ns = Ns Ar value
 | 
			
		||||
Assign the value
 | 
			
		||||
.Ar value
 | 
			
		||||
to the variable
 | 
			
		||||
.Va var
 | 
			
		||||
before
 | 
			
		||||
.Ar prog
 | 
			
		||||
is executed.
 | 
			
		||||
Any number of
 | 
			
		||||
.Fl v
 | 
			
		||||
options may be present.
 | 
			
		||||
.It Fl version
 | 
			
		||||
Print
 | 
			
		||||
.Nm
 | 
			
		||||
version on standard output and exit.
 | 
			
		||||
.El
 | 
			
		||||
.Pp
 | 
			
		||||
An input line is normally made up of fields separated by white space,
 | 
			
		||||
or by regular expression
 | 
			
		||||
.Va FS .
 | 
			
		||||
The fields are denoted
 | 
			
		||||
.Va $1 ,
 | 
			
		||||
.Va $2 ,
 | 
			
		||||
\&..., while
 | 
			
		||||
.Va $0
 | 
			
		||||
refers to the entire line.
 | 
			
		||||
If
 | 
			
		||||
.Va FS
 | 
			
		||||
is null, the input line is split into one field per character.
 | 
			
		||||
.Pp
 | 
			
		||||
A pattern-action statement has the form
 | 
			
		||||
.Lp
 | 
			
		||||
.Dl pattern \&{ action \&}
 | 
			
		||||
.Lp
 | 
			
		||||
A missing \&{ action \&}
 | 
			
		||||
means print the line;
 | 
			
		||||
a missing pattern always matches.
 | 
			
		||||
Pattern-action statements are separated by newlines or semicolons.
 | 
			
		||||
.Pp
 | 
			
		||||
An action is a sequence of statements.
 | 
			
		||||
Statements are terminated by
 | 
			
		||||
semicolons, newlines or right braces.
 | 
			
		||||
An empty
 | 
			
		||||
.Ar expression-list
 | 
			
		||||
stands for
 | 
			
		||||
.Va $0 .
 | 
			
		||||
String constants are quoted
 | 
			
		||||
.Em \&"\ \&" ,
 | 
			
		||||
with the usual C escapes recognized within.
 | 
			
		||||
Expressions take on string or numeric values as appropriate,
 | 
			
		||||
and are built using the
 | 
			
		||||
.Sx Operators
 | 
			
		||||
(see next subsection).
 | 
			
		||||
Variables may be scalars, array elements
 | 
			
		||||
(denoted
 | 
			
		||||
.Va x[i] )
 | 
			
		||||
or fields.
 | 
			
		||||
Variables are initialized to the null string.
 | 
			
		||||
Array subscripts may be any string,
 | 
			
		||||
not necessarily numeric;
 | 
			
		||||
this allows for a form of associative memory.
 | 
			
		||||
Multiple subscripts such as
 | 
			
		||||
.Va [i,j,k]
 | 
			
		||||
are permitted; the constituents are concatenated,
 | 
			
		||||
separated by the value of
 | 
			
		||||
.Va SUBSEP .
 | 
			
		||||
.Ss Operators
 | 
			
		||||
.Nm
 | 
			
		||||
operators, in order of decreasing precedence, are:
 | 
			
		||||
.Pp
 | 
			
		||||
.Bl -tag -width ident -compact
 | 
			
		||||
.It Ic (...)
 | 
			
		||||
Grouping
 | 
			
		||||
.It Ic $
 | 
			
		||||
Field reference
 | 
			
		||||
.It Ic ++ --
 | 
			
		||||
Increment and decrement, can be used either as postfix or prefix.
 | 
			
		||||
.It Ic ^
 | 
			
		||||
Exponentiation (the
 | 
			
		||||
.Ic **
 | 
			
		||||
form is also supported, and
 | 
			
		||||
.Ic **=
 | 
			
		||||
for the assignment operator).
 | 
			
		||||
.It + - \&!
 | 
			
		||||
Unary plus, unary minus and logical negation.
 | 
			
		||||
.It * / %
 | 
			
		||||
Multiplication, division and modulus.
 | 
			
		||||
.It + -
 | 
			
		||||
Addition and subtraction.
 | 
			
		||||
.It Ar space
 | 
			
		||||
String concatenation.
 | 
			
		||||
.It Ic \*[Lt] \*[Gt]
 | 
			
		||||
.It Ic \*[Le] \*[Ge]
 | 
			
		||||
.It Ic != ==
 | 
			
		||||
Regular relational operators
 | 
			
		||||
.It Ic ~ !~
 | 
			
		||||
Regular expression match and not match
 | 
			
		||||
.It Ic in
 | 
			
		||||
Array membership
 | 
			
		||||
.It Ic "\*[Am]\*[Am]"
 | 
			
		||||
Logical AND
 | 
			
		||||
.It Ic "||"
 | 
			
		||||
Logical OR
 | 
			
		||||
.It Ic ?:
 | 
			
		||||
C conditional expression.
 | 
			
		||||
This is used as
 | 
			
		||||
.Ar expr1 Ic \&? Ar expr2 Ic \&: Ar expr3 No .
 | 
			
		||||
If
 | 
			
		||||
.Ar expr1
 | 
			
		||||
is true, the result value is
 | 
			
		||||
.Ar expr2 ,
 | 
			
		||||
otherwise it is
 | 
			
		||||
.Ar expr3 .
 | 
			
		||||
Only one of
 | 
			
		||||
.Ar expr2
 | 
			
		||||
and
 | 
			
		||||
.Ar expr3
 | 
			
		||||
is evaluated.
 | 
			
		||||
.It Ic = += -=
 | 
			
		||||
.It Ic *= /= %= ^=
 | 
			
		||||
Assignment and Operator-Assignment
 | 
			
		||||
.El
 | 
			
		||||
.Ss Control Statements
 | 
			
		||||
The control statements are as follows:
 | 
			
		||||
.Pp
 | 
			
		||||
.Bl -hang -offset indent -width indent -compact
 | 
			
		||||
.It Ic if \&( Ar expression Ic \&) Ar statement Bq Ic else Ar statement
 | 
			
		||||
.It Ic while \&( Ar expression Ic \&) Ar statement
 | 
			
		||||
.It Ic for \&( Ar expression Ic \&; Ar expression Ic \&; \
 | 
			
		||||
Ar expression Ic \&) Ar statement
 | 
			
		||||
.It Ic for \&( Va var Ic in Ar array Ic \&) Ar statement
 | 
			
		||||
.It Ic do Ar statement Ic while \&( Ar expression Ic \&)
 | 
			
		||||
.It Ic break
 | 
			
		||||
.It Ic continue
 | 
			
		||||
.It Ic delete Va array Bq Ar expression
 | 
			
		||||
.It Ic delete Va array
 | 
			
		||||
.It Ic exit Bq Ar expression
 | 
			
		||||
.Ar expression
 | 
			
		||||
.It Ic return Bq Ar expression
 | 
			
		||||
.It Ic \&{ Ar [ statement ... ] Ic \&}
 | 
			
		||||
.El
 | 
			
		||||
.Ss I/O Statements
 | 
			
		||||
The input/output statements are as follows:
 | 
			
		||||
.Pp
 | 
			
		||||
.Bl -tag -width indent
 | 
			
		||||
.It Fn close expr
 | 
			
		||||
Closes the file or pipe
 | 
			
		||||
.Ar expr .
 | 
			
		||||
Returns zero on success; otherwise nonzero.
 | 
			
		||||
.It Fn fflush expr
 | 
			
		||||
Flushes any buffered output for the file or pipe
 | 
			
		||||
.Ar expr .
 | 
			
		||||
Returns zero on success; otherwise nonzero.
 | 
			
		||||
.It Ic getline Bq Va var
 | 
			
		||||
Set
 | 
			
		||||
.Va var
 | 
			
		||||
(or
 | 
			
		||||
.Va $0 if
 | 
			
		||||
.Va var
 | 
			
		||||
is not specified)
 | 
			
		||||
to the next input record from the current input file.
 | 
			
		||||
.Ic getline
 | 
			
		||||
returns 1 for a successful input,
 | 
			
		||||
0 for end of file, and \-1 for an error.
 | 
			
		||||
.It Ic getline Bo Va var Bc Ic \*[Lt] Ar file
 | 
			
		||||
Set
 | 
			
		||||
.Va var
 | 
			
		||||
(or
 | 
			
		||||
.Va $0 if
 | 
			
		||||
.Va var
 | 
			
		||||
is not specified)
 | 
			
		||||
to the next input record from the specified file
 | 
			
		||||
.Ar file .
 | 
			
		||||
.It Ar expr Ic \&| getline
 | 
			
		||||
Pipes the output of
 | 
			
		||||
.Ar expr
 | 
			
		||||
into
 | 
			
		||||
.Ic getline ;
 | 
			
		||||
each call of
 | 
			
		||||
.Ic getline
 | 
			
		||||
returns the next line of output from
 | 
			
		||||
.Ar expr .
 | 
			
		||||
.It Ic next
 | 
			
		||||
Skip remaining patterns on this input line.
 | 
			
		||||
.It Ic nextfile
 | 
			
		||||
Skip rest of this file, open next, start at top.
 | 
			
		||||
.It Ic print Bo Ar expr-list Bc Bq Ic \*[Gt] Ar file
 | 
			
		||||
The
 | 
			
		||||
.Ic print
 | 
			
		||||
statement prints its arguments on the standard output (or to a file
 | 
			
		||||
if
 | 
			
		||||
.Ic \*[Gt] file
 | 
			
		||||
or to a pipe if
 | 
			
		||||
.Ic | Ar expr
 | 
			
		||||
is present),
 | 
			
		||||
separated by the current output field separator
 | 
			
		||||
.Va OFS ,
 | 
			
		||||
and terminated by the
 | 
			
		||||
output record separator
 | 
			
		||||
.Va ORS .
 | 
			
		||||
Both
 | 
			
		||||
.Ar file
 | 
			
		||||
and
 | 
			
		||||
.Ar expr
 | 
			
		||||
may be literal names or parenthesized expressions; identical string values in
 | 
			
		||||
different statements denote the same open file.
 | 
			
		||||
.It Ic printf Ar format Bo Ic \&, Ar expr-list Bc Bq Ic \*[Gt] Ar file
 | 
			
		||||
Format and print its expression list according to
 | 
			
		||||
.Ar format .
 | 
			
		||||
See
 | 
			
		||||
.Xr printf 3
 | 
			
		||||
for list of supported formats and their meaning.
 | 
			
		||||
.El
 | 
			
		||||
.Ss Mathematical and Numeric Functions
 | 
			
		||||
AWK has the following mathematical and numerical functions built-in:
 | 
			
		||||
.Pp
 | 
			
		||||
.Bl -tag -width indent
 | 
			
		||||
.It Fn atan2 x y
 | 
			
		||||
Returns the arctangent of
 | 
			
		||||
.Ar x Ic / Ar y
 | 
			
		||||
in radians.
 | 
			
		||||
See also
 | 
			
		||||
.Xr atan2 3 .
 | 
			
		||||
.It Fn cos expr
 | 
			
		||||
Computes the cosine of
 | 
			
		||||
.Ar expr ,
 | 
			
		||||
measured in radians.
 | 
			
		||||
See also
 | 
			
		||||
.Xr cos 3 .
 | 
			
		||||
.It Fn exp expr
 | 
			
		||||
Computes the exponential value of the given argument
 | 
			
		||||
.Ar expr .
 | 
			
		||||
See also
 | 
			
		||||
.Xr exp 3 .
 | 
			
		||||
.It Fn int expr
 | 
			
		||||
Truncates
 | 
			
		||||
.Ar expr
 | 
			
		||||
to integer.
 | 
			
		||||
.It Fn log expr
 | 
			
		||||
Computes the value of the natural logarithm of argument
 | 
			
		||||
.Ar expr .
 | 
			
		||||
See also
 | 
			
		||||
.Xr log 3 .
 | 
			
		||||
.It Fn rand
 | 
			
		||||
Returns random number between 0 and 1.
 | 
			
		||||
.It Fn sin expr
 | 
			
		||||
Computes the sine of
 | 
			
		||||
.Ar expr ,
 | 
			
		||||
measured in radians.
 | 
			
		||||
See also
 | 
			
		||||
.Xr sin 3 .
 | 
			
		||||
.It Fn sqrt expr
 | 
			
		||||
Computes the non-negative square root of
 | 
			
		||||
.Ar expr .
 | 
			
		||||
See also
 | 
			
		||||
.Xr sqrt 3 .
 | 
			
		||||
.It Fn srand [expr]
 | 
			
		||||
Sets seed for random number generator (
 | 
			
		||||
.Fn rand )
 | 
			
		||||
and returns the previous seed.
 | 
			
		||||
.El
 | 
			
		||||
.Ss String Functions
 | 
			
		||||
AWK has the following string functions built-in:
 | 
			
		||||
.Pp
 | 
			
		||||
.Bl -tag -width indent
 | 
			
		||||
.It Fn gensub r s h [t]
 | 
			
		||||
Search the target string
 | 
			
		||||
.Ar t
 | 
			
		||||
for matches of the regular expression
 | 
			
		||||
.Ar r .
 | 
			
		||||
If
 | 
			
		||||
.Ar h
 | 
			
		||||
is a string beginning with
 | 
			
		||||
.Ic g
 | 
			
		||||
or
 | 
			
		||||
.Ic G ,
 | 
			
		||||
then replace all matches of
 | 
			
		||||
.Ar r
 | 
			
		||||
with
 | 
			
		||||
.Ar s .
 | 
			
		||||
Otherwise,
 | 
			
		||||
.Ar h
 | 
			
		||||
is a number indicating which match of
 | 
			
		||||
.Ar r
 | 
			
		||||
to replace.
 | 
			
		||||
If no
 | 
			
		||||
.Ar t
 | 
			
		||||
is supplied,
 | 
			
		||||
.Va $0
 | 
			
		||||
is used instead.
 | 
			
		||||
.\"Within the replacement text
 | 
			
		||||
.\".Ar s ,
 | 
			
		||||
.\"the sequence
 | 
			
		||||
.\".Ar \en ,
 | 
			
		||||
.\"where
 | 
			
		||||
.\".Ar n
 | 
			
		||||
.\"is a digit from 1 to 9, may be used to indicate just the text that
 | 
			
		||||
.\"matched the
 | 
			
		||||
.\".Ar n Ap th
 | 
			
		||||
.\"parenthesized subexpression.
 | 
			
		||||
.\"The sequence
 | 
			
		||||
.\".Ic \e0
 | 
			
		||||
.\"represents the entire text, as does the character
 | 
			
		||||
.\".Ic & .
 | 
			
		||||
Unlike
 | 
			
		||||
.Fn sub
 | 
			
		||||
and
 | 
			
		||||
.Fn gsub ,
 | 
			
		||||
the modified string is returned as the result of the function,
 | 
			
		||||
and the original target is
 | 
			
		||||
.Em not
 | 
			
		||||
changed.
 | 
			
		||||
Note that the
 | 
			
		||||
.Ar \en
 | 
			
		||||
sequences within replacement string
 | 
			
		||||
.Ar s
 | 
			
		||||
supported by GNU
 | 
			
		||||
.Nm
 | 
			
		||||
are
 | 
			
		||||
.Em not
 | 
			
		||||
supported at this moment.
 | 
			
		||||
.It Fn gsub r t "[s]"
 | 
			
		||||
same as
 | 
			
		||||
.Fn sub
 | 
			
		||||
except that all occurrences of the regular expression
 | 
			
		||||
are replaced;
 | 
			
		||||
.Fn sub
 | 
			
		||||
and
 | 
			
		||||
.Fn gsub
 | 
			
		||||
return the number of replacements.
 | 
			
		||||
.It Fn index s t
 | 
			
		||||
the position in
 | 
			
		||||
.Ar s
 | 
			
		||||
where the string
 | 
			
		||||
.Ar t
 | 
			
		||||
occurs, or 0 if it does not.
 | 
			
		||||
.It Fn length "[string]"
 | 
			
		||||
the length of its argument
 | 
			
		||||
taken as a string,
 | 
			
		||||
or of
 | 
			
		||||
.Va $0
 | 
			
		||||
if no argument.
 | 
			
		||||
.It Fn match s r
 | 
			
		||||
the position in
 | 
			
		||||
.Ar s
 | 
			
		||||
where the regular expression
 | 
			
		||||
.Ar r
 | 
			
		||||
occurs, or 0 if it does not.
 | 
			
		||||
The variables
 | 
			
		||||
.Va RSTART
 | 
			
		||||
and
 | 
			
		||||
.Va RLENGTH
 | 
			
		||||
are set to the position and length of the matched string.
 | 
			
		||||
.It Fn split s a "[fs]"
 | 
			
		||||
splits the string
 | 
			
		||||
.Ar s
 | 
			
		||||
into array elements
 | 
			
		||||
.Va a[1] ,
 | 
			
		||||
.Va a[2] ,
 | 
			
		||||
\&...,
 | 
			
		||||
.Va a[n] ,
 | 
			
		||||
and returns
 | 
			
		||||
.Va n .
 | 
			
		||||
The separation is done with the regular expression
 | 
			
		||||
.Ar fs
 | 
			
		||||
or with the field separator
 | 
			
		||||
.Va FS
 | 
			
		||||
if
 | 
			
		||||
.Ar fs
 | 
			
		||||
is not given.
 | 
			
		||||
An empty string as field separator splits the string
 | 
			
		||||
into one array element per character.
 | 
			
		||||
.It Fn sprintf fmt expr "..."
 | 
			
		||||
Returns the string resulting from formatting
 | 
			
		||||
.Ar expr
 | 
			
		||||
according to the
 | 
			
		||||
.Xr printf 3
 | 
			
		||||
format
 | 
			
		||||
.Ar fmt .
 | 
			
		||||
.It Fn sub r t "[s]"
 | 
			
		||||
substitutes
 | 
			
		||||
.Ar t
 | 
			
		||||
for the first occurrence of the regular expression
 | 
			
		||||
.Ar r
 | 
			
		||||
in the string
 | 
			
		||||
.Ar s .
 | 
			
		||||
If
 | 
			
		||||
.Ar s
 | 
			
		||||
is not given,
 | 
			
		||||
.Va $0
 | 
			
		||||
is used.
 | 
			
		||||
.It Fn substr s m [n]
 | 
			
		||||
Returns the at most
 | 
			
		||||
.Ar n Ns No -character
 | 
			
		||||
substring of
 | 
			
		||||
.Ar s
 | 
			
		||||
starting at position
 | 
			
		||||
.Ar m ,
 | 
			
		||||
counted from 1.
 | 
			
		||||
If
 | 
			
		||||
.Ar n
 | 
			
		||||
is omitted, the rest of
 | 
			
		||||
.Ar s
 | 
			
		||||
is returned.
 | 
			
		||||
.It Fn tolower str
 | 
			
		||||
returns a copy of
 | 
			
		||||
.Ar str
 | 
			
		||||
with all upper-case characters translated to their
 | 
			
		||||
corresponding lower-case equivalents.
 | 
			
		||||
.It Fn toupper str
 | 
			
		||||
returns a copy of
 | 
			
		||||
.Ar str
 | 
			
		||||
with all lower-case characters translated to their
 | 
			
		||||
corresponding upper-case equivalents.
 | 
			
		||||
.El
 | 
			
		||||
.Ss Time Functions
 | 
			
		||||
This
 | 
			
		||||
.Nm
 | 
			
		||||
provides the following two functions for obtaining time
 | 
			
		||||
stamps and formatting them:
 | 
			
		||||
.Bl -tag -width indent
 | 
			
		||||
.It Fn systime
 | 
			
		||||
Returns the value of time in seconds since the start of
 | 
			
		||||
.Tn Unix
 | 
			
		||||
Epoch (Midnight, January 1, 1970, Coordinated Universal Time).
 | 
			
		||||
See also
 | 
			
		||||
.Xr time 3 .
 | 
			
		||||
.It Fn strftime "[format [, timestamp]]"
 | 
			
		||||
Formats the time
 | 
			
		||||
.Ar timestamp
 | 
			
		||||
according to the string
 | 
			
		||||
.Ar format .
 | 
			
		||||
.Ar timestamp
 | 
			
		||||
should be in same form as value returned by
 | 
			
		||||
.Fn systime .
 | 
			
		||||
If
 | 
			
		||||
.Ar timestamp
 | 
			
		||||
is missing, current time is used.
 | 
			
		||||
If
 | 
			
		||||
.Ar format
 | 
			
		||||
is missing, a default format equivalent to the output of
 | 
			
		||||
.Xr date 1
 | 
			
		||||
would be used.
 | 
			
		||||
See the specification of ANSI C
 | 
			
		||||
.Xr strftime 3
 | 
			
		||||
for the format conversions which are supported.
 | 
			
		||||
.El
 | 
			
		||||
.Ss Other built-in functions
 | 
			
		||||
.Bl -tag -width indent
 | 
			
		||||
.It Fn system cmd
 | 
			
		||||
executes
 | 
			
		||||
.Ar cmd
 | 
			
		||||
and returns its exit status
 | 
			
		||||
.El
 | 
			
		||||
.Ss Patterns
 | 
			
		||||
Patterns are arbitrary Boolean combinations
 | 
			
		||||
(with
 | 
			
		||||
.Ic "! || \*[Am]\*[Am]" )
 | 
			
		||||
of regular expressions and
 | 
			
		||||
relational expressions.
 | 
			
		||||
Regular expressions are as in
 | 
			
		||||
.Xr egrep 1 .
 | 
			
		||||
Isolated regular expressions
 | 
			
		||||
in a pattern apply to the entire line.
 | 
			
		||||
Regular expressions may also occur in
 | 
			
		||||
relational expressions, using the operators
 | 
			
		||||
.Ic ~
 | 
			
		||||
and
 | 
			
		||||
.Ic !~ .
 | 
			
		||||
.Ic / re /
 | 
			
		||||
is a constant regular expression;
 | 
			
		||||
any string (constant or variable) may be used
 | 
			
		||||
as a regular expression, except in the position of an isolated regular expression
 | 
			
		||||
in a pattern.
 | 
			
		||||
.Pp
 | 
			
		||||
A pattern may consist of two patterns separated by a comma;
 | 
			
		||||
in this case, the action is performed for all lines
 | 
			
		||||
from an occurrence of the first pattern
 | 
			
		||||
though an occurrence of the second.
 | 
			
		||||
.Pp
 | 
			
		||||
A relational expression is one of the following:
 | 
			
		||||
.Bl -tag -offset indent -width indent -compact
 | 
			
		||||
.It Ar expression matchop regular-expression
 | 
			
		||||
.It Ar expression relop expression
 | 
			
		||||
.It Ar expression Ic in Ar array-name
 | 
			
		||||
.It ( Ar expr , expr,\&... Ic ") in" Ar array-name
 | 
			
		||||
.El
 | 
			
		||||
.Pp
 | 
			
		||||
where a
 | 
			
		||||
.Ar relop
 | 
			
		||||
is any of the six relational operators in C,
 | 
			
		||||
and a
 | 
			
		||||
.Ar matchop
 | 
			
		||||
is either
 | 
			
		||||
.Ic ~
 | 
			
		||||
(matches)
 | 
			
		||||
or
 | 
			
		||||
.Ic !~
 | 
			
		||||
(does not match).
 | 
			
		||||
A conditional is an arithmetic expression,
 | 
			
		||||
a relational expression,
 | 
			
		||||
or a Boolean combination
 | 
			
		||||
of these.
 | 
			
		||||
.Pp
 | 
			
		||||
The special patterns
 | 
			
		||||
.Ic BEGIN
 | 
			
		||||
and
 | 
			
		||||
.Ic END
 | 
			
		||||
may be used to capture control before the first input line is read
 | 
			
		||||
and after the last.
 | 
			
		||||
.Ic BEGIN
 | 
			
		||||
and
 | 
			
		||||
.Ic END
 | 
			
		||||
do not combine with other patterns.
 | 
			
		||||
.Ss Built-in Variables
 | 
			
		||||
Variable names with special meanings:
 | 
			
		||||
.Bl -hang -width FILENAMES
 | 
			
		||||
.It Va ARGC
 | 
			
		||||
argument count, assignable
 | 
			
		||||
.It Va ARGV
 | 
			
		||||
argument array, assignable;
 | 
			
		||||
non-null members are taken as filenames
 | 
			
		||||
.It Va CONVFMT
 | 
			
		||||
conversion format used when converting numbers
 | 
			
		||||
(default
 | 
			
		||||
.Qq %.6g )
 | 
			
		||||
.It Va ENVIRON
 | 
			
		||||
array of environment variables; subscripts are names.
 | 
			
		||||
.It Va FILENAME
 | 
			
		||||
the name of the current input file
 | 
			
		||||
.It Va FNR
 | 
			
		||||
ordinal number of the current record in the current file
 | 
			
		||||
.It Va FS
 | 
			
		||||
regular expression used to separate fields; also settable
 | 
			
		||||
by option
 | 
			
		||||
.Fl F Ar fs .
 | 
			
		||||
.It Va NF
 | 
			
		||||
number of fields in the current record
 | 
			
		||||
.It Va NR
 | 
			
		||||
ordinal number of the current record
 | 
			
		||||
.It Va OFMT
 | 
			
		||||
output format for numbers (default
 | 
			
		||||
.Qq "%.6g"
 | 
			
		||||
)
 | 
			
		||||
.It Va OFS
 | 
			
		||||
output field separator (default blank)
 | 
			
		||||
.It Va ORS
 | 
			
		||||
output record separator (default newline)
 | 
			
		||||
.It Va RS
 | 
			
		||||
input record separator (default newline)
 | 
			
		||||
.It Va RSTART
 | 
			
		||||
Position of the first character matched by
 | 
			
		||||
.Fn match ;
 | 
			
		||||
0 if not match.
 | 
			
		||||
.It Va RLENGTH
 | 
			
		||||
Length of the string matched by
 | 
			
		||||
.Fn match ;
 | 
			
		||||
-1 if no match.
 | 
			
		||||
.It Va SUBSEP
 | 
			
		||||
separates multiple subscripts (default 034)
 | 
			
		||||
.El
 | 
			
		||||
.Ss Functions
 | 
			
		||||
Functions may be defined (at the position of a pattern-action statement) thus:
 | 
			
		||||
.Bd -filled -offset indent
 | 
			
		||||
.Ic function foo(a, b, c) { ...; return x }
 | 
			
		||||
.Ed
 | 
			
		||||
.Pp
 | 
			
		||||
Parameters are passed by value if scalar and by reference if array name;
 | 
			
		||||
functions may be called recursively.
 | 
			
		||||
Parameters are local to the function; all other variables are global.
 | 
			
		||||
Thus local variables may be created by providing excess parameters in
 | 
			
		||||
the function definition.
 | 
			
		||||
.Sh EXAMPLES
 | 
			
		||||
.Bl -tag -width indent -compact
 | 
			
		||||
.It Ic length($0) \*[Gt] 72
 | 
			
		||||
Print lines longer than 72 characters.
 | 
			
		||||
.Pp
 | 
			
		||||
.It Ic \&{ print $2, $1 \&}
 | 
			
		||||
Print first two fields in opposite order.
 | 
			
		||||
.Pp
 | 
			
		||||
.It Ic BEGIN { FS =  \&",[ \et]*|[ \et]+\&" }
 | 
			
		||||
.It Ic "\ \ \ \ \ \ {" print \&$2, \&$1 }
 | 
			
		||||
Same, with input fields separated by comma and/or blanks and tabs.
 | 
			
		||||
.Pp
 | 
			
		||||
.It Ic "\ \ \ \ {" s += $1 }
 | 
			
		||||
.It Ic END { print \&"sum is\&", s, \&" average is\ \&",\ s/NR\ }
 | 
			
		||||
Add up first column, print sum and average.
 | 
			
		||||
.Pp
 | 
			
		||||
.It Ic /start/, /stop/
 | 
			
		||||
Print all lines between start/stop pairs.
 | 
			
		||||
.Pp
 | 
			
		||||
.It Ic BEGIN { # Simulate echo(1)
 | 
			
		||||
.It Ic "\ \ \ \ " for (i = 1; i \*[Lt] ARGC;\ i++)\ printf\ \&"%s\ \&",\ ARGV[i]
 | 
			
		||||
.It Ic "\ \ \ \ " printf \&"\en\&"
 | 
			
		||||
.It Ic "\ \ \ \ " exit }
 | 
			
		||||
.El
 | 
			
		||||
.Sh SEE ALSO
 | 
			
		||||
.Xr egrep 1 ,
 | 
			
		||||
.Xr lex 1 ,
 | 
			
		||||
.Xr sed 1 ,
 | 
			
		||||
.Xr atan2 3 ,
 | 
			
		||||
.Xr cos 3 ,
 | 
			
		||||
.Xr exp 3 ,
 | 
			
		||||
.Xr log 3 ,
 | 
			
		||||
.Xr sin 3 ,
 | 
			
		||||
.Xr sqrt 3 ,
 | 
			
		||||
.Xr strftime 3 ,
 | 
			
		||||
.Xr time 3
 | 
			
		||||
.Pp
 | 
			
		||||
A. V. Aho, B. W. Kernighan, P. J. Weinberger,
 | 
			
		||||
.Em The AWK Programming Language ,
 | 
			
		||||
Addison-Wesley, 1988.
 | 
			
		||||
ISBN 0-201-07981-X
 | 
			
		||||
.Pp
 | 
			
		||||
.Em AWK Language Programming ,
 | 
			
		||||
Edition 1.0, published by the Free Software Foundation, 1995
 | 
			
		||||
.Sh HISTORY
 | 
			
		||||
.Nm nawk
 | 
			
		||||
has been the default system
 | 
			
		||||
.Nm
 | 
			
		||||
since
 | 
			
		||||
.Nx 2.0 ,
 | 
			
		||||
replacing the previously used GNU
 | 
			
		||||
.Nm .
 | 
			
		||||
.Sh BUGS
 | 
			
		||||
There are no explicit conversions between numbers and strings.
 | 
			
		||||
To force an expression to be treated as a number add 0 to it;
 | 
			
		||||
to force it to be treated as a string concatenate
 | 
			
		||||
\&"\&" to it.
 | 
			
		||||
.Pp
 | 
			
		||||
The scope rules for variables in functions are a botch;
 | 
			
		||||
the syntax is worse.
 | 
			
		||||
@ -25,6 +25,13 @@ THIS SOFTWARE.
 | 
			
		||||
This file lists all bug fixes, changes, etc., made since the AWK book
 | 
			
		||||
was sent to the printers in August, 1987.
 | 
			
		||||
 | 
			
		||||
May 23, 2010:
 | 
			
		||||
	fixed long-standing overflow bug in run.c; many thanks to
 | 
			
		||||
	nelson beebe for spotting it and providing the fix.
 | 
			
		||||
 | 
			
		||||
	fixed bug that didn't parse -vd=1 properly; thanks to santiago
 | 
			
		||||
	vila for spotting it.
 | 
			
		||||
 | 
			
		||||
Feb 8, 2010:
 | 
			
		||||
	i give up.  replaced isblank with isspace in b.c; there are
 | 
			
		||||
	no consistent header files.
 | 
			
		||||
@ -48,6 +48,7 @@ extern int	safe;		/* 0 => unsafe, 1 => safe */
 | 
			
		||||
#define	RECSIZE	(8 * 1024)	/* sets limit on records, fields, etc., etc. */
 | 
			
		||||
extern int	recsize;	/* size of current record, orig RECSIZE */
 | 
			
		||||
 | 
			
		||||
extern char	EMPTY[];
 | 
			
		||||
extern char	**FS;
 | 
			
		||||
extern char	**RS;
 | 
			
		||||
extern char	**ORS;
 | 
			
		||||
@ -61,16 +62,15 @@ extern char	**SUBSEP;
 | 
			
		||||
extern Awkfloat *RSTART;
 | 
			
		||||
extern Awkfloat *RLENGTH;
 | 
			
		||||
 | 
			
		||||
extern char	*record;	/* points to $0 */
 | 
			
		||||
extern uschar	*record;	/* points to $0 */
 | 
			
		||||
extern int	lineno;		/* line number in awk program */
 | 
			
		||||
extern int	errorflag;	/* 1 if error has occurred */
 | 
			
		||||
extern int	donefld;	/* 1 if record broken into fields */
 | 
			
		||||
extern int	donerec;	/* 1 if record is valid (no fld has changed */
 | 
			
		||||
extern char	inputFS[];	/* FS at time of input, for field splitting */
 | 
			
		||||
 | 
			
		||||
extern int	dbg;
 | 
			
		||||
 | 
			
		||||
extern	char	*patbeg;	/* beginning of pattern matched */
 | 
			
		||||
extern	uschar	*patbeg;	/* beginning of pattern matched */
 | 
			
		||||
extern	int	patlen;		/* length of pattern matched.  set in b.c */
 | 
			
		||||
 | 
			
		||||
/* Cell:  all information about a variable or constant */
 | 
			
		||||
@ -126,6 +126,8 @@ extern Cell	*rlengthloc;	/* RLENGTH */
 | 
			
		||||
#define	FTOUPPER 12
 | 
			
		||||
#define	FTOLOWER 13
 | 
			
		||||
#define	FFLUSH	14
 | 
			
		||||
#define FSYSTIME	15
 | 
			
		||||
#define FSTRFTIME	16
 | 
			
		||||
 | 
			
		||||
/* Node:  parse tree is made of nodes, with Cell's at bottom */
 | 
			
		||||
 | 
			
		||||
@ -203,8 +205,6 @@ extern	int	pairstack[], paircnt;
 | 
			
		||||
 | 
			
		||||
#define NCHARS	(256+3)		/* 256 handles 8-bit chars; 128 does 7-bit */
 | 
			
		||||
				/* watch out in match(), etc. */
 | 
			
		||||
#define NSTATES	32
 | 
			
		||||
 | 
			
		||||
typedef struct rrow {
 | 
			
		||||
	long	ltype;	/* long avoids pointer warnings on 64-bit */
 | 
			
		||||
	union {
 | 
			
		||||
@ -216,16 +216,16 @@ typedef struct rrow {
 | 
			
		||||
} rrow;
 | 
			
		||||
 | 
			
		||||
typedef struct fa {
 | 
			
		||||
	uschar	gototab[NSTATES][NCHARS];
 | 
			
		||||
	uschar	out[NSTATES];
 | 
			
		||||
	unsigned int	**gototab;
 | 
			
		||||
	uschar	*out;
 | 
			
		||||
	uschar	*restr;
 | 
			
		||||
	int	*posns[NSTATES];
 | 
			
		||||
	int	**posns;
 | 
			
		||||
	int	state_count;
 | 
			
		||||
	int	anchor;
 | 
			
		||||
	int	use;
 | 
			
		||||
	int	initstat;
 | 
			
		||||
	int	curstat;
 | 
			
		||||
	int	accept;
 | 
			
		||||
	int	reset;
 | 
			
		||||
	struct	rrow re[1];	/* variable: actual size set by calling malloc */
 | 
			
		||||
} fa;
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,10 @@ THIS SOFTWARE.
 | 
			
		||||
****************************************************************/
 | 
			
		||||
 | 
			
		||||
%{
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "awk.h"
 | 
			
		||||
@ -71,6 +75,7 @@ Node	*arglist = 0;	/* list of args for current function */
 | 
			
		||||
%type	<i>	do st
 | 
			
		||||
%type	<i>	pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
 | 
			
		||||
%type	<i>	subop print
 | 
			
		||||
%type	<cp>	string
 | 
			
		||||
 | 
			
		||||
%right	ASGNOP
 | 
			
		||||
%right	'?'
 | 
			
		||||
@ -80,7 +85,7 @@ Node	*arglist = 0;	/* list of args for current function */
 | 
			
		||||
%left	GETLINE
 | 
			
		||||
%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
 | 
			
		||||
%left	ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC 
 | 
			
		||||
%left	GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
 | 
			
		||||
%left	GENSUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
 | 
			
		||||
%left	PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
 | 
			
		||||
%left	REGEXPR VAR VARNF IVAR WHILE '('
 | 
			
		||||
%left	CAT
 | 
			
		||||
@ -348,6 +353,11 @@ subop:
 | 
			
		||||
	  SUB | GSUB
 | 
			
		||||
	;
 | 
			
		||||
 | 
			
		||||
string:
 | 
			
		||||
	  STRING
 | 
			
		||||
	| string STRING		{ $$ = catstr($1, $2); }
 | 
			
		||||
	;
 | 
			
		||||
 | 
			
		||||
term:
 | 
			
		||||
 	  term '/' ASGNOP term		{ $$ = op2(DIVEQ, $1, $4); }
 | 
			
		||||
 	| term '+' term			{ $$ = op2(ADD, $1, $3); }
 | 
			
		||||
@ -369,6 +379,22 @@ term:
 | 
			
		||||
	| INCR var			{ $$ = op1(PREINCR, $2); }
 | 
			
		||||
	| var DECR			{ $$ = op1(POSTDECR, $1); }
 | 
			
		||||
	| var INCR			{ $$ = op1(POSTINCR, $1); }
 | 
			
		||||
	| GENSUB '(' reg_expr comma pattern comma pattern ')'
 | 
			
		||||
		{ $$ = op5(GENSUB, NIL, (Node*)makedfa($3, 1), $5, $7, rectonode()); }
 | 
			
		||||
	| GENSUB '(' pattern comma pattern comma pattern ')'
 | 
			
		||||
		{ if (constnode($3))
 | 
			
		||||
			$$ = op5(GENSUB, NIL, (Node *)makedfa(strnode($3), 1), $5, $7, rectonode());
 | 
			
		||||
		  else
 | 
			
		||||
			$$ = op5(GENSUB, (Node *)1, $3, $5, $7, rectonode());
 | 
			
		||||
		}
 | 
			
		||||
	| GENSUB '(' reg_expr comma pattern comma pattern comma pattern ')'
 | 
			
		||||
		{ $$ = op5(GENSUB, NIL, (Node*)makedfa($3, 1), $5, $7, $9); }
 | 
			
		||||
	| GENSUB '(' pattern comma pattern comma pattern comma pattern ')'
 | 
			
		||||
		{ if (constnode($3))
 | 
			
		||||
			$$ = op5(GENSUB, NIL, (Node *)makedfa(strnode($3),1), $5,$7,$9);
 | 
			
		||||
		  else
 | 
			
		||||
			$$ = op5(GENSUB, (Node *)1, $3, $5, $7, $9);
 | 
			
		||||
		}
 | 
			
		||||
	| GETLINE var LT term		{ $$ = op3(GETLINE, $2, itonp($3), $4); }
 | 
			
		||||
	| GETLINE LT term		{ $$ = op3(GETLINE, NIL, itonp($2), $3); }
 | 
			
		||||
	| GETLINE var			{ $$ = op3(GETLINE, $2, NIL, NIL); }
 | 
			
		||||
@ -394,7 +420,7 @@ term:
 | 
			
		||||
	| SPLIT '(' pattern comma varname ')'
 | 
			
		||||
		{ $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); }  /* default */
 | 
			
		||||
	| SPRINTF '(' patlist ')'	{ $$ = op1($1, $3); }
 | 
			
		||||
	| STRING	 		{ $$ = celltonode($1, CCON); }
 | 
			
		||||
	| string	 		{ $$ = celltonode($1, CCON); }
 | 
			
		||||
	| subop '(' reg_expr comma pattern ')'
 | 
			
		||||
		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
 | 
			
		||||
	| subop '(' pattern comma pattern ')'
 | 
			
		||||
							
								
								
									
										383
									
								
								commands/awk/b.c → external/historical/nawk/dist/b.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										383
									
								
								commands/awk/b.c → external/historical/nawk/dist/b.c
									
									
									
									
										vendored
									
									
								
							@ -24,12 +24,17 @@ THIS SOFTWARE.
 | 
			
		||||
 | 
			
		||||
/* lasciate ogne speranza, voi ch'intrate. */
 | 
			
		||||
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define	DEBUG
 | 
			
		||||
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include "awk.h"
 | 
			
		||||
#include "awkgram.h"
 | 
			
		||||
 | 
			
		||||
@ -62,33 +67,80 @@ int	maxsetvec = 0;
 | 
			
		||||
 | 
			
		||||
int	rtok;		/* next token in current re */
 | 
			
		||||
int	rlxval;
 | 
			
		||||
static uschar	*rlxstr;
 | 
			
		||||
static uschar	*prestr;	/* current position in current re */
 | 
			
		||||
static uschar	*lastre;	/* origin of last re */
 | 
			
		||||
static const uschar	*rlxstr;
 | 
			
		||||
static const uschar	*prestr;	/* current position in current re */
 | 
			
		||||
static const uschar	*lastre;	/* origin of last re */
 | 
			
		||||
 | 
			
		||||
static	int setcnt;
 | 
			
		||||
static	int poscnt;
 | 
			
		||||
 | 
			
		||||
char	*patbeg;
 | 
			
		||||
uschar	*patbeg;
 | 
			
		||||
int	patlen;
 | 
			
		||||
 | 
			
		||||
#define	NFA	20	/* cache this many dynamic fa's */
 | 
			
		||||
#define	NFA	128	/* cache this many dynamic fa's */
 | 
			
		||||
fa	*fatab[NFA];
 | 
			
		||||
int	nfatab	= 0;	/* entries in fatab */
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
resizesetvec(const char *msg)
 | 
			
		||||
{
 | 
			
		||||
	if (maxsetvec == 0)
 | 
			
		||||
		maxsetvec = MAXLIN;
 | 
			
		||||
	else
 | 
			
		||||
		maxsetvec *= 4;
 | 
			
		||||
	setvec = realloc(setvec, maxsetvec * sizeof(*setvec));
 | 
			
		||||
	tmpset = realloc(tmpset, maxsetvec * sizeof(*tmpset));
 | 
			
		||||
	if (setvec == 0 || tmpset == 0)
 | 
			
		||||
	    overflo(msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
resize_state(fa *f, int state)
 | 
			
		||||
{
 | 
			
		||||
	void *p;
 | 
			
		||||
	int i, new_count;
 | 
			
		||||
 | 
			
		||||
	if (++state < f->state_count)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	new_count = state + 10; /* needs to be tuned */
 | 
			
		||||
 | 
			
		||||
	p = realloc(f->gototab, new_count * sizeof(f->gototab[0]));
 | 
			
		||||
	if (p == NULL)
 | 
			
		||||
		goto out;
 | 
			
		||||
	f->gototab = p;
 | 
			
		||||
 | 
			
		||||
	p = realloc(f->out, new_count * sizeof(f->out[0]));
 | 
			
		||||
	if (p == NULL)
 | 
			
		||||
		goto out;
 | 
			
		||||
	f->out = p;
 | 
			
		||||
 | 
			
		||||
	p = realloc(f->posns, new_count * sizeof(f->posns[0]));
 | 
			
		||||
	if (p == NULL)
 | 
			
		||||
		goto out;
 | 
			
		||||
	f->posns = p;
 | 
			
		||||
 | 
			
		||||
	for (i = f->state_count; i < new_count; ++i) {
 | 
			
		||||
		f->gototab[i] = calloc(1, NCHARS * sizeof (**f->gototab));
 | 
			
		||||
		if (f->gototab[i] == NULL)
 | 
			
		||||
			goto out;
 | 
			
		||||
		f->out[i]  = 0;
 | 
			
		||||
		f->posns[i] = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	f->state_count = new_count;
 | 
			
		||||
	return;
 | 
			
		||||
out:
 | 
			
		||||
	overflo("out of memory in resize_state");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fa *makedfa(const char *s, int anchor)	/* returns dfa for reg expr s */
 | 
			
		||||
{
 | 
			
		||||
	int i, use, nuse;
 | 
			
		||||
	fa *pfa;
 | 
			
		||||
	static int now = 1;
 | 
			
		||||
 | 
			
		||||
	if (setvec == 0) {	/* first time through any RE */
 | 
			
		||||
		maxsetvec = MAXLIN;
 | 
			
		||||
		setvec = (int *) malloc(maxsetvec * sizeof(int));
 | 
			
		||||
		tmpset = (int *) malloc(maxsetvec * sizeof(int));
 | 
			
		||||
		if (setvec == 0 || tmpset == 0)
 | 
			
		||||
			overflo("out of space initializing makedfa");
 | 
			
		||||
	}
 | 
			
		||||
	if (setvec == 0)	/* first time through any RE */
 | 
			
		||||
		resizesetvec("out of space initializing makedfa");
 | 
			
		||||
 | 
			
		||||
	if (compile_time)	/* a constant for sure */
 | 
			
		||||
		return mkdfa(s, anchor);
 | 
			
		||||
@ -132,14 +184,15 @@ fa *mkdfa(const char *s, int anchor)	/* does the real work of making a dfa */
 | 
			
		||||
 | 
			
		||||
	poscnt = 0;
 | 
			
		||||
	penter(p1);	/* enter parent pointers and leaf indices */
 | 
			
		||||
	if ((f = (fa *) calloc(1, sizeof(fa) + poscnt*sizeof(rrow))) == NULL)
 | 
			
		||||
	if ((f = calloc(1, sizeof(*f) + poscnt*sizeof(rrow))) == NULL)
 | 
			
		||||
		overflo("out of space for fa");
 | 
			
		||||
	f->accept = poscnt-1;	/* penter has computed number of positions in re */
 | 
			
		||||
	cfoll(f, p1);	/* set up follow sets */
 | 
			
		||||
	freetr(p1);
 | 
			
		||||
	if ((f->posns[0] = (int *) calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL)
 | 
			
		||||
	resize_state(f, 1);
 | 
			
		||||
	if ((f->posns[0] = calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL)
 | 
			
		||||
			overflo("out of space in makedfa");
 | 
			
		||||
	if ((f->posns[1] = (int *) calloc(1, sizeof(int))) == NULL)
 | 
			
		||||
	if ((f->posns[1] = calloc(1, sizeof(int))) == NULL)
 | 
			
		||||
		overflo("out of space in makedfa");
 | 
			
		||||
	*f->posns[1] = 0;
 | 
			
		||||
	f->initstat = makeinit(f, anchor);
 | 
			
		||||
@ -152,12 +205,12 @@ int makeinit(fa *f, int anchor)
 | 
			
		||||
{
 | 
			
		||||
	int i, k;
 | 
			
		||||
 | 
			
		||||
	resize_state(f, 2);
 | 
			
		||||
	f->curstat = 2;
 | 
			
		||||
	f->out[2] = 0;
 | 
			
		||||
	f->reset = 0;
 | 
			
		||||
	k = *(f->re[0].lfollow);
 | 
			
		||||
	xfree(f->posns[2]);			
 | 
			
		||||
	if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
 | 
			
		||||
	if ((f->posns[2] = calloc(1, (k+1)*sizeof(int))) == NULL)
 | 
			
		||||
		overflo("out of space in makeinit");
 | 
			
		||||
	for (i=0; i <= k; i++) {
 | 
			
		||||
		(f->posns[2])[i] = (f->re[0].lfollow)[i];
 | 
			
		||||
@ -174,8 +227,10 @@ int makeinit(fa *f, int anchor)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		f->out[0] = f->out[2];
 | 
			
		||||
		if (f->curstat != 2)
 | 
			
		||||
		if (f->curstat != 2) {
 | 
			
		||||
			resize_state(f, f->curstat);
 | 
			
		||||
			--(*f->posns[f->curstat]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return f->curstat;
 | 
			
		||||
}
 | 
			
		||||
@ -231,13 +286,13 @@ void freetr(Node *p)	/* free parse tree */
 | 
			
		||||
/* in the parsing of regular expressions, metacharacters like . have */
 | 
			
		||||
/* to be seen literally;  \056 is not a metacharacter. */
 | 
			
		||||
 | 
			
		||||
int hexstr(char **pp)	/* find and eval hex string at pp, return new p */
 | 
			
		||||
int hexstr(const uschar **pp)	/* find and eval hex string at pp, return new p */
 | 
			
		||||
{			/* only pick up one 8-bit byte (2 chars) */
 | 
			
		||||
	uschar *p;
 | 
			
		||||
	const uschar *p;
 | 
			
		||||
	int n = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0, p = (uschar *) *pp; i < 2 && isxdigit(*p); i++, p++) {
 | 
			
		||||
	for (i = 0, p = *pp; i < 2 && isxdigit(*p); i++, p++) {
 | 
			
		||||
		if (isdigit(*p))
 | 
			
		||||
			n = 16 * n + *p - '0';
 | 
			
		||||
		else if (*p >= 'a' && *p <= 'f')
 | 
			
		||||
@ -245,16 +300,16 @@ int hexstr(char **pp)	/* find and eval hex string at pp, return new p */
 | 
			
		||||
		else if (*p >= 'A' && *p <= 'F')
 | 
			
		||||
			n = 16 * n + *p - 'A' + 10;
 | 
			
		||||
	}
 | 
			
		||||
	*pp = (char *) p;
 | 
			
		||||
	*pp = p;
 | 
			
		||||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define isoctdigit(c) ((c) >= '0' && (c) <= '7')	/* multiple use of arg */
 | 
			
		||||
 | 
			
		||||
int quoted(char **pp)	/* pick up next thing after a \\ */
 | 
			
		||||
int quoted(const uschar **pp)	/* pick up next thing after a \\ */
 | 
			
		||||
			/* and increment *pp */
 | 
			
		||||
{
 | 
			
		||||
	char *p = *pp;
 | 
			
		||||
	const uschar *p = *pp;
 | 
			
		||||
	int c;
 | 
			
		||||
 | 
			
		||||
	if ((c = *p++) == 't')
 | 
			
		||||
@ -288,31 +343,32 @@ int quoted(char **pp)	/* pick up next thing after a \\ */
 | 
			
		||||
char *cclenter(const char *argp)	/* add a character class */
 | 
			
		||||
{
 | 
			
		||||
	int i, c, c2;
 | 
			
		||||
	uschar *p = (uschar *) argp;
 | 
			
		||||
	uschar *op, *bp;
 | 
			
		||||
	const uschar *p = (const uschar *) argp;
 | 
			
		||||
	const uschar *op;
 | 
			
		||||
	uschar *bp;
 | 
			
		||||
	static uschar *buf = 0;
 | 
			
		||||
	static int bufsz = 100;
 | 
			
		||||
 | 
			
		||||
	op = p;
 | 
			
		||||
	if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL)
 | 
			
		||||
	if (buf == 0 && (buf = malloc(bufsz)) == NULL)
 | 
			
		||||
		FATAL("out of space for character class [%.10s...] 1", p);
 | 
			
		||||
	bp = buf;
 | 
			
		||||
	for (i = 0; (c = *p++) != 0; ) {
 | 
			
		||||
		if (c == '\\') {
 | 
			
		||||
			c = quoted((char **) &p);
 | 
			
		||||
			c = quoted(&p);
 | 
			
		||||
		} else if (c == '-' && i > 0 && bp[-1] != 0) {
 | 
			
		||||
			if (*p != 0) {
 | 
			
		||||
				c = bp[-1];
 | 
			
		||||
				c2 = *p++;
 | 
			
		||||
				if (c2 == '\\')
 | 
			
		||||
					c2 = quoted((char **) &p);
 | 
			
		||||
					c2 = quoted(&p);
 | 
			
		||||
				if (c > c2) {	/* empty; ignore */
 | 
			
		||||
					bp--;
 | 
			
		||||
					i--;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				while (c < c2) {
 | 
			
		||||
					if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, "cclenter1"))
 | 
			
		||||
					if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, "cclenter1"))
 | 
			
		||||
						FATAL("out of space for character class [%.10s...] 2", p);
 | 
			
		||||
					*bp++ = ++c;
 | 
			
		||||
					i++;
 | 
			
		||||
@ -320,14 +376,14 @@ char *cclenter(const char *argp)	/* add a character class */
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, "cclenter2"))
 | 
			
		||||
		if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, "cclenter2"))
 | 
			
		||||
			FATAL("out of space for character class [%.10s...] 3", p);
 | 
			
		||||
		*bp++ = c;
 | 
			
		||||
		i++;
 | 
			
		||||
	}
 | 
			
		||||
	*bp = 0;
 | 
			
		||||
	dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) );
 | 
			
		||||
	xfree(op);
 | 
			
		||||
	free(__UNCONST(op));
 | 
			
		||||
	return (char *) tostring((char *) buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -346,18 +402,13 @@ void cfoll(fa *f, Node *v)	/* enter follow set of each leaf of vertex v into lfo
 | 
			
		||||
	LEAF
 | 
			
		||||
		f->re[info(v)].ltype = type(v);
 | 
			
		||||
		f->re[info(v)].lval.np = right(v);
 | 
			
		||||
		while (f->accept >= maxsetvec) {	/* guessing here! */
 | 
			
		||||
			maxsetvec *= 4;
 | 
			
		||||
			setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
 | 
			
		||||
			tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
 | 
			
		||||
			if (setvec == 0 || tmpset == 0)
 | 
			
		||||
				overflo("out of space in cfoll()");
 | 
			
		||||
		}
 | 
			
		||||
		while (f->accept >= maxsetvec) /* guessing here! */
 | 
			
		||||
			resizesetvec("out of space in cfoll()");
 | 
			
		||||
		for (i = 0; i <= f->accept; i++)
 | 
			
		||||
			setvec[i] = 0;
 | 
			
		||||
		setcnt = 0;
 | 
			
		||||
		follow(v);	/* computes setvec and setcnt */
 | 
			
		||||
		if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL)
 | 
			
		||||
		if ((p = calloc(1, (setcnt+1)*sizeof(int))) == NULL)
 | 
			
		||||
			overflo("out of space building follow set");
 | 
			
		||||
		f->re[info(v)].lfollow = p;
 | 
			
		||||
		*p = setcnt;
 | 
			
		||||
@ -378,7 +429,7 @@ void cfoll(fa *f, Node *v)	/* enter follow set of each leaf of vertex v into lfo
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int first(const Node *p)	/* collects initially active leaves of p into setvec */
 | 
			
		||||
int first(Node *p)	/* collects initially active leaves of p into setvec */
 | 
			
		||||
			/* returns 0 if p matches empty string */
 | 
			
		||||
{
 | 
			
		||||
	int b, lp;
 | 
			
		||||
@ -387,13 +438,8 @@ int first(const Node *p)	/* collects initially active leaves of p into setvec */
 | 
			
		||||
	ELEAF
 | 
			
		||||
	LEAF
 | 
			
		||||
		lp = info(p);	/* look for high-water mark of subscripts */
 | 
			
		||||
		while (setcnt >= maxsetvec || lp >= maxsetvec) {	/* guessing here! */
 | 
			
		||||
			maxsetvec *= 4;
 | 
			
		||||
			setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
 | 
			
		||||
			tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
 | 
			
		||||
			if (setvec == 0 || tmpset == 0)
 | 
			
		||||
				overflo("out of space in first()");
 | 
			
		||||
		}
 | 
			
		||||
		while (setcnt >= maxsetvec || lp >= maxsetvec) /* guessing here! */
 | 
			
		||||
			resizesetvec("out of space in first()");
 | 
			
		||||
		if (type(p) == EMPTYRE) {
 | 
			
		||||
			setvec[lp] = 0;
 | 
			
		||||
			return(0);
 | 
			
		||||
@ -457,7 +503,7 @@ void follow(Node *v)	/* collects leaves that can follow v into setvec */
 | 
			
		||||
 | 
			
		||||
int member(int c, const char *sarg)	/* is c in s? */
 | 
			
		||||
{
 | 
			
		||||
	uschar *s = (uschar *) sarg;
 | 
			
		||||
	const uschar *s = (const uschar *) sarg;
 | 
			
		||||
 | 
			
		||||
	while (*s)
 | 
			
		||||
		if (c == *s++)
 | 
			
		||||
@ -468,9 +514,11 @@ int member(int c, const char *sarg)	/* is c in s? */
 | 
			
		||||
int match(fa *f, const char *p0)	/* shortest match ? */
 | 
			
		||||
{
 | 
			
		||||
	int s, ns;
 | 
			
		||||
	uschar *p = (uschar *) p0;
 | 
			
		||||
	const uschar *p = (const uschar *) p0;
 | 
			
		||||
 | 
			
		||||
	s = f->initstat;
 | 
			
		||||
	assert (s < f->state_count);
 | 
			
		||||
 | 
			
		||||
	s = f->reset ? makeinit(f,0) : f->initstat;
 | 
			
		||||
	if (f->out[s])
 | 
			
		||||
		return(1);
 | 
			
		||||
	do {
 | 
			
		||||
@ -479,6 +527,9 @@ int match(fa *f, const char *p0)	/* shortest match ? */
 | 
			
		||||
			s = ns;
 | 
			
		||||
		else
 | 
			
		||||
			s = cgoto(f, s, *p);
 | 
			
		||||
 | 
			
		||||
		assert (s < f->state_count);
 | 
			
		||||
 | 
			
		||||
		if (f->out[s])
 | 
			
		||||
			return(1);
 | 
			
		||||
	} while (*p++ != 0);
 | 
			
		||||
@ -488,17 +539,12 @@ int match(fa *f, const char *p0)	/* shortest match ? */
 | 
			
		||||
int pmatch(fa *f, const char *p0)	/* longest match, for sub */
 | 
			
		||||
{
 | 
			
		||||
	int s, ns;
 | 
			
		||||
	uschar *p = (uschar *) p0;
 | 
			
		||||
	uschar *p = __UNCONST(p0);
 | 
			
		||||
	uschar *q;
 | 
			
		||||
	int i, k;
 | 
			
		||||
 | 
			
		||||
	/* s = f->reset ? makeinit(f,1) : f->initstat; */
 | 
			
		||||
	if (f->reset) {
 | 
			
		||||
		f->initstat = s = makeinit(f,1);
 | 
			
		||||
	} else {
 | 
			
		||||
		s = f->initstat;
 | 
			
		||||
	}
 | 
			
		||||
	patbeg = (char *) p;
 | 
			
		||||
	s = f->initstat;
 | 
			
		||||
	assert(s < f->state_count);
 | 
			
		||||
	patbeg = p;
 | 
			
		||||
	patlen = -1;
 | 
			
		||||
	do {
 | 
			
		||||
		q = p;
 | 
			
		||||
@ -510,9 +556,12 @@ int pmatch(fa *f, const char *p0)	/* longest match, for sub */
 | 
			
		||||
				s = ns;
 | 
			
		||||
			else
 | 
			
		||||
				s = cgoto(f, s, *q);
 | 
			
		||||
 | 
			
		||||
			assert(s < f->state_count);
 | 
			
		||||
 | 
			
		||||
			if (s == 1) {	/* no transition */
 | 
			
		||||
				if (patlen >= 0) {
 | 
			
		||||
					patbeg = (char *) p;
 | 
			
		||||
					patbeg = p;
 | 
			
		||||
					return(1);
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
@ -522,24 +571,11 @@ int pmatch(fa *f, const char *p0)	/* longest match, for sub */
 | 
			
		||||
		if (f->out[s])
 | 
			
		||||
			patlen = q-p-1;	/* don't count $ */
 | 
			
		||||
		if (patlen >= 0) {
 | 
			
		||||
			patbeg = (char *) p;
 | 
			
		||||
			patbeg = p;
 | 
			
		||||
			return(1);
 | 
			
		||||
		}
 | 
			
		||||
	nextin:
 | 
			
		||||
		s = 2;
 | 
			
		||||
		if (f->reset) {
 | 
			
		||||
			for (i = 2; i <= f->curstat; i++)
 | 
			
		||||
				xfree(f->posns[i]);
 | 
			
		||||
			k = *f->posns[0];			
 | 
			
		||||
			if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
 | 
			
		||||
				overflo("out of space in pmatch");
 | 
			
		||||
			for (i = 0; i <= k; i++)
 | 
			
		||||
				(f->posns[2])[i] = (f->posns[0])[i];
 | 
			
		||||
			f->initstat = f->curstat = 2;
 | 
			
		||||
			f->out[2] = f->out[0];
 | 
			
		||||
			for (i = 0; i < NCHARS; i++)
 | 
			
		||||
				f->gototab[2][i] = 0;
 | 
			
		||||
		}
 | 
			
		||||
	} while (*p++ != 0);
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
@ -547,16 +583,12 @@ int pmatch(fa *f, const char *p0)	/* longest match, for sub */
 | 
			
		||||
int nematch(fa *f, const char *p0)	/* non-empty match, for sub */
 | 
			
		||||
{
 | 
			
		||||
	int s, ns;
 | 
			
		||||
	uschar *p = (uschar *) p0;
 | 
			
		||||
	uschar *p = __UNCONST(p0);
 | 
			
		||||
	uschar *q;
 | 
			
		||||
	int i, k;
 | 
			
		||||
 | 
			
		||||
	/* s = f->reset ? makeinit(f,1) : f->initstat; */
 | 
			
		||||
	if (f->reset) {
 | 
			
		||||
		f->initstat = s = makeinit(f,1);
 | 
			
		||||
	} else {
 | 
			
		||||
		s = f->initstat;
 | 
			
		||||
	}
 | 
			
		||||
	s = f->initstat;
 | 
			
		||||
	assert(s < f->state_count);
 | 
			
		||||
 | 
			
		||||
	patlen = -1;
 | 
			
		||||
	while (*p) {
 | 
			
		||||
		q = p;
 | 
			
		||||
@ -568,9 +600,12 @@ int nematch(fa *f, const char *p0)	/* non-empty match, for sub */
 | 
			
		||||
				s = ns;
 | 
			
		||||
			else
 | 
			
		||||
				s = cgoto(f, s, *q);
 | 
			
		||||
 | 
			
		||||
			assert(s < f->state_count);
 | 
			
		||||
 | 
			
		||||
			if (s == 1) {	/* no transition */
 | 
			
		||||
				if (patlen > 0) {
 | 
			
		||||
					patbeg = (char *) p;
 | 
			
		||||
					patbeg = p;
 | 
			
		||||
					return(1);
 | 
			
		||||
				} else
 | 
			
		||||
					goto nnextin;	/* no nonempty match */
 | 
			
		||||
@ -579,35 +614,112 @@ int nematch(fa *f, const char *p0)	/* non-empty match, for sub */
 | 
			
		||||
		if (f->out[s])
 | 
			
		||||
			patlen = q-p-1;	/* don't count $ */
 | 
			
		||||
		if (patlen > 0 ) {
 | 
			
		||||
			patbeg = (char *) p;
 | 
			
		||||
			patbeg = p;
 | 
			
		||||
			return(1);
 | 
			
		||||
		}
 | 
			
		||||
	nnextin:
 | 
			
		||||
		s = 2;
 | 
			
		||||
		if (f->reset) {
 | 
			
		||||
			for (i = 2; i <= f->curstat; i++)
 | 
			
		||||
				xfree(f->posns[i]);
 | 
			
		||||
			k = *f->posns[0];			
 | 
			
		||||
			if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
 | 
			
		||||
				overflo("out of state space");
 | 
			
		||||
			for (i = 0; i <= k; i++)
 | 
			
		||||
				(f->posns[2])[i] = (f->posns[0])[i];
 | 
			
		||||
			f->initstat = f->curstat = 2;
 | 
			
		||||
			f->out[2] = f->out[0];
 | 
			
		||||
			for (i = 0; i < NCHARS; i++)
 | 
			
		||||
				f->gototab[2][i] = 0;
 | 
			
		||||
		}
 | 
			
		||||
		p++;
 | 
			
		||||
	}
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * NAME
 | 
			
		||||
 *     fnematch
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *     A stream-fed version of nematch which transfers characters to a
 | 
			
		||||
 *     null-terminated buffer. All characters up to and including the last
 | 
			
		||||
 *     character of the matching text or EOF are placed in the buffer. If
 | 
			
		||||
 *     a match is found, patbeg and patlen are set appropriately.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURN VALUES
 | 
			
		||||
 *     0    No match found.
 | 
			
		||||
 *     1    Match found.
 | 
			
		||||
 */  
 | 
			
		||||
 | 
			
		||||
int fnematch(fa *pfa, FILE *f, uschar **pbuf, int *pbufsize, int quantum)	
 | 
			
		||||
{
 | 
			
		||||
	uschar *buf = *pbuf;
 | 
			
		||||
	int bufsize = *pbufsize;
 | 
			
		||||
	int c, i, j, k, ns, s;
 | 
			
		||||
 | 
			
		||||
	s = pfa->initstat;
 | 
			
		||||
	assert(s < pfa->state_count);
 | 
			
		||||
	patlen = 0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * All indices relative to buf.
 | 
			
		||||
	 * i <= j <= k <= bufsize
 | 
			
		||||
	 *
 | 
			
		||||
	 * i: origin of active substring
 | 
			
		||||
	 * j: current character
 | 
			
		||||
	 * k: destination of next getc()
 | 
			
		||||
	 */
 | 
			
		||||
	i = -1, k = 0;
 | 
			
		||||
        do {
 | 
			
		||||
		j = i++;
 | 
			
		||||
		do {
 | 
			
		||||
			if (++j == k) {
 | 
			
		||||
				if (k == bufsize)
 | 
			
		||||
					if (!adjbuf(&buf, &bufsize, bufsize+1, quantum, 0, "fnematch"))
 | 
			
		||||
						FATAL("stream '%.30s...' too long", buf);	
 | 
			
		||||
				buf[k++] = (c = getc(f)) != EOF ? c : 0;
 | 
			
		||||
			}
 | 
			
		||||
			c = buf[j];
 | 
			
		||||
			/* assert(c < NCHARS); */
 | 
			
		||||
 | 
			
		||||
			if ((ns = pfa->gototab[s][c]) != 0)
 | 
			
		||||
				s = ns;
 | 
			
		||||
			else
 | 
			
		||||
				s = cgoto(pfa, s, c);
 | 
			
		||||
			assert(s < pfa->state_count);
 | 
			
		||||
 | 
			
		||||
			if (pfa->out[s]) {	/* final state */
 | 
			
		||||
				patlen = j - i + 1;
 | 
			
		||||
				if (c == 0)	/* don't count $ */
 | 
			
		||||
					patlen--;
 | 
			
		||||
			}
 | 
			
		||||
		} while (buf[j] && s != 1);
 | 
			
		||||
		s = 2;
 | 
			
		||||
	} while (buf[i] && !patlen);
 | 
			
		||||
 | 
			
		||||
	/* adjbuf() may have relocated a resized buffer. Inform the world. */
 | 
			
		||||
	*pbuf = buf;
 | 
			
		||||
	*pbufsize = bufsize;
 | 
			
		||||
 | 
			
		||||
	if (patlen) {
 | 
			
		||||
		patbeg = buf + i;
 | 
			
		||||
		/*
 | 
			
		||||
		 * Under no circumstances is the last character fed to
 | 
			
		||||
		 * the automaton part of the match. It is EOF's nullbyte,
 | 
			
		||||
		 * or it sent the automaton into a state with no further
 | 
			
		||||
		 * transitions available (s==1), or both. Room for a
 | 
			
		||||
		 * terminating nullbyte is guaranteed.
 | 
			
		||||
		 *
 | 
			
		||||
		 * ungetc any chars after the end of matching text
 | 
			
		||||
		 * (except for EOF's nullbyte, if present) and null
 | 
			
		||||
		 * terminate the buffer.
 | 
			
		||||
		 */
 | 
			
		||||
		do
 | 
			
		||||
			if (buf[--k] && ungetc(buf[k], f) == EOF)
 | 
			
		||||
				FATAL("unable to ungetc '%c'", buf[k]);	
 | 
			
		||||
		while (k > i + patlen);
 | 
			
		||||
		buf[k] = 0;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Node *reparse(const char *p)	/* parses regular expression pointed to by p */
 | 
			
		||||
{			/* uses relex() to scan regular expression */
 | 
			
		||||
	Node *np;
 | 
			
		||||
 | 
			
		||||
	dprintf( ("reparse <%s>\n", p) );
 | 
			
		||||
	lastre = prestr = (uschar *) p;	/* prestr points to string to be parsed */
 | 
			
		||||
	lastre = prestr = (const uschar *) p;	/* prestr points to string to be parsed */
 | 
			
		||||
	rtok = relex();
 | 
			
		||||
	/* GNU compatibility: an empty regexp matches anything */
 | 
			
		||||
	if (rtok == '\0') {
 | 
			
		||||
@ -644,11 +756,11 @@ Node *primary(void)
 | 
			
		||||
		rtok = relex();
 | 
			
		||||
		return (unary(op2(DOT, NIL, NIL)));
 | 
			
		||||
	case CCL:
 | 
			
		||||
		np = op2(CCL, NIL, (Node*) cclenter((char *) rlxstr));
 | 
			
		||||
		np = op2(CCL, NIL, (Node*) cclenter((const char *) rlxstr));
 | 
			
		||||
		rtok = relex();
 | 
			
		||||
		return (unary(np));
 | 
			
		||||
	case NCCL:
 | 
			
		||||
		np = op2(NCCL, NIL, (Node *) cclenter((char *) rlxstr));
 | 
			
		||||
		np = op2(NCCL, NIL, (Node *) cclenter((const char *) rlxstr));
 | 
			
		||||
		rtok = relex();
 | 
			
		||||
		return (unary(np));
 | 
			
		||||
	case '^':
 | 
			
		||||
@ -732,23 +844,15 @@ Node *unary(Node *np)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* #define HAS_ISBLANK */
 | 
			
		||||
#ifndef HAS_ISBLANK
 | 
			
		||||
 | 
			
		||||
int (xisblank)(int c)
 | 
			
		||||
{
 | 
			
		||||
	return c==' ' || c=='\t';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct charclass {
 | 
			
		||||
static const struct charclass {
 | 
			
		||||
	const char *cc_name;
 | 
			
		||||
	int cc_namelen;
 | 
			
		||||
	int (*cc_func)(int);
 | 
			
		||||
} charclasses[] = {
 | 
			
		||||
	{ "alnum",	5,	isalnum },
 | 
			
		||||
	{ "alpha",	5,	isalpha },
 | 
			
		||||
	{ "blank",	5,	isspace }, /* was isblank */
 | 
			
		||||
	{ "blank",	5,	isblank },
 | 
			
		||||
	{ "cntrl",	5,	iscntrl },
 | 
			
		||||
	{ "digit",	5,	isdigit },
 | 
			
		||||
	{ "graph",	5,	isgraph },
 | 
			
		||||
@ -769,7 +873,7 @@ int relex(void)		/* lexical analyzer for reparse */
 | 
			
		||||
	static uschar *buf = 0;
 | 
			
		||||
	static int bufsz = 100;
 | 
			
		||||
	uschar *bp;
 | 
			
		||||
	struct charclass *cc;
 | 
			
		||||
	const struct charclass *cc;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	switch (c = *prestr++) {
 | 
			
		||||
@ -785,13 +889,13 @@ int relex(void)		/* lexical analyzer for reparse */
 | 
			
		||||
	case ')':
 | 
			
		||||
		return c;
 | 
			
		||||
	case '\\':
 | 
			
		||||
		rlxval = quoted((char **) &prestr);
 | 
			
		||||
		rlxval = quoted(&prestr);
 | 
			
		||||
		return CHAR;
 | 
			
		||||
	default:
 | 
			
		||||
		rlxval = c;
 | 
			
		||||
		return CHAR;
 | 
			
		||||
	case '[': 
 | 
			
		||||
		if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL)
 | 
			
		||||
		if (buf == 0 && (buf = malloc(bufsz)) == NULL)
 | 
			
		||||
			FATAL("out of space in reg expr %.10s..", lastre);
 | 
			
		||||
		bp = buf;
 | 
			
		||||
		if (*prestr == '^') {
 | 
			
		||||
@ -801,7 +905,7 @@ int relex(void)		/* lexical analyzer for reparse */
 | 
			
		||||
		else
 | 
			
		||||
			cflag = 0;
 | 
			
		||||
		n = 2 * strlen((const char *) prestr)+1;
 | 
			
		||||
		if (!adjbuf((char **) &buf, &bufsz, n, n, (char **) &bp, "relex1"))
 | 
			
		||||
		if (!adjbuf(&buf, &bufsz, n, n, &bp, "relex1"))
 | 
			
		||||
			FATAL("out of space for reg expr %.10s...", lastre);
 | 
			
		||||
		for (; ; ) {
 | 
			
		||||
			if ((c = *prestr++) == '\\') {
 | 
			
		||||
@ -819,8 +923,8 @@ int relex(void)		/* lexical analyzer for reparse */
 | 
			
		||||
				if (cc->cc_name != NULL && prestr[1 + cc->cc_namelen] == ':' &&
 | 
			
		||||
				    prestr[2 + cc->cc_namelen] == ']') {
 | 
			
		||||
					prestr += cc->cc_namelen + 3;
 | 
			
		||||
					for (i = 0; i < NCHARS; i++) {
 | 
			
		||||
						if (!adjbuf((char **) &buf, &bufsz, bp-buf+1, 100, (char **) &bp, "relex2"))
 | 
			
		||||
					for (i = 1; i < NCHARS; i++) {
 | 
			
		||||
						if (!adjbuf(&buf, &bufsz, bp-buf+1, 100, &bp, "relex2"))
 | 
			
		||||
						    FATAL("out of space for reg expr %.10s...", lastre);
 | 
			
		||||
						if (cc->cc_func(i)) {
 | 
			
		||||
							*bp++ = i;
 | 
			
		||||
@ -852,16 +956,12 @@ int cgoto(fa *f, int s, int c)
 | 
			
		||||
	int *p, *q;
 | 
			
		||||
 | 
			
		||||
	assert(c == HAT || c < NCHARS);
 | 
			
		||||
	while (f->accept >= maxsetvec) {	/* guessing here! */
 | 
			
		||||
		maxsetvec *= 4;
 | 
			
		||||
		setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
 | 
			
		||||
		tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
 | 
			
		||||
		if (setvec == 0 || tmpset == 0)
 | 
			
		||||
			overflo("out of space in cgoto()");
 | 
			
		||||
	}
 | 
			
		||||
	while (f->accept >= maxsetvec) 	/* guessing here! */
 | 
			
		||||
		resizesetvec("out of space in cgoto()");
 | 
			
		||||
	for (i = 0; i <= f->accept; i++)
 | 
			
		||||
		setvec[i] = 0;
 | 
			
		||||
	setcnt = 0;
 | 
			
		||||
	resize_state(f, s);
 | 
			
		||||
	/* compute positions of gototab[s,c] into setvec */
 | 
			
		||||
	p = f->posns[s];
 | 
			
		||||
	for (i = 1; i <= *p; i++) {
 | 
			
		||||
@ -874,13 +974,8 @@ int cgoto(fa *f, int s, int c)
 | 
			
		||||
			 || (k == NCCL && !member(c, (char *) f->re[p[i]].lval.up) && c != 0 && c != HAT)) {
 | 
			
		||||
				q = f->re[p[i]].lfollow;
 | 
			
		||||
				for (j = 1; j <= *q; j++) {
 | 
			
		||||
					if (q[j] >= maxsetvec) {
 | 
			
		||||
						maxsetvec *= 4;
 | 
			
		||||
						setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
 | 
			
		||||
						tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
 | 
			
		||||
						if (setvec == 0 || tmpset == 0)
 | 
			
		||||
							overflo("cgoto overflow");
 | 
			
		||||
					}
 | 
			
		||||
					if (q[j] >= maxsetvec)
 | 
			
		||||
						resizesetvec("cgoto overflow");
 | 
			
		||||
					if (setvec[q[j]] == 0) {
 | 
			
		||||
						setcnt++;
 | 
			
		||||
						setvec[q[j]] = 1;
 | 
			
		||||
@ -896,6 +991,8 @@ int cgoto(fa *f, int s, int c)
 | 
			
		||||
		if (setvec[i]) {
 | 
			
		||||
			tmpset[j++] = i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	resize_state(f, f->curstat > s ? f->curstat : s);
 | 
			
		||||
	/* tmpset == previous state? */
 | 
			
		||||
	for (i = 1; i <= f->curstat; i++) {
 | 
			
		||||
		p = f->posns[i];
 | 
			
		||||
@ -905,27 +1002,24 @@ int cgoto(fa *f, int s, int c)
 | 
			
		||||
			if (tmpset[j] != p[j])
 | 
			
		||||
				goto different;
 | 
			
		||||
		/* setvec is state i */
 | 
			
		||||
		f->gototab[s][c] = i;
 | 
			
		||||
		if (c != HAT)
 | 
			
		||||
			f->gototab[s][c] = i;
 | 
			
		||||
		return i;
 | 
			
		||||
	  different:;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* add tmpset to current set of states */
 | 
			
		||||
	if (f->curstat >= NSTATES-1) {
 | 
			
		||||
		f->curstat = 2;
 | 
			
		||||
		f->reset = 1;
 | 
			
		||||
		for (i = 2; i < NSTATES; i++)
 | 
			
		||||
			xfree(f->posns[i]);
 | 
			
		||||
	} else
 | 
			
		||||
		++(f->curstat);
 | 
			
		||||
	++(f->curstat);
 | 
			
		||||
	resize_state(f, f->curstat);
 | 
			
		||||
	for (i = 0; i < NCHARS; i++)
 | 
			
		||||
		f->gototab[f->curstat][i] = 0;
 | 
			
		||||
	xfree(f->posns[f->curstat]);
 | 
			
		||||
	if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL)
 | 
			
		||||
	if ((p = calloc(1, (setcnt+1)*sizeof(int))) == NULL)
 | 
			
		||||
		overflo("out of space in cgoto");
 | 
			
		||||
 | 
			
		||||
	f->posns[f->curstat] = p;
 | 
			
		||||
	f->gototab[s][c] = f->curstat;
 | 
			
		||||
	if (c != HAT)
 | 
			
		||||
		f->gototab[s][c] = f->curstat;
 | 
			
		||||
	for (i = 0; i <= setcnt; i++)
 | 
			
		||||
		p[i] = tmpset[i];
 | 
			
		||||
	if (setvec[f->accept])
 | 
			
		||||
@ -942,13 +1036,18 @@ void freefa(fa *f)	/* free a finite automaton */
 | 
			
		||||
 | 
			
		||||
	if (f == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
	for (i = 0; i <= f->curstat; i++)
 | 
			
		||||
	for (i = 0; i < f->state_count; i++) {
 | 
			
		||||
		xfree(f->gototab[i])
 | 
			
		||||
		xfree(f->posns[i]);
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i <= f->accept; i++) {
 | 
			
		||||
		xfree(f->re[i].lfollow);
 | 
			
		||||
		if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL)
 | 
			
		||||
			xfree((f->re[i].lval.np));
 | 
			
		||||
	}
 | 
			
		||||
	xfree(f->restr);
 | 
			
		||||
	xfree(f->out);
 | 
			
		||||
	xfree(f->posns);
 | 
			
		||||
	xfree(f->gototab);
 | 
			
		||||
	xfree(f);
 | 
			
		||||
}
 | 
			
		||||
@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 | 
			
		||||
THIS SOFTWARE.
 | 
			
		||||
****************************************************************/
 | 
			
		||||
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@ -43,7 +47,11 @@ typedef struct Keyword {
 | 
			
		||||
	int	type;
 | 
			
		||||
} Keyword;
 | 
			
		||||
 | 
			
		||||
Keyword keywords[] ={	/* keep sorted: binary searched */
 | 
			
		||||
int peek(void);
 | 
			
		||||
int gettok(char **, int *);
 | 
			
		||||
int binsearch(const char *, const Keyword *, int);
 | 
			
		||||
 | 
			
		||||
const Keyword keywords[] ={	/* keep sorted: binary searched */
 | 
			
		||||
	{ "BEGIN",	XBEGIN,		XBEGIN },
 | 
			
		||||
	{ "END",	XEND,		XEND },
 | 
			
		||||
	{ "NF",		VARNF,		VARNF },
 | 
			
		||||
@ -61,6 +69,7 @@ Keyword keywords[] ={	/* keep sorted: binary searched */
 | 
			
		||||
	{ "for",	FOR,		FOR },
 | 
			
		||||
	{ "func",	FUNC,		FUNC },
 | 
			
		||||
	{ "function",	FUNC,		FUNC },
 | 
			
		||||
	{ "gensub",	GENSUB,		GENSUB },
 | 
			
		||||
	{ "getline",	GETLINE,	GETLINE },
 | 
			
		||||
	{ "gsub",	GSUB,		GSUB },
 | 
			
		||||
	{ "if",		IF,		IF },
 | 
			
		||||
@ -81,9 +90,11 @@ Keyword keywords[] ={	/* keep sorted: binary searched */
 | 
			
		||||
	{ "sprintf",	SPRINTF,	SPRINTF },
 | 
			
		||||
	{ "sqrt",	FSQRT,		BLTIN },
 | 
			
		||||
	{ "srand",	FSRAND,		BLTIN },
 | 
			
		||||
	{ "strftime",	FSTRFTIME,	BLTIN },
 | 
			
		||||
	{ "sub",	SUB,		SUB },
 | 
			
		||||
	{ "substr",	SUBSTR,		SUBSTR },
 | 
			
		||||
	{ "system",	FSYSTEM,	BLTIN },
 | 
			
		||||
	{ "systime",	FSYSTIME,	BLTIN },
 | 
			
		||||
	{ "tolower",	FTOLOWER,	BLTIN },
 | 
			
		||||
	{ "toupper",	FTOUPPER,	BLTIN },
 | 
			
		||||
	{ "while",	WHILE,		WHILE },
 | 
			
		||||
@ -101,9 +112,9 @@ int peek(void)
 | 
			
		||||
int gettok(char **pbuf, int *psz)	/* get next input token */
 | 
			
		||||
{
 | 
			
		||||
	int c, retc;
 | 
			
		||||
	char *buf = *pbuf;
 | 
			
		||||
	uschar *buf = (uschar *) *pbuf;
 | 
			
		||||
	int sz = *psz;
 | 
			
		||||
	char *bp = buf;
 | 
			
		||||
	uschar *bp = buf;
 | 
			
		||||
 | 
			
		||||
	c = input();
 | 
			
		||||
	if (c == 0)
 | 
			
		||||
@ -146,7 +157,7 @@ int gettok(char **pbuf, int *psz)	/* get next input token */
 | 
			
		||||
		}
 | 
			
		||||
		*bp = 0;
 | 
			
		||||
		strtod(buf, &rem);	/* parse the number */
 | 
			
		||||
		if (rem == buf) {	/* it wasn't a valid number at all */
 | 
			
		||||
		if (rem == (char *)buf) {	/* it wasn't a valid number at all */
 | 
			
		||||
			buf[1] = 0;	/* return one character as token */
 | 
			
		||||
			retc = buf[0];	/* character is its own type */
 | 
			
		||||
			unputstr(rem+1); /* put rest back for later */
 | 
			
		||||
@ -173,7 +184,7 @@ int yylex(void)
 | 
			
		||||
	static char *buf = 0;
 | 
			
		||||
	static int bufsize = 5; /* BUG: setting this small causes core dump! */
 | 
			
		||||
 | 
			
		||||
	if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL)
 | 
			
		||||
	if (buf == 0 && (buf = malloc(bufsize)) == NULL)
 | 
			
		||||
		FATAL( "out of space in yylex" );
 | 
			
		||||
	if (sc) {
 | 
			
		||||
		sc = 0;
 | 
			
		||||
@ -357,11 +368,11 @@ int yylex(void)
 | 
			
		||||
int string(void)
 | 
			
		||||
{
 | 
			
		||||
	int c, n;
 | 
			
		||||
	char *s, *bp;
 | 
			
		||||
	static char *buf = 0;
 | 
			
		||||
	uschar *s, *bp;
 | 
			
		||||
	static uschar *buf = 0;
 | 
			
		||||
	static int bufsz = 500;
 | 
			
		||||
 | 
			
		||||
	if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
 | 
			
		||||
	if (buf == 0 && (buf = malloc(bufsz)) == NULL)
 | 
			
		||||
		FATAL("out of space for strings");
 | 
			
		||||
	for (bp = buf; (c = input()) != '"'; ) {
 | 
			
		||||
		if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
 | 
			
		||||
@ -378,6 +389,7 @@ int string(void)
 | 
			
		||||
		case '\\':
 | 
			
		||||
			c = input();
 | 
			
		||||
			switch (c) {
 | 
			
		||||
			case '\n': break;
 | 
			
		||||
			case '"': *bp++ = '"'; break;
 | 
			
		||||
			case 'n': *bp++ = '\n'; break;	
 | 
			
		||||
			case 't': *bp++ = '\t'; break;
 | 
			
		||||
@ -416,7 +428,9 @@ int string(void)
 | 
			
		||||
				break;
 | 
			
		||||
			    }
 | 
			
		||||
 | 
			
		||||
			default: 
 | 
			
		||||
			default:
 | 
			
		||||
				WARNING("warning: escape sequence `\\%c' "
 | 
			
		||||
				    "treated as plain `%c'", c, c);
 | 
			
		||||
				*bp++ = c;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
@ -454,7 +468,7 @@ int binsearch(const char *w, const Keyword *kp, int n)
 | 
			
		||||
 | 
			
		||||
int word(char *w) 
 | 
			
		||||
{
 | 
			
		||||
	Keyword *kp;
 | 
			
		||||
	const Keyword *kp;
 | 
			
		||||
	int c, n;
 | 
			
		||||
 | 
			
		||||
	n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
 | 
			
		||||
@ -504,11 +518,11 @@ void startreg(void)	/* next call to yylex will return a regular expression */
 | 
			
		||||
int regexpr(void)
 | 
			
		||||
{
 | 
			
		||||
	int c;
 | 
			
		||||
	static char *buf = 0;
 | 
			
		||||
	static uschar *buf = 0;
 | 
			
		||||
	static int bufsz = 500;
 | 
			
		||||
	char *bp;
 | 
			
		||||
	uschar *bp;
 | 
			
		||||
 | 
			
		||||
	if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
 | 
			
		||||
	if (buf == 0 && (buf = malloc(bufsz)) == NULL)
 | 
			
		||||
		FATAL("out of space for rex expr");
 | 
			
		||||
	bp = buf;
 | 
			
		||||
	for ( ; (c = input()) != '/' && c != 0; ) {
 | 
			
		||||
@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 | 
			
		||||
THIS SOFTWARE.
 | 
			
		||||
****************************************************************/
 | 
			
		||||
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEBUG
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@ -32,15 +36,19 @@ THIS SOFTWARE.
 | 
			
		||||
#include "awk.h"
 | 
			
		||||
#include "awkgram.h"
 | 
			
		||||
 | 
			
		||||
char	EMPTY[] = { '\0' };
 | 
			
		||||
FILE	*infile	= NULL;
 | 
			
		||||
char	*file	= "";
 | 
			
		||||
char	*record;
 | 
			
		||||
int	innew;		/* 1 = infile has not been read by readrec */
 | 
			
		||||
char	*file	= EMPTY;
 | 
			
		||||
uschar	*record;
 | 
			
		||||
int	recsize	= RECSIZE;
 | 
			
		||||
char	*fields;
 | 
			
		||||
int	fieldssize = RECSIZE;
 | 
			
		||||
 | 
			
		||||
Cell	**fldtab;	/* pointers to Cells */
 | 
			
		||||
char	inputFS[100] = " ";
 | 
			
		||||
 | 
			
		||||
static size_t	len_inputFS = 0;
 | 
			
		||||
static char	*inputFS = NULL;
 | 
			
		||||
 | 
			
		||||
#define	MAXFLD	2
 | 
			
		||||
int	nfields	= MAXFLD;	/* last allocated slot for $i */
 | 
			
		||||
@ -52,15 +60,15 @@ int	lastfld	= 0;	/* last used field */
 | 
			
		||||
int	argno	= 1;	/* current input argument number */
 | 
			
		||||
extern	Awkfloat *ARGC;
 | 
			
		||||
 | 
			
		||||
static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
 | 
			
		||||
static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
 | 
			
		||||
static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL };
 | 
			
		||||
static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL };
 | 
			
		||||
 | 
			
		||||
void recinit(unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	if ( (record = (char *) malloc(n)) == NULL
 | 
			
		||||
	  || (fields = (char *) malloc(n+1)) == NULL
 | 
			
		||||
	  || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL
 | 
			
		||||
	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
 | 
			
		||||
	if ( (record = malloc(n)) == NULL
 | 
			
		||||
	  || (fields = malloc(n+1)) == NULL
 | 
			
		||||
	  || (fldtab = malloc((nfields+1) * sizeof(*fldtab))) == NULL
 | 
			
		||||
	  || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL )
 | 
			
		||||
		FATAL("out of space for $0 and fields");
 | 
			
		||||
	*fldtab[0] = dollar0;
 | 
			
		||||
	fldtab[0]->sval = record;
 | 
			
		||||
@ -74,11 +82,11 @@ void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = n1; i <= n2; i++) {
 | 
			
		||||
		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
 | 
			
		||||
		fldtab[i] = malloc(sizeof(**fldtab));
 | 
			
		||||
		if (fldtab[i] == NULL)
 | 
			
		||||
			FATAL("out of space in makefields %d", i);
 | 
			
		||||
		*fldtab[i] = dollar1;
 | 
			
		||||
		sprintf(temp, "%d", i);
 | 
			
		||||
		snprintf(temp, sizeof(temp), "%d", i);
 | 
			
		||||
		fldtab[i]->nval = tostring(temp);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -97,14 +105,15 @@ void initgetrec(void)
 | 
			
		||||
		argno++;
 | 
			
		||||
	}
 | 
			
		||||
	infile = stdin;		/* no filenames, so use stdin */
 | 
			
		||||
	innew = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int firsttime = 1;
 | 
			
		||||
 | 
			
		||||
int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
 | 
			
		||||
int getrec(uschar **pbuf, int *pbufsize, int isrecord)	/* get next input record */
 | 
			
		||||
{			/* note: cares whether buf == record */
 | 
			
		||||
	int c;
 | 
			
		||||
	char *buf = *pbuf;
 | 
			
		||||
	uschar *buf = *pbuf;
 | 
			
		||||
	uschar saveb0;
 | 
			
		||||
	int bufsize = *pbufsize, savebufsize = bufsize;
 | 
			
		||||
 | 
			
		||||
@ -139,9 +148,12 @@ int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
 | 
			
		||||
				infile = stdin;
 | 
			
		||||
			else if ((infile = fopen(file, "r")) == NULL)
 | 
			
		||||
				FATAL("can't open file %s", file);
 | 
			
		||||
			innew = 1;
 | 
			
		||||
			setfval(fnrloc, 0.0);
 | 
			
		||||
		}
 | 
			
		||||
		c = readrec(&buf, &bufsize, infile);
 | 
			
		||||
		c = readrec(&buf, &bufsize, infile, innew);
 | 
			
		||||
		if (innew)
 | 
			
		||||
			innew = 0;
 | 
			
		||||
		if (c != 0 || buf[0] != '\0') {	/* normal record */
 | 
			
		||||
			if (isrecord) {
 | 
			
		||||
				if (freeable(fldtab[0]))
 | 
			
		||||
@ -179,45 +191,71 @@ void nextfile(void)
 | 
			
		||||
	argno++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
 | 
			
		||||
int readrec(uschar **pbuf, int *pbufsize, FILE *inf, int newflag)	/* read one record into buf */
 | 
			
		||||
{
 | 
			
		||||
	int sep, c;
 | 
			
		||||
	char *rr, *buf = *pbuf;
 | 
			
		||||
	int sep, c, isrec, found, tempstat;
 | 
			
		||||
	uschar *rr, *buf = *pbuf;
 | 
			
		||||
	int bufsize = *pbufsize;
 | 
			
		||||
	size_t len;
 | 
			
		||||
 | 
			
		||||
	if (strlen(*FS) >= sizeof(inputFS))
 | 
			
		||||
		FATAL("field separator %.10s... is too long", *FS);
 | 
			
		||||
	strcpy(inputFS, *FS);	/* for subsequent field splitting */
 | 
			
		||||
	if ((sep = **RS) == 0) {
 | 
			
		||||
		sep = '\n';
 | 
			
		||||
		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
 | 
			
		||||
			;
 | 
			
		||||
		if (c != EOF)
 | 
			
		||||
			ungetc(c, inf);
 | 
			
		||||
	if ((len = strlen(*FS)) < len_inputFS) {
 | 
			
		||||
		strcpy(inputFS, *FS);	/* for subsequent field splitting */
 | 
			
		||||
	} else {
 | 
			
		||||
		len_inputFS = len + 1;
 | 
			
		||||
		inputFS = realloc(inputFS, len_inputFS);
 | 
			
		||||
		if (inputFS == NULL)
 | 
			
		||||
			FATAL("field separator %.10s... is too long", *FS);
 | 
			
		||||
		memcpy(inputFS, *FS, len_inputFS);
 | 
			
		||||
	}
 | 
			
		||||
	for (rr = buf; ; ) {
 | 
			
		||||
		for (; (c=getc(inf)) != sep && c != EOF; ) {
 | 
			
		||||
			if (rr-buf+1 > bufsize)
 | 
			
		||||
				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
 | 
			
		||||
					FATAL("input record `%.30s...' too long", buf);
 | 
			
		||||
	if (**RS && (*RS)[1]) {
 | 
			
		||||
		fa *pfa = makedfa(*RS, 1);
 | 
			
		||||
		if (newflag)
 | 
			
		||||
			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
 | 
			
		||||
		else {
 | 
			
		||||
			tempstat = pfa->initstat;
 | 
			
		||||
			pfa->initstat = 2;
 | 
			
		||||
			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
 | 
			
		||||
			pfa->initstat = tempstat;
 | 
			
		||||
		}
 | 
			
		||||
		if (found)
 | 
			
		||||
			*patbeg = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		if ((sep = **RS) == 0) {
 | 
			
		||||
			sep = '\n';
 | 
			
		||||
			while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
 | 
			
		||||
				;
 | 
			
		||||
			if (c != EOF)
 | 
			
		||||
				ungetc(c, inf);
 | 
			
		||||
		}
 | 
			
		||||
		for (rr = buf; ; ) {
 | 
			
		||||
			for (; (c=getc(inf)) != sep && c != EOF; ) {
 | 
			
		||||
				if (rr-buf+1 > bufsize)
 | 
			
		||||
					if (!adjbuf(&buf, &bufsize, 1+rr-buf,
 | 
			
		||||
					    recsize, &rr, "readrec 1"))
 | 
			
		||||
						FATAL("input record `%.30s...'"
 | 
			
		||||
						    " too long", buf);
 | 
			
		||||
				*rr++ = c;
 | 
			
		||||
			}
 | 
			
		||||
			if (**RS == sep || c == EOF)
 | 
			
		||||
				break;
 | 
			
		||||
			if ((c = getc(inf)) == '\n' || c == EOF)
 | 
			
		||||
				/* 2 in a row */
 | 
			
		||||
				break;
 | 
			
		||||
			if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
 | 
			
		||||
			    "readrec 2"))
 | 
			
		||||
				FATAL("input record `%.30s...' too long", buf);
 | 
			
		||||
			*rr++ = '\n';
 | 
			
		||||
			*rr++ = c;
 | 
			
		||||
		}
 | 
			
		||||
		if (**RS == sep || c == EOF)
 | 
			
		||||
			break;
 | 
			
		||||
		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
 | 
			
		||||
			break;
 | 
			
		||||
		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
 | 
			
		||||
		if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
 | 
			
		||||
			FATAL("input record `%.30s...' too long", buf);
 | 
			
		||||
		*rr++ = '\n';
 | 
			
		||||
		*rr++ = c;
 | 
			
		||||
		*rr = 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
 | 
			
		||||
		FATAL("input record `%.30s...' too long", buf);
 | 
			
		||||
	*rr = 0;
 | 
			
		||||
	   dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
 | 
			
		||||
	*pbuf = buf;
 | 
			
		||||
	*pbufsize = bufsize;
 | 
			
		||||
	return c == EOF && rr == buf ? 0 : 1;
 | 
			
		||||
	isrec = *buf || !feof(inf);
 | 
			
		||||
	   dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) );
 | 
			
		||||
	return isrec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *getargv(int n)	/* get ARGV[n] */
 | 
			
		||||
@ -226,7 +264,7 @@ char *getargv(int n)	/* get ARGV[n] */
 | 
			
		||||
	char *s, temp[50];
 | 
			
		||||
	extern Array *ARGVtab;
 | 
			
		||||
 | 
			
		||||
	sprintf(temp, "%d", n);
 | 
			
		||||
	snprintf(temp, sizeof(temp), "%d", n);
 | 
			
		||||
	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
 | 
			
		||||
	s = getsval(x);
 | 
			
		||||
	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
 | 
			
		||||
@ -268,14 +306,15 @@ void fldbld(void)	/* create fields from current record */
 | 
			
		||||
	n = strlen(r);
 | 
			
		||||
	if (n > fieldssize) {
 | 
			
		||||
		xfree(fields);
 | 
			
		||||
		if ((fields = (char *) malloc(n+1)) == NULL)
 | 
			
		||||
		if ((fields = malloc(n+1)) == NULL)
 | 
			
		||||
			FATAL("out of space for fields in fldbld %d", n);
 | 
			
		||||
		fieldssize = n;
 | 
			
		||||
	}
 | 
			
		||||
	fr = fields;
 | 
			
		||||
	i = 0;	/* number of fields accumulated here */
 | 
			
		||||
	strcpy(inputFS, *FS);
 | 
			
		||||
	if (strlen(inputFS) > 1) {	/* it's a regular expression */
 | 
			
		||||
	if (!inputFS) {
 | 
			
		||||
		/* do nothing */
 | 
			
		||||
	} else if (inputFS[0] && inputFS[1]) {	/* it's a regular expression */
 | 
			
		||||
		i = refldbld(r, inputFS);
 | 
			
		||||
	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
 | 
			
		||||
		for (i = 0; ; ) {
 | 
			
		||||
@ -347,6 +386,7 @@ void fldbld(void)	/* create fields from current record */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	setfval(nfloc, (Awkfloat) lastfld);
 | 
			
		||||
	donerec = 1; /* restore */
 | 
			
		||||
	if (dbg) {
 | 
			
		||||
		for (j = 0; j <= lastfld; j++) {
 | 
			
		||||
			p = fldtab[j];
 | 
			
		||||
@ -364,7 +404,7 @@ void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
 | 
			
		||||
		p = fldtab[i];
 | 
			
		||||
		if (freeable(p))
 | 
			
		||||
			xfree(p->sval);
 | 
			
		||||
		p->sval = "";
 | 
			
		||||
		p->sval = EMPTY;
 | 
			
		||||
		p->tval = FLD | STR | DONTFREE;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -378,6 +418,19 @@ void newfld(int n)	/* add field n after end of existing lastfld */
 | 
			
		||||
	setfval(nfloc, (Awkfloat) n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setlastfld(int n)	/* set lastfld cleaning fldtab cells if necessary */
 | 
			
		||||
{
 | 
			
		||||
	if (n > nfields)
 | 
			
		||||
		growfldtab(n);
 | 
			
		||||
 | 
			
		||||
	if (lastfld < n)
 | 
			
		||||
	    cleanfld(lastfld+1, n);
 | 
			
		||||
	else
 | 
			
		||||
	    cleanfld(n+1, lastfld);
 | 
			
		||||
 | 
			
		||||
	lastfld = n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cell *fieldadr(int n)	/* get nth field */
 | 
			
		||||
{
 | 
			
		||||
	if (n < 0)
 | 
			
		||||
@ -395,8 +448,8 @@ void growfldtab(int n)	/* make new fields up to at least $n */
 | 
			
		||||
	if (n > nf)
 | 
			
		||||
		nf = n;
 | 
			
		||||
	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
 | 
			
		||||
	if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
 | 
			
		||||
		fldtab = (Cell **) realloc(fldtab, s);
 | 
			
		||||
	if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
 | 
			
		||||
		fldtab = realloc(fldtab, s);
 | 
			
		||||
	else					/* overflow sizeof int */
 | 
			
		||||
		xfree(fldtab);	/* make it null */
 | 
			
		||||
	if (fldtab == NULL)
 | 
			
		||||
@ -416,7 +469,7 @@ int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in F
 | 
			
		||||
	n = strlen(rec);
 | 
			
		||||
	if (n > fieldssize) {
 | 
			
		||||
		xfree(fields);
 | 
			
		||||
		if ((fields = (char *) malloc(n+1)) == NULL)
 | 
			
		||||
		if ((fields = malloc(n+1)) == NULL)
 | 
			
		||||
			FATAL("out of space for fields in refldbld %d", n);
 | 
			
		||||
		fieldssize = n;
 | 
			
		||||
	}
 | 
			
		||||
@ -438,8 +491,8 @@ int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in F
 | 
			
		||||
		if (nematch(pfa, rec)) {
 | 
			
		||||
			pfa->initstat = 2;	/* horrible coupling to b.c */
 | 
			
		||||
			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
 | 
			
		||||
			strncpy(fr, rec, patbeg-rec);
 | 
			
		||||
			fr += patbeg - rec + 1;
 | 
			
		||||
			strncpy(fr, rec, ((const char*)patbeg)-rec);
 | 
			
		||||
			fr += ((const char*)patbeg) - rec + 1;
 | 
			
		||||
			*(fr-1) = '\0';
 | 
			
		||||
			rec = patbeg + patlen;
 | 
			
		||||
		} else {
 | 
			
		||||
@ -455,7 +508,8 @@ int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in F
 | 
			
		||||
void recbld(void)	/* create $0 from $1..$NF if necessary */
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	char *r, *p;
 | 
			
		||||
	uschar *r;
 | 
			
		||||
	char *p;
 | 
			
		||||
 | 
			
		||||
	if (donerec == 1)
 | 
			
		||||
		return;
 | 
			
		||||
@ -517,11 +571,6 @@ void SYNTAX(const char *fmt, ...)
 | 
			
		||||
	eprint();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void fpecatch(int n)
 | 
			
		||||
{
 | 
			
		||||
	FATAL("floating point exception %d", n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern int bracecnt, brackcnt, parencnt;
 | 
			
		||||
 | 
			
		||||
void bracecheck(void)
 | 
			
		||||
@ -603,7 +652,6 @@ void error()
 | 
			
		||||
void eprint(void)	/* try to print context around error */
 | 
			
		||||
{
 | 
			
		||||
	char *p, *q;
 | 
			
		||||
	int c;
 | 
			
		||||
	static int been_here = 0;
 | 
			
		||||
	extern char ebuf[], *ep;
 | 
			
		||||
 | 
			
		||||
@ -627,11 +675,25 @@ void eprint(void)	/* try to print context around error */
 | 
			
		||||
		if (*p)
 | 
			
		||||
			putc(*p, stderr);
 | 
			
		||||
	fprintf(stderr, " <<< ");
 | 
			
		||||
	if (*ep)
 | 
			
		||||
#if 0
 | 
			
		||||
	/*
 | 
			
		||||
	 * The following code was used to print the rest of the line of
 | 
			
		||||
	 * error context. It naively counts brackets, parens and braces in
 | 
			
		||||
	 * order to minimize the parsing effect of dropping the rest of the
 | 
			
		||||
	 * line but it does not work in all the cases. It is too much work
 | 
			
		||||
	 * to save the current program input point and restore it in all the
 | 
			
		||||
	 * cases just for the benefit of error printing so for now this
 | 
			
		||||
	 * code is disabled. In particular this code is confused if the
 | 
			
		||||
	 * [ { ( ) } ] is inside a quoted string or a pattern.
 | 
			
		||||
	 */
 | 
			
		||||
	if (*ep) {
 | 
			
		||||
		int c;
 | 
			
		||||
		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
 | 
			
		||||
			putc(c, stderr);
 | 
			
		||||
			bclass(c);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	putc('\n', stderr);
 | 
			
		||||
	ep = ebuf;
 | 
			
		||||
}
 | 
			
		||||
@ -686,7 +748,9 @@ int is_number(const char *s)
 | 
			
		||||
	char *ep;
 | 
			
		||||
	errno = 0;
 | 
			
		||||
	r = strtod(s, &ep);
 | 
			
		||||
	if (ep == s || r == HUGE_VAL || errno == ERANGE)
 | 
			
		||||
	if (ep == s || errno == ERANGE)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (ep - s >= 3 && strncasecmp(ep - 3, "nan", 3) == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
 | 
			
		||||
		ep++;
 | 
			
		||||
@ -22,7 +22,11 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 | 
			
		||||
THIS SOFTWARE.
 | 
			
		||||
****************************************************************/
 | 
			
		||||
 | 
			
		||||
const char	*version = "version 20100208";
 | 
			
		||||
const char	*version = "version 20100523";
 | 
			
		||||
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEBUG
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
@ -38,6 +42,7 @@ extern	char	**environ;
 | 
			
		||||
extern	int	nfields;
 | 
			
		||||
 | 
			
		||||
int	dbg	= 0;
 | 
			
		||||
unsigned int srand_seed;
 | 
			
		||||
char	*cmdname;	/* gets argv[0] for error messages */
 | 
			
		||||
extern	FILE	*yyin;	/* lex input file */
 | 
			
		||||
char	*lexprog;	/* points to program argument if it exists */
 | 
			
		||||
@ -45,19 +50,59 @@ extern	int errorflag;	/* non-zero if any syntax errors; set by yyerror */
 | 
			
		||||
int	compile_time = 2;	/* for error printing: */
 | 
			
		||||
				/* 2 = cmdline, 1 = compile, 0 = running */
 | 
			
		||||
 | 
			
		||||
#define	MAX_PFILE	20	/* max number of -f's */
 | 
			
		||||
 | 
			
		||||
char	*pfile[MAX_PFILE];	/* program filenames from -f's */
 | 
			
		||||
int	npfile = 0;	/* number of filenames */
 | 
			
		||||
int	curpfile = 0;	/* current filename */
 | 
			
		||||
static char	**pfile = NULL;	/* program filenames from -f's */
 | 
			
		||||
static size_t 	maxpfile = 0;	/* max program filenames */
 | 
			
		||||
static size_t	npfile = 0;	/* number of filenames */
 | 
			
		||||
static size_t	curpfile = 0;	/* current filename */
 | 
			
		||||
 | 
			
		||||
int	safe	= 0;	/* 1 => "safe" mode */
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
setfs(char *p)
 | 
			
		||||
{
 | 
			
		||||
#ifdef notdef
 | 
			
		||||
	/* wart: t=>\t */
 | 
			
		||||
	if (p[0] == 't' && p[1] == 0)
 | 
			
		||||
		return "\t";
 | 
			
		||||
	else
 | 
			
		||||
#endif
 | 
			
		||||
	if (p[0] != 0)
 | 
			
		||||
		return p;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__dead static void fpecatch(int n
 | 
			
		||||
#ifdef SA_SIGINFO
 | 
			
		||||
	, siginfo_t *si, void *uc
 | 
			
		||||
#endif
 | 
			
		||||
)
 | 
			
		||||
{
 | 
			
		||||
#ifdef SA_SIGINFO
 | 
			
		||||
	static const char *emsg[] = {
 | 
			
		||||
	    "Unknown error",
 | 
			
		||||
	    "Integer divide by zero",
 | 
			
		||||
	    "Integer overflow",
 | 
			
		||||
	    "Floating point divide by zero",
 | 
			
		||||
	    "Floating point overflow",
 | 
			
		||||
	    "Floating point underflow",
 | 
			
		||||
	    "Floating point inexact result",
 | 
			
		||||
	    "Invalid Floating point operation",
 | 
			
		||||
	    "Subscript out of range",
 | 
			
		||||
	};
 | 
			
		||||
#endif
 | 
			
		||||
	FATAL("floating point exception"
 | 
			
		||||
#ifdef SA_SIGINFO
 | 
			
		||||
	    ": %s\n", emsg[si->si_code >= 1 && si->si_code <= 8 ?
 | 
			
		||||
	    si->si_code : 0]
 | 
			
		||||
#endif
 | 
			
		||||
	    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	const char *fs = NULL;
 | 
			
		||||
 | 
			
		||||
	setlocale(LC_CTYPE, "");
 | 
			
		||||
	setlocale(LC_ALL, "");
 | 
			
		||||
	setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
 | 
			
		||||
	cmdname = argv[0];
 | 
			
		||||
	if (argc == 1) {
 | 
			
		||||
@ -66,7 +111,22 @@ int main(int argc, char *argv[])
 | 
			
		||||
		  cmdname);
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	signal(SIGFPE, fpecatch);
 | 
			
		||||
 | 
			
		||||
#ifdef SA_SIGINFO
 | 
			
		||||
	{
 | 
			
		||||
		struct sigaction sa;
 | 
			
		||||
		sa.sa_sigaction = fpecatch;
 | 
			
		||||
		sa.sa_flags = SA_SIGINFO;
 | 
			
		||||
		sigemptyset(&sa.sa_mask);
 | 
			
		||||
		(void)sigaction(SIGFPE, &sa, NULL);
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	(void)signal(SIGFPE, fpecatch);
 | 
			
		||||
#endif
 | 
			
		||||
	/* Set and keep track of the random seed */
 | 
			
		||||
	srand_seed = 1;
 | 
			
		||||
	srand(srand_seed);
 | 
			
		||||
 | 
			
		||||
	yyin = NULL;
 | 
			
		||||
	symtab = makesymtab(NSYMTAB/NSYMTAB);
 | 
			
		||||
	while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
 | 
			
		||||
@ -90,22 +150,23 @@ int main(int argc, char *argv[])
 | 
			
		||||
			argv++;
 | 
			
		||||
			if (argc <= 1)
 | 
			
		||||
				FATAL("no program filename");
 | 
			
		||||
			if (npfile >= MAX_PFILE - 1)
 | 
			
		||||
				FATAL("too many -f options"); 
 | 
			
		||||
			if (npfile >= maxpfile) {
 | 
			
		||||
				maxpfile += 20;
 | 
			
		||||
				pfile = realloc(pfile,
 | 
			
		||||
				    maxpfile * sizeof(*pfile));
 | 
			
		||||
				if (pfile == NULL)
 | 
			
		||||
					FATAL("error allocating space for "
 | 
			
		||||
					    "-f options"); 
 | 
			
		||||
			}
 | 
			
		||||
			pfile[npfile++] = argv[1];
 | 
			
		||||
			break;
 | 
			
		||||
		case 'F':	/* set field separator */
 | 
			
		||||
			if (argv[1][2] != 0) {	/* arg is -Fsomething */
 | 
			
		||||
				if (argv[1][2] == 't' && argv[1][3] == 0)	/* wart: t=>\t */
 | 
			
		||||
					fs = "\t";
 | 
			
		||||
				else if (argv[1][2] != 0)
 | 
			
		||||
					fs = &argv[1][2];
 | 
			
		||||
				fs = setfs(argv[1] + 2);
 | 
			
		||||
			} else {		/* arg is -F something */
 | 
			
		||||
				argc--; argv++;
 | 
			
		||||
				if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0)	/* wart: t=>\t */
 | 
			
		||||
					fs = "\t";
 | 
			
		||||
				else if (argc > 1 && argv[1][0] != 0)
 | 
			
		||||
					fs = &argv[1][0];
 | 
			
		||||
				if (argc > 1)
 | 
			
		||||
					fs = setfs(argv[1]);
 | 
			
		||||
			}
 | 
			
		||||
			if (fs == NULL || *fs == '\0')
 | 
			
		||||
				WARNING("field separator FS is empty");
 | 
			
		||||
@ -113,6 +174,8 @@ int main(int argc, char *argv[])
 | 
			
		||||
		case 'v':	/* -v a=1 to be done NOW.  one -v for each */
 | 
			
		||||
			if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1]))
 | 
			
		||||
				setclvar(argv[1]);
 | 
			
		||||
			else if (argv[1][2] != '\0')
 | 
			
		||||
				setclvar(&argv[1][2]);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'd':
 | 
			
		||||
			dbg = atoi(&argv[1][2]);
 | 
			
		||||
@ -148,7 +211,6 @@ int main(int argc, char *argv[])
 | 
			
		||||
	if (!safe)
 | 
			
		||||
		envinit(environ);
 | 
			
		||||
	yyparse();
 | 
			
		||||
	setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
 | 
			
		||||
	if (fs)
 | 
			
		||||
		*FS = qstring(fs, '\0');
 | 
			
		||||
	   dprintf( ("errorflag=%d\n", errorflag) );
 | 
			
		||||
@ -26,13 +26,13 @@ CFLAGS = -g
 | 
			
		||||
CFLAGS = -O2
 | 
			
		||||
CFLAGS =
 | 
			
		||||
 | 
			
		||||
CC = gcc -Wall -g
 | 
			
		||||
CC = /opt/SUNWspro/bin/cc
 | 
			
		||||
CC = /opt/pure/purify/purify cc
 | 
			
		||||
CC = cc
 | 
			
		||||
CC = gcc -Wall -g -Wwrite-strings
 | 
			
		||||
CC = gcc -fprofile-arcs -ftest-coverage # then gcov f1.c; cat f1.c.gcov
 | 
			
		||||
CC = gcc -Wall -g
 | 
			
		||||
CC = cc
 | 
			
		||||
CC = gcc -O4
 | 
			
		||||
CC = cc -O
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
YACC = bison -y
 | 
			
		||||
YACC = yacc
 | 
			
		||||
@ -49,19 +49,13 @@ LISTING = awk.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c \
 | 
			
		||||
SHIP = README FIXES $(SOURCE) ytab[ch].bak makefile makefile.win \
 | 
			
		||||
	vcvars32.bat buildwin.bat awk.1
 | 
			
		||||
 | 
			
		||||
all: awk
 | 
			
		||||
 | 
			
		||||
install: awk awk.1
 | 
			
		||||
	install -m 755 -o bin -g operator awk /usr/bin/awk
 | 
			
		||||
	install -m 644 -o bin -g operator awk.1 /usr/man/man1
 | 
			
		||||
 | 
			
		||||
awk:	ytab.o $(OFILES)
 | 
			
		||||
	$(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC)  -lm -o $@
 | 
			
		||||
a.out:	ytab.o $(OFILES)
 | 
			
		||||
	$(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC)  -lm
 | 
			
		||||
 | 
			
		||||
$(OFILES):	awk.h ytab.h proto.h
 | 
			
		||||
 | 
			
		||||
ytab.o ytab.c ytab.h:	awk.h proto.h awkgram.y
 | 
			
		||||
	$(YACC) $(YFLAGS) awkgram.y 2>/dev/null
 | 
			
		||||
ytab.o:	awk.h proto.h awkgram.y
 | 
			
		||||
	$(YACC) $(YFLAGS) awkgram.y
 | 
			
		||||
	mv y.tab.c ytab.c
 | 
			
		||||
	mv y.tab.h ytab.h
 | 
			
		||||
	$(CC) $(CFLAGS) -c ytab.c
 | 
			
		||||
@ -91,4 +85,4 @@ names:
 | 
			
		||||
	@echo $(LISTING)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f awk *.o *.obj maketab maketab.exe *.bb *.bbg *.da *.gcov *.gcno *.gcda # proctab.c
 | 
			
		||||
	rm -f a.out *.o *.obj maketab maketab.exe ytab.[ch] *.bb *.bbg *.da *.gcov *.gcno *.gcda # proctab.c
 | 
			
		||||
@ -25,9 +25,13 @@ THIS SOFTWARE.
 | 
			
		||||
/*
 | 
			
		||||
 * this program makes the table to link function names
 | 
			
		||||
 * and type indices that is used by execute() in run.c.
 | 
			
		||||
 * it finds the indices in awkgram.h, produced by yacc.
 | 
			
		||||
 * it finds the indices in ytab.h, produced by yacc.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
@ -103,6 +107,7 @@ struct xx
 | 
			
		||||
	{ ARG, "arg", "arg" },
 | 
			
		||||
	{ VARNF, "getnf", "NF" },
 | 
			
		||||
	{ GETLINE, "awkgetline", "getline" },
 | 
			
		||||
	{ GENSUB, "gensub", "gensub" },
 | 
			
		||||
	{ 0, "", "" },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -128,19 +133,22 @@ int main(int argc, char *argv[])
 | 
			
		||||
		fprintf(stderr, "maketab can't open awkgram.h!\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	printf("static char *printname[%d] = {\n", SIZE);
 | 
			
		||||
	printf("static const char * const printname[%d] = {\n", SIZE);
 | 
			
		||||
	i = 0;
 | 
			
		||||
	while (fgets(buf, sizeof buf, fp) != NULL) {
 | 
			
		||||
		n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok);
 | 
			
		||||
		n = sscanf(buf, "%1c %199s %199s %d", &c, def, name, &tok);
 | 
			
		||||
		if (c != '#' || (n != 4 && strcmp(def,"define") != 0))	/* not a valid #define */
 | 
			
		||||
			continue;
 | 
			
		||||
		if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
 | 
			
		||||
			/* fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf); */
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1);
 | 
			
		||||
		strcpy(names[tok-FIRSTTOKEN], name);
 | 
			
		||||
		printf("\t(char *) \"%s\",\t/* %d */\n", name, tok);
 | 
			
		||||
		names[tok-FIRSTTOKEN] = strdup(name);
 | 
			
		||||
		if (names[tok-FIRSTTOKEN] == NULL) {
 | 
			
		||||
			fprintf(stderr, "maketab out of space copying %s", name);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		printf("\t\"%s\",\t/* %d */\n", name, tok);
 | 
			
		||||
		i++;
 | 
			
		||||
	}
 | 
			
		||||
	printf("};\n\n");
 | 
			
		||||
@ -155,11 +163,11 @@ int main(int argc, char *argv[])
 | 
			
		||||
			printf("\t%s,\t/* %s */\n", table[i], names[i]);
 | 
			
		||||
	printf("};\n\n");
 | 
			
		||||
 | 
			
		||||
	printf("char *tokname(int n)\n");	/* print a tokname() function */
 | 
			
		||||
	printf("const char *tokname(int n)\n");	/* print a tokname() function */
 | 
			
		||||
	printf("{\n");
 | 
			
		||||
	printf("	static char buf[100];\n\n");
 | 
			
		||||
	printf("	if (n < FIRSTTOKEN || n > LASTTOKEN) {\n");
 | 
			
		||||
	printf("		sprintf(buf, \"token %%d\", n);\n");
 | 
			
		||||
	printf("		snprintf(buf, sizeof(buf), \"token %%d\", n);\n");
 | 
			
		||||
	printf("		return buf;\n");
 | 
			
		||||
	printf("	}\n");
 | 
			
		||||
	printf("	return printname[n-FIRSTTOKEN];\n");
 | 
			
		||||
@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 | 
			
		||||
THIS SOFTWARE.
 | 
			
		||||
****************************************************************/
 | 
			
		||||
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEBUG
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@ -33,7 +37,7 @@ Node *nodealloc(int n)
 | 
			
		||||
{
 | 
			
		||||
	Node *x;
 | 
			
		||||
 | 
			
		||||
	x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *));
 | 
			
		||||
	x = malloc(sizeof(Node) + (n-1)*sizeof(Node *));
 | 
			
		||||
	if (x == NULL)
 | 
			
		||||
		FATAL("out of space in nodealloc");
 | 
			
		||||
	x->nnext = NULL;
 | 
			
		||||
@ -93,6 +97,20 @@ Node *node4(int a, Node *b, Node *c, Node *d, Node *e)
 | 
			
		||||
	return(x);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Node *node5(int a, Node *b, Node *c, Node *d, Node *e, Node *f)
 | 
			
		||||
{
 | 
			
		||||
	Node *x;
 | 
			
		||||
 | 
			
		||||
	x = nodealloc(5);
 | 
			
		||||
	x->nobj = a;
 | 
			
		||||
	x->narg[0] = b;
 | 
			
		||||
	x->narg[1] = c;
 | 
			
		||||
	x->narg[2] = d;
 | 
			
		||||
	x->narg[3] = e;
 | 
			
		||||
	x->narg[4] = f;
 | 
			
		||||
	return(x);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Node *stat1(int a, Node *b)
 | 
			
		||||
{
 | 
			
		||||
	Node *x;
 | 
			
		||||
@ -165,6 +183,15 @@ Node *op4(int a, Node *b, Node *c, Node *d, Node *e)
 | 
			
		||||
	return(x);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Node *op5(int a, Node *b, Node *c, Node *d, Node *e, Node *f)
 | 
			
		||||
{
 | 
			
		||||
	Node *x;
 | 
			
		||||
 | 
			
		||||
	x = node5(a,b,c,d,e, f);
 | 
			
		||||
	x->ntype = NEXPR;
 | 
			
		||||
	return(x);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Node *celltonode(Cell *a, int b)
 | 
			
		||||
{
 | 
			
		||||
	Node *x;
 | 
			
		||||
							
								
								
									
										213
									
								
								external/historical/nawk/dist/proctab.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								external/historical/nawk/dist/proctab.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,213 @@
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include "awk.h"
 | 
			
		||||
#include "awkgram.h"
 | 
			
		||||
 | 
			
		||||
static const char * const printname[94] = {
 | 
			
		||||
	"FIRSTTOKEN",	/* 257 */
 | 
			
		||||
	"PROGRAM",	/* 258 */
 | 
			
		||||
	"PASTAT",	/* 259 */
 | 
			
		||||
	"PASTAT2",	/* 260 */
 | 
			
		||||
	"XBEGIN",	/* 261 */
 | 
			
		||||
	"XEND",	/* 262 */
 | 
			
		||||
	"NL",	/* 263 */
 | 
			
		||||
	"ARRAY",	/* 264 */
 | 
			
		||||
	"MATCH",	/* 265 */
 | 
			
		||||
	"NOTMATCH",	/* 266 */
 | 
			
		||||
	"MATCHOP",	/* 267 */
 | 
			
		||||
	"FINAL",	/* 268 */
 | 
			
		||||
	"DOT",	/* 269 */
 | 
			
		||||
	"ALL",	/* 270 */
 | 
			
		||||
	"CCL",	/* 271 */
 | 
			
		||||
	"NCCL",	/* 272 */
 | 
			
		||||
	"CHAR",	/* 273 */
 | 
			
		||||
	"OR",	/* 274 */
 | 
			
		||||
	"STAR",	/* 275 */
 | 
			
		||||
	"QUEST",	/* 276 */
 | 
			
		||||
	"PLUS",	/* 277 */
 | 
			
		||||
	"EMPTYRE",	/* 278 */
 | 
			
		||||
	"AND",	/* 279 */
 | 
			
		||||
	"BOR",	/* 280 */
 | 
			
		||||
	"APPEND",	/* 281 */
 | 
			
		||||
	"EQ",	/* 282 */
 | 
			
		||||
	"GE",	/* 283 */
 | 
			
		||||
	"GT",	/* 284 */
 | 
			
		||||
	"LE",	/* 285 */
 | 
			
		||||
	"LT",	/* 286 */
 | 
			
		||||
	"NE",	/* 287 */
 | 
			
		||||
	"IN",	/* 288 */
 | 
			
		||||
	"ARG",	/* 289 */
 | 
			
		||||
	"BLTIN",	/* 290 */
 | 
			
		||||
	"BREAK",	/* 291 */
 | 
			
		||||
	"CLOSE",	/* 292 */
 | 
			
		||||
	"CONTINUE",	/* 293 */
 | 
			
		||||
	"DELETE",	/* 294 */
 | 
			
		||||
	"DO",	/* 295 */
 | 
			
		||||
	"EXIT",	/* 296 */
 | 
			
		||||
	"FOR",	/* 297 */
 | 
			
		||||
	"FUNC",	/* 298 */
 | 
			
		||||
	"SUB",	/* 299 */
 | 
			
		||||
	"GSUB",	/* 300 */
 | 
			
		||||
	"IF",	/* 301 */
 | 
			
		||||
	"INDEX",	/* 302 */
 | 
			
		||||
	"LSUBSTR",	/* 303 */
 | 
			
		||||
	"MATCHFCN",	/* 304 */
 | 
			
		||||
	"NEXT",	/* 305 */
 | 
			
		||||
	"NEXTFILE",	/* 306 */
 | 
			
		||||
	"ADD",	/* 307 */
 | 
			
		||||
	"MINUS",	/* 308 */
 | 
			
		||||
	"MULT",	/* 309 */
 | 
			
		||||
	"DIVIDE",	/* 310 */
 | 
			
		||||
	"MOD",	/* 311 */
 | 
			
		||||
	"ASSIGN",	/* 312 */
 | 
			
		||||
	"ASGNOP",	/* 313 */
 | 
			
		||||
	"ADDEQ",	/* 314 */
 | 
			
		||||
	"SUBEQ",	/* 315 */
 | 
			
		||||
	"MULTEQ",	/* 316 */
 | 
			
		||||
	"DIVEQ",	/* 317 */
 | 
			
		||||
	"MODEQ",	/* 318 */
 | 
			
		||||
	"POWEQ",	/* 319 */
 | 
			
		||||
	"PRINT",	/* 320 */
 | 
			
		||||
	"PRINTF",	/* 321 */
 | 
			
		||||
	"SPRINTF",	/* 322 */
 | 
			
		||||
	"ELSE",	/* 323 */
 | 
			
		||||
	"INTEST",	/* 324 */
 | 
			
		||||
	"CONDEXPR",	/* 325 */
 | 
			
		||||
	"POSTINCR",	/* 326 */
 | 
			
		||||
	"PREINCR",	/* 327 */
 | 
			
		||||
	"POSTDECR",	/* 328 */
 | 
			
		||||
	"PREDECR",	/* 329 */
 | 
			
		||||
	"VAR",	/* 330 */
 | 
			
		||||
	"IVAR",	/* 331 */
 | 
			
		||||
	"VARNF",	/* 332 */
 | 
			
		||||
	"CALL",	/* 333 */
 | 
			
		||||
	"NUMBER",	/* 334 */
 | 
			
		||||
	"STRING",	/* 335 */
 | 
			
		||||
	"REGEXPR",	/* 336 */
 | 
			
		||||
	"GETLINE",	/* 337 */
 | 
			
		||||
	"GENSUB",	/* 338 */
 | 
			
		||||
	"RETURN",	/* 339 */
 | 
			
		||||
	"SPLIT",	/* 340 */
 | 
			
		||||
	"SUBSTR",	/* 341 */
 | 
			
		||||
	"WHILE",	/* 342 */
 | 
			
		||||
	"CAT",	/* 343 */
 | 
			
		||||
	"NOT",	/* 344 */
 | 
			
		||||
	"UMINUS",	/* 345 */
 | 
			
		||||
	"POWER",	/* 346 */
 | 
			
		||||
	"DECR",	/* 347 */
 | 
			
		||||
	"INCR",	/* 348 */
 | 
			
		||||
	"INDIRECT",	/* 349 */
 | 
			
		||||
	"LASTTOKEN",	/* 350 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Cell *(*proctab[94])(Node **, int) = {
 | 
			
		||||
	nullproc,	/* FIRSTTOKEN */
 | 
			
		||||
	program,	/* PROGRAM */
 | 
			
		||||
	pastat,	/* PASTAT */
 | 
			
		||||
	dopa2,	/* PASTAT2 */
 | 
			
		||||
	nullproc,	/* XBEGIN */
 | 
			
		||||
	nullproc,	/* XEND */
 | 
			
		||||
	nullproc,	/* NL */
 | 
			
		||||
	array,	/* ARRAY */
 | 
			
		||||
	matchop,	/* MATCH */
 | 
			
		||||
	matchop,	/* NOTMATCH */
 | 
			
		||||
	nullproc,	/* MATCHOP */
 | 
			
		||||
	nullproc,	/* FINAL */
 | 
			
		||||
	nullproc,	/* DOT */
 | 
			
		||||
	nullproc,	/* ALL */
 | 
			
		||||
	nullproc,	/* CCL */
 | 
			
		||||
	nullproc,	/* NCCL */
 | 
			
		||||
	nullproc,	/* CHAR */
 | 
			
		||||
	nullproc,	/* OR */
 | 
			
		||||
	nullproc,	/* STAR */
 | 
			
		||||
	nullproc,	/* QUEST */
 | 
			
		||||
	nullproc,	/* PLUS */
 | 
			
		||||
	nullproc,	/* EMPTYRE */
 | 
			
		||||
	boolop,	/* AND */
 | 
			
		||||
	boolop,	/* BOR */
 | 
			
		||||
	nullproc,	/* APPEND */
 | 
			
		||||
	relop,	/* EQ */
 | 
			
		||||
	relop,	/* GE */
 | 
			
		||||
	relop,	/* GT */
 | 
			
		||||
	relop,	/* LE */
 | 
			
		||||
	relop,	/* LT */
 | 
			
		||||
	relop,	/* NE */
 | 
			
		||||
	instat,	/* IN */
 | 
			
		||||
	arg,	/* ARG */
 | 
			
		||||
	bltin,	/* BLTIN */
 | 
			
		||||
	jump,	/* BREAK */
 | 
			
		||||
	closefile,	/* CLOSE */
 | 
			
		||||
	jump,	/* CONTINUE */
 | 
			
		||||
	awkdelete,	/* DELETE */
 | 
			
		||||
	dostat,	/* DO */
 | 
			
		||||
	jump,	/* EXIT */
 | 
			
		||||
	forstat,	/* FOR */
 | 
			
		||||
	nullproc,	/* FUNC */
 | 
			
		||||
	sub,	/* SUB */
 | 
			
		||||
	gsub,	/* GSUB */
 | 
			
		||||
	ifstat,	/* IF */
 | 
			
		||||
	sindex,	/* INDEX */
 | 
			
		||||
	nullproc,	/* LSUBSTR */
 | 
			
		||||
	matchop,	/* MATCHFCN */
 | 
			
		||||
	jump,	/* NEXT */
 | 
			
		||||
	jump,	/* NEXTFILE */
 | 
			
		||||
	arith,	/* ADD */
 | 
			
		||||
	arith,	/* MINUS */
 | 
			
		||||
	arith,	/* MULT */
 | 
			
		||||
	arith,	/* DIVIDE */
 | 
			
		||||
	arith,	/* MOD */
 | 
			
		||||
	assign,	/* ASSIGN */
 | 
			
		||||
	nullproc,	/* ASGNOP */
 | 
			
		||||
	assign,	/* ADDEQ */
 | 
			
		||||
	assign,	/* SUBEQ */
 | 
			
		||||
	assign,	/* MULTEQ */
 | 
			
		||||
	assign,	/* DIVEQ */
 | 
			
		||||
	assign,	/* MODEQ */
 | 
			
		||||
	assign,	/* POWEQ */
 | 
			
		||||
	printstat,	/* PRINT */
 | 
			
		||||
	awkprintf,	/* PRINTF */
 | 
			
		||||
	awksprintf,	/* SPRINTF */
 | 
			
		||||
	nullproc,	/* ELSE */
 | 
			
		||||
	intest,	/* INTEST */
 | 
			
		||||
	condexpr,	/* CONDEXPR */
 | 
			
		||||
	incrdecr,	/* POSTINCR */
 | 
			
		||||
	incrdecr,	/* PREINCR */
 | 
			
		||||
	incrdecr,	/* POSTDECR */
 | 
			
		||||
	incrdecr,	/* PREDECR */
 | 
			
		||||
	nullproc,	/* VAR */
 | 
			
		||||
	nullproc,	/* IVAR */
 | 
			
		||||
	getnf,	/* VARNF */
 | 
			
		||||
	call,	/* CALL */
 | 
			
		||||
	nullproc,	/* NUMBER */
 | 
			
		||||
	nullproc,	/* STRING */
 | 
			
		||||
	nullproc,	/* REGEXPR */
 | 
			
		||||
	awkgetline,	/* GETLINE */
 | 
			
		||||
	gensub,	/* GENSUB */
 | 
			
		||||
	jump,	/* RETURN */
 | 
			
		||||
	split,	/* SPLIT */
 | 
			
		||||
	substr,	/* SUBSTR */
 | 
			
		||||
	whilestat,	/* WHILE */
 | 
			
		||||
	cat,	/* CAT */
 | 
			
		||||
	boolop,	/* NOT */
 | 
			
		||||
	arith,	/* UMINUS */
 | 
			
		||||
	arith,	/* POWER */
 | 
			
		||||
	nullproc,	/* DECR */
 | 
			
		||||
	nullproc,	/* INCR */
 | 
			
		||||
	indirect,	/* INDIRECT */
 | 
			
		||||
	nullproc,	/* LASTTOKEN */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char *tokname(int n)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[100];
 | 
			
		||||
 | 
			
		||||
	if (n < FIRSTTOKEN || n > LASTTOKEN) {
 | 
			
		||||
		snprintf(buf, sizeof(buf), "token %d", n);
 | 
			
		||||
		return buf;
 | 
			
		||||
	}
 | 
			
		||||
	return printname[n-FIRSTTOKEN];
 | 
			
		||||
}
 | 
			
		||||
@ -43,17 +43,18 @@ extern	fa	*mkdfa(const char *, int);
 | 
			
		||||
extern	int	makeinit(fa *, int);
 | 
			
		||||
extern	void	penter(Node *);
 | 
			
		||||
extern	void	freetr(Node *);
 | 
			
		||||
extern	int	hexstr(char **);
 | 
			
		||||
extern	int	quoted(char **);
 | 
			
		||||
extern	int	hexstr(const uschar **);
 | 
			
		||||
extern	int	quoted(const uschar **);
 | 
			
		||||
extern	char	*cclenter(const char *);
 | 
			
		||||
extern	void	overflo(const char *);
 | 
			
		||||
extern	void	overflo(const char *) __dead;
 | 
			
		||||
extern	void	cfoll(fa *, Node *);
 | 
			
		||||
extern	int	first(const Node *);
 | 
			
		||||
extern	int	first(Node *);
 | 
			
		||||
extern	void	follow(Node *);
 | 
			
		||||
extern	int	member(int, const char *);
 | 
			
		||||
extern	int	match(fa *, const char *);
 | 
			
		||||
extern	int	pmatch(fa *, const char *);
 | 
			
		||||
extern	int	nematch(fa *, const char *);
 | 
			
		||||
extern	int	fnematch(fa *, FILE *, uschar **, int *, int);
 | 
			
		||||
extern	Node	*reparse(const char *);
 | 
			
		||||
extern	Node	*regexp(void);
 | 
			
		||||
extern	Node	*primary(void);
 | 
			
		||||
@ -73,12 +74,14 @@ extern	Node	*node1(int, Node *);
 | 
			
		||||
extern	Node	*node2(int, Node *, Node *);
 | 
			
		||||
extern	Node	*node3(int, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*node4(int, Node *, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*node5(int, Node *, Node *, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*stat3(int, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*op2(int, Node *, Node *);
 | 
			
		||||
extern	Node	*op1(int, Node *);
 | 
			
		||||
extern	Node	*stat1(int, Node *);
 | 
			
		||||
extern	Node	*op3(int, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*op4(int, Node *, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*op5(int, Node *, Node *, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*stat2(int, Node *, Node *);
 | 
			
		||||
extern	Node	*stat4(int, Node *, Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*celltonode(Cell *, int);
 | 
			
		||||
@ -88,7 +91,7 @@ extern	Node	*pa2stat(Node *, Node *, Node *);
 | 
			
		||||
extern	Node	*linkum(Node *, Node *);
 | 
			
		||||
extern	void	defn(Cell *, Node *, Node *);
 | 
			
		||||
extern	int	isarg(const char *);
 | 
			
		||||
extern	char	*tokname(int);
 | 
			
		||||
extern	const char	*tokname(int);
 | 
			
		||||
extern	Cell	*(*proctab[])(Node **, int);
 | 
			
		||||
extern	int	ptoi(void *);
 | 
			
		||||
extern	Node	*itonp(int);
 | 
			
		||||
@ -97,12 +100,12 @@ extern	void	syminit(void);
 | 
			
		||||
extern	void	arginit(int, char **);
 | 
			
		||||
extern	void	envinit(char **);
 | 
			
		||||
extern	Array	*makesymtab(int);
 | 
			
		||||
extern	void	freesymtab(const Cell *);
 | 
			
		||||
extern	void	freeelem(const Cell *, const char *);
 | 
			
		||||
extern	void	freesymtab(Cell *);
 | 
			
		||||
extern	void	freeelem(Cell *, const char *);
 | 
			
		||||
extern	Cell	*setsymtab(const char *, const char *, double, unsigned int, Array *);
 | 
			
		||||
extern	int	hash(const char *, int);
 | 
			
		||||
extern	void	rehash(Array *);
 | 
			
		||||
extern	Cell	*lookup(const char *, const Array *);
 | 
			
		||||
extern	Cell	*lookup(const char *, Array *);
 | 
			
		||||
extern	double	setfval(Cell *, double);
 | 
			
		||||
extern	void	funnyvar(Cell *, const char *);
 | 
			
		||||
extern	char	*setsval(Cell *, const char *);
 | 
			
		||||
@ -110,30 +113,35 @@ extern	double	getfval(Cell *);
 | 
			
		||||
extern	char	*getsval(Cell *);
 | 
			
		||||
extern	char	*getpssval(Cell *);     /* for print */
 | 
			
		||||
extern	char	*tostring(const char *);
 | 
			
		||||
extern	char	*tostringN(const char *, size_t n);
 | 
			
		||||
extern	char	*qstring(const char *, int);
 | 
			
		||||
extern	Cell	*catstr(Cell *, Cell *);
 | 
			
		||||
 | 
			
		||||
extern	void	recinit(unsigned int);
 | 
			
		||||
extern	void	initgetrec(void);
 | 
			
		||||
extern	void	makefields(int, int);
 | 
			
		||||
extern	void	growfldtab(int n);
 | 
			
		||||
extern	int	getrec(char **, int *, int);
 | 
			
		||||
extern	int	getrec(uschar **, int *, int);
 | 
			
		||||
extern	void	nextfile(void);
 | 
			
		||||
extern	int	readrec(char **buf, int *bufsize, FILE *inf);
 | 
			
		||||
extern	int	readrec(uschar **buf, int *bufsize, FILE *inf, int newflag);
 | 
			
		||||
extern	char	*getargv(int);
 | 
			
		||||
extern	void	setclvar(char *);
 | 
			
		||||
extern	void	fldbld(void);
 | 
			
		||||
extern	void	cleanfld(int, int);
 | 
			
		||||
extern	void	newfld(int);
 | 
			
		||||
extern	void	setlastfld(int);
 | 
			
		||||
extern	int	refldbld(const char *, const char *);
 | 
			
		||||
extern	void	recbld(void);
 | 
			
		||||
extern	Cell	*fieldadr(int);
 | 
			
		||||
extern	void	yyerror(const char *);
 | 
			
		||||
extern	void	fpecatch(int);
 | 
			
		||||
extern	void	bracecheck(void);
 | 
			
		||||
extern	void	bcheck2(int, int, int);
 | 
			
		||||
extern	void	SYNTAX(const char *, ...);
 | 
			
		||||
extern	void	FATAL(const char *, ...);
 | 
			
		||||
extern	void	WARNING(const char *, ...);
 | 
			
		||||
extern	void	SYNTAX(const char *, ...)
 | 
			
		||||
    __attribute__((__format__(__printf__, 1, 2)));
 | 
			
		||||
extern	void	FATAL(const char *, ...) __dead
 | 
			
		||||
    __attribute__((__format__(__printf__, 1, 2)));
 | 
			
		||||
extern	void	WARNING(const char *, ...)
 | 
			
		||||
    __attribute__((__format__(__printf__, 1, 2)));
 | 
			
		||||
extern	void	error(void);
 | 
			
		||||
extern	void	eprint(void);
 | 
			
		||||
extern	void	bclass(int);
 | 
			
		||||
@ -141,7 +149,7 @@ extern	double	errcheck(double, const char *);
 | 
			
		||||
extern	int	isclvar(const char *);
 | 
			
		||||
extern	int	is_number(const char *);
 | 
			
		||||
 | 
			
		||||
extern	int	adjbuf(char **pb, int *sz, int min, int q, char **pbp, const char *what);
 | 
			
		||||
extern	int	adjbuf(uschar **pb, int *sz, int min, int q, uschar **pbp, const char *what);
 | 
			
		||||
extern	void	run(Node *);
 | 
			
		||||
extern	Cell	*execute(Node *);
 | 
			
		||||
extern	Cell	*program(Node **, int);
 | 
			
		||||
@ -184,12 +192,13 @@ extern	Cell	*bltin(Node **, int);
 | 
			
		||||
extern	Cell	*printstat(Node **, int);
 | 
			
		||||
extern	Cell	*nullproc(Node **, int);
 | 
			
		||||
extern	FILE	*redirect(int, Node *);
 | 
			
		||||
extern	FILE	*openfile(int, const char *);
 | 
			
		||||
extern	FILE	*openfile(int, const char *, int *);
 | 
			
		||||
extern	const char	*filename(FILE *);
 | 
			
		||||
extern	Cell	*closefile(Node **, int);
 | 
			
		||||
extern	void	closeall(void);
 | 
			
		||||
extern	Cell	*sub(Node **, int);
 | 
			
		||||
extern	Cell	*gsub(Node **, int);
 | 
			
		||||
extern	Cell	*gensub(Node **, int);
 | 
			
		||||
 | 
			
		||||
extern	FILE	*popen(const char *, const char *);
 | 
			
		||||
extern	int	pclose(FILE *);
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 | 
			
		||||
THIS SOFTWARE.
 | 
			
		||||
****************************************************************/
 | 
			
		||||
 | 
			
		||||
#if HAVE_NBTOOL_CONFIG_H
 | 
			
		||||
#include "nbtool_config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define	DEBUG
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
@ -108,7 +112,7 @@ void arginit(int ac, char **av)	/* set up ARGV and ARGC */
 | 
			
		||||
	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
 | 
			
		||||
	cp->sval = (char *) ARGVtab;
 | 
			
		||||
	for (i = 0; i < ac; i++) {
 | 
			
		||||
		sprintf(temp, "%d", i);
 | 
			
		||||
		snprintf(temp, sizeof(temp), "%d", i);
 | 
			
		||||
		if (is_number(*av))
 | 
			
		||||
			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
 | 
			
		||||
		else
 | 
			
		||||
@ -144,8 +148,8 @@ Array *makesymtab(int n)	/* make a new symbol table */
 | 
			
		||||
	Array *ap;
 | 
			
		||||
	Cell **tp;
 | 
			
		||||
 | 
			
		||||
	ap = (Array *) malloc(sizeof(Array));
 | 
			
		||||
	tp = (Cell **) calloc(n, sizeof(Cell *));
 | 
			
		||||
	ap = malloc(sizeof(*ap));
 | 
			
		||||
	tp = calloc(n, sizeof(*tp));
 | 
			
		||||
	if (ap == NULL || tp == NULL)
 | 
			
		||||
		FATAL("out of space in makesymtab");
 | 
			
		||||
	ap->nelem = 0;
 | 
			
		||||
@ -154,7 +158,7 @@ Array *makesymtab(int n)	/* make a new symbol table */
 | 
			
		||||
	return(ap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void freesymtab(const Cell *ap)	/* free a symbol table */
 | 
			
		||||
void freesymtab(Cell *ap)	/* free a symbol table */
 | 
			
		||||
{
 | 
			
		||||
	Cell *cp, *temp;
 | 
			
		||||
	Array *tp;
 | 
			
		||||
@ -182,8 +186,7 @@ void freesymtab(const Cell *ap)	/* free a symbol table */
 | 
			
		||||
	free(tp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void freeelem(const Cell *ap, const char *s)
 | 
			
		||||
/* free elem s from ap (i.e., ap["s"] */
 | 
			
		||||
void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
 | 
			
		||||
{
 | 
			
		||||
	Array *tp;
 | 
			
		||||
	Cell *p, *prev = NULL;
 | 
			
		||||
@ -211,12 +214,15 @@ Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
 | 
			
		||||
	int h;
 | 
			
		||||
	Cell *p;
 | 
			
		||||
 | 
			
		||||
	if (n != NULL && (p = lookup(n, tp)) != NULL) {
 | 
			
		||||
	if (n == NULL)
 | 
			
		||||
		n = "";
 | 
			
		||||
 | 
			
		||||
	if ((p = lookup(n, tp)) != NULL) {
 | 
			
		||||
		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
 | 
			
		||||
			p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
 | 
			
		||||
		return(p);
 | 
			
		||||
	}
 | 
			
		||||
	p = (Cell *) malloc(sizeof(Cell));
 | 
			
		||||
	p = malloc(sizeof(*p));
 | 
			
		||||
	if (p == NULL)
 | 
			
		||||
		FATAL("out of space for symbol table at %s", n);
 | 
			
		||||
	p->nval = tostring(n);
 | 
			
		||||
@ -251,7 +257,7 @@ void rehash(Array *tp)	/* rehash items in small table into big one */
 | 
			
		||||
	Cell *cp, *op, **np;
 | 
			
		||||
 | 
			
		||||
	nsz = GROWTAB * tp->size;
 | 
			
		||||
	np = (Cell **) calloc(nsz, sizeof(Cell *));
 | 
			
		||||
	np = calloc(nsz, sizeof(*np));
 | 
			
		||||
	if (np == NULL)		/* can't do it, but can keep running. */
 | 
			
		||||
		return;		/* someone else will run out later. */
 | 
			
		||||
	for (i = 0; i < tp->size; i++) {
 | 
			
		||||
@ -267,7 +273,7 @@ void rehash(Array *tp)	/* rehash items in small table into big one */
 | 
			
		||||
	tp->size = nsz;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cell *lookup(const char *s, const Array *tp)	/* look for s in tp */
 | 
			
		||||
Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
 | 
			
		||||
{
 | 
			
		||||
	Cell *p;
 | 
			
		||||
	int h;
 | 
			
		||||
@ -283,6 +289,7 @@ Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
 | 
			
		||||
{
 | 
			
		||||
	int fldno;
 | 
			
		||||
 | 
			
		||||
	f += 0.0;		/* normalise negative zero to positive zero */
 | 
			
		||||
	if ((vp->tval & (NUM | STR)) == 0) 
 | 
			
		||||
		funnyvar(vp, "assign to");
 | 
			
		||||
	if (isfld(vp)) {
 | 
			
		||||
@ -291,6 +298,10 @@ Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
 | 
			
		||||
		if (fldno > *NF)
 | 
			
		||||
			newfld(fldno);
 | 
			
		||||
		   dprintf( ("setting field %d to %g\n", fldno, f) );
 | 
			
		||||
	} else if (&vp->fval == NF) {
 | 
			
		||||
		donerec = 0;	/* mark $0 invalid */
 | 
			
		||||
		setlastfld(f);
 | 
			
		||||
		dprintf( ("setting NF to %g\n", f) );
 | 
			
		||||
	} else if (isrec(vp)) {
 | 
			
		||||
		donefld = 0;	/* mark $1... invalid */
 | 
			
		||||
		donerec = 1;
 | 
			
		||||
@ -317,6 +328,7 @@ char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
 | 
			
		||||
{
 | 
			
		||||
	char *t;
 | 
			
		||||
	int fldno;
 | 
			
		||||
	Awkfloat f;
 | 
			
		||||
 | 
			
		||||
	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 
 | 
			
		||||
		vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
 | 
			
		||||
@ -340,7 +352,16 @@ char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
 | 
			
		||||
	vp->tval &= ~DONTFREE;
 | 
			
		||||
	   dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 
 | 
			
		||||
		vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
 | 
			
		||||
	return(vp->sval = t);
 | 
			
		||||
 | 
			
		||||
	vp->sval = t;
 | 
			
		||||
	if (&vp->fval == NF) {
 | 
			
		||||
		donerec = 0;	/* mark $0 invalid */
 | 
			
		||||
		f = getfval(vp);
 | 
			
		||||
		setlastfld(f);
 | 
			
		||||
		dprintf( ("setting NF to %g\n", f) );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return(vp->sval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
 | 
			
		||||
@ -360,10 +381,9 @@ Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
 | 
			
		||||
	return(vp->fval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *get_str_val(Cell *vp, char **fmt)
 | 
			
		||||
/* get string val of a Cell */
 | 
			
		||||
static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
 | 
			
		||||
{
 | 
			
		||||
	char s[100];	/* BUG: unchecked */
 | 
			
		||||
	char s[100];
 | 
			
		||||
	double dtemp;
 | 
			
		||||
 | 
			
		||||
	if ((vp->tval & (NUM | STR)) == 0)
 | 
			
		||||
@ -376,9 +396,9 @@ static char *get_str_val(Cell *vp, char **fmt)
 | 
			
		||||
		if (freeable(vp))
 | 
			
		||||
			xfree(vp->sval);
 | 
			
		||||
		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
 | 
			
		||||
			sprintf(s, "%.30g", vp->fval);
 | 
			
		||||
			snprintf(s, sizeof(s), "%.30g", vp->fval);
 | 
			
		||||
		else
 | 
			
		||||
			sprintf(s, *fmt, vp->fval);
 | 
			
		||||
			snprintf(s, sizeof(s), *fmt, vp->fval);
 | 
			
		||||
		vp->sval = tostring(s);
 | 
			
		||||
		vp->tval &= ~DONTFREE;
 | 
			
		||||
		vp->tval |= STR;
 | 
			
		||||
@ -402,7 +422,33 @@ char *tostring(const char *s)	/* make a copy of string s */
 | 
			
		||||
{
 | 
			
		||||
	char *p;
 | 
			
		||||
 | 
			
		||||
	p = (char *) malloc(strlen(s)+1);
 | 
			
		||||
	p = strdup(s);
 | 
			
		||||
	if (p == NULL)
 | 
			
		||||
		FATAL("out of space in tostring on %s", s);
 | 
			
		||||
	return(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
 | 
			
		||||
{
 | 
			
		||||
	Cell *c;
 | 
			
		||||
	char *p;
 | 
			
		||||
	char *sa = getsval(a);
 | 
			
		||||
	char *sb = getsval(b);
 | 
			
		||||
	size_t l = strlen(sa) + strlen(sb) + 1;
 | 
			
		||||
	p = malloc(l);
 | 
			
		||||
	if (p == NULL)
 | 
			
		||||
		FATAL("out of space concatenating %s and %s", sa, sb);
 | 
			
		||||
	snprintf(p, l, "%s%s", sa, sb);
 | 
			
		||||
	c = setsymtab(p, p, 0.0, CON|STR|DONTFREE, symtab);
 | 
			
		||||
	free(p);
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *tostringN(const char *s, size_t n)	/* make a copy of string s */
 | 
			
		||||
{
 | 
			
		||||
	char *p;
 | 
			
		||||
 | 
			
		||||
	p = malloc(n);
 | 
			
		||||
	if (p == NULL)
 | 
			
		||||
		FATAL("out of space in tostring on %s", s);
 | 
			
		||||
	strcpy(p, s);
 | 
			
		||||
@ -413,10 +459,10 @@ char *qstring(const char *is, int delim)	/* collect string up to next delim */
 | 
			
		||||
{
 | 
			
		||||
	const char *os = is;
 | 
			
		||||
	int c, n;
 | 
			
		||||
	uschar *s = (uschar *) is;
 | 
			
		||||
	const uschar *s = (const uschar *) is;
 | 
			
		||||
	uschar *buf, *bp;
 | 
			
		||||
 | 
			
		||||
	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
 | 
			
		||||
	if ((buf = malloc(strlen(is)+3)) == NULL)
 | 
			
		||||
		FATAL( "out of space in qstring(%s)", s);
 | 
			
		||||
	for (bp = buf; (c = *s) != delim; s++) {
 | 
			
		||||
		if (c == '\n')
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user