awk2.c revision cb4658fbb85e4290093c4fea0eb396a7d98de1fb
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 1986, 1994 by Mortice Kern Systems Inc. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* awk -- process input files, field extraction, output
*
*/
#include "awk.h"
#include "y.tab.h"
static int reclen; /* Length of last record */
static int exstat; /* Exit status */
/*
* mainline for awk execution
*/
void
awk()
{
running = 1;
dobegin();
}
/*
* "cp" is the buffer to fill. There is a special case if this buffer is
* "linebuf" ($0)
* Return 1 if OK, zero on EOF, -1 on error.
*/
int
{
return (0);
goto nextfile;
}
return (-1);
return (0);
}
else
(void) exprreduce(incNR);
else
(void) exprreduce(incFNR);
}
splitdone = 0;
if (needsplit)
fieldsplit();
}
/* if record length is too long then bail out */
NLINE - 1);
/* Not Reached */
}
return (1);
}
/*
* isclvar()
*
* Returns 1 if the input string, arg, is a variable assignment,
* otherwise returns 0.
*
* An argument to awk can be either a pathname of a file, or a variable
* assignment. An operand that begins with an undersore or alphabetic
* character from the portable character set, followed by a sequence of
* underscores, digits, and alphabetics from the portable character set,
* followed by the '=' character, shall specify a variable assignment
* rather than a pathname.
*/
int
{
/* Begins with an underscore or alphabetic character */
/*
* followed by a sequence of underscores, digits,
* and alphabetics
*/
break;
}
}
return (*tmpptr == '=');
}
}
return (0);
}
/*
* Return the next file from the command line.
* Return FNULL when no more files.
* Sets awkinfp variable to the new current input file.
*/
static FILE *
newfile()
{
static int argindex = 1;
static int filedone;
int argc;
for (;;) {
if (filedone)
return (FNULL);
++filedone;
break;
}
/*
* If the argument contains a '=', determine if the
* argument needs to be treated as a variable assignment
* or as the pathname of a file.
*/
*ap = '\0';
*ap = '=';
continue;
}
if (arg[0] == '\0')
continue;
++filedone;
break;
}
mbunconvert(arg));
exstat = 1;
continue;
}
break;
}
else
(void) exprreduce(clrFNR);
return (awkinfp);
}
/*
* Default record reading code
* Uses fgets for potential speedups found in some (e.g. MKS)
* stdio packages.
*/
wchar_t *
{
*bp = '\0';
return (NULL);
}
/*
* XXXX
* switch (fgetws(bp, lim, fp)) {
* case M_FGETS_EOF:
* *bp = '\0';
* return (NULL);
* case M_FGETS_BINARY:
* awkerr(gettext("file is binary"));
* case M_FGETS_LONG:
* awkerr(gettext("line too long: limit %d"),
* lim);
* case M_FGETS_ERROR:
* awkperr(gettext("error reading file"));
* }
*/
*endp = '\0';
reclen--;
}
return (bp);
}
/*
* Read a record separated by one character in the RS.
* Compatible calling sequence with fgets, but don't include
* record separator character in string.
*/
wchar_t *
{
wint_t c;
*bp++ = c;
*bp = '\0';
}
/*
* Special routine for multiple line records.
*/
wchar_t *
{
int c;
;
if (c != WEOF) do {
if (--limit == 0)
break;
break;
*bp++ = c;
*bp = '\0';
*--bp = '\0';
}
/*
* Look for fields separated by spaces, tabs or newlines.
* Extract the next field, given pointer to start address.
* Return pointer to beginning of field or NULL.
* Reset end of field reference, which is the beginning of the
* next field.
*/
wchar_t *
{
++sp;
if (*sp == '\0')
return (NULL);
;
return (sp);
}
/*
* Look for fields separated by non-whitespace characters.
* Same calling sequence as whitefield().
*/
wchar_t *
{
int endc;
if (*cp == '\0')
return (NULL);
cp++;
return (cp);
}
/*
* This field separation routine uses the same logic as
* blackfield but uses a regular expression to separate
* the fields.
*/
wchar_t *
{
int flags;
int result;
if (*cp == '\0') {
return (NULL);
}
flags = REG_NOTBOL;
} else
flags = 0;
case REG_OK:
/*
* Check to see if a null string was matched. If this is the
* case, then move the current pointer beyond this position.
*/
if (*cp++ != '\0') {
goto again;
}
}
break;
case REG_NOMATCH:
break;
default:
sizeof (linebuf));
(char *)linebuf);
}
return (start);
}
/*
* do begin processing
*/
void
dobegin()
{
/*
* Free all keyword nodes to save space.
*/
{
int nbuck;
nbuck = 0;
}
/*
* Copy ENVIRON array only if needed.
* Note the convoluted work to assign to an array
* and that the temporary nodes will be freed by
* freetemps() because we are "running".
*/
if (needenviron) {
char **app;
extern char **environ;
/* (void) m_setenv(); XXX what's this do? */
*value++ = '\0';
} else {
}
}
}
phase = 0;
if (npattern == 0)
doend(0);
/*
* point to save space.
* NOTE: this is not yet implemented.
*/
}
/*
* Do end processing.
* Exit with a status
*/
void
doend(int s)
{
}
exit(s);
}
/*
* Print statement.
*/
void
{
char *ofs;
int notfirst = 0;
else {
if (notfirst++)
else
}
}
fp);
awkperr("error on print");
}
/*
* printf statement.
*/
void
{
awkperr("error on printf");
}
/*
* Get next input line.
* Read into variable on left of node (or $0 if NULL).
* Read from pipe or file on right of node (or from regular
* input if NULL).
* This is an oddball inasmuch as it is a function
* but parses more like the keywords print, etc.
*/
NODE *
{
/* Pretend we've reached end of (the non-existant) file. */
return (intnode(0));
}
} else {
} else
}
} else
ret = -1;
}
/*
* Open a file. Flag is non-zero for output.
*/
static FILE *
{
char *cp;
int type;
if (flag)
return (stdout);
return (awkinfp);
}
continue;
}
}
} else {
case WRITE:
}
break;
case APPEND:
break;
case PIPE:
break;
case PIPESYM:
break;
case LT:
break;
default:
}
}
} else if (fatal) {
}
return (fp);
}
/*
* Close a stream.
*/
void
{
}
/*
* Internal routine common to printf, sprintf.
* The node is that describing the arguments.
* Returns the number of characters written to file
* pointer `fp' or the length of the string return
* in cp. If cp is NULL then the file pointer is used. If
* cp points to a string pointer, a pointer to an allocated
* buffer will be returned in it.
*/
{
int c;
char fmtbuf[40];
char *ofmtp;
int slen;
int cplen;
} else
/*
* if a char * pointer has been passed in then allocate an initial
* buffer for the string. Make it LINE_MAX plus the length of
* the format string but do reallocs only based LINE_MAX.
*/
}
while ((c = *fmt++) != '\0') {
if (c != '%') {
else
*bptr++ = c;
++length;
continue;
}
*ofmtp++ = (char)c;
switch (c = *fmt++) {
case '%':
else
*bptr++ = c;
++length;
continue;
case 'c':
*ofmtp++ = 'w';
*ofmtp++ = 'c';
*ofmtp = '\0';
else
else {
/*
* Make sure that the buffer is long
* enough to hold the formatted string.
*/
/*
* Since the call to adjust_buf() has already
* guaranteed that the buffer will be long
* enough, just pass in INT_MAX as
* the length.
*/
}
continue;
/* XXXX Is this bogus? Figure out what s & S mean - look at original code */
case 's':
case 'S':
*ofmtp++ = 'w';
*ofmtp++ = 's';
*ofmtp = '\0';
else {
ts);
}
continue;
case 'o':
case 'O':
case 'X':
case 'x':
case 'd':
case 'i':
case 'D':
case 'U':
case 'u':
*ofmtp++ = 'l';
*ofmtp++ = c;
*ofmtp = '\0';
else {
}
continue;
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
*ofmtp++ = c;
*ofmtp = '\0';
else {
}
continue;
case 'l':
case 'L':
break;
case '*':
#ifdef M_BSD_SPRINTF
#else
#endif
break;
default:
if (c == '\0') {
continue;
} else {
break;
}
}
goto nextc;
}
/*
* If printing to a character buffer then make sure it is
* null-terminated and only uses as much space as required.
*/
*bptr = '\0';
}
return (length);
}
/*
* Return the next argument from the list.
*/
static NODE *
{
return (np);
}
/*
* Check and adjust the length of the buffer that has been passed in
* to make sure that it has space to accomodate the sequence string
* described in fmtstr. This routine is used by xprintf() to allow
* for arbitrarily long sprintf() strings.
*
* bp = start of current buffer
* len = length of current buffer
* offset = offset in current buffer
* fmtstr = format string to check
* slen = size of string for %s formats
*/
static void
{
int ioff;
int width = 0;
int prec = 0;
do {
fmtstr++;
if (*fmtstr != '*') {
}
} else
fmtstr++;
if (*fmtstr == '.') {
if (*++fmtstr != '*') {
} else
fmtstr++;
}
fmtstr++;
if (*fmtstr == 'S') {
} else
if (width == 0)
}
}
static void
{
char mb[MB_LEN_MAX];
} else
}