]> Zhao Yanbai Git Server - minix.git/commitdiff
Import NetBSD nawk
authorThomas Veerman <thomas@minix3.org>
Wed, 6 Jun 2012 13:03:39 +0000 (13:03 +0000)
committerThomas Veerman <thomas@minix3.org>
Mon, 18 Jun 2012 10:53:38 +0000 (10:53 +0000)
24 files changed:
commands/Makefile
commands/awk/Makefile [deleted file]
external/Makefile
external/historical/Makefile [new file with mode: 0644]
external/historical/nawk/Makefile [new file with mode: 0644]
external/historical/nawk/bin/Makefile [new file with mode: 0644]
external/historical/nawk/bin/TODO [new file with mode: 0644]
external/historical/nawk/bin/awk.1 [new file with mode: 0644]
external/historical/nawk/dist/FIXES [moved from commands/awk/FIXES with 99% similarity]
external/historical/nawk/dist/README [moved from commands/awk/README with 100% similarity]
external/historical/nawk/dist/awk.1 [moved from commands/awk/awk.1 with 100% similarity]
external/historical/nawk/dist/awk.h [moved from commands/awk/awk.h with 95% similarity]
external/historical/nawk/dist/awkgram.y [moved from commands/awk/awkgram.y with 93% similarity]
external/historical/nawk/dist/b.c [moved from commands/awk/b.c with 74% similarity]
external/historical/nawk/dist/lex.c [moved from commands/awk/lex.c with 94% similarity]
external/historical/nawk/dist/lib.c [moved from commands/awk/lib.c with 79% similarity]
external/historical/nawk/dist/main.c [moved from commands/awk/main.c with 71% similarity]
external/historical/nawk/dist/makefile [moved from commands/awk/Makefile.orig with 85% similarity]
external/historical/nawk/dist/maketab.c [moved from commands/awk/maketab.c with 88% similarity]
external/historical/nawk/dist/parse.c [moved from commands/awk/parse.c with 91% similarity]
external/historical/nawk/dist/proctab.c [new file with mode: 0644]
external/historical/nawk/dist/proto.h [moved from commands/awk/proto.h with 84% similarity]
external/historical/nawk/dist/run.c [moved from commands/awk/run.c with 76% similarity]
external/historical/nawk/dist/tran.c [moved from commands/awk/tran.c with 87% similarity]

index 9ac6b40032fdda09f0791fd02dda3792d4e36f9f..814f2aea4adbd8f9dbf062e0a194a918bfa8b888 100644 (file)
@@ -2,7 +2,7 @@
 
 .include <bsd.own.mk>
 
-SUBDIR=        add_route arp ash at awk \
+SUBDIR=        add_route arp ash at \
        backup badblocks banner basename \
        btrace cal \
        cawf cd  cdprobe checkhier cpp \
diff --git a/commands/awk/Makefile b/commands/awk/Makefile
deleted file mode 100644 (file)
index ea7d01e..0000000
+++ /dev/null
@@ -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>
index 4072adc24375c6fb8eadd0ca7d8754b51363a125..a9ec2eb91454ef04d53bd02ce6298b66facd86f9 100644 (file)
@@ -1,3 +1,3 @@
-SUBDIR=bsd
+SUBDIR=bsd historical
 
 .include <bsd.subdir.mk>
diff --git a/external/historical/Makefile b/external/historical/Makefile
new file mode 100644 (file)
index 0000000..f2ce085
--- /dev/null
@@ -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>
diff --git a/external/historical/nawk/Makefile b/external/historical/nawk/Makefile
new file mode 100644 (file)
index 0000000..f9ee78b
--- /dev/null
@@ -0,0 +1,5 @@
+#      $NetBSD: Makefile,v 1.1 2010/08/26 14:57:16 christos Exp $
+
+SUBDIR+= bin
+
+.include <bsd.subdir.mk>
diff --git a/external/historical/nawk/bin/Makefile b/external/historical/nawk/bin/Makefile
new file mode 100644 (file)
index 0000000..b421c31
--- /dev/null
@@ -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>
diff --git a/external/historical/nawk/bin/TODO b/external/historical/nawk/bin/TODO
new file mode 100644 (file)
index 0000000..00e3767
--- /dev/null
@@ -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; }
diff --git a/external/historical/nawk/bin/awk.1 b/external/historical/nawk/bin/awk.1
new file mode 100644 (file)
index 0000000..5059710
--- /dev/null
@@ -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.
similarity index 99%
rename from commands/awk/FIXES
rename to external/historical/nawk/dist/FIXES
index e611e2a7c9a6103568ddb6903a78b93aef2bbe6d..310da07904eb427a0286b67401e0ed7d45c3ec8d 100644 (file)
@@ -25,6 +25,13 @@ THIS SOFTWARE.
 This file lists all bug fixes, changes, etc., made since the AWK book
 was sent to the printers in August, 1987.
 
+May 23, 2010:
+       fixed long-standing overflow bug in run.c; many thanks to
+       nelson beebe for spotting it and providing the fix.
+
+       fixed bug that didn't parse -vd=1 properly; thanks to santiago
+       vila for spotting it.
+
 Feb 8, 2010:
        i give up.  replaced isblank with isspace in b.c; there are
        no consistent header files.
similarity index 95%
rename from commands/awk/awk.h
rename to external/historical/nawk/dist/awk.h
index a36cdb151e7505e22cbefb0fd0555bc4275ccf97..71418a73b74b1f79f05d3a2362034f6cfe190c00 100644 (file)
@@ -48,6 +48,7 @@ extern int    safe;           /* 0 => unsafe, 1 => safe */
 #define        RECSIZE (8 * 1024)      /* sets limit on records, fields, etc., etc. */
 extern int     recsize;        /* size of current record, orig RECSIZE */
 
+extern char    EMPTY[];
 extern char    **FS;
 extern char    **RS;
 extern char    **ORS;
@@ -61,16 +62,15 @@ extern char **SUBSEP;
 extern Awkfloat *RSTART;
 extern Awkfloat *RLENGTH;
 
-extern char    *record;        /* points to $0 */
+extern uschar  *record;        /* points to $0 */
 extern int     lineno;         /* line number in awk program */
 extern int     errorflag;      /* 1 if error has occurred */
 extern int     donefld;        /* 1 if record broken into fields */
 extern int     donerec;        /* 1 if record is valid (no fld has changed */
-extern char    inputFS[];      /* FS at time of input, for field splitting */
 
 extern int     dbg;
 
-extern char    *patbeg;        /* beginning of pattern matched */
+extern uschar  *patbeg;        /* beginning of pattern matched */
 extern int     patlen;         /* length of pattern matched.  set in b.c */
 
 /* Cell:  all information about a variable or constant */
@@ -126,6 +126,8 @@ extern Cell *rlengthloc;    /* RLENGTH */
 #define        FTOUPPER 12
 #define        FTOLOWER 13
 #define        FFLUSH  14
+#define FSYSTIME       15
+#define FSTRFTIME      16
 
 /* Node:  parse tree is made of nodes, with Cell's at bottom */
 
@@ -203,8 +205,6 @@ extern      int     pairstack[], paircnt;
 
 #define NCHARS (256+3)         /* 256 handles 8-bit chars; 128 does 7-bit */
                                /* watch out in match(), etc. */
-#define NSTATES        32
-
 typedef struct rrow {
        long    ltype;  /* long avoids pointer warnings on 64-bit */
        union {
@@ -216,16 +216,16 @@ typedef struct rrow {
 } rrow;
 
 typedef struct fa {
-       uschar  gototab[NSTATES][NCHARS];
-       uschar  out[NSTATES];
+       unsigned int    **gototab;
+       uschar  *out;
        uschar  *restr;
-       int     *posns[NSTATES];
+       int     **posns;
+       int     state_count;
        int     anchor;
        int     use;
        int     initstat;
        int     curstat;
        int     accept;
-       int     reset;
        struct  rrow re[1];     /* variable: actual size set by calling malloc */
 } fa;
 
similarity index 93%
rename from commands/awk/awkgram.y
rename to external/historical/nawk/dist/awkgram.y
index 91b62571b8a93aa24d1204c1163e8ffb24aac3bf..46731c22c4e6cd217bad483025ca15d5d7dc11a1 100644 (file)
@@ -23,6 +23,10 @@ THIS SOFTWARE.
 ****************************************************************/
 
 %{
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #include <stdio.h>
 #include <string.h>
 #include "awk.h"
@@ -71,6 +75,7 @@ Node  *arglist = 0;   /* list of args for current function */
 %type  <i>     do st
 %type  <i>     pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
 %type  <i>     subop print
+%type  <cp>    string
 
 %right ASGNOP
 %right '?'
@@ -80,7 +85,7 @@ Node  *arglist = 0;   /* list of args for current function */
 %left  GETLINE
 %nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
 %left  ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC 
-%left  GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
+%left  GENSUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
 %left  PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
 %left  REGEXPR VAR VARNF IVAR WHILE '('
 %left  CAT
@@ -348,6 +353,11 @@ subop:
          SUB | GSUB
        ;
 
+string:
+         STRING
+       | string STRING         { $$ = catstr($1, $2); }
+       ;
+
 term:
          term '/' ASGNOP term          { $$ = op2(DIVEQ, $1, $4); }
        | term '+' term                 { $$ = op2(ADD, $1, $3); }
@@ -369,6 +379,22 @@ term:
        | INCR var                      { $$ = op1(PREINCR, $2); }
        | var DECR                      { $$ = op1(POSTDECR, $1); }
        | var INCR                      { $$ = op1(POSTINCR, $1); }
+       | GENSUB '(' reg_expr comma pattern comma pattern ')'
+               { $$ = op5(GENSUB, NIL, (Node*)makedfa($3, 1), $5, $7, rectonode()); }
+       | GENSUB '(' pattern comma pattern comma pattern ')'
+               { if (constnode($3))
+                       $$ = op5(GENSUB, NIL, (Node *)makedfa(strnode($3), 1), $5, $7, rectonode());
+                 else
+                       $$ = op5(GENSUB, (Node *)1, $3, $5, $7, rectonode());
+               }
+       | GENSUB '(' reg_expr comma pattern comma pattern comma pattern ')'
+               { $$ = op5(GENSUB, NIL, (Node*)makedfa($3, 1), $5, $7, $9); }
+       | GENSUB '(' pattern comma pattern comma pattern comma pattern ')'
+               { if (constnode($3))
+                       $$ = op5(GENSUB, NIL, (Node *)makedfa(strnode($3),1), $5,$7,$9);
+                 else
+                       $$ = op5(GENSUB, (Node *)1, $3, $5, $7, $9);
+               }
        | GETLINE var LT term           { $$ = op3(GETLINE, $2, itonp($3), $4); }
        | GETLINE LT term               { $$ = op3(GETLINE, NIL, itonp($2), $3); }
        | GETLINE var                   { $$ = op3(GETLINE, $2, NIL, NIL); }
@@ -394,7 +420,7 @@ term:
        | SPLIT '(' pattern comma varname ')'
                { $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); }  /* default */
        | SPRINTF '(' patlist ')'       { $$ = op1($1, $3); }
-       | STRING                        { $$ = celltonode($1, CCON); }
+       | string                        { $$ = celltonode($1, CCON); }
        | subop '(' reg_expr comma pattern ')'
                { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
        | subop '(' pattern comma pattern ')'
similarity index 74%
rename from commands/awk/b.c
rename to external/historical/nawk/dist/b.c
index 0fbfab1fbaac4e666912fdf5d4e9489823f28e6d..a99bb87fc70fcf40f54c6b64384d4d4c4a912a2d 100644 (file)
@@ -24,12 +24,17 @@ THIS SOFTWARE.
 
 /* lasciate ogne speranza, voi ch'intrate. */
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #define        DEBUG
 
 #include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <assert.h>
 #include "awk.h"
 #include "awkgram.h"
 
@@ -62,33 +67,80 @@ int maxsetvec = 0;
 
 int    rtok;           /* next token in current re */
 int    rlxval;
-static uschar  *rlxstr;
-static uschar  *prestr;        /* current position in current re */
-static uschar  *lastre;        /* origin of last re */
+static const uschar    *rlxstr;
+static const uschar    *prestr;        /* current position in current re */
+static const uschar    *lastre;        /* origin of last re */
 
 static int setcnt;
 static int poscnt;
 
-char   *patbeg;
+uschar *patbeg;
 int    patlen;
 
-#define        NFA     20      /* cache this many dynamic fa's */
+#define        NFA     128     /* cache this many dynamic fa's */
 fa     *fatab[NFA];
 int    nfatab  = 0;    /* entries in fatab */
 
+static void
+resizesetvec(const char *msg)
+{
+       if (maxsetvec == 0)
+               maxsetvec = MAXLIN;
+       else
+               maxsetvec *= 4;
+       setvec = realloc(setvec, maxsetvec * sizeof(*setvec));
+       tmpset = realloc(tmpset, maxsetvec * sizeof(*tmpset));
+       if (setvec == 0 || tmpset == 0)
+           overflo(msg);
+}
+
+static void
+resize_state(fa *f, int state)
+{
+       void *p;
+       int i, new_count;
+
+       if (++state < f->state_count)
+               return;
+
+       new_count = state + 10; /* needs to be tuned */
+
+       p = realloc(f->gototab, new_count * sizeof(f->gototab[0]));
+       if (p == NULL)
+               goto out;
+       f->gototab = p;
+
+       p = realloc(f->out, new_count * sizeof(f->out[0]));
+       if (p == NULL)
+               goto out;
+       f->out = p;
+
+       p = realloc(f->posns, new_count * sizeof(f->posns[0]));
+       if (p == NULL)
+               goto out;
+       f->posns = p;
+
+       for (i = f->state_count; i < new_count; ++i) {
+               f->gototab[i] = calloc(1, NCHARS * sizeof (**f->gototab));
+               if (f->gototab[i] == NULL)
+                       goto out;
+               f->out[i]  = 0;
+               f->posns[i] = NULL;
+       }
+       f->state_count = new_count;
+       return;
+out:
+       overflo("out of memory in resize_state");
+}
+
 fa *makedfa(const char *s, int anchor) /* returns dfa for reg expr s */
 {
        int i, use, nuse;
        fa *pfa;
        static int now = 1;
 
-       if (setvec == 0) {      /* first time through any RE */
-               maxsetvec = MAXLIN;
-               setvec = (int *) malloc(maxsetvec * sizeof(int));
-               tmpset = (int *) malloc(maxsetvec * sizeof(int));
-               if (setvec == 0 || tmpset == 0)
-                       overflo("out of space initializing makedfa");
-       }
+       if (setvec == 0)        /* first time through any RE */
+               resizesetvec("out of space initializing makedfa");
 
        if (compile_time)       /* a constant for sure */
                return mkdfa(s, anchor);
@@ -132,14 +184,15 @@ fa *mkdfa(const char *s, int anchor)      /* does the real work of making a dfa */
 
        poscnt = 0;
        penter(p1);     /* enter parent pointers and leaf indices */
-       if ((f = (fa *) calloc(1, sizeof(fa) + poscnt*sizeof(rrow))) == NULL)
+       if ((f = calloc(1, sizeof(*f) + poscnt*sizeof(rrow))) == NULL)
                overflo("out of space for fa");
        f->accept = poscnt-1;   /* penter has computed number of positions in re */
        cfoll(f, p1);   /* set up follow sets */
        freetr(p1);
-       if ((f->posns[0] = (int *) calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL)
+       resize_state(f, 1);
+       if ((f->posns[0] = calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL)
                        overflo("out of space in makedfa");
-       if ((f->posns[1] = (int *) calloc(1, sizeof(int))) == NULL)
+       if ((f->posns[1] = calloc(1, sizeof(int))) == NULL)
                overflo("out of space in makedfa");
        *f->posns[1] = 0;
        f->initstat = makeinit(f, anchor);
@@ -152,12 +205,12 @@ int makeinit(fa *f, int anchor)
 {
        int i, k;
 
+       resize_state(f, 2);
        f->curstat = 2;
        f->out[2] = 0;
-       f->reset = 0;
        k = *(f->re[0].lfollow);
        xfree(f->posns[2]);                     
-       if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
+       if ((f->posns[2] = calloc(1, (k+1)*sizeof(int))) == NULL)
                overflo("out of space in makeinit");
        for (i=0; i <= k; i++) {
                (f->posns[2])[i] = (f->re[0].lfollow)[i];
@@ -174,8 +227,10 @@ int makeinit(fa *f, int anchor)
                }
 
                f->out[0] = f->out[2];
-               if (f->curstat != 2)
+               if (f->curstat != 2) {
+                       resize_state(f, f->curstat);
                        --(*f->posns[f->curstat]);
+               }
        }
        return f->curstat;
 }
@@ -231,13 +286,13 @@ void freetr(Node *p)      /* free parse tree */
 /* in the parsing of regular expressions, metacharacters like . have */
 /* to be seen literally;  \056 is not a metacharacter. */
 
-int hexstr(char **pp)  /* find and eval hex string at pp, return new p */
+int hexstr(const uschar **pp)  /* find and eval hex string at pp, return new p */
 {                      /* only pick up one 8-bit byte (2 chars) */
-       uschar *p;
+       const uschar *p;
        int n = 0;
        int i;
 
-       for (i = 0, p = (uschar *) *pp; i < 2 && isxdigit(*p); i++, p++) {
+       for (i = 0, p = *pp; i < 2 && isxdigit(*p); i++, p++) {
                if (isdigit(*p))
                        n = 16 * n + *p - '0';
                else if (*p >= 'a' && *p <= 'f')
@@ -245,16 +300,16 @@ int hexstr(char **pp)     /* find and eval hex string at pp, return new p */
                else if (*p >= 'A' && *p <= 'F')
                        n = 16 * n + *p - 'A' + 10;
        }
-       *pp = (char *) p;
+       *pp = p;
        return n;
 }
 
 #define isoctdigit(c) ((c) >= '0' && (c) <= '7')       /* multiple use of arg */
 
-int quoted(char **pp)  /* pick up next thing after a \\ */
+int quoted(const uschar **pp)  /* pick up next thing after a \\ */
                        /* and increment *pp */
 {
-       char *p = *pp;
+       const uschar *p = *pp;
        int c;
 
        if ((c = *p++) == 't')
@@ -288,31 +343,32 @@ int quoted(char **pp)     /* pick up next thing after a \\ */
 char *cclenter(const char *argp)       /* add a character class */
 {
        int i, c, c2;
-       uschar *p = (uschar *) argp;
-       uschar *op, *bp;
+       const uschar *p = (const uschar *) argp;
+       const uschar *op;
+       uschar *bp;
        static uschar *buf = 0;
        static int bufsz = 100;
 
        op = p;
-       if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL)
+       if (buf == 0 && (buf = malloc(bufsz)) == NULL)
                FATAL("out of space for character class [%.10s...] 1", p);
        bp = buf;
        for (i = 0; (c = *p++) != 0; ) {
                if (c == '\\') {
-                       c = quoted((char **) &p);
+                       c = quoted(&p);
                } else if (c == '-' && i > 0 && bp[-1] != 0) {
                        if (*p != 0) {
                                c = bp[-1];
                                c2 = *p++;
                                if (c2 == '\\')
-                                       c2 = quoted((char **) &p);
+                                       c2 = quoted(&p);
                                if (c > c2) {   /* empty; ignore */
                                        bp--;
                                        i--;
                                        continue;
                                }
                                while (c < c2) {
-                                       if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, "cclenter1"))
+                                       if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, "cclenter1"))
                                                FATAL("out of space for character class [%.10s...] 2", p);
                                        *bp++ = ++c;
                                        i++;
@@ -320,14 +376,14 @@ char *cclenter(const char *argp)  /* add a character class */
                                continue;
                        }
                }
-               if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, "cclenter2"))
+               if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, "cclenter2"))
                        FATAL("out of space for character class [%.10s...] 3", p);
                *bp++ = c;
                i++;
        }
        *bp = 0;
        dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) );
