Import NetBSD nawk
This commit is contained in:
parent
a23f4844ba
commit
5ea9e707be
24 changed files with 2121 additions and 485 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
.include <bsd.own.mk>
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
SUBDIR= add_route arp ash at awk \
|
SUBDIR= add_route arp ash at \
|
||||||
backup badblocks banner basename \
|
backup badblocks banner basename \
|
||||||
btrace cal \
|
btrace cal \
|
||||||
cawf cd cdprobe checkhier cpp \
|
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>
|
.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
|
This file lists all bug fixes, changes, etc., made since the AWK book
|
||||||
was sent to the printers in August, 1987.
|
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:
|
Feb 8, 2010:
|
||||||
i give up. replaced isblank with isspace in b.c; there are
|
i give up. replaced isblank with isspace in b.c; there are
|
||||||
no consistent header files.
|
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. */
|
#define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */
|
||||||
extern int recsize; /* size of current record, orig RECSIZE */
|
extern int recsize; /* size of current record, orig RECSIZE */
|
||||||
|
|
||||||
|
extern char EMPTY[];
|
||||||
extern char **FS;
|
extern char **FS;
|
||||||
extern char **RS;
|
extern char **RS;
|
||||||
extern char **ORS;
|
extern char **ORS;
|
||||||
|
@ -61,16 +62,15 @@ extern char **SUBSEP;
|
||||||
extern Awkfloat *RSTART;
|
extern Awkfloat *RSTART;
|
||||||
extern Awkfloat *RLENGTH;
|
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 lineno; /* line number in awk program */
|
||||||
extern int errorflag; /* 1 if error has occurred */
|
extern int errorflag; /* 1 if error has occurred */
|
||||||
extern int donefld; /* 1 if record broken into fields */
|
extern int donefld; /* 1 if record broken into fields */
|
||||||
extern int donerec; /* 1 if record is valid (no fld has changed */
|
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 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 */
|
extern int patlen; /* length of pattern matched. set in b.c */
|
||||||
|
|
||||||
/* Cell: all information about a variable or constant */
|
/* Cell: all information about a variable or constant */
|
||||||
|
@ -126,6 +126,8 @@ extern Cell *rlengthloc; /* RLENGTH */
|
||||||
#define FTOUPPER 12
|
#define FTOUPPER 12
|
||||||
#define FTOLOWER 13
|
#define FTOLOWER 13
|
||||||
#define FFLUSH 14
|
#define FFLUSH 14
|
||||||
|
#define FSYSTIME 15
|
||||||
|
#define FSTRFTIME 16
|
||||||
|
|
||||||
/* Node: parse tree is made of nodes, with Cell's at bottom */
|
/* 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 */
|
#define NCHARS (256+3) /* 256 handles 8-bit chars; 128 does 7-bit */
|
||||||
/* watch out in match(), etc. */
|
/* watch out in match(), etc. */
|
||||||
#define NSTATES 32
|
|
||||||
|
|
||||||
typedef struct rrow {
|
typedef struct rrow {
|
||||||
long ltype; /* long avoids pointer warnings on 64-bit */
|
long ltype; /* long avoids pointer warnings on 64-bit */
|
||||||
union {
|
union {
|
||||||
|
@ -216,16 +216,16 @@ typedef struct rrow {
|
||||||
} rrow;
|
} rrow;
|
||||||
|
|
||||||
typedef struct fa {
|
typedef struct fa {
|
||||||
uschar gototab[NSTATES][NCHARS];
|
unsigned int **gototab;
|
||||||
uschar out[NSTATES];
|
uschar *out;
|
||||||
uschar *restr;
|
uschar *restr;
|
||||||
int *posns[NSTATES];
|
int **posns;
|
||||||
|
int state_count;
|
||||||
int anchor;
|
int anchor;
|
||||||
int use;
|
int use;
|
||||||
int initstat;
|
int initstat;
|
||||||
int curstat;
|
int curstat;
|
||||||
int accept;
|
int accept;
|
||||||
int reset;
|
|
||||||
struct rrow re[1]; /* variable: actual size set by calling malloc */
|
struct rrow re[1]; /* variable: actual size set by calling malloc */
|
||||||
} fa;
|
} fa;
|
||||||
|
|
|
@ -23,6 +23,10 @@ THIS SOFTWARE.
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
#if HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "awk.h"
|
#include "awk.h"
|
||||||
|
@ -71,6 +75,7 @@ Node *arglist = 0; /* list of args for current function */
|
||||||
%type <i> do st
|
%type <i> do st
|
||||||
%type <i> pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
|
%type <i> pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
|
||||||
%type <i> subop print
|
%type <i> subop print
|
||||||
|
%type <cp> string
|
||||||
|
|
||||||
%right ASGNOP
|
%right ASGNOP
|
||||||
%right '?'
|
%right '?'
|
||||||
|
@ -80,7 +85,7 @@ Node *arglist = 0; /* list of args for current function */
|
||||||
%left GETLINE
|
%left GETLINE
|
||||||
%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
|
%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
|
||||||
%left ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC
|
%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 PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
|
||||||
%left REGEXPR VAR VARNF IVAR WHILE '('
|
%left REGEXPR VAR VARNF IVAR WHILE '('
|
||||||
%left CAT
|
%left CAT
|
||||||
|
@ -348,6 +353,11 @@ subop:
|
||||||
SUB | GSUB
|
SUB | GSUB
|
||||||
;
|
;
|
||||||
|
|
||||||
|
string:
|
||||||
|
STRING
|
||||||
|
| string STRING { $$ = catstr($1, $2); }
|
||||||
|
;
|
||||||
|
|
||||||
term:
|
term:
|
||||||
term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); }
|
term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); }
|
||||||
| term '+' term { $$ = op2(ADD, $1, $3); }
|
| term '+' term { $$ = op2(ADD, $1, $3); }
|
||||||
|
@ -369,6 +379,22 @@ term:
|
||||||
| INCR var { $$ = op1(PREINCR, $2); }
|
| INCR var { $$ = op1(PREINCR, $2); }
|
||||||
| var DECR { $$ = op1(POSTDECR, $1); }
|
| var DECR { $$ = op1(POSTDECR, $1); }
|
||||||
| var INCR { $$ = op1(POSTINCR, $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 var LT term { $$ = op3(GETLINE, $2, itonp($3), $4); }
|
||||||
| GETLINE LT term { $$ = op3(GETLINE, NIL, itonp($2), $3); }
|
| GETLINE LT term { $$ = op3(GETLINE, NIL, itonp($2), $3); }
|
||||||
| GETLINE var { $$ = op3(GETLINE, $2, NIL, NIL); }
|
| GETLINE var { $$ = op3(GETLINE, $2, NIL, NIL); }
|
||||||
|
@ -394,7 +420,7 @@ term:
|
||||||
| SPLIT '(' pattern comma varname ')'
|
| SPLIT '(' pattern comma varname ')'
|
||||||
{ $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); } /* default */
|
{ $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); } /* default */
|
||||||
| SPRINTF '(' patlist ')' { $$ = op1($1, $3); }
|
| SPRINTF '(' patlist ')' { $$ = op1($1, $3); }
|
||||||
| STRING { $$ = celltonode($1, CCON); }
|
| string { $$ = celltonode($1, CCON); }
|
||||||
| subop '(' reg_expr comma pattern ')'
|
| subop '(' reg_expr comma pattern ')'
|
||||||
{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
|
{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
|
||||||
| subop '(' pattern comma pattern ')'
|
| subop '(' pattern comma pattern ')'
|
373
commands/awk/b.c → external/historical/nawk/dist/b.c
vendored
373
commands/awk/b.c → external/historical/nawk/dist/b.c
vendored
|
@ -24,12 +24,17 @@ THIS SOFTWARE.
|
||||||
|
|
||||||
/* lasciate ogne speranza, voi ch'intrate. */
|
/* lasciate ogne speranza, voi ch'intrate. */
|
||||||
|
|
||||||
|
#if HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "awk.h"
|
#include "awk.h"
|
||||||
#include "awkgram.h"
|
#include "awkgram.h"
|
||||||
|
|
||||||
|
@ -62,33 +67,80 @@ int maxsetvec = 0;
|
||||||
|
|
||||||
int rtok; /* next token in current re */
|
int rtok; /* next token in current re */
|
||||||
int rlxval;
|
int rlxval;
|
||||||
static uschar *rlxstr;
|
static const uschar *rlxstr;
|
||||||
static uschar *prestr; /* current position in current re */
|
static const uschar *prestr; /* current position in current re */
|
||||||
static uschar *lastre; /* origin of last re */
|
static const uschar *lastre; /* origin of last re */
|
||||||
|
|
||||||
static int setcnt;
|
static int setcnt;
|
||||||
static int poscnt;
|
static int poscnt;
|
||||||
|
|
||||||
char *patbeg;
|
uschar *patbeg;
|
||||||
int patlen;
|
int patlen;
|
||||||
|
|
||||||
#define NFA 20 /* cache this many dynamic fa's */
|
#define NFA 128 /* cache this many dynamic fa's */
|
||||||
fa *fatab[NFA];
|
fa *fatab[NFA];
|
||||||
int nfatab = 0; /* entries in fatab */
|
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 */
|
fa *makedfa(const char *s, int anchor) /* returns dfa for reg expr s */
|
||||||
{
|
{
|
||||||
int i, use, nuse;
|
int i, use, nuse;
|
||||||
fa *pfa;
|
fa *pfa;
|
||||||
static int now = 1;
|
static int now = 1;
|
||||||
|
|
||||||
if (setvec == 0) { /* first time through any RE */
|
if (setvec == 0) /* first time through any RE */
|
||||||
maxsetvec = MAXLIN;
|
resizesetvec("out of space initializing makedfa");
|
||||||
setvec = (int *) malloc(maxsetvec * sizeof(int));
|
|
||||||
tmpset = (int *) malloc(maxsetvec * sizeof(int));
|
|
||||||
if (setvec == 0 || tmpset == 0)
|
|
||||||
overflo("out of space initializing makedfa");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compile_time) /* a constant for sure */
|
if (compile_time) /* a constant for sure */
|
||||||
return mkdfa(s, anchor);
|
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;
|
poscnt = 0;
|
||||||
penter(p1); /* enter parent pointers and leaf indices */
|
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");
|
overflo("out of space for fa");
|
||||||
f->accept = poscnt-1; /* penter has computed number of positions in re */
|
f->accept = poscnt-1; /* penter has computed number of positions in re */
|
||||||
cfoll(f, p1); /* set up follow sets */
|
cfoll(f, p1); /* set up follow sets */
|
||||||
freetr(p1);
|
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");
|
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");
|
overflo("out of space in makedfa");
|
||||||
*f->posns[1] = 0;
|
*f->posns[1] = 0;
|
||||||
f->initstat = makeinit(f, anchor);
|
f->initstat = makeinit(f, anchor);
|
||||||
|
@ -152,12 +205,12 @@ int makeinit(fa *f, int anchor)
|
||||||
{
|
{
|
||||||
int i, k;
|
int i, k;
|
||||||
|
|
||||||
|
resize_state(f, 2);
|
||||||
f->curstat = 2;
|
f->curstat = 2;
|
||||||
f->out[2] = 0;
|
f->out[2] = 0;
|
||||||
f->reset = 0;
|
|
||||||
k = *(f->re[0].lfollow);
|
k = *(f->re[0].lfollow);
|
||||||
xfree(f->posns[2]);
|
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");
|
overflo("out of space in makeinit");
|
||||||
for (i=0; i <= k; i++) {
|
for (i=0; i <= k; i++) {
|
||||||
(f->posns[2])[i] = (f->re[0].lfollow)[i];
|
(f->posns[2])[i] = (f->re[0].lfollow)[i];
|
||||||
|
@ -174,9 +227,11 @@ int makeinit(fa *f, int anchor)
|
||||||
}
|
}
|
||||||
|
|
||||||
f->out[0] = f->out[2];
|
f->out[0] = f->out[2];
|
||||||
if (f->curstat != 2)
|
if (f->curstat != 2) {
|
||||||
|
resize_state(f, f->curstat);
|
||||||
--(*f->posns[f->curstat]);
|
--(*f->posns[f->curstat]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 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 */
|
/* in the parsing of regular expressions, metacharacters like . have */
|
||||||
/* to be seen literally; \056 is not a metacharacter. */
|
/* 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) */
|
{ /* only pick up one 8-bit byte (2 chars) */
|
||||||
uschar *p;
|
const uschar *p;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int i;
|
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))
|
if (isdigit(*p))
|
||||||
n = 16 * n + *p - '0';
|
n = 16 * n + *p - '0';
|
||||||
else if (*p >= 'a' && *p <= 'f')
|
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')
|
else if (*p >= 'A' && *p <= 'F')
|
||||||
n = 16 * n + *p - 'A' + 10;
|
n = 16 * n + *p - 'A' + 10;
|
||||||
}
|
}
|
||||||
*pp = (char *) p;
|
*pp = p;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define isoctdigit(c) ((c) >= '0' && (c) <= '7') /* multiple use of arg */
|
#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 */
|
/* and increment *pp */
|
||||||
{
|
{
|
||||||
char *p = *pp;
|
const uschar *p = *pp;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if ((c = *p++) == 't')
|
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 */
|
char *cclenter(const char *argp) /* add a character class */
|
||||||
{
|
{
|
||||||
int i, c, c2;
|
int i, c, c2;
|
||||||
uschar *p = (uschar *) argp;
|
const uschar *p = (const uschar *) argp;
|
||||||
uschar *op, *bp;
|
const uschar *op;
|
||||||
|
uschar *bp;
|
||||||
static uschar *buf = 0;
|
static uschar *buf = 0;
|
||||||
static int bufsz = 100;
|
static int bufsz = 100;
|
||||||
|
|
||||||
op = p;
|
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);
|
FATAL("out of space for character class [%.10s...] 1", p);
|
||||||
bp = buf;
|
bp = buf;
|
||||||
for (i = 0; (c = *p++) != 0; ) {
|
for (i = 0; (c = *p++) != 0; ) {
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
c = quoted((char **) &p);
|
c = quoted(&p);
|
||||||
} else if (c == '-' && i > 0 && bp[-1] != 0) {
|
} else if (c == '-' && i > 0 && bp[-1] != 0) {
|
||||||
if (*p != 0) {
|
if (*p != 0) {
|
||||||
c = bp[-1];
|
c = bp[-1];
|
||||||
c2 = *p++;
|
c2 = *p++;
|
||||||
if (c2 == '\\')
|
if (c2 == '\\')
|
||||||
c2 = quoted((char **) &p);
|
c2 = quoted(&p);
|
||||||
if (c > c2) { /* empty; ignore */
|
if (c > c2) { /* empty; ignore */
|
||||||
bp--;
|
bp--;
|
||||||
i--;
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
while (c < c2) {
|
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);
|
FATAL("out of space for character class [%.10s...] 2", p);
|
||||||
*bp++ = ++c;
|
*bp++ = ++c;
|
||||||
i++;
|
i++;
|
||||||
|
@ -320,14 +376,14 @@ char *cclenter(const char *argp) /* add a character class */
|
||||||
continue;
|
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);
|
FATAL("out of space for character class [%.10s...] 3", p);
|
||||||
*bp++ = c;
|
*bp++ = c;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
*bp = 0;
|
*bp = 0;
|
||||||
dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) );
|
dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) );
|
||||||
xfree(op);
|
free(__UNCONST(op));
|
||||||
return (char *) tostring((char *) buf);
|
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
|
LEAF
|
||||||
f->re[info(v)].ltype = type(v);
|
f->re[info(v)].ltype = type(v);
|
||||||
f->re[info(v)].lval.np = right(v);
|
f->re[info(v)].lval.np = right(v);
|
||||||
while (f->accept >= maxsetvec) { /* guessing here! */
|
while (f->accept >= maxsetvec) /* guessing here! */
|
||||||
maxsetvec *= 4;
|
resizesetvec("out of space in cfoll()");
|
||||||
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()");
|
|
||||||
}
|
|
||||||
for (i = 0; i <= f->accept; i++)
|
for (i = 0; i <= f->accept; i++)
|
||||||
setvec[i] = 0;
|
setvec[i] = 0;
|
||||||
setcnt = 0;
|
setcnt = 0;
|
||||||
follow(v); /* computes setvec and setcnt */
|
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");
|
overflo("out of space building follow set");
|
||||||
f->re[info(v)].lfollow = p;
|
f->re[info(v)].lfollow = p;
|
||||||
*p = setcnt;
|
*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 */
|
/* returns 0 if p matches empty string */
|
||||||
{
|
{
|
||||||
int b, lp;
|
int b, lp;
|
||||||
|
@ -387,13 +438,8 @@ int first(const Node *p) /* collects initially active leaves of p into setvec */
|
||||||
ELEAF
|
ELEAF
|
||||||
LEAF
|
LEAF
|
||||||
lp = info(p); /* look for high-water mark of subscripts */
|
lp = info(p); /* look for high-water mark of subscripts */
|
||||||
while (setcnt >= maxsetvec || lp >= maxsetvec) { /* guessing here! */
|
while (setcnt >= maxsetvec || lp >= maxsetvec) /* guessing here! */
|
||||||
maxsetvec *= 4;
|
resizesetvec("out of space in first()");
|
||||||
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()");
|
|
||||||
}
|
|
||||||
if (type(p) == EMPTYRE) {
|
if (type(p) == EMPTYRE) {
|
||||||
setvec[lp] = 0;
|
setvec[lp] = 0;
|
||||||
return(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? */
|
int member(int c, const char *sarg) /* is c in s? */
|
||||||
{
|
{
|
||||||
uschar *s = (uschar *) sarg;
|
const uschar *s = (const uschar *) sarg;
|
||||||
|
|
||||||
while (*s)
|
while (*s)
|
||||||
if (c == *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 match(fa *f, const char *p0) /* shortest match ? */
|
||||||
{
|
{
|
||||||
int s, ns;
|
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])
|
if (f->out[s])
|
||||||
return(1);
|
return(1);
|
||||||
do {
|
do {
|
||||||
|
@ -479,6 +527,9 @@ int match(fa *f, const char *p0) /* shortest match ? */
|
||||||
s = ns;
|
s = ns;
|
||||||
else
|
else
|
||||||
s = cgoto(f, s, *p);
|
s = cgoto(f, s, *p);
|
||||||
|
|
||||||
|
assert (s < f->state_count);
|
||||||
|
|
||||||
if (f->out[s])
|
if (f->out[s])
|
||||||
return(1);
|
return(1);
|
||||||
} while (*p++ != 0);
|
} 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 pmatch(fa *f, const char *p0) /* longest match, for sub */
|
||||||
{
|
{
|
||||||
int s, ns;
|
int s, ns;
|
||||||
uschar *p = (uschar *) p0;
|
uschar *p = __UNCONST(p0);
|
||||||
uschar *q;
|
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);
|
||||||
patbeg = (char *) p;
|
patbeg = p;
|
||||||
patlen = -1;
|
patlen = -1;
|
||||||
do {
|
do {
|
||||||
q = p;
|
q = p;
|
||||||
|
@ -510,9 +556,12 @@ int pmatch(fa *f, const char *p0) /* longest match, for sub */
|
||||||
s = ns;
|
s = ns;
|
||||||
else
|
else
|
||||||
s = cgoto(f, s, *q);
|
s = cgoto(f, s, *q);
|
||||||
|
|
||||||
|
assert(s < f->state_count);
|
||||||
|
|
||||||
if (s == 1) { /* no transition */
|
if (s == 1) { /* no transition */
|
||||||
if (patlen >= 0) {
|
if (patlen >= 0) {
|
||||||
patbeg = (char *) p;
|
patbeg = p;
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -522,24 +571,11 @@ int pmatch(fa *f, const char *p0) /* longest match, for sub */
|
||||||
if (f->out[s])
|
if (f->out[s])
|
||||||
patlen = q-p-1; /* don't count $ */
|
patlen = q-p-1; /* don't count $ */
|
||||||
if (patlen >= 0) {
|
if (patlen >= 0) {
|
||||||
patbeg = (char *) p;
|
patbeg = p;
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
nextin:
|
nextin:
|
||||||
s = 2;
|
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);
|
} while (*p++ != 0);
|
||||||
return (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 nematch(fa *f, const char *p0) /* non-empty match, for sub */
|
||||||
{
|
{
|
||||||
int s, ns;
|
int s, ns;
|
||||||
uschar *p = (uschar *) p0;
|
uschar *p = __UNCONST(p0);
|
||||||
uschar *q;
|
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;
|
patlen = -1;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
q = p;
|
q = p;
|
||||||
|
@ -568,9 +600,12 @@ int nematch(fa *f, const char *p0) /* non-empty match, for sub */
|
||||||
s = ns;
|
s = ns;
|
||||||
else
|
else
|
||||||
s = cgoto(f, s, *q);
|
s = cgoto(f, s, *q);
|
||||||
|
|
||||||
|
assert(s < f->state_count);
|
||||||
|
|
||||||
if (s == 1) { /* no transition */
|
if (s == 1) { /* no transition */
|
||||||
if (patlen > 0) {
|
if (patlen > 0) {
|
||||||
patbeg = (char *) p;
|
patbeg = p;
|
||||||
return(1);
|
return(1);
|
||||||
} else
|
} else
|
||||||
goto nnextin; /* no nonempty match */
|
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])
|
if (f->out[s])
|
||||||
patlen = q-p-1; /* don't count $ */
|
patlen = q-p-1; /* don't count $ */
|
||||||
if (patlen > 0 ) {
|
if (patlen > 0 ) {
|
||||||
patbeg = (char *) p;
|
patbeg = p;
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
nnextin:
|
nnextin:
|
||||||
s = 2;
|
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++;
|
p++;
|
||||||
}
|
}
|
||||||
return (0);
|
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 */
|
Node *reparse(const char *p) /* parses regular expression pointed to by p */
|
||||||
{ /* uses relex() to scan regular expression */
|
{ /* uses relex() to scan regular expression */
|
||||||
Node *np;
|
Node *np;
|
||||||
|
|
||||||
dprintf( ("reparse <%s>\n", p) );
|
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();
|
rtok = relex();
|
||||||
/* GNU compatibility: an empty regexp matches anything */
|
/* GNU compatibility: an empty regexp matches anything */
|
||||||
if (rtok == '\0') {
|
if (rtok == '\0') {
|
||||||
|
@ -644,11 +756,11 @@ Node *primary(void)
|
||||||
rtok = relex();
|
rtok = relex();
|
||||||
return (unary(op2(DOT, NIL, NIL)));
|
return (unary(op2(DOT, NIL, NIL)));
|
||||||
case CCL:
|
case CCL:
|
||||||
np = op2(CCL, NIL, (Node*) cclenter((char *) rlxstr));
|
np = op2(CCL, NIL, (Node*) cclenter((const char *) rlxstr));
|
||||||
rtok = relex();
|
rtok = relex();
|
||||||
return (unary(np));
|
return (unary(np));
|
||||||
case NCCL:
|
case NCCL:
|
||||||
np = op2(NCCL, NIL, (Node *) cclenter((char *) rlxstr));
|
np = op2(NCCL, NIL, (Node *) cclenter((const char *) rlxstr));
|
||||||
rtok = relex();
|
rtok = relex();
|
||||||
return (unary(np));
|
return (unary(np));
|
||||||
case '^':
|
case '^':
|
||||||
|
@ -732,23 +844,15 @@ Node *unary(Node *np)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* #define HAS_ISBLANK */
|
/* #define HAS_ISBLANK */
|
||||||
#ifndef HAS_ISBLANK
|
|
||||||
|
|
||||||
int (xisblank)(int c)
|
static const struct charclass {
|
||||||
{
|
|
||||||
return c==' ' || c=='\t';
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct charclass {
|
|
||||||
const char *cc_name;
|
const char *cc_name;
|
||||||
int cc_namelen;
|
int cc_namelen;
|
||||||
int (*cc_func)(int);
|
int (*cc_func)(int);
|
||||||
} charclasses[] = {
|
} charclasses[] = {
|
||||||
{ "alnum", 5, isalnum },
|
{ "alnum", 5, isalnum },
|
||||||
{ "alpha", 5, isalpha },
|
{ "alpha", 5, isalpha },
|
||||||
{ "blank", 5, isspace }, /* was isblank */
|
{ "blank", 5, isblank },
|
||||||
{ "cntrl", 5, iscntrl },
|
{ "cntrl", 5, iscntrl },
|
||||||
{ "digit", 5, isdigit },
|
{ "digit", 5, isdigit },
|
||||||
{ "graph", 5, isgraph },
|
{ "graph", 5, isgraph },
|
||||||
|
@ -769,7 +873,7 @@ int relex(void) /* lexical analyzer for reparse */
|
||||||
static uschar *buf = 0;
|
static uschar *buf = 0;
|
||||||
static int bufsz = 100;
|
static int bufsz = 100;
|
||||||
uschar *bp;
|
uschar *bp;
|
||||||
struct charclass *cc;
|
const struct charclass *cc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
switch (c = *prestr++) {
|
switch (c = *prestr++) {
|
||||||
|
@ -785,13 +889,13 @@ int relex(void) /* lexical analyzer for reparse */
|
||||||
case ')':
|
case ')':
|
||||||
return c;
|
return c;
|
||||||
case '\\':
|
case '\\':
|
||||||
rlxval = quoted((char **) &prestr);
|
rlxval = quoted(&prestr);
|
||||||
return CHAR;
|
return CHAR;
|
||||||
default:
|
default:
|
||||||
rlxval = c;
|
rlxval = c;
|
||||||
return CHAR;
|
return CHAR;
|
||||||
case '[':
|
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);
|
FATAL("out of space in reg expr %.10s..", lastre);
|
||||||
bp = buf;
|
bp = buf;
|
||||||
if (*prestr == '^') {
|
if (*prestr == '^') {
|
||||||
|
@ -801,7 +905,7 @@ int relex(void) /* lexical analyzer for reparse */
|
||||||
else
|
else
|
||||||
cflag = 0;
|
cflag = 0;
|
||||||
n = 2 * strlen((const char *) prestr)+1;
|
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);
|
FATAL("out of space for reg expr %.10s...", lastre);
|
||||||
for (; ; ) {
|
for (; ; ) {
|
||||||
if ((c = *prestr++) == '\\') {
|
if ((c = *prestr++) == '\\') {
|
||||||
|
@ -819,8 +923,8 @@ int relex(void) /* lexical analyzer for reparse */
|
||||||
if (cc->cc_name != NULL && prestr[1 + cc->cc_namelen] == ':' &&
|
if (cc->cc_name != NULL && prestr[1 + cc->cc_namelen] == ':' &&
|
||||||
prestr[2 + cc->cc_namelen] == ']') {
|
prestr[2 + cc->cc_namelen] == ']') {
|
||||||
prestr += cc->cc_namelen + 3;
|
prestr += cc->cc_namelen + 3;
|
||||||
for (i = 0; i < NCHARS; i++) {
|
for (i = 1; i < NCHARS; i++) {
|
||||||
if (!adjbuf((char **) &buf, &bufsz, bp-buf+1, 100, (char **) &bp, "relex2"))
|
if (!adjbuf(&buf, &bufsz, bp-buf+1, 100, &bp, "relex2"))
|
||||||
FATAL("out of space for reg expr %.10s...", lastre);
|
FATAL("out of space for reg expr %.10s...", lastre);
|
||||||
if (cc->cc_func(i)) {
|
if (cc->cc_func(i)) {
|
||||||
*bp++ = i;
|
*bp++ = i;
|
||||||
|
@ -852,16 +956,12 @@ int cgoto(fa *f, int s, int c)
|
||||||
int *p, *q;
|
int *p, *q;
|
||||||
|
|
||||||
assert(c == HAT || c < NCHARS);
|
assert(c == HAT || c < NCHARS);
|
||||||
while (f->accept >= maxsetvec) { /* guessing here! */
|
while (f->accept >= maxsetvec) /* guessing here! */
|
||||||
maxsetvec *= 4;
|
resizesetvec("out of space in cgoto()");
|
||||||
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()");
|
|
||||||
}
|
|
||||||
for (i = 0; i <= f->accept; i++)
|
for (i = 0; i <= f->accept; i++)
|
||||||
setvec[i] = 0;
|
setvec[i] = 0;
|
||||||
setcnt = 0;
|
setcnt = 0;
|
||||||
|
resize_state(f, s);
|
||||||
/* compute positions of gototab[s,c] into setvec */
|
/* compute positions of gototab[s,c] into setvec */
|
||||||
p = f->posns[s];
|
p = f->posns[s];
|
||||||
for (i = 1; i <= *p; i++) {
|
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)) {
|
|| (k == NCCL && !member(c, (char *) f->re[p[i]].lval.up) && c != 0 && c != HAT)) {
|
||||||
q = f->re[p[i]].lfollow;
|
q = f->re[p[i]].lfollow;
|
||||||
for (j = 1; j <= *q; j++) {
|
for (j = 1; j <= *q; j++) {
|
||||||
if (q[j] >= maxsetvec) {
|
if (q[j] >= maxsetvec)
|
||||||
maxsetvec *= 4;
|
resizesetvec("cgoto overflow");
|
||||||
setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
|
|
||||||
tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
|
|
||||||
if (setvec == 0 || tmpset == 0)
|
|
||||||
overflo("cgoto overflow");
|
|
||||||
}
|
|
||||||
if (setvec[q[j]] == 0) {
|
if (setvec[q[j]] == 0) {
|
||||||
setcnt++;
|
setcnt++;
|
||||||
setvec[q[j]] = 1;
|
setvec[q[j]] = 1;
|
||||||
|
@ -896,6 +991,8 @@ int cgoto(fa *f, int s, int c)
|
||||||
if (setvec[i]) {
|
if (setvec[i]) {
|
||||||
tmpset[j++] = i;
|
tmpset[j++] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resize_state(f, f->curstat > s ? f->curstat : s);
|
||||||
/* tmpset == previous state? */
|
/* tmpset == previous state? */
|
||||||
for (i = 1; i <= f->curstat; i++) {
|
for (i = 1; i <= f->curstat; i++) {
|
||||||
p = f->posns[i];
|
p = f->posns[i];
|
||||||
|
@ -905,26 +1002,23 @@ int cgoto(fa *f, int s, int c)
|
||||||
if (tmpset[j] != p[j])
|
if (tmpset[j] != p[j])
|
||||||
goto different;
|
goto different;
|
||||||
/* setvec is state i */
|
/* setvec is state i */
|
||||||
|
if (c != HAT)
|
||||||
f->gototab[s][c] = i;
|
f->gototab[s][c] = i;
|
||||||
return i;
|
return i;
|
||||||
different:;
|
different:;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add tmpset to current set of states */
|
/* 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++)
|
for (i = 0; i < NCHARS; i++)
|
||||||
f->gototab[f->curstat][i] = 0;
|
f->gototab[f->curstat][i] = 0;
|
||||||
xfree(f->posns[f->curstat]);
|
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");
|
overflo("out of space in cgoto");
|
||||||
|
|
||||||
f->posns[f->curstat] = p;
|
f->posns[f->curstat] = p;
|
||||||
|
if (c != HAT)
|
||||||
f->gototab[s][c] = f->curstat;
|
f->gototab[s][c] = f->curstat;
|
||||||
for (i = 0; i <= setcnt; i++)
|
for (i = 0; i <= setcnt; i++)
|
||||||
p[i] = tmpset[i];
|
p[i] = tmpset[i];
|
||||||
|
@ -942,13 +1036,18 @@ void freefa(fa *f) /* free a finite automaton */
|
||||||
|
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return;
|
return;
|
||||||
for (i = 0; i <= f->curstat; i++)
|
for (i = 0; i < f->state_count; i++) {
|
||||||
|
xfree(f->gototab[i])
|
||||||
xfree(f->posns[i]);
|
xfree(f->posns[i]);
|
||||||
|
}
|
||||||
for (i = 0; i <= f->accept; i++) {
|
for (i = 0; i <= f->accept; i++) {
|
||||||
xfree(f->re[i].lfollow);
|
xfree(f->re[i].lfollow);
|
||||||
if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL)
|
if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL)
|
||||||
xfree((f->re[i].lval.np));
|
xfree((f->re[i].lval.np));
|
||||||
}
|
}
|
||||||
xfree(f->restr);
|
xfree(f->restr);
|
||||||
|
xfree(f->out);
|
||||||
|
xfree(f->posns);
|
||||||
|
xfree(f->gototab);
|
||||||
xfree(f);
|
xfree(f);
|
||||||
}
|
}
|
|
@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
THIS SOFTWARE.
|
THIS SOFTWARE.
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
#if HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -43,7 +47,11 @@ typedef struct Keyword {
|
||||||
int type;
|
int type;
|
||||||
} Keyword;
|
} 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 },
|
{ "BEGIN", XBEGIN, XBEGIN },
|
||||||
{ "END", XEND, XEND },
|
{ "END", XEND, XEND },
|
||||||
{ "NF", VARNF, VARNF },
|
{ "NF", VARNF, VARNF },
|
||||||
|
@ -61,6 +69,7 @@ Keyword keywords[] ={ /* keep sorted: binary searched */
|
||||||
{ "for", FOR, FOR },
|
{ "for", FOR, FOR },
|
||||||
{ "func", FUNC, FUNC },
|
{ "func", FUNC, FUNC },
|
||||||
{ "function", FUNC, FUNC },
|
{ "function", FUNC, FUNC },
|
||||||
|
{ "gensub", GENSUB, GENSUB },
|
||||||
{ "getline", GETLINE, GETLINE },
|
{ "getline", GETLINE, GETLINE },
|
||||||
{ "gsub", GSUB, GSUB },
|
{ "gsub", GSUB, GSUB },
|
||||||
{ "if", IF, IF },
|
{ "if", IF, IF },
|
||||||
|
@ -81,9 +90,11 @@ Keyword keywords[] ={ /* keep sorted: binary searched */
|
||||||
{ "sprintf", SPRINTF, SPRINTF },
|
{ "sprintf", SPRINTF, SPRINTF },
|
||||||
{ "sqrt", FSQRT, BLTIN },
|
{ "sqrt", FSQRT, BLTIN },
|
||||||
{ "srand", FSRAND, BLTIN },
|
{ "srand", FSRAND, BLTIN },
|
||||||
|
{ "strftime", FSTRFTIME, BLTIN },
|
||||||
{ "sub", SUB, SUB },
|
{ "sub", SUB, SUB },
|
||||||
{ "substr", SUBSTR, SUBSTR },
|
{ "substr", SUBSTR, SUBSTR },
|
||||||
{ "system", FSYSTEM, BLTIN },
|
{ "system", FSYSTEM, BLTIN },
|
||||||
|
{ "systime", FSYSTIME, BLTIN },
|
||||||
{ "tolower", FTOLOWER, BLTIN },
|
{ "tolower", FTOLOWER, BLTIN },
|
||||||
{ "toupper", FTOUPPER, BLTIN },
|
{ "toupper", FTOUPPER, BLTIN },
|
||||||
{ "while", WHILE, WHILE },
|
{ "while", WHILE, WHILE },
|
||||||
|
@ -101,9 +112,9 @@ int peek(void)
|
||||||
int gettok(char **pbuf, int *psz) /* get next input token */
|
int gettok(char **pbuf, int *psz) /* get next input token */
|
||||||
{
|
{
|
||||||
int c, retc;
|
int c, retc;
|
||||||
char *buf = *pbuf;
|
uschar *buf = (uschar *) *pbuf;
|
||||||
int sz = *psz;
|
int sz = *psz;
|
||||||
char *bp = buf;
|
uschar *bp = buf;
|
||||||
|
|
||||||
c = input();
|
c = input();
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
|
@ -146,7 +157,7 @@ int gettok(char **pbuf, int *psz) /* get next input token */
|
||||||
}
|
}
|
||||||
*bp = 0;
|
*bp = 0;
|
||||||
strtod(buf, &rem); /* parse the number */
|
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 */
|
buf[1] = 0; /* return one character as token */
|
||||||
retc = buf[0]; /* character is its own type */
|
retc = buf[0]; /* character is its own type */
|
||||||
unputstr(rem+1); /* put rest back for later */
|
unputstr(rem+1); /* put rest back for later */
|
||||||
|
@ -173,7 +184,7 @@ int yylex(void)
|
||||||
static char *buf = 0;
|
static char *buf = 0;
|
||||||
static int bufsize = 5; /* BUG: setting this small causes core dump! */
|
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" );
|
FATAL( "out of space in yylex" );
|
||||||
if (sc) {
|
if (sc) {
|
||||||
sc = 0;
|
sc = 0;
|
||||||
|
@ -357,11 +368,11 @@ int yylex(void)
|
||||||
int string(void)
|
int string(void)
|
||||||
{
|
{
|
||||||
int c, n;
|
int c, n;
|
||||||
char *s, *bp;
|
uschar *s, *bp;
|
||||||
static char *buf = 0;
|
static uschar *buf = 0;
|
||||||
static int bufsz = 500;
|
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");
|
FATAL("out of space for strings");
|
||||||
for (bp = buf; (c = input()) != '"'; ) {
|
for (bp = buf; (c = input()) != '"'; ) {
|
||||||
if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
|
if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
|
||||||
|
@ -378,6 +389,7 @@ int string(void)
|
||||||
case '\\':
|
case '\\':
|
||||||
c = input();
|
c = input();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case '\n': break;
|
||||||
case '"': *bp++ = '"'; break;
|
case '"': *bp++ = '"'; break;
|
||||||
case 'n': *bp++ = '\n'; break;
|
case 'n': *bp++ = '\n'; break;
|
||||||
case 't': *bp++ = '\t'; break;
|
case 't': *bp++ = '\t'; break;
|
||||||
|
@ -417,6 +429,8 @@ int string(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
WARNING("warning: escape sequence `\\%c' "
|
||||||
|
"treated as plain `%c'", c, c);
|
||||||
*bp++ = c;
|
*bp++ = c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +468,7 @@ int binsearch(const char *w, const Keyword *kp, int n)
|
||||||
|
|
||||||
int word(char *w)
|
int word(char *w)
|
||||||
{
|
{
|
||||||
Keyword *kp;
|
const Keyword *kp;
|
||||||
int c, n;
|
int c, n;
|
||||||
|
|
||||||
n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
|
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 regexpr(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
static char *buf = 0;
|
static uschar *buf = 0;
|
||||||
static int bufsz = 500;
|
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");
|
FATAL("out of space for rex expr");
|
||||||
bp = buf;
|
bp = buf;
|
||||||
for ( ; (c = input()) != '/' && c != 0; ) {
|
for ( ; (c = input()) != '/' && c != 0; ) {
|
|
@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
THIS SOFTWARE.
|
THIS SOFTWARE.
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
#if HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -32,15 +36,19 @@ THIS SOFTWARE.
|
||||||
#include "awk.h"
|
#include "awk.h"
|
||||||
#include "awkgram.h"
|
#include "awkgram.h"
|
||||||
|
|
||||||
|
char EMPTY[] = { '\0' };
|
||||||
FILE *infile = NULL;
|
FILE *infile = NULL;
|
||||||
char *file = "";
|
int innew; /* 1 = infile has not been read by readrec */
|
||||||
char *record;
|
char *file = EMPTY;
|
||||||
|
uschar *record;
|
||||||
int recsize = RECSIZE;
|
int recsize = RECSIZE;
|
||||||
char *fields;
|
char *fields;
|
||||||
int fieldssize = RECSIZE;
|
int fieldssize = RECSIZE;
|
||||||
|
|
||||||
Cell **fldtab; /* pointers to Cells */
|
Cell **fldtab; /* pointers to Cells */
|
||||||
char inputFS[100] = " ";
|
|
||||||
|
static size_t len_inputFS = 0;
|
||||||
|
static char *inputFS = NULL;
|
||||||
|
|
||||||
#define MAXFLD 2
|
#define MAXFLD 2
|
||||||
int nfields = MAXFLD; /* last allocated slot for $i */
|
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 */
|
int argno = 1; /* current input argument number */
|
||||||
extern Awkfloat *ARGC;
|
extern Awkfloat *ARGC;
|
||||||
|
|
||||||
static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
|
static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL };
|
||||||
static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
|
static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL };
|
||||||
|
|
||||||
void recinit(unsigned int n)
|
void recinit(unsigned int n)
|
||||||
{
|
{
|
||||||
if ( (record = (char *) malloc(n)) == NULL
|
if ( (record = malloc(n)) == NULL
|
||||||
|| (fields = (char *) malloc(n+1)) == NULL
|
|| (fields = malloc(n+1)) == NULL
|
||||||
|| (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL
|
|| (fldtab = malloc((nfields+1) * sizeof(*fldtab))) == NULL
|
||||||
|| (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
|
|| (fldtab[0] = malloc(sizeof(**fldtab))) == NULL )
|
||||||
FATAL("out of space for $0 and fields");
|
FATAL("out of space for $0 and fields");
|
||||||
*fldtab[0] = dollar0;
|
*fldtab[0] = dollar0;
|
||||||
fldtab[0]->sval = record;
|
fldtab[0]->sval = record;
|
||||||
|
@ -74,11 +82,11 @@ void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = n1; i <= n2; i++) {
|
for (i = n1; i <= n2; i++) {
|
||||||
fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
|
fldtab[i] = malloc(sizeof(**fldtab));
|
||||||
if (fldtab[i] == NULL)
|
if (fldtab[i] == NULL)
|
||||||
FATAL("out of space in makefields %d", i);
|
FATAL("out of space in makefields %d", i);
|
||||||
*fldtab[i] = dollar1;
|
*fldtab[i] = dollar1;
|
||||||
sprintf(temp, "%d", i);
|
snprintf(temp, sizeof(temp), "%d", i);
|
||||||
fldtab[i]->nval = tostring(temp);
|
fldtab[i]->nval = tostring(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,14 +105,15 @@ void initgetrec(void)
|
||||||
argno++;
|
argno++;
|
||||||
}
|
}
|
||||||
infile = stdin; /* no filenames, so use stdin */
|
infile = stdin; /* no filenames, so use stdin */
|
||||||
|
innew = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int firsttime = 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 */
|
{ /* note: cares whether buf == record */
|
||||||
int c;
|
int c;
|
||||||
char *buf = *pbuf;
|
uschar *buf = *pbuf;
|
||||||
uschar saveb0;
|
uschar saveb0;
|
||||||
int bufsize = *pbufsize, savebufsize = bufsize;
|
int bufsize = *pbufsize, savebufsize = bufsize;
|
||||||
|
|
||||||
|
@ -139,9 +148,12 @@ int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
|
||||||
infile = stdin;
|
infile = stdin;
|
||||||
else if ((infile = fopen(file, "r")) == NULL)
|
else if ((infile = fopen(file, "r")) == NULL)
|
||||||
FATAL("can't open file %s", file);
|
FATAL("can't open file %s", file);
|
||||||
|
innew = 1;
|
||||||
setfval(fnrloc, 0.0);
|
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 (c != 0 || buf[0] != '\0') { /* normal record */
|
||||||
if (isrecord) {
|
if (isrecord) {
|
||||||
if (freeable(fldtab[0]))
|
if (freeable(fldtab[0]))
|
||||||
|
@ -179,15 +191,35 @@ void nextfile(void)
|
||||||
argno++;
|
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;
|
int sep, c, isrec, found, tempstat;
|
||||||
char *rr, *buf = *pbuf;
|
uschar *rr, *buf = *pbuf;
|
||||||
int bufsize = *pbufsize;
|
int bufsize = *pbufsize;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
if (strlen(*FS) >= sizeof(inputFS))
|
if ((len = strlen(*FS)) < len_inputFS) {
|
||||||
FATAL("field separator %.10s... is too long", *FS);
|
|
||||||
strcpy(inputFS, *FS); /* for subsequent field splitting */
|
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);
|
||||||
|
}
|
||||||
|
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) {
|
if ((sep = **RS) == 0) {
|
||||||
sep = '\n';
|
sep = '\n';
|
||||||
while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
|
while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
|
||||||
|
@ -198,15 +230,19 @@ int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf *
|
||||||
for (rr = buf; ; ) {
|
for (rr = buf; ; ) {
|
||||||
for (; (c=getc(inf)) != sep && c != EOF; ) {
|
for (; (c=getc(inf)) != sep && c != EOF; ) {
|
||||||
if (rr-buf+1 > bufsize)
|
if (rr-buf+1 > bufsize)
|
||||||
if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
|
if (!adjbuf(&buf, &bufsize, 1+rr-buf,
|
||||||
FATAL("input record `%.30s...' too long", buf);
|
recsize, &rr, "readrec 1"))
|
||||||
|
FATAL("input record `%.30s...'"
|
||||||
|
" too long", buf);
|
||||||
*rr++ = c;
|
*rr++ = c;
|
||||||
}
|
}
|
||||||
if (**RS == sep || c == EOF)
|
if (**RS == sep || c == EOF)
|
||||||
break;
|
break;
|
||||||
if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
|
if ((c = getc(inf)) == '\n' || c == EOF)
|
||||||
|
/* 2 in a row */
|
||||||
break;
|
break;
|
||||||
if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
|
if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
|
||||||
|
"readrec 2"))
|
||||||
FATAL("input record `%.30s...' too long", buf);
|
FATAL("input record `%.30s...' too long", buf);
|
||||||
*rr++ = '\n';
|
*rr++ = '\n';
|
||||||
*rr++ = c;
|
*rr++ = c;
|
||||||
|
@ -214,10 +250,12 @@ int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf *
|
||||||
if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
|
if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
|
||||||
FATAL("input record `%.30s...' too long", buf);
|
FATAL("input record `%.30s...' too long", buf);
|
||||||
*rr = 0;
|
*rr = 0;
|
||||||
dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
|
}
|
||||||
*pbuf = buf;
|
*pbuf = buf;
|
||||||
*pbufsize = bufsize;
|
*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] */
|
char *getargv(int n) /* get ARGV[n] */
|
||||||
|
@ -226,7 +264,7 @@ char *getargv(int n) /* get ARGV[n] */
|
||||||
char *s, temp[50];
|
char *s, temp[50];
|
||||||
extern Array *ARGVtab;
|
extern Array *ARGVtab;
|
||||||
|
|
||||||
sprintf(temp, "%d", n);
|
snprintf(temp, sizeof(temp), "%d", n);
|
||||||
x = setsymtab(temp, "", 0.0, STR, ARGVtab);
|
x = setsymtab(temp, "", 0.0, STR, ARGVtab);
|
||||||
s = getsval(x);
|
s = getsval(x);
|
||||||
dprintf( ("getargv(%d) returns |%s|\n", n, s) );
|
dprintf( ("getargv(%d) returns |%s|\n", n, s) );
|
||||||
|
@ -268,14 +306,15 @@ void fldbld(void) /* create fields from current record */
|
||||||
n = strlen(r);
|
n = strlen(r);
|
||||||
if (n > fieldssize) {
|
if (n > fieldssize) {
|
||||||
xfree(fields);
|
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);
|
FATAL("out of space for fields in fldbld %d", n);
|
||||||
fieldssize = n;
|
fieldssize = n;
|
||||||
}
|
}
|
||||||
fr = fields;
|
fr = fields;
|
||||||
i = 0; /* number of fields accumulated here */
|
i = 0; /* number of fields accumulated here */
|
||||||
strcpy(inputFS, *FS);
|
if (!inputFS) {
|
||||||
if (strlen(inputFS) > 1) { /* it's a regular expression */
|
/* do nothing */
|
||||||
|
} else if (inputFS[0] && inputFS[1]) { /* it's a regular expression */
|
||||||
i = refldbld(r, inputFS);
|
i = refldbld(r, inputFS);
|
||||||
} else if ((sep = *inputFS) == ' ') { /* default whitespace */
|
} else if ((sep = *inputFS) == ' ') { /* default whitespace */
|
||||||
for (i = 0; ; ) {
|
for (i = 0; ; ) {
|
||||||
|
@ -347,6 +386,7 @@ void fldbld(void) /* create fields from current record */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setfval(nfloc, (Awkfloat) lastfld);
|
setfval(nfloc, (Awkfloat) lastfld);
|
||||||
|
donerec = 1; /* restore */
|
||||||
if (dbg) {
|
if (dbg) {
|
||||||
for (j = 0; j <= lastfld; j++) {
|
for (j = 0; j <= lastfld; j++) {
|
||||||
p = fldtab[j];
|
p = fldtab[j];
|
||||||
|
@ -364,7 +404,7 @@ void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
|
||||||
p = fldtab[i];
|
p = fldtab[i];
|
||||||
if (freeable(p))
|
if (freeable(p))
|
||||||
xfree(p->sval);
|
xfree(p->sval);
|
||||||
p->sval = "";
|
p->sval = EMPTY;
|
||||||
p->tval = FLD | STR | DONTFREE;
|
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);
|
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 */
|
Cell *fieldadr(int n) /* get nth field */
|
||||||
{
|
{
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
|
@ -395,8 +448,8 @@ void growfldtab(int n) /* make new fields up to at least $n */
|
||||||
if (n > nf)
|
if (n > nf)
|
||||||
nf = n;
|
nf = n;
|
||||||
s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
|
s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
|
||||||
if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
|
if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
|
||||||
fldtab = (Cell **) realloc(fldtab, s);
|
fldtab = realloc(fldtab, s);
|
||||||
else /* overflow sizeof int */
|
else /* overflow sizeof int */
|
||||||
xfree(fldtab); /* make it null */
|
xfree(fldtab); /* make it null */
|
||||||
if (fldtab == 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);
|
n = strlen(rec);
|
||||||
if (n > fieldssize) {
|
if (n > fieldssize) {
|
||||||
xfree(fields);
|
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);
|
FATAL("out of space for fields in refldbld %d", n);
|
||||||
fieldssize = 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)) {
|
if (nematch(pfa, rec)) {
|
||||||
pfa->initstat = 2; /* horrible coupling to b.c */
|
pfa->initstat = 2; /* horrible coupling to b.c */
|
||||||
dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
|
dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
|
||||||
strncpy(fr, rec, patbeg-rec);
|
strncpy(fr, rec, ((const char*)patbeg)-rec);
|
||||||
fr += patbeg - rec + 1;
|
fr += ((const char*)patbeg) - rec + 1;
|
||||||
*(fr-1) = '\0';
|
*(fr-1) = '\0';
|
||||||
rec = patbeg + patlen;
|
rec = patbeg + patlen;
|
||||||
} else {
|
} 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 */
|
void recbld(void) /* create $0 from $1..$NF if necessary */
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *r, *p;
|
uschar *r;
|
||||||
|
char *p;
|
||||||
|
|
||||||
if (donerec == 1)
|
if (donerec == 1)
|
||||||
return;
|
return;
|
||||||
|
@ -517,11 +571,6 @@ void SYNTAX(const char *fmt, ...)
|
||||||
eprint();
|
eprint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpecatch(int n)
|
|
||||||
{
|
|
||||||
FATAL("floating point exception %d", n);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int bracecnt, brackcnt, parencnt;
|
extern int bracecnt, brackcnt, parencnt;
|
||||||
|
|
||||||
void bracecheck(void)
|
void bracecheck(void)
|
||||||
|
@ -603,7 +652,6 @@ void error()
|
||||||
void eprint(void) /* try to print context around error */
|
void eprint(void) /* try to print context around error */
|
||||||
{
|
{
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
int c;
|
|
||||||
static int been_here = 0;
|
static int been_here = 0;
|
||||||
extern char ebuf[], *ep;
|
extern char ebuf[], *ep;
|
||||||
|
|
||||||
|
@ -627,11 +675,25 @@ void eprint(void) /* try to print context around error */
|
||||||
if (*p)
|
if (*p)
|
||||||
putc(*p, stderr);
|
putc(*p, stderr);
|
||||||
fprintf(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) {
|
while ((c = input()) != '\n' && c != '\0' && c != EOF) {
|
||||||
putc(c, stderr);
|
putc(c, stderr);
|
||||||
bclass(c);
|
bclass(c);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
ep = ebuf;
|
ep = ebuf;
|
||||||
}
|
}
|
||||||
|
@ -686,7 +748,9 @@ int is_number(const char *s)
|
||||||
char *ep;
|
char *ep;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
r = strtod(s, &ep);
|
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;
|
return 0;
|
||||||
while (*ep == ' ' || *ep == '\t' || *ep == '\n')
|
while (*ep == ' ' || *ep == '\t' || *ep == '\n')
|
||||||
ep++;
|
ep++;
|
|
@ -22,7 +22,11 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
THIS SOFTWARE.
|
THIS SOFTWARE.
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
const char *version = "version 20100208";
|
const char *version = "version 20100523";
|
||||||
|
|
||||||
|
#if HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -38,6 +42,7 @@ extern char **environ;
|
||||||
extern int nfields;
|
extern int nfields;
|
||||||
|
|
||||||
int dbg = 0;
|
int dbg = 0;
|
||||||
|
unsigned int srand_seed;
|
||||||
char *cmdname; /* gets argv[0] for error messages */
|
char *cmdname; /* gets argv[0] for error messages */
|
||||||
extern FILE *yyin; /* lex input file */
|
extern FILE *yyin; /* lex input file */
|
||||||
char *lexprog; /* points to program argument if it exists */
|
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: */
|
int compile_time = 2; /* for error printing: */
|
||||||
/* 2 = cmdline, 1 = compile, 0 = running */
|
/* 2 = cmdline, 1 = compile, 0 = running */
|
||||||
|
|
||||||
#define MAX_PFILE 20 /* max number of -f's */
|
static char **pfile = NULL; /* program filenames from -f's */
|
||||||
|
static size_t maxpfile = 0; /* max program filenames */
|
||||||
char *pfile[MAX_PFILE]; /* program filenames from -f's */
|
static size_t npfile = 0; /* number of filenames */
|
||||||
int npfile = 0; /* number of filenames */
|
static size_t curpfile = 0; /* current filename */
|
||||||
int curpfile = 0; /* current filename */
|
|
||||||
|
|
||||||
int safe = 0; /* 1 => "safe" mode */
|
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[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
const char *fs = NULL;
|
const char *fs = NULL;
|
||||||
|
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_ALL, "");
|
||||||
setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
|
setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
|
||||||
cmdname = argv[0];
|
cmdname = argv[0];
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
|
@ -66,7 +111,22 @@ int main(int argc, char *argv[])
|
||||||
cmdname);
|
cmdname);
|
||||||
exit(1);
|
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;
|
yyin = NULL;
|
||||||
symtab = makesymtab(NSYMTAB/NSYMTAB);
|
symtab = makesymtab(NSYMTAB/NSYMTAB);
|
||||||
while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
|
while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
|
||||||
|
@ -90,22 +150,23 @@ int main(int argc, char *argv[])
|
||||||
argv++;
|
argv++;
|
||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
FATAL("no program filename");
|
FATAL("no program filename");
|
||||||
if (npfile >= MAX_PFILE - 1)
|
if (npfile >= maxpfile) {
|
||||||
FATAL("too many -f options");
|
maxpfile += 20;
|
||||||
|
pfile = realloc(pfile,
|
||||||
|
maxpfile * sizeof(*pfile));
|
||||||
|
if (pfile == NULL)
|
||||||
|
FATAL("error allocating space for "
|
||||||
|
"-f options");
|
||||||
|
}
|
||||||
pfile[npfile++] = argv[1];
|
pfile[npfile++] = argv[1];
|
||||||
break;
|
break;
|
||||||
case 'F': /* set field separator */
|
case 'F': /* set field separator */
|
||||||
if (argv[1][2] != 0) { /* arg is -Fsomething */
|
if (argv[1][2] != 0) { /* arg is -Fsomething */
|
||||||
if (argv[1][2] == 't' && argv[1][3] == 0) /* wart: t=>\t */
|
fs = setfs(argv[1] + 2);
|
||||||
fs = "\t";
|
|
||||||
else if (argv[1][2] != 0)
|
|
||||||
fs = &argv[1][2];
|
|
||||||
} else { /* arg is -F something */
|
} else { /* arg is -F something */
|
||||||
argc--; argv++;
|
argc--; argv++;
|
||||||
if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0) /* wart: t=>\t */
|
if (argc > 1)
|
||||||
fs = "\t";
|
fs = setfs(argv[1]);
|
||||||
else if (argc > 1 && argv[1][0] != 0)
|
|
||||||
fs = &argv[1][0];
|
|
||||||
}
|
}
|
||||||
if (fs == NULL || *fs == '\0')
|
if (fs == NULL || *fs == '\0')
|
||||||
WARNING("field separator FS is empty");
|
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 */
|
case 'v': /* -v a=1 to be done NOW. one -v for each */
|
||||||
if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1]))
|
if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1]))
|
||||||
setclvar(argv[1]);
|
setclvar(argv[1]);
|
||||||
|
else if (argv[1][2] != '\0')
|
||||||
|
setclvar(&argv[1][2]);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
dbg = atoi(&argv[1][2]);
|
dbg = atoi(&argv[1][2]);
|
||||||
|
@ -148,7 +211,6 @@ int main(int argc, char *argv[])
|
||||||
if (!safe)
|
if (!safe)
|
||||||
envinit(environ);
|
envinit(environ);
|
||||||
yyparse();
|
yyparse();
|
||||||
setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
|
|
||||||
if (fs)
|
if (fs)
|
||||||
*FS = qstring(fs, '\0');
|
*FS = qstring(fs, '\0');
|
||||||
dprintf( ("errorflag=%d\n", errorflag) );
|
dprintf( ("errorflag=%d\n", errorflag) );
|
|
@ -26,13 +26,13 @@ CFLAGS = -g
|
||||||
CFLAGS = -O2
|
CFLAGS = -O2
|
||||||
CFLAGS =
|
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 -Wall -g -Wwrite-strings
|
||||||
CC = gcc -fprofile-arcs -ftest-coverage # then gcov f1.c; cat f1.c.gcov
|
CC = gcc -fprofile-arcs -ftest-coverage # then gcov f1.c; cat f1.c.gcov
|
||||||
CC = gcc -Wall -g
|
|
||||||
CC = cc
|
|
||||||
CC = gcc -O4
|
CC = gcc -O4
|
||||||
CC = cc -O
|
|
||||||
|
|
||||||
|
|
||||||
YACC = bison -y
|
YACC = bison -y
|
||||||
YACC = yacc
|
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 \
|
SHIP = README FIXES $(SOURCE) ytab[ch].bak makefile makefile.win \
|
||||||
vcvars32.bat buildwin.bat awk.1
|
vcvars32.bat buildwin.bat awk.1
|
||||||
|
|
||||||
all: awk
|
a.out: ytab.o $(OFILES)
|
||||||
|
$(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC) -lm
|
||||||
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 $@
|
|
||||||
|
|
||||||
$(OFILES): awk.h ytab.h proto.h
|
$(OFILES): awk.h ytab.h proto.h
|
||||||
|
|
||||||
ytab.o ytab.c ytab.h: awk.h proto.h awkgram.y
|
ytab.o: awk.h proto.h awkgram.y
|
||||||
$(YACC) $(YFLAGS) awkgram.y 2>/dev/null
|
$(YACC) $(YFLAGS) awkgram.y
|
||||||
mv y.tab.c ytab.c
|
mv y.tab.c ytab.c
|
||||||
mv y.tab.h ytab.h
|
mv y.tab.h ytab.h
|
||||||
$(CC) $(CFLAGS) -c ytab.c
|
$(CC) $(CFLAGS) -c ytab.c
|
||||||
|
@ -91,4 +85,4 @@ names:
|
||||||
@echo $(LISTING)
|
@echo $(LISTING)
|
||||||
|
|
||||||
clean:
|
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
|
* this program makes the table to link function names
|
||||||
* and type indices that is used by execute() in run.c.
|
* 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 <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -103,6 +107,7 @@ struct xx
|
||||||
{ ARG, "arg", "arg" },
|
{ ARG, "arg", "arg" },
|
||||||
{ VARNF, "getnf", "NF" },
|
{ VARNF, "getnf", "NF" },
|
||||||
{ GETLINE, "awkgetline", "getline" },
|
{ GETLINE, "awkgetline", "getline" },
|
||||||
|
{ GENSUB, "gensub", "gensub" },
|
||||||
{ 0, "", "" },
|
{ 0, "", "" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,19 +133,22 @@ int main(int argc, char *argv[])
|
||||||
fprintf(stderr, "maketab can't open awkgram.h!\n");
|
fprintf(stderr, "maketab can't open awkgram.h!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
printf("static char *printname[%d] = {\n", SIZE);
|
printf("static const char * const printname[%d] = {\n", SIZE);
|
||||||
i = 0;
|
i = 0;
|
||||||
while (fgets(buf, sizeof buf, fp) != NULL) {
|
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 */
|
if (c != '#' || (n != 4 && strcmp(def,"define") != 0)) /* not a valid #define */
|
||||||
continue;
|
continue;
|
||||||
if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
|
if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
|
||||||
/* fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf); */
|
/* fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf); */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1);
|
names[tok-FIRSTTOKEN] = strdup(name);
|
||||||
strcpy(names[tok-FIRSTTOKEN], name);
|
if (names[tok-FIRSTTOKEN] == NULL) {
|
||||||
printf("\t(char *) \"%s\",\t/* %d */\n", name, tok);
|
fprintf(stderr, "maketab out of space copying %s", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("\t\"%s\",\t/* %d */\n", name, tok);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
printf("};\n\n");
|
printf("};\n\n");
|
||||||
|
@ -155,11 +163,11 @@ int main(int argc, char *argv[])
|
||||||
printf("\t%s,\t/* %s */\n", table[i], names[i]);
|
printf("\t%s,\t/* %s */\n", table[i], names[i]);
|
||||||
printf("};\n\n");
|
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("{\n");
|
||||||
printf(" static char buf[100];\n\n");
|
printf(" static char buf[100];\n\n");
|
||||||
printf(" if (n < FIRSTTOKEN || n > LASTTOKEN) {\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(" return buf;\n");
|
||||||
printf(" }\n");
|
printf(" }\n");
|
||||||
printf(" return printname[n-FIRSTTOKEN];\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.
|
THIS SOFTWARE.
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
#if HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -33,7 +37,7 @@ Node *nodealloc(int n)
|
||||||
{
|
{
|
||||||
Node *x;
|
Node *x;
|
||||||
|
|
||||||
x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *));
|
x = malloc(sizeof(Node) + (n-1)*sizeof(Node *));
|
||||||
if (x == NULL)
|
if (x == NULL)
|
||||||
FATAL("out of space in nodealloc");
|
FATAL("out of space in nodealloc");
|
||||||
x->nnext = NULL;
|
x->nnext = NULL;
|
||||||
|
@ -93,6 +97,20 @@ Node *node4(int a, Node *b, Node *c, Node *d, Node *e)
|
||||||
return(x);
|
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 *stat1(int a, Node *b)
|
||||||
{
|
{
|
||||||
Node *x;
|
Node *x;
|
||||||
|
@ -165,6 +183,15 @@ Node *op4(int a, Node *b, Node *c, Node *d, Node *e)
|
||||||
return(x);
|
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 *celltonode(Cell *a, int b)
|
||||||
{
|
{
|
||||||
Node *x;
|
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 int makeinit(fa *, int);
|
||||||
extern void penter(Node *);
|
extern void penter(Node *);
|
||||||
extern void freetr(Node *);
|
extern void freetr(Node *);
|
||||||
extern int hexstr(char **);
|
extern int hexstr(const uschar **);
|
||||||
extern int quoted(char **);
|
extern int quoted(const uschar **);
|
||||||
extern char *cclenter(const char *);
|
extern char *cclenter(const char *);
|
||||||
extern void overflo(const char *);
|
extern void overflo(const char *) __dead;
|
||||||
extern void cfoll(fa *, Node *);
|
extern void cfoll(fa *, Node *);
|
||||||
extern int first(const Node *);
|
extern int first(Node *);
|
||||||
extern void follow(Node *);
|
extern void follow(Node *);
|
||||||
extern int member(int, const char *);
|
extern int member(int, const char *);
|
||||||
extern int match(fa *, const char *);
|
extern int match(fa *, const char *);
|
||||||
extern int pmatch(fa *, const char *);
|
extern int pmatch(fa *, const char *);
|
||||||
extern int nematch(fa *, const char *);
|
extern int nematch(fa *, const char *);
|
||||||
|
extern int fnematch(fa *, FILE *, uschar **, int *, int);
|
||||||
extern Node *reparse(const char *);
|
extern Node *reparse(const char *);
|
||||||
extern Node *regexp(void);
|
extern Node *regexp(void);
|
||||||
extern Node *primary(void);
|
extern Node *primary(void);
|
||||||
|
@ -73,12 +74,14 @@ extern Node *node1(int, Node *);
|
||||||
extern Node *node2(int, Node *, Node *);
|
extern Node *node2(int, Node *, Node *);
|
||||||
extern Node *node3(int, Node *, Node *, Node *);
|
extern Node *node3(int, Node *, Node *, Node *);
|
||||||
extern Node *node4(int, Node *, 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 *stat3(int, Node *, Node *, Node *);
|
||||||
extern Node *op2(int, Node *, Node *);
|
extern Node *op2(int, Node *, Node *);
|
||||||
extern Node *op1(int, Node *);
|
extern Node *op1(int, Node *);
|
||||||
extern Node *stat1(int, Node *);
|
extern Node *stat1(int, Node *);
|
||||||
extern Node *op3(int, Node *, Node *, Node *);
|
extern Node *op3(int, Node *, Node *, Node *);
|
||||||
extern Node *op4(int, Node *, 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 *stat2(int, Node *, Node *);
|
||||||
extern Node *stat4(int, Node *, Node *, Node *, Node *);
|
extern Node *stat4(int, Node *, Node *, Node *, Node *);
|
||||||
extern Node *celltonode(Cell *, int);
|
extern Node *celltonode(Cell *, int);
|
||||||
|
@ -88,7 +91,7 @@ extern Node *pa2stat(Node *, Node *, Node *);
|
||||||
extern Node *linkum(Node *, Node *);
|
extern Node *linkum(Node *, Node *);
|
||||||
extern void defn(Cell *, Node *, Node *);
|
extern void defn(Cell *, Node *, Node *);
|
||||||
extern int isarg(const char *);
|
extern int isarg(const char *);
|
||||||
extern char *tokname(int);
|
extern const char *tokname(int);
|
||||||
extern Cell *(*proctab[])(Node **, int);
|
extern Cell *(*proctab[])(Node **, int);
|
||||||
extern int ptoi(void *);
|
extern int ptoi(void *);
|
||||||
extern Node *itonp(int);
|
extern Node *itonp(int);
|
||||||
|
@ -97,12 +100,12 @@ extern void syminit(void);
|
||||||
extern void arginit(int, char **);
|
extern void arginit(int, char **);
|
||||||
extern void envinit(char **);
|
extern void envinit(char **);
|
||||||
extern Array *makesymtab(int);
|
extern Array *makesymtab(int);
|
||||||
extern void freesymtab(const Cell *);
|
extern void freesymtab(Cell *);
|
||||||
extern void freeelem(const Cell *, const char *);
|
extern void freeelem(Cell *, const char *);
|
||||||
extern Cell *setsymtab(const char *, const char *, double, unsigned int, Array *);
|
extern Cell *setsymtab(const char *, const char *, double, unsigned int, Array *);
|
||||||
extern int hash(const char *, int);
|
extern int hash(const char *, int);
|
||||||
extern void rehash(Array *);
|
extern void rehash(Array *);
|
||||||
extern Cell *lookup(const char *, const Array *);
|
extern Cell *lookup(const char *, Array *);
|
||||||
extern double setfval(Cell *, double);
|
extern double setfval(Cell *, double);
|
||||||
extern void funnyvar(Cell *, const char *);
|
extern void funnyvar(Cell *, const char *);
|
||||||
extern char *setsval(Cell *, const char *);
|
extern char *setsval(Cell *, const char *);
|
||||||
|
@ -110,30 +113,35 @@ extern double getfval(Cell *);
|
||||||
extern char *getsval(Cell *);
|
extern char *getsval(Cell *);
|
||||||
extern char *getpssval(Cell *); /* for print */
|
extern char *getpssval(Cell *); /* for print */
|
||||||
extern char *tostring(const char *);
|
extern char *tostring(const char *);
|
||||||
|
extern char *tostringN(const char *, size_t n);
|
||||||
extern char *qstring(const char *, int);
|
extern char *qstring(const char *, int);
|
||||||
|
extern Cell *catstr(Cell *, Cell *);
|
||||||
|
|
||||||
extern void recinit(unsigned int);
|
extern void recinit(unsigned int);
|
||||||
extern void initgetrec(void);
|
extern void initgetrec(void);
|
||||||
extern void makefields(int, int);
|
extern void makefields(int, int);
|
||||||
extern void growfldtab(int n);
|
extern void growfldtab(int n);
|
||||||
extern int getrec(char **, int *, int);
|
extern int getrec(uschar **, int *, int);
|
||||||
extern void nextfile(void);
|
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 char *getargv(int);
|
||||||
extern void setclvar(char *);
|
extern void setclvar(char *);
|
||||||
extern void fldbld(void);
|
extern void fldbld(void);
|
||||||
extern void cleanfld(int, int);
|
extern void cleanfld(int, int);
|
||||||
extern void newfld(int);
|
extern void newfld(int);
|
||||||
|
extern void setlastfld(int);
|
||||||
extern int refldbld(const char *, const char *);
|
extern int refldbld(const char *, const char *);
|
||||||
extern void recbld(void);
|
extern void recbld(void);
|
||||||
extern Cell *fieldadr(int);
|
extern Cell *fieldadr(int);
|
||||||
extern void yyerror(const char *);
|
extern void yyerror(const char *);
|
||||||
extern void fpecatch(int);
|
|
||||||
extern void bracecheck(void);
|
extern void bracecheck(void);
|
||||||
extern void bcheck2(int, int, int);
|
extern void bcheck2(int, int, int);
|
||||||
extern void SYNTAX(const char *, ...);
|
extern void SYNTAX(const char *, ...)
|
||||||
extern void FATAL(const char *, ...);
|
__attribute__((__format__(__printf__, 1, 2)));
|
||||||
extern void WARNING(const char *, ...);
|
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 error(void);
|
||||||
extern void eprint(void);
|
extern void eprint(void);
|
||||||
extern void bclass(int);
|
extern void bclass(int);
|
||||||
|
@ -141,7 +149,7 @@ extern double errcheck(double, const char *);
|
||||||
extern int isclvar(const char *);
|
extern int isclvar(const char *);
|
||||||
extern int is_number(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 void run(Node *);
|
||||||
extern Cell *execute(Node *);
|
extern Cell *execute(Node *);
|
||||||
extern Cell *program(Node **, int);
|
extern Cell *program(Node **, int);
|
||||||
|
@ -184,12 +192,13 @@ extern Cell *bltin(Node **, int);
|
||||||
extern Cell *printstat(Node **, int);
|
extern Cell *printstat(Node **, int);
|
||||||
extern Cell *nullproc(Node **, int);
|
extern Cell *nullproc(Node **, int);
|
||||||
extern FILE *redirect(int, Node *);
|
extern FILE *redirect(int, Node *);
|
||||||
extern FILE *openfile(int, const char *);
|
extern FILE *openfile(int, const char *, int *);
|
||||||
extern const char *filename(FILE *);
|
extern const char *filename(FILE *);
|
||||||
extern Cell *closefile(Node **, int);
|
extern Cell *closefile(Node **, int);
|
||||||
extern void closeall(void);
|
extern void closeall(void);
|
||||||
extern Cell *sub(Node **, int);
|
extern Cell *sub(Node **, int);
|
||||||
extern Cell *gsub(Node **, int);
|
extern Cell *gsub(Node **, int);
|
||||||
|
extern Cell *gensub(Node **, int);
|
||||||
|
|
||||||
extern FILE *popen(const char *, const char *);
|
extern FILE *popen(const char *, const char *);
|
||||||
extern int pclose(FILE *);
|
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.
|
THIS SOFTWARE.
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
|
#if HAVE_NBTOOL_CONFIG_H
|
||||||
|
#include "nbtool_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.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 */
|
ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
|
||||||
cp->sval = (char *) ARGVtab;
|
cp->sval = (char *) ARGVtab;
|
||||||
for (i = 0; i < ac; i++) {
|
for (i = 0; i < ac; i++) {
|
||||||
sprintf(temp, "%d", i);
|
snprintf(temp, sizeof(temp), "%d", i);
|
||||||
if (is_number(*av))
|
if (is_number(*av))
|
||||||
setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
|
setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
|
||||||
else
|
else
|
||||||
|
@ -144,8 +148,8 @@ Array *makesymtab(int n) /* make a new symbol table */
|
||||||
Array *ap;
|
Array *ap;
|
||||||
Cell **tp;
|
Cell **tp;
|
||||||
|
|
||||||
ap = (Array *) malloc(sizeof(Array));
|
ap = malloc(sizeof(*ap));
|
||||||
tp = (Cell **) calloc(n, sizeof(Cell *));
|
tp = calloc(n, sizeof(*tp));
|
||||||
if (ap == NULL || tp == NULL)
|
if (ap == NULL || tp == NULL)
|
||||||
FATAL("out of space in makesymtab");
|
FATAL("out of space in makesymtab");
|
||||||
ap->nelem = 0;
|
ap->nelem = 0;
|
||||||
|
@ -154,7 +158,7 @@ Array *makesymtab(int n) /* make a new symbol table */
|
||||||
return(ap);
|
return(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freesymtab(const Cell *ap) /* free a symbol table */
|
void freesymtab(Cell *ap) /* free a symbol table */
|
||||||
{
|
{
|
||||||
Cell *cp, *temp;
|
Cell *cp, *temp;
|
||||||
Array *tp;
|
Array *tp;
|
||||||
|
@ -182,8 +186,7 @@ void freesymtab(const Cell *ap) /* free a symbol table */
|
||||||
free(tp);
|
free(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeelem(const Cell *ap, const char *s)
|
void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
|
||||||
/* free elem s from ap (i.e., ap["s"] */
|
|
||||||
{
|
{
|
||||||
Array *tp;
|
Array *tp;
|
||||||
Cell *p, *prev = NULL;
|
Cell *p, *prev = NULL;
|
||||||
|
@ -211,12 +214,15 @@ Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
|
||||||
int h;
|
int h;
|
||||||
Cell *p;
|
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",
|
dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
|
||||||
p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
|
p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
|
||||||
return(p);
|
return(p);
|
||||||
}
|
}
|
||||||
p = (Cell *) malloc(sizeof(Cell));
|
p = malloc(sizeof(*p));
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
FATAL("out of space for symbol table at %s", n);
|
FATAL("out of space for symbol table at %s", n);
|
||||||
p->nval = tostring(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;
|
Cell *cp, *op, **np;
|
||||||
|
|
||||||
nsz = GROWTAB * tp->size;
|
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. */
|
if (np == NULL) /* can't do it, but can keep running. */
|
||||||
return; /* someone else will run out later. */
|
return; /* someone else will run out later. */
|
||||||
for (i = 0; i < tp->size; i++) {
|
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;
|
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;
|
Cell *p;
|
||||||
int h;
|
int h;
|
||||||
|
@ -283,6 +289,7 @@ Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
|
||||||
{
|
{
|
||||||
int fldno;
|
int fldno;
|
||||||
|
|
||||||
|
f += 0.0; /* normalise negative zero to positive zero */
|
||||||
if ((vp->tval & (NUM | STR)) == 0)
|
if ((vp->tval & (NUM | STR)) == 0)
|
||||||
funnyvar(vp, "assign to");
|
funnyvar(vp, "assign to");
|
||||||
if (isfld(vp)) {
|
if (isfld(vp)) {
|
||||||
|
@ -291,6 +298,10 @@ Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
|
||||||
if (fldno > *NF)
|
if (fldno > *NF)
|
||||||
newfld(fldno);
|
newfld(fldno);
|
||||||
dprintf( ("setting field %d to %g\n", fldno, f) );
|
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)) {
|
} else if (isrec(vp)) {
|
||||||
donefld = 0; /* mark $1... invalid */
|
donefld = 0; /* mark $1... invalid */
|
||||||
donerec = 1;
|
donerec = 1;
|
||||||
|
@ -317,6 +328,7 @@ char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
|
||||||
{
|
{
|
||||||
char *t;
|
char *t;
|
||||||
int fldno;
|
int fldno;
|
||||||
|
Awkfloat f;
|
||||||
|
|
||||||
dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
|
dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
|
||||||
vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
|
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;
|
vp->tval &= ~DONTFREE;
|
||||||
dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
|
dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
|
||||||
vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
|
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 */
|
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);
|
return(vp->fval);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_str_val(Cell *vp, char **fmt)
|
static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
|
||||||
/* get string val of a Cell */
|
|
||||||
{
|
{
|
||||||
char s[100]; /* BUG: unchecked */
|
char s[100];
|
||||||
double dtemp;
|
double dtemp;
|
||||||
|
|
||||||
if ((vp->tval & (NUM | STR)) == 0)
|
if ((vp->tval & (NUM | STR)) == 0)
|
||||||
|
@ -376,9 +396,9 @@ static char *get_str_val(Cell *vp, char **fmt)
|
||||||
if (freeable(vp))
|
if (freeable(vp))
|
||||||
xfree(vp->sval);
|
xfree(vp->sval);
|
||||||
if (modf(vp->fval, &dtemp) == 0) /* it's integral */
|
if (modf(vp->fval, &dtemp) == 0) /* it's integral */
|
||||||
sprintf(s, "%.30g", vp->fval);
|
snprintf(s, sizeof(s), "%.30g", vp->fval);
|
||||||
else
|
else
|
||||||
sprintf(s, *fmt, vp->fval);
|
snprintf(s, sizeof(s), *fmt, vp->fval);
|
||||||
vp->sval = tostring(s);
|
vp->sval = tostring(s);
|
||||||
vp->tval &= ~DONTFREE;
|
vp->tval &= ~DONTFREE;
|
||||||
vp->tval |= STR;
|
vp->tval |= STR;
|
||||||
|
@ -402,7 +422,33 @@ char *tostring(const char *s) /* make a copy of string s */
|
||||||
{
|
{
|
||||||
char *p;
|
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)
|
if (p == NULL)
|
||||||
FATAL("out of space in tostring on %s", s);
|
FATAL("out of space in tostring on %s", s);
|
||||||
strcpy(p, 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;
|
const char *os = is;
|
||||||
int c, n;
|
int c, n;
|
||||||
uschar *s = (uschar *) is;
|
const uschar *s = (const uschar *) is;
|
||||||
uschar *buf, *bp;
|
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);
|
FATAL( "out of space in qstring(%s)", s);
|
||||||
for (bp = buf; (c = *s) != delim; s++) {
|
for (bp = buf; (c = *s) != delim; s++) {
|
||||||
if (c == '\n')
|
if (c == '\n')
|
Loading…
Reference in a new issue