.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 \
+++ /dev/null
-.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>
-SUBDIR=bsd
+SUBDIR=bsd historical
.include <bsd.subdir.mk>
--- /dev/null
+# $NetBSD: Makefile,v 1.1 2010/08/26 14:57:15 christos Exp $
+
+.include <bsd.own.mk>
+
+SUBDIR+= nawk
+
+.include <bsd.subdir.mk>
--- /dev/null
+# $NetBSD: Makefile,v 1.1 2010/08/26 14:57:16 christos Exp $
+
+SUBDIR+= bin
+
+.include <bsd.subdir.mk>
--- /dev/null
+# $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>
--- /dev/null
+$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; }
--- /dev/null
+.\" $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.
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.
#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;
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 */
#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 */
#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 {
} 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;
****************************************************************/
%{
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
#include <stdio.h>
#include <string.h>
#include "awk.h"
%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 '?'
%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
SUB | GSUB
;
+string:
+ STRING
+ | string STRING { $$ = catstr($1, $2); }
+ ;
+
term:
term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); }
| term '+' term { $$ = op2(ADD, $1, $3); }
| 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); }
| 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 ')'
/* 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"
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);
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);
{
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];
}
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;
}
/* 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')
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')
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++;
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);
}
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;
}
}
-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;
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);
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++)
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 {
s = ns;
else
s = cgoto(f, s, *p);
+
+ assert (s < f->state_count);
+
if (f->out[s])
return(1);
} while (*p++ != 0);
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;
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
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);
}
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;
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 */
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') {
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 '^':
*/
/* #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 },
static uschar *buf = 0;
static int bufsz = 100;
uschar *bp;
- struct charclass *cc;
+ const struct charclass *cc;
int i;
switch (c = *prestr++) {
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 == '^') {
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++) == '\\') {
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;
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++) {
|| (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;
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];
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])
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);
}
THIS SOFTWARE.
****************************************************************/
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 },
{ "for", FOR, FOR },
{ "func", FUNC, FUNC },
{ "function", FUNC, FUNC },
+ { "gensub", GENSUB, GENSUB },
{ "getline", GETLINE, GETLINE },
{ "gsub", GSUB, GSUB },
{ "if", IF, IF },
{ "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 },
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)
}
*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 */
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;
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"))
case '\\':
c = input();
switch (c) {
+ case '\n': break;
case '"': *bp++ = '"'; break;
case 'n': *bp++ = '\n'; break;
case 't': *bp++ = '\t'; break;
break;
}
- default:
+ default:
+ WARNING("warning: escape sequence `\\%c' "
+ "treated as plain `%c'", c, c);
*bp++ = c;
break;
}
int word(char *w)
{
- Keyword *kp;
+ const Keyword *kp;
int c, n;
n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
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; ) {
THIS SOFTWARE.
****************************************************************/
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
#define DEBUG
#include <stdio.h>
#include <string.h>
#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 */
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;
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);
}
}
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;
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]))
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] */
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) );
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; ; ) {
}
}
setfval(nfloc, (Awkfloat) lastfld);
+ donerec = 1; /* restore */
if (dbg) {
for (j = 0; j <= lastfld; j++) {
p = fldtab[j];
p = fldtab[i];
if (freeable(p))
xfree(p->sval);
- p->sval = "";
+ p->sval = EMPTY;
p->tval = FLD | STR | DONTFREE;
}
}
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)
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)
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;
}
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 {
void recbld(void) /* create $0 from $1..$NF if necessary */
{
int i;
- char *r, *p;
+ uschar *r;
+ char *p;
if (donerec == 1)
return;
eprint();
}
-void fpecatch(int n)
-{
- FATAL("floating point exception %d", n);
-}
-
extern int bracecnt, brackcnt, parencnt;
void bracecheck(void)
void eprint(void) /* try to print context around error */
{
char *p, *q;
- int c;
static int been_here = 0;
extern char ebuf[], *ep;
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;
}
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++;
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>
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 */
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) {
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') {
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");
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]);
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) );
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
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
@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
/*
* 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>
{ ARG, "arg", "arg" },
{ VARNF, "getnf", "NF" },
{ GETLINE, "awkgetline", "getline" },
+ { GENSUB, "gensub", "gensub" },
{ 0, "", "" },
};
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");
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");
THIS SOFTWARE.
****************************************************************/
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
#define DEBUG
#include <stdio.h>
#include <string.h>
{
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;
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;
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;
--- /dev/null
+#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];
+}
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);
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);
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);
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 *);
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);
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);
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 *);
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
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
/* 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)
void run(Node *a) /* execution of parse tree starts here */
{
- extern void stdinit(void);
-
stdinit();
execute(a);
closeall();
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;
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",
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) {
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);
}
{
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;
}
{
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 */
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);
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 */
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 */
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 */
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)) {
{
Cell *x, *y;
Node *np;
- char *s;
+ uschar *s;
int nsub = strlen(*SUBSEP);
x = execute(a[0]); /* Cell* for symbol table */
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) {
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);
{
Cell *x, *ap, *k;
Node *p;
- char *buf;
+ uschar *buf;
char *s;
int bufsz = recsize;
int nsub = strlen(*SUBSEP);
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;
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;
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++)
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");
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");
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';
flag = 'c';
break;
default:
+ weird:
WARNING("weird printf conversion %s", fmt);
flag = '?';
break;
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);
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);
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]);
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]);
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);
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;
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;
pfa->initstat = 2;
do {
n++;
- sprintf(num, "%d", n);
+ snprintf(num, sizeof(num), "%d", n);
temp = *patbeg;
*patbeg = '\0';
if (is_number(s))
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;
/* 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
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
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]))
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
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]);
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);
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;
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);
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) {
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 "???";
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;
}
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 );
}
}
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);
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;
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;
}
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] == '&') { /* \\\& -> \& */
THIS SOFTWARE.
****************************************************************/
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
#define DEBUG
#include <stdio.h>
#include <math.h>
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
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;
return(ap);
}
-void freesymtab(const Cell *ap) /* free a symbol table */
+void freesymtab(Cell *ap) /* free a symbol table */
{
Cell *cp, *temp;
Array *tp;
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;
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);
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++) {
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;
{
int fldno;
+ f += 0.0; /* normalise negative zero to positive zero */
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "assign to");
if (isfld(vp)) {
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;
{
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) );
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 */
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)
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;
{
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);
{
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')