-       xfree(op);
+       free(__UNCONST(op));
        return (char *) tostring((char *) buf);
 }
 
@@ -346,18 +402,13 @@ void cfoll(fa *f, Node *v)        /* enter follow set of each leaf of vertex v into lfo
        LEAF
                f->re[info(v)].ltype = type(v);
                f->re[info(v)].lval.np = right(v);
-               while (f->accept >= maxsetvec) {        /* guessing here! */
-                       maxsetvec *= 4;
-                       setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
-                       tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
-                       if (setvec == 0 || tmpset == 0)
-                               overflo("out of space in cfoll()");
-               }
+               while (f->accept >= maxsetvec) /* guessing here! */
+                       resizesetvec("out of space in cfoll()");
                for (i = 0; i <= f->accept; i++)
                        setvec[i] = 0;
                setcnt = 0;
                follow(v);      /* computes setvec and setcnt */
-               if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL)
+               if ((p = calloc(1, (setcnt+1)*sizeof(int))) == NULL)
                        overflo("out of space building follow set");
                f->re[info(v)].lfollow = p;
                *p = setcnt;
@@ -378,7 +429,7 @@ void cfoll(fa *f, Node *v)  /* enter follow set of each leaf of vertex v into lfo
        }
 }
 
-int first(const Node *p)       /* collects initially active leaves of p into setvec */
+int first(Node *p)     /* collects initially active leaves of p into setvec */
                        /* returns 0 if p matches empty string */
 {
        int b, lp;
@@ -387,13 +438,8 @@ int first(const Node *p)   /* collects initially active leaves of p into setvec */
        ELEAF
        LEAF
                lp = info(p);   /* look for high-water mark of subscripts */
-               while (setcnt >= maxsetvec || lp >= maxsetvec) {        /* guessing here! */
-                       maxsetvec *= 4;
-                       setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
-                       tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
-                       if (setvec == 0 || tmpset == 0)
-                               overflo("out of space in first()");
-               }
+               while (setcnt >= maxsetvec || lp >= maxsetvec) /* guessing here! */
+                       resizesetvec("out of space in first()");
                if (type(p) == EMPTYRE) {
                        setvec[lp] = 0;
                        return(0);
@@ -457,7 +503,7 @@ void follow(Node *v)        /* collects leaves that can follow v into setvec */
 
 int member(int c, const char *sarg)    /* is c in s? */
 {
-       uschar *s = (uschar *) sarg;
+       const uschar *s = (const uschar *) sarg;
 
        while (*s)
                if (c == *s++)
@@ -468,9 +514,11 @@ int member(int c, const char *sarg)        /* is c in s? */
 int match(fa *f, const char *p0)       /* shortest match ? */
 {
        int s, ns;
-       uschar *p = (uschar *) p0;
+       const uschar *p = (const uschar *) p0;
+
+       s = f->initstat;
+       assert (s < f->state_count);
 
-       s = f->reset ? makeinit(f,0) : f->initstat;
        if (f->out[s])
                return(1);
        do {
@@ -479,6 +527,9 @@ int match(fa *f, const char *p0)    /* shortest match ? */
                        s = ns;
                else
                        s = cgoto(f, s, *p);
+
+               assert (s < f->state_count);
+
                if (f->out[s])
                        return(1);
        } while (*p++ != 0);
@@ -488,17 +539,12 @@ int match(fa *f, const char *p0)  /* shortest match ? */
 int pmatch(fa *f, const char *p0)      /* longest match, for sub */
 {
        int s, ns;
-       uschar *p = (uschar *) p0;
+       uschar *p = __UNCONST(p0);
        uschar *q;
-       int i, k;
 
-       /* s = f->reset ? makeinit(f,1) : f->initstat; */
-       if (f->reset) {
-               f->initstat = s = makeinit(f,1);
-       } else {
-               s = f->initstat;
-       }
-       patbeg = (char *) p;
+       s = f->initstat;
+       assert(s < f->state_count);
+       patbeg = p;
        patlen = -1;
        do {
                q = p;
@@ -510,9 +556,12 @@ int pmatch(fa *f, const char *p0)  /* longest match, for sub */
                                s = ns;
                        else
                                s = cgoto(f, s, *q);
+
+                       assert(s < f->state_count);
+
                        if (s == 1) {   /* no transition */
                                if (patlen >= 0) {
-                                       patbeg = (char *) p;
+                                       patbeg = p;
                                        return(1);
                                }
                                else
@@ -522,24 +571,11 @@ int pmatch(fa *f, const char *p0) /* longest match, for sub */
                if (f->out[s])
                        patlen = q-p-1; /* don't count $ */
                if (patlen >= 0) {
-                       patbeg = (char *) p;
+                       patbeg = p;
                        return(1);
                }
        nextin:
                s = 2;
-               if (f->reset) {
-                       for (i = 2; i <= f->curstat; i++)
-                               xfree(f->posns[i]);
-                       k = *f->posns[0];                       
-                       if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
-                               overflo("out of space in pmatch");
-                       for (i = 0; i <= k; i++)
-                               (f->posns[2])[i] = (f->posns[0])[i];
-                       f->initstat = f->curstat = 2;
-                       f->out[2] = f->out[0];
-                       for (i = 0; i < NCHARS; i++)
-                               f->gototab[2][i] = 0;
-               }
        } while (*p++ != 0);
        return (0);
 }
@@ -547,16 +583,12 @@ int pmatch(fa *f, const char *p0) /* longest match, for sub */
 int nematch(fa *f, const char *p0)     /* non-empty match, for sub */
 {
        int s, ns;
-       uschar *p = (uschar *) p0;
+       uschar *p = __UNCONST(p0);
        uschar *q;
-       int i, k;
 
-       /* s = f->reset ? makeinit(f,1) : f->initstat; */
-       if (f->reset) {
-               f->initstat = s = makeinit(f,1);
-       } else {
-               s = f->initstat;
-       }
+       s = f->initstat;
+       assert(s < f->state_count);
+
        patlen = -1;
        while (*p) {
                q = p;
@@ -568,9 +600,12 @@ int nematch(fa *f, const char *p0) /* non-empty match, for sub */
                                s = ns;
                        else
                                s = cgoto(f, s, *q);
+
+                       assert(s < f->state_count);
+
                        if (s == 1) {   /* no transition */
                                if (patlen > 0) {
-                                       patbeg = (char *) p;
+                                       patbeg = p;
                                        return(1);
                                } else
                                        goto nnextin;   /* no nonempty match */
@@ -579,35 +614,112 @@ int nematch(fa *f, const char *p0)       /* non-empty match, for sub */
                if (f->out[s])
                        patlen = q-p-1; /* don't count $ */
                if (patlen > 0 ) {
-                       patbeg = (char *) p;
+                       patbeg = p;
                        return(1);
                }
        nnextin:
                s = 2;
-               if (f->reset) {
-                       for (i = 2; i <= f->curstat; i++)
-                               xfree(f->posns[i]);
-                       k = *f->posns[0];                       
-                       if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL)
-                               overflo("out of state space");
-                       for (i = 0; i <= k; i++)
-                               (f->posns[2])[i] = (f->posns[0])[i];
-                       f->initstat = f->curstat = 2;
-                       f->out[2] = f->out[0];
-                       for (i = 0; i < NCHARS; i++)
-                               f->gototab[2][i] = 0;
-               }
                p++;
        }
        return (0);
 }
 
+
+/*
+ * NAME
+ *     fnematch
+ *
+ * DESCRIPTION
+ *     A stream-fed version of nematch which transfers characters to a
+ *     null-terminated buffer. All characters up to and including the last
+ *     character of the matching text or EOF are placed in the buffer. If
+ *     a match is found, patbeg and patlen are set appropriately.
+ *
+ * RETURN VALUES
+ *     0    No match found.
+ *     1    Match found.
+ */  
+
+int fnematch(fa *pfa, FILE *f, uschar **pbuf, int *pbufsize, int quantum)      
+{
+       uschar *buf = *pbuf;
+       int bufsize = *pbufsize;
+       int c, i, j, k, ns, s;
+
+       s = pfa->initstat;
+       assert(s < pfa->state_count);
+       patlen = 0;
+
+       /*
+        * All indices relative to buf.
+        * i <= j <= k <= bufsize
+        *
+        * i: origin of active substring
+        * j: current character
+        * k: destination of next getc()
+        */
+       i = -1, k = 0;
+        do {
+               j = i++;
+               do {
+                       if (++j == k) {
+                               if (k == bufsize)
+                                       if (!adjbuf(&buf, &bufsize, bufsize+1, quantum, 0, "fnematch"))
+                                               FATAL("stream '%.30s...' too long", buf);       
+                               buf[k++] = (c = getc(f)) != EOF ? c : 0;
+                       }
+                       c = buf[j];
+                       /* assert(c < NCHARS); */
+
+                       if ((ns = pfa->gototab[s][c]) != 0)
+                               s = ns;
+                       else
+                               s = cgoto(pfa, s, c);
+                       assert(s < pfa->state_count);
+
+                       if (pfa->out[s]) {      /* final state */
+                               patlen = j - i + 1;
+                               if (c == 0)     /* don't count $ */
+                                       patlen--;
+                       }
+               } while (buf[j] && s != 1);
+               s = 2;
+       } while (buf[i] && !patlen);
+
+       /* adjbuf() may have relocated a resized buffer. Inform the world. */
+       *pbuf = buf;
+       *pbufsize = bufsize;
+
+       if (patlen) {
+               patbeg = buf + i;
+               /*
+                * Under no circumstances is the last character fed to
+                * the automaton part of the match. It is EOF's nullbyte,
+                * or it sent the automaton into a state with no further
+                * transitions available (s==1), or both. Room for a
+                * terminating nullbyte is guaranteed.
+                *
+                * ungetc any chars after the end of matching text
+                * (except for EOF's nullbyte, if present) and null
+                * terminate the buffer.
+                */
+               do
+                       if (buf[--k] && ungetc(buf[k], f) == EOF)
+                               FATAL("unable to ungetc '%c'", buf[k]); 
+               while (k > i + patlen);
+               buf[k] = 0;
+               return 1;
+       }
+       else
+               return 0;
+}
+
 Node *reparse(const char *p)   /* parses regular expression pointed to by p */
 {                      /* uses relex() to scan regular expression */
        Node *np;
 
        dprintf( ("reparse <%s>\n", p) );
-       lastre = prestr = (uschar *) p; /* prestr points to string to be parsed */
+       lastre = prestr = (const uschar *) p;   /* prestr points to string to be parsed */
        rtok = relex();
        /* GNU compatibility: an empty regexp matches anything */
        if (rtok == '\0') {
@@ -644,11 +756,11 @@ Node *primary(void)
                rtok = relex();
                return (unary(op2(DOT, NIL, NIL)));
        case CCL:
-               np = op2(CCL, NIL, (Node*) cclenter((char *) rlxstr));
+               np = op2(CCL, NIL, (Node*) cclenter((const char *) rlxstr));
                rtok = relex();
                return (unary(np));
        case NCCL:
-               np = op2(NCCL, NIL, (Node *) cclenter((char *) rlxstr));
+               np = op2(NCCL, NIL, (Node *) cclenter((const char *) rlxstr));
                rtok = relex();
                return (unary(np));
        case '^':
@@ -732,23 +844,15 @@ Node *unary(Node *np)
  */
 
 /* #define HAS_ISBLANK */
-#ifndef HAS_ISBLANK
-
-int (xisblank)(int c)
-{
-       return c==' ' || c=='\t';
-}
-
-#endif
 
-struct charclass {
+static const struct charclass {
        const char *cc_name;
        int cc_namelen;
        int (*cc_func)(int);
 } charclasses[] = {
        { "alnum",      5,      isalnum },
        { "alpha",      5,      isalpha },
-       { "blank",      5,      isspace }, /* was isblank */
+       { "blank",      5,      isblank },
        { "cntrl",      5,      iscntrl },
        { "digit",      5,      isdigit },
        { "graph",      5,      isgraph },
@@ -769,7 +873,7 @@ int relex(void)             /* lexical analyzer for reparse */
        static uschar *buf = 0;
        static int bufsz = 100;
        uschar *bp;
-       struct charclass *cc;
+       const struct charclass *cc;
        int i;
 
        switch (c = *prestr++) {
@@ -785,13 +889,13 @@ int relex(void)           /* lexical analyzer for reparse */
        case ')':
                return c;
        case '\\':
-               rlxval = quoted((char **) &prestr);
+               rlxval = quoted(&prestr);
                return CHAR;
        default:
                rlxval = c;
                return CHAR;
        case '[': 
-               if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL)
+               if (buf == 0 && (buf = malloc(bufsz)) == NULL)
                        FATAL("out of space in reg expr %.10s..", lastre);
                bp = buf;
                if (*prestr == '^') {
@@ -801,7 +905,7 @@ int relex(void)             /* lexical analyzer for reparse */
                else
                        cflag = 0;
                n = 2 * strlen((const char *) prestr)+1;
-               if (!adjbuf((char **) &buf, &bufsz, n, n, (char **) &bp, "relex1"))
+               if (!adjbuf(&buf, &bufsz, n, n, &bp, "relex1"))
                        FATAL("out of space for reg expr %.10s...", lastre);
                for (; ; ) {
                        if ((c = *prestr++) == '\\') {
@@ -819,8 +923,8 @@ int relex(void)             /* lexical analyzer for reparse */
                                if (cc->cc_name != NULL && prestr[1 + cc->cc_namelen] == ':' &&
                                    prestr[2 + cc->cc_namelen] == ']') {
                                        prestr += cc->cc_namelen + 3;
-                                       for (i = 0; i < NCHARS; i++) {
-                                               if (!adjbuf((char **) &buf, &bufsz, bp-buf+1, 100, (char **) &bp, "relex2"))
+                                       for (i = 1; i < NCHARS; i++) {
+                                               if (!adjbuf(&buf, &bufsz, bp-buf+1, 100, &bp, "relex2"))
                                                    FATAL("out of space for reg expr %.10s...", lastre);
                                                if (cc->cc_func(i)) {
                                                        *bp++ = i;
@@ -852,16 +956,12 @@ int cgoto(fa *f, int s, int c)
        int *p, *q;
 
        assert(c == HAT || c < NCHARS);
-       while (f->accept >= maxsetvec) {        /* guessing here! */
-               maxsetvec *= 4;
-               setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
-               tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
-               if (setvec == 0 || tmpset == 0)
-                       overflo("out of space in cgoto()");
-       }
+       while (f->accept >= maxsetvec)  /* guessing here! */
+               resizesetvec("out of space in cgoto()");
        for (i = 0; i <= f->accept; i++)
                setvec[i] = 0;
        setcnt = 0;
+       resize_state(f, s);
        /* compute positions of gototab[s,c] into setvec */
        p = f->posns[s];
        for (i = 1; i <= *p; i++) {
@@ -874,13 +974,8 @@ int cgoto(fa *f, int s, int c)
                         || (k == NCCL && !member(c, (char *) f->re[p[i]].lval.up) && c != 0 && c != HAT)) {
                                q = f->re[p[i]].lfollow;
                                for (j = 1; j <= *q; j++) {
-                                       if (q[j] >= maxsetvec) {
-                                               maxsetvec *= 4;
-                                               setvec = (int *) realloc(setvec, maxsetvec * sizeof(int));
-                                               tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int));
-                                               if (setvec == 0 || tmpset == 0)
-                                                       overflo("cgoto overflow");
-                                       }
+                                       if (q[j] >= maxsetvec)
+                                               resizesetvec("cgoto overflow");
                                        if (setvec[q[j]] == 0) {
                                                setcnt++;
                                                setvec[q[j]] = 1;
@@ -896,6 +991,8 @@ int cgoto(fa *f, int s, int c)
                if (setvec[i]) {
                        tmpset[j++] = i;
                }
+
+       resize_state(f, f->curstat > s ? f->curstat : s);
        /* tmpset == previous state? */
        for (i = 1; i <= f->curstat; i++) {
                p = f->posns[i];
@@ -905,27 +1002,24 @@ int cgoto(fa *f, int s, int c)
                        if (tmpset[j] != p[j])
                                goto different;
                /* setvec is state i */
-               f->gototab[s][c] = i;
+               if (c != HAT)
+                       f->gototab[s][c] = i;
                return i;
          different:;
        }
 
        /* add tmpset to current set of states */
-       if (f->curstat >= NSTATES-1) {
-               f->curstat = 2;
-               f->reset = 1;
-               for (i = 2; i < NSTATES; i++)
-                       xfree(f->posns[i]);
-       } else
-               ++(f->curstat);
+       ++(f->curstat);
+       resize_state(f, f->curstat);
        for (i = 0; i < NCHARS; i++)
                f->gototab[f->curstat][i] = 0;
        xfree(f->posns[f->curstat]);
-       if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL)
+       if ((p = calloc(1, (setcnt+1)*sizeof(int))) == NULL)
                overflo("out of space in cgoto");
 
        f->posns[f->curstat] = p;
-       f->gototab[s][c] = f->curstat;
+       if (c != HAT)
+               f->gototab[s][c] = f->curstat;
        for (i = 0; i <= setcnt; i++)
                p[i] = tmpset[i];
        if (setvec[f->accept])
@@ -942,13 +1036,18 @@ void freefa(fa *f)       /* free a finite automaton */
 
        if (f == NULL)
                return;
-       for (i = 0; i <= f->curstat; i++)
+       for (i = 0; i < f->state_count; i++) {
+               xfree(f->gototab[i])
                xfree(f->posns[i]);
+       }
        for (i = 0; i <= f->accept; i++) {
                xfree(f->re[i].lfollow);
                if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL)
                        xfree((f->re[i].lval.np));
        }
        xfree(f->restr);
+       xfree(f->out);
+       xfree(f->posns);
+       xfree(f->gototab);
        xfree(f);
 }
similarity index 94%
rename from commands/awk/lex.c
rename to external/historical/nawk/dist/lex.c
index 8c59c4a0bb8189ef1f1e8051050a4351d13c4281..82f06daad7d5b8fa2ca85244259944ff366b7a25 100644 (file)
@@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 THIS SOFTWARE.
 ****************************************************************/
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -43,7 +47,11 @@ typedef struct Keyword {
        int     type;
 } Keyword;
 
-Keyword keywords[] ={  /* keep sorted: binary searched */
+int peek(void);
+int gettok(char **, int *);
+int binsearch(const char *, const Keyword *, int);
+
+const Keyword keywords[] ={    /* keep sorted: binary searched */
        { "BEGIN",      XBEGIN,         XBEGIN },
        { "END",        XEND,           XEND },
        { "NF",         VARNF,          VARNF },
@@ -61,6 +69,7 @@ Keyword keywords[] ={ /* keep sorted: binary searched */
        { "for",        FOR,            FOR },
        { "func",       FUNC,           FUNC },
        { "function",   FUNC,           FUNC },
+       { "gensub",     GENSUB,         GENSUB },
        { "getline",    GETLINE,        GETLINE },
        { "gsub",       GSUB,           GSUB },
        { "if",         IF,             IF },
@@ -81,9 +90,11 @@ Keyword keywords[] ={        /* keep sorted: binary searched */
        { "sprintf",    SPRINTF,        SPRINTF },
        { "sqrt",       FSQRT,          BLTIN },
        { "srand",      FSRAND,         BLTIN },
+       { "strftime",   FSTRFTIME,      BLTIN },
        { "sub",        SUB,            SUB },
        { "substr",     SUBSTR,         SUBSTR },
        { "system",     FSYSTEM,        BLTIN },
+       { "systime",    FSYSTIME,       BLTIN },
        { "tolower",    FTOLOWER,       BLTIN },
        { "toupper",    FTOUPPER,       BLTIN },
        { "while",      WHILE,          WHILE },
@@ -101,9 +112,9 @@ int peek(void)
 int gettok(char **pbuf, int *psz)      /* get next input token */
 {
        int c, retc;
-       char *buf = *pbuf;
+       uschar *buf = (uschar *) *pbuf;
        int sz = *psz;
-       char *bp = buf;
+       uschar *bp = buf;
 
        c = input();
        if (c == 0)
@@ -146,7 +157,7 @@ int gettok(char **pbuf, int *psz)   /* get next input token */
                }
                *bp = 0;
                strtod(buf, &rem);      /* parse the number */
-               if (rem == buf) {       /* it wasn't a valid number at all */
+               if (rem == (char *)buf) {       /* it wasn't a valid number at all */
                        buf[1] = 0;     /* return one character as token */
                        retc = buf[0];  /* character is its own type */
                        unputstr(rem+1); /* put rest back for later */
@@ -173,7 +184,7 @@ int yylex(void)
        static char *buf = 0;
        static int bufsize = 5; /* BUG: setting this small causes core dump! */
 
-       if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL)
+       if (buf == 0 && (buf = malloc(bufsize)) == NULL)
                FATAL( "out of space in yylex" );
        if (sc) {
                sc = 0;
@@ -357,11 +368,11 @@ int yylex(void)
 int string(void)
 {
        int c, n;
-       char *s, *bp;
-       static char *buf = 0;
+       uschar *s, *bp;
+       static uschar *buf = 0;
        static int bufsz = 500;
 
-       if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
+       if (buf == 0 && (buf = malloc(bufsz)) == NULL)
                FATAL("out of space for strings");
        for (bp = buf; (c = input()) != '"'; ) {
                if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
@@ -378,6 +389,7 @@ int string(void)
                case '\\':
                        c = input();
                        switch (c) {
+                       case '\n': break;
                        case '"': *bp++ = '"'; break;
                        case 'n': *bp++ = '\n'; break;  
                        case 't': *bp++ = '\t'; break;
@@ -416,7 +428,9 @@ int string(void)
                                break;
                            }
 
-                       default: 
+                       default:
+                               WARNING("warning: escape sequence `\\%c' "
+                                   "treated as plain `%c'", c, c);
                                *bp++ = c;
                                break;
                        }
@@ -454,7 +468,7 @@ int binsearch(const char *w, const Keyword *kp, int n)
 
 int word(char *w) 
 {
-       Keyword *kp;
+       const Keyword *kp;
        int c, n;
 
        n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
@@ -504,11 +518,11 @@ void startreg(void)       /* next call to yylex will return a regular expression */
 int regexpr(void)
 {
        int c;
-       static char *buf = 0;
+       static uschar *buf = 0;
        static int bufsz = 500;
-       char *bp;
+       uschar *bp;
 
-       if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
+       if (buf == 0 && (buf = malloc(bufsz)) == NULL)
                FATAL("out of space for rex expr");
        bp = buf;
        for ( ; (c = input()) != '/' && c != 0; ) {
similarity index 79%
rename from commands/awk/lib.c
rename to external/historical/nawk/dist/lib.c
index 8ba14e6df9a8e8e8e777c64c09bb3f58b4cc0f99..28a4b97e8d021402882e41bd96776259c6899cbf 100644 (file)
@@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 THIS SOFTWARE.
 ****************************************************************/
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #define DEBUG
 #include <stdio.h>
 #include <string.h>
@@ -32,15 +36,19 @@ THIS SOFTWARE.
 #include "awk.h"
 #include "awkgram.h"
 
+char   EMPTY[] = { '\0' };
 FILE   *infile = NULL;
-char   *file   = "";
-char   *record;
+int    innew;          /* 1 = infile has not been read by readrec */
+char   *file   = EMPTY;
+uschar *record;
 int    recsize = RECSIZE;
 char   *fields;
 int    fieldssize = RECSIZE;
 
 Cell   **fldtab;       /* pointers to Cells */
-char   inputFS[100] = " ";
+
+static size_t  len_inputFS = 0;
+static char    *inputFS = NULL;
 
 #define        MAXFLD  2
 int    nfields = MAXFLD;       /* last allocated slot for $i */
@@ -52,15 +60,15 @@ int lastfld = 0;    /* last used field */
 int    argno   = 1;    /* current input argument number */
 extern Awkfloat *ARGC;
 
-static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
-static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
+static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL };
+static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL };
 
 void recinit(unsigned int n)
 {
-       if ( (record = (char *) malloc(n)) == NULL
-         || (fields = (char *) malloc(n+1)) == NULL
-         || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL
-         || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
+       if ( (record = malloc(n)) == NULL
+         || (fields = malloc(n+1)) == NULL
+         || (fldtab = malloc((nfields+1) * sizeof(*fldtab))) == NULL
+         || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL )
                FATAL("out of space for $0 and fields");
        *fldtab[0] = dollar0;
        fldtab[0]->sval = record;
@@ -74,11 +82,11 @@ void makefields(int n1, int n2)             /* create $n1..$n2 inclusive */
        int i;
 
        for (i = n1; i <= n2; i++) {
-               fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
+               fldtab[i] = malloc(sizeof(**fldtab));
                if (fldtab[i] == NULL)
                        FATAL("out of space in makefields %d", i);
                *fldtab[i] = dollar1;
-               sprintf(temp, "%d", i);
+               snprintf(temp, sizeof(temp), "%d", i);
                fldtab[i]->nval = tostring(temp);
        }
 }
@@ -97,14 +105,15 @@ void initgetrec(void)
                argno++;
        }
        infile = stdin;         /* no filenames, so use stdin */
+       innew = 1;
 }
 
 static int firsttime = 1;
 
-int getrec(char **pbuf, int *pbufsize, int isrecord)   /* get next input record */
+int getrec(uschar **pbuf, int *pbufsize, int isrecord) /* get next input record */
 {                      /* note: cares whether buf == record */
        int c;
-       char *buf = *pbuf;
+       uschar *buf = *pbuf;
        uschar saveb0;
        int bufsize = *pbufsize, savebufsize = bufsize;
 
@@ -139,9 +148,12 @@ int getrec(char **pbuf, int *pbufsize, int isrecord)       /* get next input record */
                                infile = stdin;
                        else if ((infile = fopen(file, "r")) == NULL)
                                FATAL("can't open file %s", file);
+                       innew = 1;
                        setfval(fnrloc, 0.0);
                }
-               c = readrec(&buf, &bufsize, infile);
+               c = readrec(&buf, &bufsize, infile, innew);
+               if (innew)
+                       innew = 0;
                if (c != 0 || buf[0] != '\0') { /* normal record */
                        if (isrecord) {
                                if (freeable(fldtab[0]))
@@ -179,45 +191,71 @@ void nextfile(void)
        argno++;
 }
 
-int readrec(char **pbuf, int *pbufsize, FILE *inf)     /* read one record into buf */
+int readrec(uschar **pbuf, int *pbufsize, FILE *inf, int newflag)      /* read one record into buf */
 {
-       int sep, c;
-       char *rr, *buf = *pbuf;
+       int sep, c, isrec, found, tempstat;
+       uschar *rr, *buf = *pbuf;
        int bufsize = *pbufsize;
-
-       if (strlen(*FS) >= sizeof(inputFS))
-               FATAL("field separator %.10s... is too long", *FS);
-       strcpy(inputFS, *FS);   /* for subsequent field splitting */
-       if ((sep = **RS) == 0) {
-               sep = '\n';
-               while ((c=getc(inf)) == '\n' && c != EOF)       /* skip leading \n's */
-                       ;
-               if (c != EOF)
-                       ungetc(c, inf);
+       size_t len;
+
+       if ((len = strlen(*FS)) < len_inputFS) {
+               strcpy(inputFS, *FS);   /* for subsequent field splitting */
+       } else {
+               len_inputFS = len + 1;
+               inputFS = realloc(inputFS, len_inputFS);
+               if (inputFS == NULL)
+                       FATAL("field separator %.10s... is too long", *FS);
+               memcpy(inputFS, *FS, len_inputFS);
        }
-       for (rr = buf; ; ) {
-               for (; (c=getc(inf)) != sep && c != EOF; ) {
-                       if (rr-buf+1 > bufsize)
-                               if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
-                                       FATAL("input record `%.30s...' too long", buf);
+       if (**RS && (*RS)[1]) {
+               fa *pfa = makedfa(*RS, 1);
+               if (newflag)
+                       found = fnematch(pfa, inf, &buf, &bufsize, recsize);
+               else {
+                       tempstat = pfa->initstat;
+                       pfa->initstat = 2;
+                       found = fnematch(pfa, inf, &buf, &bufsize, recsize);
+                       pfa->initstat = tempstat;
+               }
+               if (found)
+                       *patbeg = 0;
+       } else {
+               if ((sep = **RS) == 0) {
+                       sep = '\n';
+                       while ((c=getc(inf)) == '\n' && c != EOF)       /* skip leading \n's */
+                               ;
+                       if (c != EOF)
+                               ungetc(c, inf);
+               }
+               for (rr = buf; ; ) {
+                       for (; (c=getc(inf)) != sep && c != EOF; ) {
+                               if (rr-buf+1 > bufsize)
+                                       if (!adjbuf(&buf, &bufsize, 1+rr-buf,
+                                           recsize, &rr, "readrec 1"))
+                                               FATAL("input record `%.30s...'"
+                                                   " too long", buf);
+                               *rr++ = c;
+                       }
+                       if (**RS == sep || c == EOF)
+                               break;
+                       if ((c = getc(inf)) == '\n' || c == EOF)
+                               /* 2 in a row */
+                               break;
+                       if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
+                           "readrec 2"))
+                               FATAL("input record `%.30s...' too long", buf);
+                       *rr++ = '\n';
                        *rr++ = c;
                }
-               if (**RS == sep || c == EOF)
-                       break;
-               if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
-                       break;
-               if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
+               if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
                        FATAL("input record `%.30s...' too long", buf);
-               *rr++ = '\n';
-               *rr++ = c;
+               *rr = 0;
        }
-       if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
-               FATAL("input record `%.30s...' too long", buf);
-       *rr = 0;
-          dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
        *pbuf = buf;
        *pbufsize = bufsize;
-       return c == EOF && rr == buf ? 0 : 1;
+       isrec = *buf || !feof(inf);
+          dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) );
+       return isrec;
 }
 
 char *getargv(int n)   /* get ARGV[n] */
@@ -226,7 +264,7 @@ char *getargv(int n)        /* get ARGV[n] */
        char *s, temp[50];
        extern Array *ARGVtab;
 
-       sprintf(temp, "%d", n);
+       snprintf(temp, sizeof(temp), "%d", n);
        x = setsymtab(temp, "", 0.0, STR, ARGVtab);
        s = getsval(x);
           dprintf( ("getargv(%d) returns |%s|\n", n, s) );
@@ -268,14 +306,15 @@ void fldbld(void) /* create fields from current record */
        n = strlen(r);
        if (n > fieldssize) {
                xfree(fields);
-               if ((fields = (char *) malloc(n+1)) == NULL)
+               if ((fields = malloc(n+1)) == NULL)
                        FATAL("out of space for fields in fldbld %d", n);
                fieldssize = n;
        }
        fr = fields;
        i = 0;  /* number of fields accumulated here */
-       strcpy(inputFS, *FS);
-       if (strlen(inputFS) > 1) {      /* it's a regular expression */
+       if (!inputFS) {
+               /* do nothing */
+       } else if (inputFS[0] && inputFS[1]) {  /* it's a regular expression */
                i = refldbld(r, inputFS);
        } else if ((sep = *inputFS) == ' ') {   /* default whitespace */
                for (i = 0; ; ) {
@@ -347,6 +386,7 @@ void fldbld(void)   /* create fields from current record */
                }
        }
        setfval(nfloc, (Awkfloat) lastfld);
+       donerec = 1; /* restore */
        if (dbg) {
                for (j = 0; j <= lastfld; j++) {
                        p = fldtab[j];
@@ -364,7 +404,7 @@ void cleanfld(int n1, int n2)       /* clean out fields n1 .. n2 inclusive */
                p = fldtab[i];
                if (freeable(p))
                        xfree(p->sval);
-               p->sval = "";
+               p->sval = EMPTY;
                p->tval = FLD | STR | DONTFREE;
        }
 }
@@ -378,6 +418,19 @@ void newfld(int n) /* add field n after end of existing lastfld */
        setfval(nfloc, (Awkfloat) n);
 }
 
+void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
+{
+       if (n > nfields)
+               growfldtab(n);
+
+       if (lastfld < n)
+           cleanfld(lastfld+1, n);
+       else
+           cleanfld(n+1, lastfld);
+
+       lastfld = n;
+}
+
 Cell *fieldadr(int n)  /* get nth field */
 {
        if (n < 0)
@@ -395,8 +448,8 @@ void growfldtab(int n)      /* make new fields up to at least $n */
        if (n > nf)
                nf = n;
        s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
-       if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
-               fldtab = (Cell **) realloc(fldtab, s);
+       if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
+               fldtab = realloc(fldtab, s);
        else                                    /* overflow sizeof int */
                xfree(fldtab);  /* make it null */
        if (fldtab == NULL)
@@ -416,7 +469,7 @@ int refldbld(const char *rec, const char *fs)       /* build fields from reg expr in F
        n = strlen(rec);
        if (n > fieldssize) {
                xfree(fields);
-               if ((fields = (char *) malloc(n+1)) == NULL)
+               if ((fields = malloc(n+1)) == NULL)
                        FATAL("out of space for fields in refldbld %d", n);
                fieldssize = n;
        }
@@ -438,8 +491,8 @@ int refldbld(const char *rec, const char *fs)       /* build fields from reg expr in F
                if (nematch(pfa, rec)) {
                        pfa->initstat = 2;      /* horrible coupling to b.c */
                           dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
-                       strncpy(fr, rec, patbeg-rec);
-                       fr += patbeg - rec + 1;
+                       strncpy(fr, rec, ((const char*)patbeg)-rec);
+                       fr += ((const char*)patbeg) - rec + 1;
                        *(fr-1) = '\0';
                        rec = patbeg + patlen;
                } else {
@@ -455,7 +508,8 @@ int refldbld(const char *rec, const char *fs)       /* build fields from reg expr in F
 void recbld(void)      /* create $0 from $1..$NF if necessary */
 {
        int i;
-       char *r, *p;
+       uschar *r;
+       char *p;
 
        if (donerec == 1)
                return;
@@ -517,11 +571,6 @@ void SYNTAX(const char *fmt, ...)
        eprint();
 }
 
-void fpecatch(int n)
-{
-       FATAL("floating point exception %d", n);
-}
-
 extern int bracecnt, brackcnt, parencnt;
 
 void bracecheck(void)
@@ -603,7 +652,6 @@ void error()
 void eprint(void)      /* try to print context around error */
 {
        char *p, *q;
-       int c;
        static int been_here = 0;
        extern char ebuf[], *ep;
 
@@ -627,11 +675,25 @@ void eprint(void) /* try to print context around error */
                if (*p)
                        putc(*p, stderr);
        fprintf(stderr, " <<< ");
-       if (*ep)
+#if 0
+       /*
+        * The following code was used to print the rest of the line of
+        * error context. It naively counts brackets, parens and braces in
+        * order to minimize the parsing effect of dropping the rest of the
+        * line but it does not work in all the cases. It is too much work
+        * to save the current program input point and restore it in all the
+        * cases just for the benefit of error printing so for now this
+        * code is disabled. In particular this code is confused if the
+        * [ { ( ) } ] is inside a quoted string or a pattern.
+        */
+       if (*ep) {
+               int c;
                while ((c = input()) != '\n' && c != '\0' && c != EOF) {
                        putc(c, stderr);
                        bclass(c);
                }
+       }
+#endif
        putc('\n', stderr);
        ep = ebuf;
 }
@@ -686,7 +748,9 @@ int is_number(const char *s)
        char *ep;
        errno = 0;
        r = strtod(s, &ep);
-       if (ep == s || r == HUGE_VAL || errno == ERANGE)
+       if (ep == s || errno == ERANGE)
+               return 0;
+       if (ep - s >= 3 && strncasecmp(ep - 3, "nan", 3) == 0)
                return 0;
        while (*ep == ' ' || *ep == '\t' || *ep == '\n')
                ep++;
similarity index 71%
rename from commands/awk/main.c
rename to external/historical/nawk/dist/main.c
index 704599ce419ed412e10d2037465a71148ee34cf5..9d64d1773b80b6adabb8d4ef8e1b252fcbe9596a 100644 (file)
@@ -22,7 +22,11 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 THIS SOFTWARE.
 ****************************************************************/
 
-const char     *version = "version 20100208";
+const char     *version = "version 20100523";
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
 
 #define DEBUG
 #include <stdio.h>
@@ -38,6 +42,7 @@ extern        char    **environ;
 extern int     nfields;
 
 int    dbg     = 0;
+unsigned int srand_seed;
 char   *cmdname;       /* gets argv[0] for error messages */
 extern FILE    *yyin;  /* lex input file */
 char   *lexprog;       /* points to program argument if it exists */
@@ -45,19 +50,59 @@ extern      int errorflag;  /* non-zero if any syntax errors; set by yyerror */
 int    compile_time = 2;       /* for error printing: */
                                /* 2 = cmdline, 1 = compile, 0 = running */
 
-#define        MAX_PFILE       20      /* max number of -f's */
-
-char   *pfile[MAX_PFILE];      /* program filenames from -f's */
-int    npfile = 0;     /* number of filenames */
-int    curpfile = 0;   /* current filename */
+static char    **pfile = NULL; /* program filenames from -f's */
+static size_t  maxpfile = 0;   /* max program filenames */
+static size_t  npfile = 0;     /* number of filenames */
+static size_t  curpfile = 0;   /* current filename */
 
 int    safe    = 0;    /* 1 => "safe" mode */
 
+static char *
+setfs(char *p)
+{
+#ifdef notdef
+       /* wart: t=>\t */
+       if (p[0] == 't' && p[1] == 0)
+               return "\t";
+       else
+#endif
+       if (p[0] != 0)
+               return p;
+       return NULL;
+}
+
+__dead static void fpecatch(int n
+#ifdef SA_SIGINFO
+       , siginfo_t *si, void *uc
+#endif
+)
+{
+#ifdef SA_SIGINFO
+       static const char *emsg[] = {
+           "Unknown error",
+           "Integer divide by zero",
+           "Integer overflow",
+           "Floating point divide by zero",
+           "Floating point overflow",
+           "Floating point underflow",
+           "Floating point inexact result",
+           "Invalid Floating point operation",
+           "Subscript out of range",
+       };
+#endif
+       FATAL("floating point exception"
+#ifdef SA_SIGINFO
+           ": %s\n", emsg[si->si_code >= 1 && si->si_code <= 8 ?
+           si->si_code : 0]
+#endif
+           );
+}
+
 int main(int argc, char *argv[])
 {
        const char *fs = NULL;
 
-       setlocale(LC_CTYPE, "");
+       setlocale(LC_ALL, "");
        setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
        cmdname = argv[0];
        if (argc == 1) {
@@ -66,7 +111,22 @@ int main(int argc, char *argv[])
                  cmdname);
                exit(1);
        }
-       signal(SIGFPE, fpecatch);
+
+#ifdef SA_SIGINFO
+       {
+               struct sigaction sa;
+               sa.sa_sigaction = fpecatch;
+               sa.sa_flags = SA_SIGINFO;
+               sigemptyset(&sa.sa_mask);
+               (void)sigaction(SIGFPE, &sa, NULL);
+       }
+#else
+       (void)signal(SIGFPE, fpecatch);
+#endif
+       /* Set and keep track of the random seed */
+       srand_seed = 1;
+       srand(srand_seed);
+
        yyin = NULL;
        symtab = makesymtab(NSYMTAB/NSYMTAB);
        while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
@@ -90,22 +150,23 @@ int main(int argc, char *argv[])
                        argv++;
                        if (argc <= 1)
                                FATAL("no program filename");
-                       if (npfile >= MAX_PFILE - 1)
-                               FATAL("too many -f options"); 
+                       if (npfile >= maxpfile) {
+                               maxpfile += 20;
+                               pfile = realloc(pfile,
+                                   maxpfile * sizeof(*pfile));
+                               if (pfile == NULL)
+                                       FATAL("error allocating space for "
+                                           "-f options"); 
+                       }
                        pfile[npfile++] = argv[1];
                        break;
                case 'F':       /* set field separator */
                        if (argv[1][2] != 0) {  /* arg is -Fsomething */
-                               if (argv[1][2] == 't' && argv[1][3] == 0)       /* wart: t=>\t */
-                                       fs = "\t";
-                               else if (argv[1][2] != 0)
-                                       fs = &argv[1][2];
+                               fs = setfs(argv[1] + 2);
                        } else {                /* arg is -F something */
                                argc--; argv++;
-                               if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0)   /* wart: t=>\t */
-                                       fs = "\t";
-                               else if (argc > 1 && argv[1][0] != 0)
-                                       fs = &argv[1][0];
+                               if (argc > 1)
+                                       fs = setfs(argv[1]);
                        }
                        if (fs == NULL || *fs == '\0')
                                WARNING("field separator FS is empty");
@@ -113,6 +174,8 @@ int main(int argc, char *argv[])
                case 'v':       /* -v a=1 to be done NOW.  one -v for each */
                        if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1]))
                                setclvar(argv[1]);
+                       else if (argv[1][2] != '\0')
+                               setclvar(&argv[1][2]);
                        break;
                case 'd':
                        dbg = atoi(&argv[1][2]);
@@ -148,7 +211,6 @@ int main(int argc, char *argv[])
        if (!safe)
                envinit(environ);
        yyparse();
-       setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
        if (fs)
                *FS = qstring(fs, '\0');
           dprintf( ("errorflag=%d\n", errorflag) );
similarity index 85%
rename from commands/awk/Makefile.orig
rename to external/historical/nawk/dist/makefile
index 7f8a389e269be334d6ed4e61ffeb25b060d2e3f8..a454d7ad9c666c384b5b3c22177d52785813cbcd 100644 (file)
@@ -26,13 +26,13 @@ CFLAGS = -g
 CFLAGS = -O2
 CFLAGS =
 
-CC = gcc -Wall -g -Wwrite-strings
-CC = gcc -fprofile-arcs -ftest-coverage # then gcov f1.c; cat f1.c.gcov
 CC = gcc -Wall -g
+CC = /opt/SUNWspro/bin/cc
+CC = /opt/pure/purify/purify cc
 CC = cc
+CC = gcc -Wall -g -Wwrite-strings
+CC = gcc -fprofile-arcs -ftest-coverage # then gcov f1.c; cat f1.c.gcov
 CC = gcc -O4
-CC = cc -O
-
 
 YACC = bison -y
 YACC = yacc
@@ -49,19 +49,13 @@ LISTING = awk.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c \
 SHIP = README FIXES $(SOURCE) ytab[ch].bak makefile makefile.win \
        vcvars32.bat buildwin.bat awk.1
 
-all: awk
-
-install: awk awk.1
-       install -m 755 -o bin -g operator awk /usr/bin/awk
-       install -m 644 -o bin -g operator awk.1 /usr/man/man1
-
-awk:   ytab.o $(OFILES)
-       $(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC)  -lm -o $@
+a.out: ytab.o $(OFILES)
+       $(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC)  -lm
 
 $(OFILES):     awk.h ytab.h proto.h
 
-ytab.o ytab.c ytab.h:  awk.h proto.h awkgram.y
-       $(YACC) $(YFLAGS) awkgram.y 2>/dev/null
+ytab.o:        awk.h proto.h awkgram.y
+       $(YACC) $(YFLAGS) awkgram.y
        mv y.tab.c ytab.c
        mv y.tab.h ytab.h
        $(CC) $(CFLAGS) -c ytab.c
@@ -91,4 +85,4 @@ names:
        @echo $(LISTING)
 
 clean:
-       rm -f awk *.o *.obj maketab maketab.exe *.bb *.bbg *.da *.gcov *.gcno *.gcda # proctab.c
+       rm -f a.out *.o *.obj maketab maketab.exe ytab.[ch] *.bb *.bbg *.da *.gcov *.gcno *.gcda # proctab.c
similarity index 88%
rename from commands/awk/maketab.c
rename to external/historical/nawk/dist/maketab.c
index 608bd58499a5a804bbfecc51010ba5f59cfb3ef2..1a5c1e596d0085c8c05da0c341a8f708d85901c9 100644 (file)
@@ -25,9 +25,13 @@ THIS SOFTWARE.
 /*
  * this program makes the table to link function names
  * and type indices that is used by execute() in run.c.
- * it finds the indices in awkgram.h, produced by yacc.
+ * it finds the indices in ytab.h, produced by yacc.
  */
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -103,6 +107,7 @@ struct xx
        { ARG, "arg", "arg" },
        { VARNF, "getnf", "NF" },
        { GETLINE, "awkgetline", "getline" },
+       { GENSUB, "gensub", "gensub" },
        { 0, "", "" },
 };
 
@@ -128,19 +133,22 @@ int main(int argc, char *argv[])
                fprintf(stderr, "maketab can't open awkgram.h!\n");
                exit(1);
        }
-       printf("static char *printname[%d] = {\n", SIZE);
+       printf("static const char * const printname[%d] = {\n", SIZE);
        i = 0;
        while (fgets(buf, sizeof buf, fp) != NULL) {
-               n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok);
+               n = sscanf(buf, "%1c %199s %199s %d", &c, def, name, &tok);
                if (c != '#' || (n != 4 && strcmp(def,"define") != 0))  /* not a valid #define */
                        continue;
                if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
                        /* fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf); */
                        continue;
                }
-               names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1);
-               strcpy(names[tok-FIRSTTOKEN], name);
-               printf("\t(char *) \"%s\",\t/* %d */\n", name, tok);
+               names[tok-FIRSTTOKEN] = strdup(name);
+               if (names[tok-FIRSTTOKEN] == NULL) {
+                       fprintf(stderr, "maketab out of space copying %s", name);
+                       continue;
+               }
+               printf("\t\"%s\",\t/* %d */\n", name, tok);
                i++;
        }
        printf("};\n\n");
@@ -155,11 +163,11 @@ int main(int argc, char *argv[])
                        printf("\t%s,\t/* %s */\n", table[i], names[i]);
        printf("};\n\n");
 
-       printf("char *tokname(int n)\n");       /* print a tokname() function */
+       printf("const char *tokname(int n)\n"); /* print a tokname() function */
        printf("{\n");
        printf("        static char buf[100];\n\n");
        printf("        if (n < FIRSTTOKEN || n > LASTTOKEN) {\n");
-       printf("                sprintf(buf, \"token %%d\", n);\n");
+       printf("                snprintf(buf, sizeof(buf), \"token %%d\", n);\n");
        printf("                return buf;\n");
        printf("        }\n");
        printf("        return printname[n-FIRSTTOKEN];\n");
similarity index 91%
rename from commands/awk/parse.c
rename to external/historical/nawk/dist/parse.c
index 05b4d1a8d4e0aad69ade96daae85944b3be08881..503e71623d98cd1feab537c60562b354c8e43afb 100644 (file)
@@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 THIS SOFTWARE.
 ****************************************************************/
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #define DEBUG
 #include <stdio.h>
 #include <string.h>
@@ -33,7 +37,7 @@ Node *nodealloc(int n)
 {
        Node *x;
 
-       x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *));
+       x = malloc(sizeof(Node) + (n-1)*sizeof(Node *));
        if (x == NULL)
                FATAL("out of space in nodealloc");
        x->nnext = NULL;
@@ -93,6 +97,20 @@ Node *node4(int a, Node *b, Node *c, Node *d, Node *e)
        return(x);
 }
 
+Node *node5(int a, Node *b, Node *c, Node *d, Node *e, Node *f)
+{
+       Node *x;
+
+       x = nodealloc(5);
+       x->nobj = a;
+       x->narg[0] = b;
+       x->narg[1] = c;
+       x->narg[2] = d;
+       x->narg[3] = e;
+       x->narg[4] = f;
+       return(x);
+}
+
 Node *stat1(int a, Node *b)
 {
        Node *x;
@@ -165,6 +183,15 @@ Node *op4(int a, Node *b, Node *c, Node *d, Node *e)
        return(x);
 }
 
+Node *op5(int a, Node *b, Node *c, Node *d, Node *e, Node *f)
+{
+       Node *x;
+
+       x = node5(a,b,c,d,e, f);
+       x->ntype = NEXPR;
+       return(x);
+}
+
 Node *celltonode(Cell *a, int b)
 {
        Node *x;
diff --git a/external/historical/nawk/dist/proctab.c b/external/historical/nawk/dist/proctab.c
new file mode 100644 (file)
index 0000000..9401744
--- /dev/null
@@ -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];
+}
similarity index 84%
rename from commands/awk/proto.h
rename to external/historical/nawk/dist/proto.h
index 359ae64c99024f376c8eb3c1d9d558309045a1e6..f1bb62daaddf89270b94250283b9c6ac4605f317 100644 (file)
@@ -43,17 +43,18 @@ extern      fa      *mkdfa(const char *, int);
 extern int     makeinit(fa *, int);
 extern void    penter(Node *);
 extern void    freetr(Node *);
-extern int     hexstr(char **);
-extern int     quoted(char **);
+extern int     hexstr(const uschar **);
+extern int     quoted(const uschar **);
 extern char    *cclenter(const char *);
-extern void    overflo(const char *);
+extern void    overflo(const char *) __dead;
 extern void    cfoll(fa *, Node *);
-extern int     first(const Node *);
+extern int     first(Node *);
 extern void    follow(Node *);
 extern int     member(int, const char *);
 extern int     match(fa *, const char *);
 extern int     pmatch(fa *, const char *);
 extern int     nematch(fa *, const char *);
+extern int     fnematch(fa *, FILE *, uschar **, int *, int);
 extern Node    *reparse(const char *);
 extern Node    *regexp(void);
 extern Node    *primary(void);
@@ -73,12 +74,14 @@ extern      Node    *node1(int, Node *);
 extern Node    *node2(int, Node *, Node *);
 extern Node    *node3(int, Node *, Node *, Node *);
 extern Node    *node4(int, Node *, Node *, Node *, Node *);
+extern Node    *node5(int, Node *, Node *, Node *, Node *, Node *);
 extern Node    *stat3(int, Node *, Node *, Node *);
 extern Node    *op2(int, Node *, Node *);
 extern Node    *op1(int, Node *);
 extern Node    *stat1(int, Node *);
 extern Node    *op3(int, Node *, Node *, Node *);
 extern Node    *op4(int, Node *, Node *, Node *, Node *);
+extern Node    *op5(int, Node *, Node *, Node *, Node *, Node *);
 extern Node    *stat2(int, Node *, Node *);
 extern Node    *stat4(int, Node *, Node *, Node *, Node *);
 extern Node    *celltonode(Cell *, int);
@@ -88,7 +91,7 @@ extern        Node    *pa2stat(Node *, Node *, Node *);
 extern Node    *linkum(Node *, Node *);
 extern void    defn(Cell *, Node *, Node *);
 extern int     isarg(const char *);
-extern char    *tokname(int);
+extern const char      *tokname(int);
 extern Cell    *(*proctab[])(Node **, int);
 extern int     ptoi(void *);
 extern Node    *itonp(int);
@@ -97,12 +100,12 @@ extern     void    syminit(void);
 extern void    arginit(int, char **);
 extern void    envinit(char **);
 extern Array   *makesymtab(int);
-extern void    freesymtab(const Cell *);
-extern void    freeelem(const Cell *, const char *);
+extern void    freesymtab(Cell *);
+extern void    freeelem(Cell *, const char *);
 extern Cell    *setsymtab(const char *, const char *, double, unsigned int, Array *);
 extern int     hash(const char *, int);
 extern void    rehash(Array *);
-extern Cell    *lookup(const char *, const Array *);
+extern Cell    *lookup(const char *, Array *);
 extern double  setfval(Cell *, double);
 extern void    funnyvar(Cell *, const char *);
 extern char    *setsval(Cell *, const char *);
@@ -110,30 +113,35 @@ extern    double  getfval(Cell *);
 extern char    *getsval(Cell *);
 extern char    *getpssval(Cell *);     /* for print */
 extern char    *tostring(const char *);
+extern char    *tostringN(const char *, size_t n);
 extern char    *qstring(const char *, int);
+extern Cell    *catstr(Cell *, Cell *);
 
 extern void    recinit(unsigned int);
 extern void    initgetrec(void);
 extern void    makefields(int, int);
 extern void    growfldtab(int n);
-extern int     getrec(char **, int *, int);
+extern int     getrec(uschar **, int *, int);
 extern void    nextfile(void);
-extern int     readrec(char **buf, int *bufsize, FILE *inf);
+extern int     readrec(uschar **buf, int *bufsize, FILE *inf, int newflag);
 extern char    *getargv(int);
 extern void    setclvar(char *);
 extern void    fldbld(void);
 extern void    cleanfld(int, int);
 extern void    newfld(int);
+extern void    setlastfld(int);
 extern int     refldbld(const char *, const char *);
 extern void    recbld(void);
 extern Cell    *fieldadr(int);
 extern void    yyerror(const char *);
-extern void    fpecatch(int);
 extern void    bracecheck(void);
 extern void    bcheck2(int, int, int);
-extern void    SYNTAX(const char *, ...);
-extern void    FATAL(const char *, ...);
-extern void    WARNING(const char *, ...);
+extern void    SYNTAX(const char *, ...)
+    __attribute__((__format__(__printf__, 1, 2)));
+extern void    FATAL(const char *, ...) __dead
+    __attribute__((__format__(__printf__, 1, 2)));
+extern void    WARNING(const char *, ...)
+    __attribute__((__format__(__printf__, 1, 2)));
 extern void    error(void);
 extern void    eprint(void);
 extern void    bclass(int);
@@ -141,7 +149,7 @@ extern      double  errcheck(double, const char *);
 extern int     isclvar(const char *);
 extern int     is_number(const char *);
 
-extern int     adjbuf(char **pb, int *sz, int min, int q, char **pbp, const char *what);
+extern int     adjbuf(uschar **pb, int *sz, int min, int q, uschar **pbp, const char *what);
 extern void    run(Node *);
 extern Cell    *execute(Node *);
 extern Cell    *program(Node **, int);
@@ -184,12 +192,13 @@ extern    Cell    *bltin(Node **, int);
 extern Cell    *printstat(Node **, int);
 extern Cell    *nullproc(Node **, int);
 extern FILE    *redirect(int, Node *);
-extern FILE    *openfile(int, const char *);
+extern FILE    *openfile(int, const char *, int *);
 extern const char      *filename(FILE *);
 extern Cell    *closefile(Node **, int);
 extern void    closeall(void);
 extern Cell    *sub(Node **, int);
 extern Cell    *gsub(Node **, int);
+extern Cell    *gensub(Node **, int);
 
 extern FILE    *popen(const char *, const char *);
 extern int     pclose(FILE *);
similarity index 76%
rename from commands/awk/run.c
rename to external/historical/nawk/dist/run.c
index 1287610427bdf0a4510ef1b385bca1151856737f..44cadc24ca8464bfda615befbbe442240e268c94 100644 (file)
@@ -22,19 +22,28 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 THIS SOFTWARE.
 ****************************************************************/
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #define DEBUG
 #include <stdio.h>
 #include <ctype.h>
+#include <wchar.h>
+#include <wctype.h>
 #include <setjmp.h>
 #include <limits.h>
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
+#include <stdint.h>
 #include "awk.h"
 #include "awkgram.h"
 
-#define tempfree(x)    if (istemp(x)) tfree(x); else
+#define tempfree(x)    do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
+
+void stdinit(void);
 
 /*
 #undef tempfree
@@ -66,32 +75,33 @@ void tempfree(Cell *p) {
 
 jmp_buf env;
 extern int     pairstack[];
+extern unsigned int srand_seed;
 
 Node   *winner = NULL; /* root of parse tree */
 Cell   *tmps;          /* free temporary cells for execution */
 
-static Cell    truecell        ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
+static Cell    truecell        ={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL };
 Cell   *True   = &truecell;
-static Cell    falsecell       ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
+static Cell    falsecell       ={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL };
 Cell   *False  = &falsecell;
-static Cell    breakcell       ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
+static Cell    breakcell       ={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL };
 Cell   *jbreak = &breakcell;
-static Cell    contcell        ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
+static Cell    contcell        ={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL };
 Cell   *jcont  = &contcell;
-static Cell    nextcell        ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
+static Cell    nextcell        ={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL };
 Cell   *jnext  = &nextcell;
-static Cell    nextfilecell    ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
+static Cell    nextfilecell    ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL};
 Cell   *jnextfile      = &nextfilecell;
-static Cell    exitcell        ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
+static Cell    exitcell        ={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL };
 Cell   *jexit  = &exitcell;
-static Cell    retcell         ={ OJUMP, JRET, 0, 0, 0.0, NUM };
+static Cell    retcell         ={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL };
 Cell   *jret   = &retcell;
-static Cell    tempcell        ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
+static Cell    tempcell        ={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
 
 Node   *curnode = NULL;        /* the node being executed, for debugging */
 
 /* buffer memory management */
-int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
+int adjbuf(uschar **pbuf, int *psiz, int minlen, int quantum, uschar **pbptr,
        const char *whatrtn)
 /* pbuf:    address of pointer to buffer being managed
  * psiz:    address of buffer size variable
@@ -110,7 +120,7 @@ int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
                /* round up to next multiple of quantum */
                if (rminlen)
                        minlen += quantum - rminlen;
-               tbuf = (char *) realloc(*pbuf, minlen);
+               tbuf = realloc(*pbuf, minlen);
                dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
                if (tbuf == NULL) {
                        if (whatrtn)
@@ -127,8 +137,6 @@ int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
 
 void run(Node *a)      /* execution of parse tree starts here */
 {
-       extern void stdinit(void);
-
        stdinit();
        execute(a);
        closeall();
@@ -216,11 +224,11 @@ struct Frame {    /* stack frame for awk function calls */
 
 struct Frame *frame = NULL;    /* base of stack frames; dynamically allocated */
 int    nframe = 0;             /* number of frames allocated */
-struct Frame *fp = NULL;       /* frame pointer. bottom level unused */
+struct Frame *frp = NULL;      /* frame pointer. bottom level unused */
 
 Cell *call(Node **a, int n)    /* function call.  very kludgy and fragile */
 {
-       static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
+       static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
        int i, ncall, ndef;
        int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
        Node *x;
@@ -233,21 +241,21 @@ Cell *call(Node **a, int n)       /* function call.  very kludgy and fragile */
        if (!isfcn(fcn))
                FATAL("calling undefined function %s", s);
        if (frame == NULL) {
-               fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
+               frp = frame = calloc(nframe += 100, sizeof(*frp));
                if (frame == NULL)
                        FATAL("out of space for stack frames calling %s", s);
        }
        for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)      /* args in call */
                ncall++;
        ndef = (int) fcn->fval;                 /* args in defn */
-          dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
+          dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (frp-frame)) );
        if (ncall > ndef)
                WARNING("function %s called with %d args, uses only %d",
                        s, ncall, ndef);
        if (ncall + ndef > NARGS)
                FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
        for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {   /* get call args */
-                  dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
+                  dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (frp-frame)) );
                y = execute(x);
                oargs[i] = y;
                   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
@@ -264,26 +272,25 @@ Cell *call(Node **a, int n)       /* function call.  very kludgy and fragile */
                args[i] = gettemp();
                *args[i] = newcopycell;
        }
-       fp++;   /* now ok to up frame */
-       if (fp >= frame + nframe) {
-               int dfp = fp - frame;   /* old index */
-               frame = (struct Frame *)
-                       realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
+       frp++;  /* now ok to up frame */
+       if (frp >= frame + nframe) {
+               int dfp = frp - frame;  /* old index */
+               frame = realloc(frame, (nframe += 100) * sizeof(*frame));
                if (frame == NULL)
                        FATAL("out of space for stack frames in %s", s);
-               fp = frame + dfp;
+               frp = frame + dfp;
        }
-       fp->fcncell = fcn;
-       fp->args = args;
-       fp->nargs = ndef;       /* number defined with (excess are locals) */
-       fp->retval = gettemp();
+       frp->fcncell = fcn;
+       frp->args = args;
+       frp->nargs = ndef;      /* number defined with (excess are locals) */
+       frp->retval = gettemp();
 
-          dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
+          dprintf( ("start exec of %s, fp=%d\n", s, (int) (frp-frame)) );
        y = execute((Node *)(fcn->sval));       /* execute body */
-          dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
+          dprintf( ("finished exec of %s, fp=%d\n", s, (int) (frp-frame)) );
 
        for (i = 0; i < ndef; i++) {
-               Cell *t = fp->args[i];
+               Cell *t = frp->args[i];
                if (isarr(t)) {
                        if (t->csub == CCOPY) {
                                if (i >= ncall) {
@@ -312,9 +319,9 @@ Cell *call(Node **a, int n) /* function call.  very kludgy and fragile */
        if (freed == 0) {
                tempfree(y);    /* don't free twice! */
        }
-       z = fp->retval;                 /* return value */
+       z = frp->retval;                        /* return value */
           dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
-       fp--;
+       frp--;
        return(z);
 }
 
@@ -322,14 +329,18 @@ Cell *copycell(Cell *x)   /* make a copy of a cell in a temp */
 {
        Cell *y;
 
+       /* copy is not constant or field */
+
        y = gettemp();
+       y->tval = x->tval & ~(CON|FLD|REC);
        y->csub = CCOPY;        /* prevents freeing until call is over */
        y->nval = x->nval;      /* BUG? */
-       if (isstr(x))
+       if (isstr(x) /* || x->ctype == OCELL */) {
                y->sval = tostring(x->sval);
+               y->tval &= ~DONTFREE;
+       } else
+               y->tval |= DONTFREE;
        y->fval = x->fval;
-       y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);    /* copy is not constant or field */
-                                                       /* is DONTFREE right? */
        return y;
 }
 
@@ -337,11 +348,11 @@ Cell *arg(Node **a, int n)        /* nth argument of a function */
 {
 
        n = ptoi(a[0]); /* argument number, counting from 0 */
-          dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
-       if (n+1 > fp->nargs)
+          dprintf( ("arg(%d), fp->nargs=%d\n", n, frp->nargs) );
+       if (n+1 > frp->nargs)
                FATAL("argument #%d of function %s was not supplied",
-                       n+1, fp->fcncell->nval);
-       return fp->args[n];
+                       n+1, frp->fcncell->nval);
+       return frp->args[n];
 }
 
 Cell *jump(Node **a, int n)    /* break, continue, next, nextfile, return */
@@ -360,14 +371,14 @@ Cell *jump(Node **a, int n)       /* break, continue, next, nextfile, return */
                if (a[0] != NULL) {
                        y = execute(a[0]);
                        if ((y->tval & (STR|NUM)) == (STR|NUM)) {
-                               setsval(fp->retval, getsval(y));
-                               fp->retval->fval = getfval(y);
-                               fp->retval->tval |= NUM;
+                               setsval(frp->retval, getsval(y));
+                               frp->retval->fval = getfval(y);
+                               frp->retval->tval |= NUM;
                        }
                        else if (y->tval & STR)
-                               setsval(fp->retval, getsval(y));
+                               setsval(frp->retval, getsval(y));
                        else if (y->tval & NUM)
-                               setfval(fp->retval, getfval(y));
+                               setfval(frp->retval, getfval(y));
                        else            /* can't happen */
                                FATAL("bad type variable %d", y->tval);
                        tempfree(y);
@@ -393,11 +404,11 @@ Cell *awkgetline(Node **a, int n) /* get next line from specific input */
        Cell *r, *x;
        extern Cell **fldtab;
        FILE *fp;
-       char *buf;
+       uschar *buf;
        int bufsize = recsize;
-       int mode;
+       int mode, newflag;
 
-       if ((buf = (char *) malloc(bufsize)) == NULL)
+       if ((buf = malloc(bufsize)) == NULL)
                FATAL("out of memory in getline");
 
        fflush(stdout); /* in case someone is waiting for a prompt */
@@ -407,12 +418,12 @@ Cell *awkgetline(Node **a, int n) /* get next line from specific input */
                mode = ptoi(a[1]);
                if (mode == '|')                /* input pipe */
                        mode = LE;      /* arbitrary flag */
-               fp = openfile(mode, getsval(x));
+               fp = openfile(mode, getsval(x), &newflag);
                tempfree(x);
                if (fp == NULL)
                        n = -1;
                else
-                       n = readrec(&buf, &bufsize, fp);
+                       n = readrec(&buf, &bufsize, fp, newflag);
                if (n <= 0) {
                        ;
                } else if (a[0] != NULL) {      /* getline var <file */
@@ -453,11 +464,11 @@ Cell *array(Node **a, int n)      /* a[0] is symtab, a[1] is list of subscripts */
        Cell *x, *y, *z;
        char *s;
        Node *np;
-       char *buf;
+       uschar *buf;
        int bufsz = recsize;
        int nsub = strlen(*SUBSEP);
 
-       if ((buf = (char *) malloc(bufsz)) == NULL)
+       if ((buf = malloc(bufsz)) == NULL)
                FATAL("out of memory in array");
 
        x = execute(a[0]);      /* Cell* for symbol table */
@@ -467,9 +478,9 @@ Cell *array(Node **a, int n)        /* a[0] is symtab, a[1] is list of subscripts */
                s = getsval(y);
                if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array"))
                        FATAL("out of memory for %s[%s...]", x->nval, buf);
-               strcat(buf, s);
+               strlcat(buf, s, bufsz);
                if (np->nnext)
-                       strcat(buf, *SUBSEP);
+                       strlcat(buf, *SUBSEP, bufsz);
                tempfree(y);
        }
        if (!isarr(x)) {
@@ -492,7 +503,7 @@ Cell *awkdelete(Node **a, int n)    /* a[0] is symtab, a[1] is list of subscripts *
 {
        Cell *x, *y;
        Node *np;
-       char *s;
+       uschar *s;
        int nsub = strlen(*SUBSEP);
 
        x = execute(a[0]);      /* Cell* for symbol table */
@@ -505,8 +516,8 @@ Cell *awkdelete(Node **a, int n)    /* a[0] is symtab, a[1] is list of subscripts *
                x->sval = (char *) makesymtab(NSYMTAB);
        } else {
                int bufsz = recsize;
-               char *buf;
-               if ((buf = (char *) malloc(bufsz)) == NULL)
+               uschar *buf;
+               if ((buf = malloc(bufsz)) == NULL)
                        FATAL("out of memory in adelete");
                buf[0] = 0;
                for (np = a[1]; np; np = np->nnext) {
@@ -514,9 +525,9 @@ Cell *awkdelete(Node **a, int n)    /* a[0] is symtab, a[1] is list of subscripts *
                        s = getsval(y);
                        if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete"))
                                FATAL("out of memory deleting %s[%s...]", x->nval, buf);
-                       strcat(buf, s); 
+                       strlcat(buf, s, bufsz);
                        if (np->nnext)
-                               strcat(buf, *SUBSEP);
+                               strlcat(buf, *SUBSEP, bufsz);
                        tempfree(y);
                }
                freeelem(x, buf);
@@ -530,7 +541,7 @@ Cell *intest(Node **a, int n)       /* a[0] is index (list), a[1] is symtab */
 {
        Cell *x, *ap, *k;
        Node *p;
-       char *buf;
+       uschar *buf;
        char *s;
        int bufsz = recsize;
        int nsub = strlen(*SUBSEP);
@@ -544,7 +555,7 @@ Cell *intest(Node **a, int n)       /* a[0] is index (list), a[1] is symtab */
                ap->tval |= ARR;
                ap->sval = (char *) makesymtab(NSYMTAB);
        }
-       if ((buf = (char *) malloc(bufsz)) == NULL) {
+       if ((buf = malloc(bufsz)) == NULL) {
                FATAL("out of memory in intest");
        }
        buf[0] = 0;
@@ -571,7 +582,8 @@ Cell *intest(Node **a, int n)       /* a[0] is index (list), a[1] is symtab */
 Cell *matchop(Node **a, int n) /* ~ and match() */
 {
        Cell *x, *y;
-       char *s, *t;
+       uschar *s;
+       char *t;
        int i;
        fa *pfa;
        int (*mf)(fa *, const char *) = match, mode = 0;
@@ -693,7 +705,7 @@ Cell *gettemp(void) /* get a tempcell */
        Cell *x;
 
        if (!tmps) {
-               tmps = (Cell *) calloc(100, sizeof(Cell));
+               tmps = calloc(100, sizeof(*tmps));
                if (!tmps)
                        FATAL("out of space for temporaries");
                for(i = 1; i < 100; i++)
@@ -806,19 +818,20 @@ Cell *sindex(Node **a, int nnn)           /* index(a[0], a[1]) */
 
 int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
 {
-       char *fmt;
-       char *p, *t;
+       uschar *fmt, *p, *t;
        const char *os;
        Cell *x;
        int flag = 0, n;
        int fmtwd; /* format width */
        int fmtsz = recsize;
-       char *buf = *pbuf;
+       uschar *buf = *pbuf;
        int bufsize = *pbufsize;
+#define FMTSZ(a)   (fmtsz - ((a) - fmt))
+#define BUFSZ(a)   (bufsize - ((a) - buf))
 
        os = s;
        p = buf;
-       if ((fmt = (char *) malloc(fmtsz)) == NULL)
+       if ((fmt = malloc(fmtsz)) == NULL)
                FATAL("out of memory in format()");
        while (*s) {
                adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
@@ -839,12 +852,18 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a)    /* printf-like co
                for (t = fmt; (*t++ = *s) != '\0'; s++) {
                        if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
                                FATAL("format item %.30s... ran format() out of memory", os);
-                       if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
+                       if (*s == 'l' || *s == 'h' || *s == 'L')
+                               goto weird;
+                       if (isalpha((uschar)*s))
                                break;  /* the ansi panoply */
                        if (*s == '*') {
+                               if (a == NULL)
+                                       FATAL("not enough args in printf("
+                                           "\"%.30s\")", os);
                                x = execute(a);
                                a = a->nnext;
-                               sprintf(t-1, "%d", fmtwd=(int) getfval(x));
+                               snprintf(t - 1, FMTSZ(t - 1), 
+                                   "%d", fmtwd=(int) getfval(x));
                                if (fmtwd < 0)
                                        fmtwd = -fmtwd;
                                adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
@@ -864,12 +883,15 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a)    /* printf-like co
                case 'd': case 'i':
                        flag = 'd';
                        if(*(s-1) == 'l') break;
-                       *(t-1) = 'l';
+                       *(t-1) = 'j';
                        *t = 'd';
                        *++t = '\0';
                        break;
                case 'o': case 'x': case 'X': case 'u':
                        flag = *(s-1) == 'l' ? 'd' : 'u';
+                       *(t-1) = 'j';
+                       *t = *s;
+                       *++t = '\0';
                        break;
                case 's':
                        flag = 's';
@@ -878,6 +900,7 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a)      /* printf-like co
                        flag = 'c';
                        break;
                default:
+               weird:
                        WARNING("weird printf conversion %s", fmt);
                        flag = '?';
                        break;
@@ -891,18 +914,18 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a)    /* printf-like co
                        n = fmtwd;
                adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
                switch (flag) {
-               case '?':       sprintf(p, "%s", fmt);  /* unknown, so dump it too */
+               case '?':       snprintf(p, BUFSZ(p), "%s", fmt);       /* unknown, so dump it too */
                        t = getsval(x);
                        n = strlen(t);
                        if (fmtwd > n)
                                n = fmtwd;
                        adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
                        p += strlen(p);
-                       sprintf(p, "%s", t);
+                       snprintf(p, BUFSZ(p), "%s", t);
                        break;
-               case 'f':       sprintf(p, fmt, getfval(x)); break;
-               case 'd':       sprintf(p, fmt, (long) getfval(x)); break;
-               case 'u':       sprintf(p, fmt, (int) getfval(x)); break;
+               case 'f':       snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
+               case 'd':       snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
+               case 'u':       snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
                case 's':
                        t = getsval(x);
                        n = strlen(t);
@@ -910,18 +933,18 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a)    /* printf-like co
                                n = fmtwd;
                        if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
                                FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
-                       sprintf(p, fmt, t);
+                       snprintf(p, BUFSZ(p), fmt, t);
                        break;
                case 'c':
                        if (isnum(x)) {
                                if (getfval(x))
-                                       sprintf(p, fmt, (int) getfval(x));
+                                       snprintf(p, BUFSZ(p), fmt, (int) getfval(x));
                                else {
                                        *p++ = '\0'; /* explicit null byte */
                                        *p = '\0';   /* next output will start here */
                                }
                        } else
-                               sprintf(p, fmt, getsval(x)[0]);
+                               snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
                        break;
                default:
                        FATAL("can't happen: bad conversion %c in format()", flag);
@@ -946,7 +969,7 @@ Cell *awksprintf(Node **a, int n)           /* sprintf(a[0]) */
        char *buf;
        int bufsz=3*recsize;
 
-       if ((buf = (char *) malloc(bufsz)) == NULL)
+       if ((buf = malloc(bufsz)) == NULL)
                FATAL("out of memory in awksprintf");
        y = a[0]->nnext;
        x = execute(a[0]);
@@ -969,7 +992,7 @@ Cell *awkprintf(Node **a, int n)            /* printf */
        int len;
        int bufsz=3*recsize;
 
-       if ((buf = (char *) malloc(bufsz)) == NULL)
+       if ((buf = malloc(bufsz)) == NULL)
                FATAL("out of memory in awkprintf");
        y = a[0]->nnext;
        x = execute(a[0]);
@@ -1153,7 +1176,7 @@ Cell *cat(Node **a, int q)        /* a[0] cat a[1] */
        getsval(y);
        n1 = strlen(x->sval);
        n2 = strlen(y->sval);
-       s = (char *) malloc(n1 + n2 + 1);
+       s = malloc(n1 + n2 + 1);
        if (s == NULL)
                FATAL("out of space concatenating %.15s... and %.15s...",
                        x->sval, y->sval);
@@ -1206,6 +1229,7 @@ Cell *dopa2(Node **a, int n)      /* a[0], a[1] { a[2] } */
        return(False);
 }
 
+static char regexpr[] = "(regexpr)";
 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
 {
        Cell *x = 0, *y, *ap;
@@ -1223,7 +1247,7 @@ Cell *split(Node **a, int nnn)    /* split(a[0], a[1], a[2]); a[3] is type */
                x = execute(a[2]);
                fs = getsval(x);
        } else if (arg3type == REGEXPR)
-               fs = "(regexpr)";       /* split(str,arr,/regexpr/) */
+               fs = regexpr;   /* split(str,arr,/regexpr/) */
        else
                FATAL("illegal type of split");
        sep = *fs;
@@ -1247,7 +1271,7 @@ Cell *split(Node **a, int nnn)    /* split(a[0], a[1], a[2]); a[3] is type */
                        pfa->initstat = 2;
                        do {
                                n++;
-                               sprintf(num, "%d", n);
+                               snprintf(num, sizeof(num), "%d", n);
                                temp = *patbeg;
                                *patbeg = '\0';
                                if (is_number(s))
@@ -1258,7 +1282,7 @@ Cell *split(Node **a, int nnn)    /* split(a[0], a[1], a[2]); a[3] is type */
                                s = patbeg + patlen;
                                if (*(patbeg+patlen-1) == 0 || *s == 0) {
                                        n++;
-                                       sprintf(num, "%d", n);
+                                       snprintf(num, sizeof(num), "%d", n);
                                        setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
                                        pfa->initstat = tempstat;
                                        goto spdone;
@@ -1268,7 +1292,7 @@ Cell *split(Node **a, int nnn)    /* split(a[0], a[1], a[2]); a[3] is type */
                                                        /* cf gsub and refldbld */
                }
                n++;
-               sprintf(num, "%d", n);
+               snprintf(num, sizeof(num), "%d", n);
                if (is_number(s))
                        setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
                else
@@ -1288,7 +1312,7 @@ Cell *split(Node **a, int nnn)    /* split(a[0], a[1], a[2]); a[3] is type */
                        while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
                        temp = *s;
                        *s = '\0';
-                       sprintf(num, "%d", n);
+                       snprintf(num, sizeof(num), "%d", n);
                        if (is_number(t))
                                setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
                        else
@@ -1301,7 +1325,7 @@ Cell *split(Node **a, int nnn)    /* split(a[0], a[1], a[2]); a[3] is type */
                for (n = 0; *s != 0; s++) {
                        char buf[2];
                        n++;
-                       sprintf(num, "%d", n);
+                       snprintf(num, sizeof(num), "%d", n);
                        buf[0] = *s;
                        buf[1] = 0;
                        if (isdigit((uschar)buf[0]))
@@ -1317,7 +1341,7 @@ Cell *split(Node **a, int nnn)    /* split(a[0], a[1], a[2]); a[3] is type */
                                s++;
                        temp = *s;
                        *s = '\0';
-                       sprintf(num, "%d", n);
+                       snprintf(num, sizeof(num), "%d", n);
                        if (is_number(t))
                                setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
                        else
@@ -1461,15 +1485,78 @@ Cell *instat(Node **a, int n)   /* for (a[0] in a[1]) a[2] */
        return True;
 }
 
+void flush_all(void);
+
+static char *nawk_toXXX(const char *s,
+                       int (*fun_c)(int),
+                       wint_t (*fun_wc)(wint_t))
+{
+       char *buf      = NULL;
+       char *pbuf     = NULL;
+       const char *ps = NULL;
+       size_t n       = 0;
+       mbstate_t mbs, mbs2;
+       wchar_t wc;
+       size_t sz = MB_CUR_MAX;
+
+       if (sz == 1) {
+               buf = tostring(s);
+
+               for (pbuf = buf; *pbuf; pbuf++)
+                       *pbuf = fun_c((uschar)*pbuf);
+
+               return buf;
+       } else {
+               /* upper/lower character may be shorter/longer */
+               buf = tostringN(s, strlen(s) * sz + 1);
+
+               memset(&mbs,  0, sizeof(mbs));
+               memset(&mbs2, 0, sizeof(mbs2));
+
+               ps   = s;
+               pbuf = buf;
+               while (n = mbrtowc(&wc, ps, sz, &mbs),
+                      n > 0 && n != (size_t)-1 && n != (size_t)-2)
+               {
+                       ps += n;
+
+                       n = wcrtomb(pbuf, fun_wc(wc), &mbs2);
+                       if (n == (size_t)-1)
+                               FATAL("illegal wide character %s", s);
+
+                       pbuf += n;
+               }
+
+               *pbuf = 0;
+
+               if (n)
+                       FATAL("illegal byte sequence %s", s);
+
+               return buf;
+       }
+}
+
+static char *nawk_toupper(const char *s)
+{
+       return nawk_toXXX(s, toupper, towupper);
+}
+
+static char *nawk_tolower(const char *s)
+{
+       return nawk_toXXX(s, tolower, towlower);
+}
+
 Cell *bltin(Node **a, int n)   /* builtin functions. a[0] is type, a[1] is arg list */
 {
        Cell *x, *y;
        Awkfloat u;
-       int t;
-       char *p, *buf;
+       int t, sz;
+       unsigned int tmp;
+       char *buf, *fmt;
        Node *nextarg;
        FILE *fp;
-       void flush_all(void);
+       time_t tv;
+       struct tm *tm;
 
        t = ptoi(a[0]);
        x = execute(a[1]);
@@ -1517,20 +1604,16 @@ Cell *bltin(Node **a, int n)    /* builtin functions. a[0] is type, a[1] is arg lis
                        u = time((time_t *)0);
                else
                        u = getfval(x);
-               srand((unsigned int) u);
+               srand(tmp = (unsigned int) u);
+               u = srand_seed;
+               srand_seed = tmp;
                break;
        case FTOUPPER:
        case FTOLOWER:
-               buf = tostring(getsval(x));
-               if (t == FTOUPPER) {
-                       for (p = buf; *p; p++)
-                               if (islower((uschar) *p))
-                                       *p = toupper((uschar)*p);
-               } else {
-                       for (p = buf; *p; p++)
-                               if (isupper((uschar) *p))
-                                       *p = tolower((uschar)*p);
-               }
+               if (t == FTOUPPER)
+                       buf = nawk_toupper(getsval(x));
+               else
+                       buf = nawk_tolower(getsval(x));
                tempfree(x);
                x = gettemp();
                setsval(x, buf);
@@ -1540,11 +1623,41 @@ Cell *bltin(Node **a, int n)    /* builtin functions. a[0] is type, a[1] is arg lis
                if (isrec(x) || strlen(getsval(x)) == 0) {
                        flush_all();    /* fflush() or fflush("") -> all */
                        u = 0;
-               } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
-                       u = EOF;
+               } else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
+                       u = -1;
                else
                        u = fflush(fp);
                break;
+       case FSYSTIME:
+               u = time((time_t *) 0); break;
+       case FSTRFTIME:
+               /* strftime([format [,timestamp]]) */
+               if (nextarg) {
+                       y = execute(nextarg), nextarg = nextarg->nnext;
+                       tv = (time_t) getfval(y);
+                       tempfree(y);
+               } else
+                       tv = time((time_t *) 0);
+               tm = localtime(&tv);
+
+               if (isrec(x)) {
+                       /* format argument not provided, use default */
+                       fmt = tostring("%a %b %d %H:%M:%S %Z %Y");
+               } else
+                       fmt = tostring(getsval(x));
+
+               sz = 32, buf = NULL;
+               do {
+                       if ((buf = realloc(buf, (sz *= 2))) == NULL)
+                               FATAL("out of memory in strftime");
+               } while(strftime(buf, sz, fmt, tm) == 0);
+
+               y = gettemp();
+               setsval(y, buf);
+               free(fmt);
+               free(buf);
+
+               return y;
        default:        /* can't happen */
                FATAL("illegal function type %d", t);
                break;
@@ -1602,7 +1715,7 @@ FILE *redirect(int a, Node *b)    /* set up all i/o redirections */
 
        x = execute(b);
        fname = getsval(x);
-       fp = openfile(a, fname);
+       fp = openfile(a, fname, NULL);
        if (fp == NULL)
                FATAL("can't open file %s", fname);
        tempfree(x);
@@ -1613,42 +1726,59 @@ struct files {
        FILE    *fp;
        const char      *fname;
        int     mode;   /* '|', 'a', 'w' => LE/LT, GT */
-} files[FOPEN_MAX] ={
-       { NULL,  "/dev/stdin",  LT },   /* watch out: don't free this! */
-       { NULL, "/dev/stdout", GT },
-       { NULL, "/dev/stderr", GT }
-};
+} *files;
+size_t nfiles;
 
 void stdinit(void)     /* in case stdin, etc., are not constants */
 {
+       nfiles = FOPEN_MAX;
+       files = calloc(nfiles, sizeof(*files));
+       if (files == NULL)
+               FATAL("can't allocate file memory for %zu files", nfiles);
        files[0].fp = stdin;
+       files[0].fname = "/dev/stdin";
+       files[0].mode = LT;
        files[1].fp = stdout;
+       files[1].fname = "/dev/stdout";
+       files[1].mode = GT;
        files[2].fp = stderr;
+       files[2].fname = "/dev/stderr";
+       files[2].mode = GT;
 }
 
-FILE *openfile(int a, const char *us)
+FILE *openfile(int a, const char *us, int *pnewflag)
 {
        const char *s = us;
-       int i, m;
+       size_t i;
+       int m;
        FILE *fp = 0;
 
        if (*s == '\0')
                FATAL("null file name in print or getline");
-       for (i=0; i < FOPEN_MAX; i++)
-               if (files[i].fname && strcmp(s, files[i].fname) == 0) {
-                       if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
-                               return files[i].fp;
-                       if (a == FFLUSH)
-                               return files[i].fp;
+       for (i = 0; i < nfiles; i++)
+               if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
+                   (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
+                    a == FFLUSH)) {
+                       if (pnewflag)
+                               *pnewflag = 0;
+                       return files[i].fp;
                }
        if (a == FFLUSH)        /* didn't find it, so don't create it! */
                return NULL;
 
-       for (i=0; i < FOPEN_MAX; i++)
-               if (files[i].fp == 0)
+       for (i = 0; i < nfiles; i++)
+               if (files[i].fp == NULL)
                        break;
-       if (i >= FOPEN_MAX)
-               FATAL("%s makes too many open files", s);
+       if (i >= nfiles) {
+               struct files *nf;
+               size_t nnf = nfiles + FOPEN_MAX;
+               nf = realloc(files, nnf * sizeof(*nf));
+               if (nf == NULL)
+                       FATAL("cannot grow files for %s and %zu files", s, nnf);
+               (void)memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
+               nfiles = nnf;
+               files = nf;
+       }
        fflush(stdout); /* force a semblance of order */
        m = a;
        if (a == GT) {
@@ -1668,15 +1798,17 @@ FILE *openfile(int a, const char *us)
                files[i].fname = tostring(s);
                files[i].fp = fp;
                files[i].mode = m;
+               if (pnewflag)
+                       *pnewflag = 1;
        }
        return fp;
 }
 
 const char *filename(FILE *fp)
 {
-       int i;
+       size_t i;
 
-       for (i = 0; i < FOPEN_MAX; i++)
+       for (i = 0; i < nfiles; i++)
                if (fp == files[i].fp)
                        return files[i].fname;
        return "???";
@@ -1685,24 +1817,28 @@ const char *filename(FILE *fp)
 Cell *closefile(Node **a, int n)
 {
        Cell *x;
-       int i, stat;
+       size_t i;
+       int stat;
 
        n = n;
        x = execute(a[0]);
        getsval(x);
        stat = -1;
-       for (i = 0; i < FOPEN_MAX; i++) {
+       for (i = 0; i < nfiles; i++) {
                if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
                        if (ferror(files[i].fp))
                                WARNING( "i/o error occurred on %s", files[i].fname );
                        if (files[i].mode == '|' || files[i].mode == LE)
-                               stat = pclose(files[i].fp);
+                               stat = pclose(files[i].fp) == -1;
                        else
-                               stat = fclose(files[i].fp);
-                       if (stat == EOF)
-                               WARNING( "i/o error occurred closing %s", files[i].fname );
+                               stat = fclose(files[i].fp) == EOF;
+                       if (stat) {
+                               stat = -1;
+                               WARNING( "i/o error occurred closing %s",
+                                   files[i].fname );
+                       }
                        if (i > 2)      /* don't do /dev/std... */
-                               xfree(files[i].fname);
+                               free(__UNCONST(files[i].fname));
                        files[i].fname = NULL;  /* watch out for ref thru this */
                        files[i].fp = NULL;
                }
@@ -1715,17 +1851,22 @@ Cell *closefile(Node **a, int n)
 
 void closeall(void)
 {
-       int i, stat;
+       size_t i;
+       int stat;
 
-       for (i = 0; i < FOPEN_MAX; i++) {
+       for (i = 0; i < nfiles; i++) {
                if (files[i].fp) {
                        if (ferror(files[i].fp))
                                WARNING( "i/o error occurred on %s", files[i].fname );
-                       if (files[i].mode == '|' || files[i].mode == LE)
-                               stat = pclose(files[i].fp);
+                       if (i == 0)
+                               stat = fpurge(files[i].fp) == EOF;
+                       else if (i <= 2)
+                               stat = fflush(files[i].fp) == EOF;
+                       else if (files[i].mode == '|' || files[i].mode == LE)
+                               stat = pclose(files[i].fp) == -1;
                        else
-                               stat = fclose(files[i].fp);
-                       if (stat == EOF)
+                               stat = fclose(files[i].fp) == EOF;
+                       if (stat)
                                WARNING( "i/o error occurred while closing %s", files[i].fname );
                }
        }
@@ -1733,24 +1874,25 @@ void closeall(void)
 
 void flush_all(void)
 {
-       int i;
+       size_t i;
 
-       for (i = 0; i < FOPEN_MAX; i++)
+       for (i = 0; i < nfiles; i++)
                if (files[i].fp)
                        fflush(files[i].fp);
 }
 
-void backsub(char **pb_ptr, char **sptr_ptr);
+void backsub(uschar **pb_ptr, const uschar **sptr_ptr);
 
 Cell *sub(Node **a, int nnn)   /* substitute command */
 {
-       char *sptr, *pb, *q;
+       const uschar *sptr;
+       uschar *q;
        Cell *x, *y, *result;
-       char *t, *buf;
+       uschar *t, *buf, *pb;
        fa *pfa;
        int bufsz = recsize;
 
-       if ((buf = (char *) malloc(bufsz)) == NULL)
+       if ((buf = malloc(bufsz)) == NULL)
                FATAL("out of memory in sub");
        x = execute(a[3]);      /* target string */
        t = getsval(x);
@@ -1805,13 +1947,15 @@ Cell *sub(Node **a, int nnn)    /* substitute command */
 Cell *gsub(Node **a, int nnn)  /* global substitute */
 {
        Cell *x, *y;
-       char *rptr, *sptr, *t, *pb, *q;
-       char *buf;
+       const char *rptr;
+       const uschar *sptr;
+       uschar *t, *q;
+       uschar *pb, *buf;
        fa *pfa;
        int mflag, tempstat, num;
        int bufsz = recsize;
 
-       if ((buf = (char *) malloc(bufsz)) == NULL)
+       if ((buf = malloc(bufsz)) == NULL)
                FATAL("out of memory in gsub");
        mflag = 0;      /* if mflag == 0, can replace empty string */
        num = 0;
@@ -1887,9 +2031,10 @@ Cell *gsub(Node **a, int nnn)    /* global substitute */
                adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
                while ((*pb++ = *sptr++) != 0)
                        ;
-       done:   if (pb > buf + bufsz)
-                       FATAL("gsub result2 %.30s too big; can't happen", buf);
-               *pb = '\0';
+       done:   if (pb < buf + bufsz)
+                       *pb = '\0';
+               else if (*(pb-1) != '\0')
+                       FATAL("gsub result2 %.30s truncated; can't happen", buf);
                setsval(x, buf);        /* BUG: should be able to avoid copy + free */
                pfa->initstat = tempstat;
        }
@@ -1902,9 +2047,149 @@ Cell *gsub(Node **a, int nnn)   /* global substitute */
        return(x);
 }
 
-void backsub(char **pb_ptr, char **sptr_ptr)   /* handle \\& variations */
+Cell *gensub(Node **a, int nnn)        /* global selective substitute */
+       /* XXX incomplete - doesn't support backreferences \0 ... \9 */
+{
+       Cell *x, *y, *res, *h;
+       char *rptr;
+       const uschar *sptr;
+       uschar *q, *pb, *t, *buf;
+       fa *pfa;
+       int mflag, tempstat, num, whichm;
+       int bufsz = recsize;
+
+       if ((buf = malloc(bufsz)) == NULL)
+               FATAL("out of memory in gensub");
+       mflag = 0;      /* if mflag == 0, can replace empty string */
+       num = 0;
+       x = execute(a[4]);      /* source string */
+       t = getsval(x);
+       res = copycell(x);      /* target string - initially copy of source */
+       if (a[0] == 0)          /* 0 => a[1] is already-compiled regexpr */
+               pfa = (fa *) a[1];      /* regular expression */
+       else {
+               y = execute(a[1]);
+               pfa = makedfa(getsval(y), 1);
+               tempfree(y);
+       }
+       y = execute(a[2]);      /* replacement string */
+       h = execute(a[3]);      /* which matches should be replaced */
+       sptr = getsval(h);
+       if (sptr[0] == 'g' || sptr[0] == 'G')
+               whichm = -1;
+       else {
+               /*
+                * The specified number is index of replacement, starting
+                * from 1. GNU awk treats index lower than 0 same as
+                * 1, we do same for compatibility.
+                */
+               whichm = (int) getfval(h) - 1;
+               if (whichm < 0)
+                       whichm = 0;
+       }
+       tempfree(h);
+
+       if (pmatch(pfa, t)) {
+               char *sl;
+
+               tempstat = pfa->initstat;
+               pfa->initstat = 2;
+               pb = buf;
+               rptr = getsval(y);
+               /*
+                * XXX if there are any backreferences in subst string,
+                * complain now.
+                */
+               for(sl=rptr; (sl = strchr(sl, '\\')) && sl[1]; sl++) {
+                       if (strchr("0123456789", sl[1])) {
+                               FATAL("gensub doesn't support backreferences (subst \"%s\")", rptr);
+                       }
+               }
+               
+               do {
+                       if (whichm >= 0 && whichm != num) {
+                               num++;
+                               adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - t) + patlen, recsize, &pb, "gensub");
+
+                               /* copy the part of string up to and including
+                                * match to output buffer */
+                               while (t < patbeg + patlen)
+                                       *pb++ = *t++;
+                               continue;
+                       }
+
+                       if (patlen == 0 && *patbeg != 0) {      /* matched empty string */
+                               if (mflag == 0) {       /* can replace empty */
+                                       num++;
+                                       sptr = rptr;
+                                       while (*sptr != 0) {
+                                               adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub");
+                                               if (*sptr == '\\') {
+                                                       backsub(&pb, &sptr);
+                                               } else if (*sptr == '&') {
+                                                       sptr++;
+                                                       adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub");
+                                                       for (q = patbeg; q < patbeg+patlen; )
+                                                               *pb++ = *q++;
+                                               } else
+                                                       *pb++ = *sptr++;
+                                       }
+                               }
+                               if (*t == 0)    /* at end */
+                                       goto done;
+                               adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gensub");
+                               *pb++ = *t++;
+                               if (pb > buf + bufsz)   /* BUG: not sure of this test */
+                                       FATAL("gensub result0 %.30s too big; can't happen", buf);
+                               mflag = 0;
+                       }
+                       else {  /* matched nonempty string */
+                               num++;
+                               sptr = t;
+                               adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gensub");
+                               while (sptr < patbeg)
+                                       *pb++ = *sptr++;
+                               sptr = rptr;
+                               while (*sptr != 0) {
+                                       adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub");
+                                       if (*sptr == '\\') {
+                                               backsub(&pb, &sptr);
+                                       } else if (*sptr == '&') {
+                                               sptr++;
+                                               adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub");
+                                               for (q = patbeg; q < patbeg+patlen; )
+                                                       *pb++ = *q++;
+                                       } else
+                                               *pb++ = *sptr++;
+                               }
+                               t = patbeg + patlen;
+                               if (patlen == 0 || *t == 0 || *(t-1) == 0)
+                                       goto done;
+                               if (pb > buf + bufsz)
+                                       FATAL("gensub result1 %.30s too big; can't happen", buf);
+                               mflag = 1;
+                       }
+               } while (pmatch(pfa,t));
+               sptr = t;
+               adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gensub");
+               while ((*pb++ = *sptr++) != 0)
+                       ;
+       done:   if (pb > buf + bufsz)
+                       FATAL("gensub result2 %.30s too big; can't happen", buf);
+               *pb = '\0';
+               setsval(res, buf);
+               pfa->initstat = tempstat;
+       }
+       tempfree(x);
+       tempfree(y);
+       free(buf);
+       return(res);
+}
+
+void backsub(uschar **pb_ptr, const uschar **sptr_ptr)/* handle \\& variations */
 {                                              /* sptr[0] == '\\' */
-       char *pb = *pb_ptr, *sptr = *sptr_ptr;
+       uschar *pb = *pb_ptr;
+       const uschar *sptr = *sptr_ptr;
 
        if (sptr[1] == '\\') {
                if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
similarity index 87%
rename from commands/awk/tran.c
rename to external/historical/nawk/dist/tran.c
index 24affc10493466930969b23fdbca46dd6960dd2d..0651cc9465fe18ed8a58a6b8ca5a199c8e7681f1 100644 (file)
@@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 THIS SOFTWARE.
 ****************************************************************/
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
 #define        DEBUG
 #include <stdio.h>
 #include <math.h>
@@ -108,7 +112,7 @@ void arginit(int ac, char **av)     /* set up ARGV and ARGC */
        ARGVtab = makesymtab(NSYMTAB);  /* could be (int) ARGC as well */
        cp->sval = (char *) ARGVtab;
        for (i = 0; i < ac; i++) {
-               sprintf(temp, "%d", i);
+               snprintf(temp, sizeof(temp), "%d", i);
                if (is_number(*av))
                        setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
                else
@@ -144,8 +148,8 @@ Array *makesymtab(int n)    /* make a new symbol table */
        Array *ap;
        Cell **tp;
 
-       ap = (Array *) malloc(sizeof(Array));
-       tp = (Cell **) calloc(n, sizeof(Cell *));
+       ap = malloc(sizeof(*ap));
+       tp = calloc(n, sizeof(*tp));
        if (ap == NULL || tp == NULL)
                FATAL("out of space in makesymtab");
        ap->nelem = 0;
@@ -154,7 +158,7 @@ Array *makesymtab(int n)    /* make a new symbol table */
        return(ap);
 }
 
-void freesymtab(const Cell *ap)        /* free a symbol table */
+void freesymtab(Cell *ap)      /* free a symbol table */
 {
        Cell *cp, *temp;
        Array *tp;
@@ -182,8 +186,7 @@ void freesymtab(const Cell *ap)     /* free a symbol table */
        free(tp);
 }
 
-void freeelem(const Cell *ap, const char *s)
-/* free elem s from ap (i.e., ap["s"] */
+void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
 {
        Array *tp;
        Cell *p, *prev = NULL;
@@ -211,12 +214,15 @@ Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
        int h;
        Cell *p;
 
-       if (n != NULL && (p = lookup(n, tp)) != NULL) {
+       if (n == NULL)
+               n = "";
+
+       if ((p = lookup(n, tp)) != NULL) {
                   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
                        p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
                return(p);
        }
-       p = (Cell *) malloc(sizeof(Cell));
+       p = malloc(sizeof(*p));
        if (p == NULL)
                FATAL("out of space for symbol table at %s", n);
        p->nval = tostring(n);
@@ -251,7 +257,7 @@ void rehash(Array *tp)      /* rehash items in small table into big one */
        Cell *cp, *op, **np;
 
        nsz = GROWTAB * tp->size;
-       np = (Cell **) calloc(nsz, sizeof(Cell *));
+       np = calloc(nsz, sizeof(*np));
        if (np == NULL)         /* can't do it, but can keep running. */
                return;         /* someone else will run out later. */
        for (i = 0; i < tp->size; i++) {
@@ -267,7 +273,7 @@ void rehash(Array *tp)      /* rehash items in small table into big one */
        tp->size = nsz;
 }
 
-Cell *lookup(const char *s, const Array *tp)   /* look for s in tp */
+Cell *lookup(const char *s, Array *tp) /* look for s in tp */
 {
        Cell *p;
        int h;
@@ -283,6 +289,7 @@ Awkfloat setfval(Cell *vp, Awkfloat f)      /* set float val of a Cell */
 {
        int fldno;
 
+       f += 0.0;               /* normalise negative zero to positive zero */
        if ((vp->tval & (NUM | STR)) == 0) 
                funnyvar(vp, "assign to");
        if (isfld(vp)) {
@@ -291,6 +298,10 @@ Awkfloat setfval(Cell *vp, Awkfloat f)     /* set float val of a Cell */
                if (fldno > *NF)
                        newfld(fldno);
                   dprintf( ("setting field %d to %g\n", fldno, f) );
+       } else if (&vp->fval == NF) {
+               donerec = 0;    /* mark $0 invalid */
+               setlastfld(f);
+               dprintf( ("setting NF to %g\n", f) );
        } else if (isrec(vp)) {
                donefld = 0;    /* mark $1... invalid */
                donerec = 1;
@@ -317,6 +328,7 @@ char *setsval(Cell *vp, const char *s)      /* set string val of a Cell */
 {
        char *t;
        int fldno;
+       Awkfloat f;
 
           dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 
                vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
@@ -340,7 +352,16 @@ char *setsval(Cell *vp, const char *s)     /* set string val of a Cell */
        vp->tval &= ~DONTFREE;
           dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 
                vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
-       return(vp->sval = t);
+
+       vp->sval = t;
+       if (&vp->fval == NF) {
+               donerec = 0;    /* mark $0 invalid */
+               f = getfval(vp);
+               setlastfld(f);
+               dprintf( ("setting NF to %g\n", f) );
+       }
+
+       return(vp->sval);
 }
 
 Awkfloat getfval(Cell *vp)     /* get float val of a Cell */
@@ -360,10 +381,9 @@ Awkfloat getfval(Cell *vp) /* get float val of a Cell */
        return(vp->fval);
 }
 
-static char *get_str_val(Cell *vp, char **fmt)
-/* get string val of a Cell */
+static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
 {
-       char s[100];    /* BUG: unchecked */
+       char s[100];
        double dtemp;
 
        if ((vp->tval & (NUM | STR)) == 0)
@@ -376,9 +396,9 @@ static char *get_str_val(Cell *vp, char **fmt)
                if (freeable(vp))
                        xfree(vp->sval);
                if (modf(vp->fval, &dtemp) == 0)        /* it's integral */
-                       sprintf(s, "%.30g", vp->fval);
+                       snprintf(s, sizeof(s), "%.30g", vp->fval);
                else
-                       sprintf(s, *fmt, vp->fval);
+                       snprintf(s, sizeof(s), *fmt, vp->fval);
                vp->sval = tostring(s);
                vp->tval &= ~DONTFREE;
                vp->tval |= STR;
@@ -402,7 +422,33 @@ char *tostring(const char *s)      /* make a copy of string s */
 {
        char *p;
 
-       p = (char *) malloc(strlen(s)+1);
+       p = strdup(s);
+       if (p == NULL)
+               FATAL("out of space in tostring on %s", s);
+       return(p);
+}
+
+Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
+{
+       Cell *c;
+       char *p;
+       char *sa = getsval(a);
+       char *sb = getsval(b);
+       size_t l = strlen(sa) + strlen(sb) + 1;
+       p = malloc(l);
+       if (p == NULL)
+               FATAL("out of space concatenating %s and %s", sa, sb);
+       snprintf(p, l, "%s%s", sa, sb);
+       c = setsymtab(p, p, 0.0, CON|STR|DONTFREE, symtab);
+       free(p);
+       return c;
+}
+
+char *tostringN(const char *s, size_t n)       /* make a copy of string s */
+{
+       char *p;
+
+       p = malloc(n);
        if (p == NULL)
                FATAL("out of space in tostring on %s", s);
        strcpy(p, s);
@@ -413,10 +459,10 @@ char *qstring(const char *is, int delim)  /* collect string up to next delim */
 {
        const char *os = is;
        int c, n;
-       uschar *s = (uschar *) is;
+       const uschar *s = (const uschar *) is;
        uschar *buf, *bp;
 
-       if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
+       if ((buf = malloc(strlen(is)+3)) == NULL)
                FATAL( "out of space in qstring(%s)", s);
        for (bp = buf; (c = *s) != delim; s++) {
                if (c == '\n')