1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * awk -- process input files, field extraction, output 24*7c478bd9Sstevel@tonic-gate * 25*7c478bd9Sstevel@tonic-gate * Copyright (c) 1995, 1996-2000 by Sun Microsystems, Inc. 26*7c478bd9Sstevel@tonic-gate * All rights reserved. 27*7c478bd9Sstevel@tonic-gate * 28*7c478bd9Sstevel@tonic-gate * Copyright 1986, 1994 by Mortice Kern Systems Inc. All rights reserved. 29*7c478bd9Sstevel@tonic-gate * 30*7c478bd9Sstevel@tonic-gate * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include "awk.h" 36*7c478bd9Sstevel@tonic-gate #include "y.tab.h" 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate static FILE *awkinfp; /* Input file pointer */ 39*7c478bd9Sstevel@tonic-gate static int reclen; /* Length of last record */ 40*7c478bd9Sstevel@tonic-gate static int exstat; /* Exit status */ 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate static FILE *openfile(NODE *np, int flag, int fatal); 43*7c478bd9Sstevel@tonic-gate static FILE *newfile(void); 44*7c478bd9Sstevel@tonic-gate static NODE *nextarg(NODE **npp); 45*7c478bd9Sstevel@tonic-gate static void adjust_buf(wchar_t **,int *, wchar_t **, char *, size_t); 46*7c478bd9Sstevel@tonic-gate static void awk_putwc(wchar_t, FILE *); 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate /* 49*7c478bd9Sstevel@tonic-gate * mainline for awk execution 50*7c478bd9Sstevel@tonic-gate */ 51*7c478bd9Sstevel@tonic-gate void 52*7c478bd9Sstevel@tonic-gate awk() 53*7c478bd9Sstevel@tonic-gate { 54*7c478bd9Sstevel@tonic-gate running = 1; 55*7c478bd9Sstevel@tonic-gate dobegin(); 56*7c478bd9Sstevel@tonic-gate while (nextrecord(linebuf, awkinfp) > 0) 57*7c478bd9Sstevel@tonic-gate execute(yytree); 58*7c478bd9Sstevel@tonic-gate doend(exstat); 59*7c478bd9Sstevel@tonic-gate } 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate /* 62*7c478bd9Sstevel@tonic-gate * "cp" is the buffer to fill. There is a special case if this buffer is 63*7c478bd9Sstevel@tonic-gate * "linebuf" ($0) 64*7c478bd9Sstevel@tonic-gate * Return 1 if OK, zero on EOF, -1 on error. 65*7c478bd9Sstevel@tonic-gate */ 66*7c478bd9Sstevel@tonic-gate int 67*7c478bd9Sstevel@tonic-gate nextrecord(wchar_t *cp, FILE *fp) 68*7c478bd9Sstevel@tonic-gate { 69*7c478bd9Sstevel@tonic-gate wchar_t *ep = cp; 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate nextfile: 72*7c478bd9Sstevel@tonic-gate if (fp==FNULL && (fp=newfile())==FNULL) 73*7c478bd9Sstevel@tonic-gate return (0); 74*7c478bd9Sstevel@tonic-gate if ((*awkrecord)(ep, NLINE, fp) == NULL) { 75*7c478bd9Sstevel@tonic-gate if (fp == awkinfp) { 76*7c478bd9Sstevel@tonic-gate if (fp != stdin) 77*7c478bd9Sstevel@tonic-gate (void)fclose(awkinfp); 78*7c478bd9Sstevel@tonic-gate awkinfp = fp = FNULL; 79*7c478bd9Sstevel@tonic-gate goto nextfile; 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate if (ferror(fp)) 82*7c478bd9Sstevel@tonic-gate return (-1); 83*7c478bd9Sstevel@tonic-gate return (0); 84*7c478bd9Sstevel@tonic-gate } 85*7c478bd9Sstevel@tonic-gate if (fp == awkinfp) { 86*7c478bd9Sstevel@tonic-gate if (varNR->n_flags & FINT) 87*7c478bd9Sstevel@tonic-gate ++varNR->n_int; else 88*7c478bd9Sstevel@tonic-gate (void)exprreduce(incNR); 89*7c478bd9Sstevel@tonic-gate if (varFNR->n_flags & FINT) 90*7c478bd9Sstevel@tonic-gate ++varFNR->n_int; else 91*7c478bd9Sstevel@tonic-gate (void)exprreduce(incFNR); 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate if (cp == linebuf) { 94*7c478bd9Sstevel@tonic-gate lbuflen = reclen; 95*7c478bd9Sstevel@tonic-gate splitdone = 0; 96*7c478bd9Sstevel@tonic-gate if (needsplit) 97*7c478bd9Sstevel@tonic-gate fieldsplit(); 98*7c478bd9Sstevel@tonic-gate } 99*7c478bd9Sstevel@tonic-gate /* if record length is too long then bail out */ 100*7c478bd9Sstevel@tonic-gate if (reclen > NLINE - 2) { 101*7c478bd9Sstevel@tonic-gate awkerr(gettext("Record too long (LIMIT: %d bytes)"), 102*7c478bd9Sstevel@tonic-gate NLINE - 1); 103*7c478bd9Sstevel@tonic-gate /* Not Reached */ 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate return (1); 106*7c478bd9Sstevel@tonic-gate } 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* 109*7c478bd9Sstevel@tonic-gate * Return the next file from the command line. 110*7c478bd9Sstevel@tonic-gate * Return FNULL when no more files. 111*7c478bd9Sstevel@tonic-gate * Sets awkinfp variable to the new current input file. 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate static FILE * 114*7c478bd9Sstevel@tonic-gate newfile() 115*7c478bd9Sstevel@tonic-gate { 116*7c478bd9Sstevel@tonic-gate static int argindex = 1; 117*7c478bd9Sstevel@tonic-gate static int filedone; 118*7c478bd9Sstevel@tonic-gate register wchar_t *ap; 119*7c478bd9Sstevel@tonic-gate register int argc; 120*7c478bd9Sstevel@tonic-gate wchar_t *arg; 121*7c478bd9Sstevel@tonic-gate extern void strescape(wchar_t *); 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate argc = (int)exprint(varARGC); 124*7c478bd9Sstevel@tonic-gate for (;;) { 125*7c478bd9Sstevel@tonic-gate if (argindex >= argc) { 126*7c478bd9Sstevel@tonic-gate if (filedone) 127*7c478bd9Sstevel@tonic-gate return (FNULL); 128*7c478bd9Sstevel@tonic-gate ++filedone; 129*7c478bd9Sstevel@tonic-gate awkinfp = stdin; 130*7c478bd9Sstevel@tonic-gate arg = M_MB_L("-"); 131*7c478bd9Sstevel@tonic-gate break; 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate constant->n_int = argindex++; 134*7c478bd9Sstevel@tonic-gate arg = (wchar_t *)exprstring(ARGVsubi); 135*7c478bd9Sstevel@tonic-gate if ((ap = wcschr(arg, '=')) != NULL) { 136*7c478bd9Sstevel@tonic-gate *ap = '\0'; 137*7c478bd9Sstevel@tonic-gate strescape(ap+1); 138*7c478bd9Sstevel@tonic-gate strassign(vlook(arg),linebuf,FALLOC|FSENSE, 139*7c478bd9Sstevel@tonic-gate wcslen(linebuf)); 140*7c478bd9Sstevel@tonic-gate *ap = '='; 141*7c478bd9Sstevel@tonic-gate continue; 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate if (arg[0] == '\0') 144*7c478bd9Sstevel@tonic-gate continue; 145*7c478bd9Sstevel@tonic-gate ++filedone; 146*7c478bd9Sstevel@tonic-gate if (arg[0]=='-' && arg[1]=='\0') { 147*7c478bd9Sstevel@tonic-gate awkinfp = stdin; 148*7c478bd9Sstevel@tonic-gate break; 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate if ((awkinfp = fopen(mbunconvert(arg), r)) == FNULL) { 151*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("input file \"%s\""), 152*7c478bd9Sstevel@tonic-gate mbunconvert(arg)); 153*7c478bd9Sstevel@tonic-gate exstat = 1; 154*7c478bd9Sstevel@tonic-gate continue; 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate break; 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate strassign(varFILENAME, arg, FALLOC, wcslen(arg)); 159*7c478bd9Sstevel@tonic-gate if (varFNR->n_flags & FINT) 160*7c478bd9Sstevel@tonic-gate varFNR->n_int = 0; else 161*7c478bd9Sstevel@tonic-gate (void)exprreduce(clrFNR); 162*7c478bd9Sstevel@tonic-gate return (awkinfp); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * Default record reading code 167*7c478bd9Sstevel@tonic-gate * Uses fgets for potential speedups found in some (e.g. MKS) 168*7c478bd9Sstevel@tonic-gate * stdio packages. 169*7c478bd9Sstevel@tonic-gate */ 170*7c478bd9Sstevel@tonic-gate wchar_t * 171*7c478bd9Sstevel@tonic-gate defrecord(wchar_t *bp, int lim, FILE *fp) 172*7c478bd9Sstevel@tonic-gate { 173*7c478bd9Sstevel@tonic-gate register wchar_t *endp; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate if (fgetws(bp, lim, fp) == NULL) { 176*7c478bd9Sstevel@tonic-gate *bp = '\0'; 177*7c478bd9Sstevel@tonic-gate return (NULL); 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate /* XXXX 180*7c478bd9Sstevel@tonic-gate switch (fgetws(bp, lim, fp)) { 181*7c478bd9Sstevel@tonic-gate case M_FGETS_EOF: 182*7c478bd9Sstevel@tonic-gate *bp = '\0'; 183*7c478bd9Sstevel@tonic-gate return (NULL); 184*7c478bd9Sstevel@tonic-gate case M_FGETS_BINARY: 185*7c478bd9Sstevel@tonic-gate awkerr(gettext("file is binary")); 186*7c478bd9Sstevel@tonic-gate case M_FGETS_LONG: 187*7c478bd9Sstevel@tonic-gate awkerr(gettext("line too long: limit %d"), 188*7c478bd9Sstevel@tonic-gate lim); 189*7c478bd9Sstevel@tonic-gate case M_FGETS_ERROR: 190*7c478bd9Sstevel@tonic-gate awkperr(gettext("error reading file")); 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate if (*(endp = (bp + (reclen = wcslen(bp))-1)) == '\n') { 195*7c478bd9Sstevel@tonic-gate *endp = '\0'; 196*7c478bd9Sstevel@tonic-gate reclen--; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate return (bp); 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* 202*7c478bd9Sstevel@tonic-gate * Read a record separated by one character in the RS. 203*7c478bd9Sstevel@tonic-gate * Compatible calling sequence with fgets, but don't include 204*7c478bd9Sstevel@tonic-gate * record separator character in string. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate wchar_t * 207*7c478bd9Sstevel@tonic-gate charrecord(wchar_t *abp, int alim, FILE *fp) 208*7c478bd9Sstevel@tonic-gate { 209*7c478bd9Sstevel@tonic-gate register wchar_t *bp; 210*7c478bd9Sstevel@tonic-gate register wint_t c; 211*7c478bd9Sstevel@tonic-gate register int limit = alim; 212*7c478bd9Sstevel@tonic-gate register wint_t endc; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate bp = abp; 215*7c478bd9Sstevel@tonic-gate endc = *(wchar_t *)varRS->n_string; 216*7c478bd9Sstevel@tonic-gate while (--limit>0 && (c = getwc(fp))!=endc && c!=WEOF) 217*7c478bd9Sstevel@tonic-gate *bp++ = c; 218*7c478bd9Sstevel@tonic-gate *bp = '\0'; 219*7c478bd9Sstevel@tonic-gate reclen = bp-abp; 220*7c478bd9Sstevel@tonic-gate return (c==WEOF && bp==abp ? NULL : abp); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate /* 224*7c478bd9Sstevel@tonic-gate * Special routine for multiple line records. 225*7c478bd9Sstevel@tonic-gate */ 226*7c478bd9Sstevel@tonic-gate wchar_t * 227*7c478bd9Sstevel@tonic-gate multirecord(wchar_t *abp, int limit, FILE *fp) 228*7c478bd9Sstevel@tonic-gate { 229*7c478bd9Sstevel@tonic-gate register wchar_t *bp; 230*7c478bd9Sstevel@tonic-gate register int c; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate while ((c = getwc(fp)) == '\n') 233*7c478bd9Sstevel@tonic-gate ; 234*7c478bd9Sstevel@tonic-gate bp = abp; 235*7c478bd9Sstevel@tonic-gate if (c != WEOF) do { 236*7c478bd9Sstevel@tonic-gate if (--limit == 0) 237*7c478bd9Sstevel@tonic-gate break; 238*7c478bd9Sstevel@tonic-gate if (c=='\n' && bp[-1]=='\n') 239*7c478bd9Sstevel@tonic-gate break; 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate *bp++ = c; 242*7c478bd9Sstevel@tonic-gate } while ((c = getwc(fp)) != WEOF); 243*7c478bd9Sstevel@tonic-gate *bp = '\0'; 244*7c478bd9Sstevel@tonic-gate if (bp > abp) 245*7c478bd9Sstevel@tonic-gate *--bp = '\0'; 246*7c478bd9Sstevel@tonic-gate reclen = bp-abp; 247*7c478bd9Sstevel@tonic-gate return (c==WEOF && bp==abp ? NULL : abp); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate /* 251*7c478bd9Sstevel@tonic-gate * Look for fields separated by spaces, tabs or newlines. 252*7c478bd9Sstevel@tonic-gate * Extract the next field, given pointer to start address. 253*7c478bd9Sstevel@tonic-gate * Return pointer to beginning of field or NULL. 254*7c478bd9Sstevel@tonic-gate * Reset end of field reference, which is the beginning of the 255*7c478bd9Sstevel@tonic-gate * next field. 256*7c478bd9Sstevel@tonic-gate */ 257*7c478bd9Sstevel@tonic-gate wchar_t * 258*7c478bd9Sstevel@tonic-gate whitefield(wchar_t **endp) 259*7c478bd9Sstevel@tonic-gate { 260*7c478bd9Sstevel@tonic-gate register wchar_t *sp; 261*7c478bd9Sstevel@tonic-gate register wchar_t *ep; 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate sp = *endp; 264*7c478bd9Sstevel@tonic-gate while (*sp==' ' || *sp=='\t' || *sp=='\n') 265*7c478bd9Sstevel@tonic-gate ++sp; 266*7c478bd9Sstevel@tonic-gate if (*sp == '\0') 267*7c478bd9Sstevel@tonic-gate return (NULL); 268*7c478bd9Sstevel@tonic-gate for (ep = sp; *ep!=' ' && *ep!='\0' && *ep!='\t' && *ep!='\n'; ++ep) 269*7c478bd9Sstevel@tonic-gate ; 270*7c478bd9Sstevel@tonic-gate *endp = ep; 271*7c478bd9Sstevel@tonic-gate return (sp); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* 275*7c478bd9Sstevel@tonic-gate * Look for fields separated by non-whitespace characters. 276*7c478bd9Sstevel@tonic-gate * Same calling sequence as whitefield(). 277*7c478bd9Sstevel@tonic-gate */ 278*7c478bd9Sstevel@tonic-gate wchar_t * 279*7c478bd9Sstevel@tonic-gate blackfield(wchar_t **endp) 280*7c478bd9Sstevel@tonic-gate { 281*7c478bd9Sstevel@tonic-gate register wchar_t *cp; 282*7c478bd9Sstevel@tonic-gate register int endc; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate endc = *(wchar_t *)varFS->n_string; 285*7c478bd9Sstevel@tonic-gate cp = *endp; 286*7c478bd9Sstevel@tonic-gate if (*cp == '\0') 287*7c478bd9Sstevel@tonic-gate return (NULL); 288*7c478bd9Sstevel@tonic-gate if (*cp==endc && fcount!=0) 289*7c478bd9Sstevel@tonic-gate cp++; 290*7c478bd9Sstevel@tonic-gate if ((*endp = wcschr(cp, endc)) == NULL) 291*7c478bd9Sstevel@tonic-gate *endp = wcschr(cp, '\0'); 292*7c478bd9Sstevel@tonic-gate return (cp); 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * This field separation routine uses the same logic as 297*7c478bd9Sstevel@tonic-gate * blackfield but uses a regular expression to separate 298*7c478bd9Sstevel@tonic-gate * the fields. 299*7c478bd9Sstevel@tonic-gate */ 300*7c478bd9Sstevel@tonic-gate wchar_t * 301*7c478bd9Sstevel@tonic-gate refield(wchar_t **endpp) 302*7c478bd9Sstevel@tonic-gate { 303*7c478bd9Sstevel@tonic-gate register wchar_t *cp, *start; 304*7c478bd9Sstevel@tonic-gate register int flags; 305*7c478bd9Sstevel@tonic-gate static REGWMATCH_T match[10]; 306*7c478bd9Sstevel@tonic-gate int result; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate cp = *endpp; 309*7c478bd9Sstevel@tonic-gate if (*cp == '\0') { 310*7c478bd9Sstevel@tonic-gate match[0].rm_ep = NULL; 311*7c478bd9Sstevel@tonic-gate return (NULL); 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate if (match[0].rm_ep != NULL) { 314*7c478bd9Sstevel@tonic-gate flags = REG_NOTBOL; 315*7c478bd9Sstevel@tonic-gate cp = (wchar_t *)match[0].rm_ep; 316*7c478bd9Sstevel@tonic-gate } else 317*7c478bd9Sstevel@tonic-gate flags = 0; 318*7c478bd9Sstevel@tonic-gate start = cp; 319*7c478bd9Sstevel@tonic-gate again: 320*7c478bd9Sstevel@tonic-gate switch ((result = REGWEXEC(resep, cp, 10, match, flags))) { 321*7c478bd9Sstevel@tonic-gate case REG_OK: 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * Check to see if a null string was matched. If this is the 324*7c478bd9Sstevel@tonic-gate * case, then move the current pointer beyond this position. 325*7c478bd9Sstevel@tonic-gate */ 326*7c478bd9Sstevel@tonic-gate if (match[0].rm_sp == match[0].rm_ep) { 327*7c478bd9Sstevel@tonic-gate cp = (wchar_t *)match[0].rm_sp; 328*7c478bd9Sstevel@tonic-gate if (*cp++ != '\0') { 329*7c478bd9Sstevel@tonic-gate goto again; 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate *endpp = (wchar_t *)match[0].rm_sp; 333*7c478bd9Sstevel@tonic-gate break; 334*7c478bd9Sstevel@tonic-gate case REG_NOMATCH: 335*7c478bd9Sstevel@tonic-gate match[0].rm_ep = NULL; 336*7c478bd9Sstevel@tonic-gate *endpp = wcschr(cp, '\0'); 337*7c478bd9Sstevel@tonic-gate break; 338*7c478bd9Sstevel@tonic-gate default: 339*7c478bd9Sstevel@tonic-gate regerror(result, resep, (char *)linebuf, sizeof(linebuf)); 340*7c478bd9Sstevel@tonic-gate awkerr(gettext("error splitting record: %s"), 341*7c478bd9Sstevel@tonic-gate (char *)linebuf); 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate return (start); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * do begin processing 348*7c478bd9Sstevel@tonic-gate */ 349*7c478bd9Sstevel@tonic-gate void 350*7c478bd9Sstevel@tonic-gate dobegin() 351*7c478bd9Sstevel@tonic-gate { 352*7c478bd9Sstevel@tonic-gate /*l 353*7c478bd9Sstevel@tonic-gate * Free all keyword nodes to save space. 354*7c478bd9Sstevel@tonic-gate */ 355*7c478bd9Sstevel@tonic-gate { 356*7c478bd9Sstevel@tonic-gate NODE *np; 357*7c478bd9Sstevel@tonic-gate int nbuck; 358*7c478bd9Sstevel@tonic-gate register NODE *knp; 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate np = NNULL; 361*7c478bd9Sstevel@tonic-gate nbuck = 0; 362*7c478bd9Sstevel@tonic-gate while ((knp = symwalk(&nbuck, &np)) != NNULL) 363*7c478bd9Sstevel@tonic-gate if (knp->n_type == KEYWORD) 364*7c478bd9Sstevel@tonic-gate delsymtab(knp, 1); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate /*l 367*7c478bd9Sstevel@tonic-gate * Copy ENVIRON array only if needed. 368*7c478bd9Sstevel@tonic-gate * Note the convoluted work to assign to an array 369*7c478bd9Sstevel@tonic-gate * and that the temporary nodes will be freed by 370*7c478bd9Sstevel@tonic-gate * freetemps() because we are "running". 371*7c478bd9Sstevel@tonic-gate */ 372*7c478bd9Sstevel@tonic-gate if (needenviron) { 373*7c478bd9Sstevel@tonic-gate register char **app; 374*7c478bd9Sstevel@tonic-gate register wchar_t *name, *value; 375*7c478bd9Sstevel@tonic-gate register NODE *namep = stringnode(_null, FSTATIC, 0); 376*7c478bd9Sstevel@tonic-gate register NODE *valuep = stringnode(_null, FSTATIC, 0); 377*7c478bd9Sstevel@tonic-gate register NODE *ENVsubname = node(INDEX, varENVIRON, namep); 378*7c478bd9Sstevel@tonic-gate extern char **environ; 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate /* (void) m_setenv(); XXX what's this do? */ 381*7c478bd9Sstevel@tonic-gate for (app = environ; *app != NULL;) { 382*7c478bd9Sstevel@tonic-gate name = mbstowcsdup(*app++); 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate if ((value = wcschr(name, '=')) != NULL) { 385*7c478bd9Sstevel@tonic-gate *value++ = '\0'; 386*7c478bd9Sstevel@tonic-gate valuep->n_strlen = wcslen(value); 387*7c478bd9Sstevel@tonic-gate valuep->n_string = value; 388*7c478bd9Sstevel@tonic-gate } else { 389*7c478bd9Sstevel@tonic-gate valuep->n_strlen = 0; 390*7c478bd9Sstevel@tonic-gate valuep->n_string = _null; 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate namep->n_strlen = wcslen(namep->n_string = name); 393*7c478bd9Sstevel@tonic-gate (void)assign(ENVsubname, valuep); 394*7c478bd9Sstevel@tonic-gate if (value != NULL) 395*7c478bd9Sstevel@tonic-gate value[-1] = '='; 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate phase = BEGIN; 399*7c478bd9Sstevel@tonic-gate execute(yytree); 400*7c478bd9Sstevel@tonic-gate phase = 0; 401*7c478bd9Sstevel@tonic-gate if (npattern == 0) 402*7c478bd9Sstevel@tonic-gate doend(0); 403*7c478bd9Sstevel@tonic-gate /* 404*7c478bd9Sstevel@tonic-gate * Delete all pattern/action rules that are BEGIN at this 405*7c478bd9Sstevel@tonic-gate * point to save space. 406*7c478bd9Sstevel@tonic-gate * NOTE: this is not yet implemented. 407*7c478bd9Sstevel@tonic-gate */ 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate /* 411*7c478bd9Sstevel@tonic-gate * Do end processing. 412*7c478bd9Sstevel@tonic-gate * Exit with a status 413*7c478bd9Sstevel@tonic-gate */ 414*7c478bd9Sstevel@tonic-gate void 415*7c478bd9Sstevel@tonic-gate doend(int s) 416*7c478bd9Sstevel@tonic-gate { 417*7c478bd9Sstevel@tonic-gate register OFILE *op; 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate if (phase != END) { 420*7c478bd9Sstevel@tonic-gate phase = END; 421*7c478bd9Sstevel@tonic-gate awkinfp = stdin; 422*7c478bd9Sstevel@tonic-gate execute(yytree); 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate for (op = &ofiles[0]; op < &ofiles[NIOSTREAM]; op++) 425*7c478bd9Sstevel@tonic-gate if (op->f_fp != FNULL) 426*7c478bd9Sstevel@tonic-gate awkclose(op); 427*7c478bd9Sstevel@tonic-gate if (awkinfp == stdin) 428*7c478bd9Sstevel@tonic-gate (void) fflush(awkinfp); 429*7c478bd9Sstevel@tonic-gate exit(s); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate /* 433*7c478bd9Sstevel@tonic-gate * Print statement. 434*7c478bd9Sstevel@tonic-gate */ 435*7c478bd9Sstevel@tonic-gate void 436*7c478bd9Sstevel@tonic-gate s_print(NODE *np) 437*7c478bd9Sstevel@tonic-gate { 438*7c478bd9Sstevel@tonic-gate register FILE *fp; 439*7c478bd9Sstevel@tonic-gate NODE *listp; 440*7c478bd9Sstevel@tonic-gate register char *ofs; 441*7c478bd9Sstevel@tonic-gate register int notfirst = 0; 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate fp = openfile(np->n_right, 1, 1); 444*7c478bd9Sstevel@tonic-gate if (np->n_left == NNULL) 445*7c478bd9Sstevel@tonic-gate (void)fputs(mbunconvert(linebuf), fp); 446*7c478bd9Sstevel@tonic-gate else { 447*7c478bd9Sstevel@tonic-gate ofs = wcstombsdup((isstring(varOFS->n_flags)) ? 448*7c478bd9Sstevel@tonic-gate (wchar_t *)varOFS->n_string : 449*7c478bd9Sstevel@tonic-gate (wchar_t *)exprstring(varOFS)); 450*7c478bd9Sstevel@tonic-gate listp = np->n_left; 451*7c478bd9Sstevel@tonic-gate while ((np = getlist(&listp)) != NNULL) { 452*7c478bd9Sstevel@tonic-gate if (notfirst++) 453*7c478bd9Sstevel@tonic-gate (void)fputs(ofs, fp); 454*7c478bd9Sstevel@tonic-gate np = exprreduce(np); 455*7c478bd9Sstevel@tonic-gate if (np->n_flags & FINT) 456*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%lld", (INT)np->n_int); 457*7c478bd9Sstevel@tonic-gate else if (isstring(np->n_flags)) 458*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%S", 459*7c478bd9Sstevel@tonic-gate np->n_string); 460*7c478bd9Sstevel@tonic-gate else 461*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, 462*7c478bd9Sstevel@tonic-gate mbunconvert((wchar_t *)exprstring(varOFMT)), 463*7c478bd9Sstevel@tonic-gate (double)np->n_real); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate free(ofs); 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate (void)fputs(mbunconvert(isstring(varORS->n_flags) ? 468*7c478bd9Sstevel@tonic-gate (wchar_t *)varORS->n_string : (wchar_t *)exprstring(varORS)), 469*7c478bd9Sstevel@tonic-gate fp); 470*7c478bd9Sstevel@tonic-gate if (ferror(fp)) 471*7c478bd9Sstevel@tonic-gate awkperr("error on print"); 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * printf statement. 476*7c478bd9Sstevel@tonic-gate */ 477*7c478bd9Sstevel@tonic-gate void 478*7c478bd9Sstevel@tonic-gate s_prf(NODE *np) 479*7c478bd9Sstevel@tonic-gate { 480*7c478bd9Sstevel@tonic-gate register FILE *fp; 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate fp = openfile(np->n_right, 1, 1); 483*7c478bd9Sstevel@tonic-gate (void)xprintf(np->n_left, fp, (wchar_t **)NULL); 484*7c478bd9Sstevel@tonic-gate if (ferror(fp)) 485*7c478bd9Sstevel@tonic-gate awkperr("error on printf"); 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate /* 489*7c478bd9Sstevel@tonic-gate * Get next input line. 490*7c478bd9Sstevel@tonic-gate * Read into variable on left of node (or $0 if NULL). 491*7c478bd9Sstevel@tonic-gate * Read from pipe or file on right of node (or from regular 492*7c478bd9Sstevel@tonic-gate * input if NULL). 493*7c478bd9Sstevel@tonic-gate * This is an oddball inasmuch as it is a function 494*7c478bd9Sstevel@tonic-gate * but parses more like the keywords print, etc. 495*7c478bd9Sstevel@tonic-gate */ 496*7c478bd9Sstevel@tonic-gate NODE * 497*7c478bd9Sstevel@tonic-gate f_getline(NODE *np) 498*7c478bd9Sstevel@tonic-gate { 499*7c478bd9Sstevel@tonic-gate register wchar_t *cp; 500*7c478bd9Sstevel@tonic-gate register INT ret; 501*7c478bd9Sstevel@tonic-gate register FILE *fp; 502*7c478bd9Sstevel@tonic-gate register size_t len; 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate if (np->n_right == NULL && phase == END) { 505*7c478bd9Sstevel@tonic-gate /* Pretend we've reached end of (the non-existant) file. */ 506*7c478bd9Sstevel@tonic-gate return intnode(0); 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate if ((fp = openfile(np->n_right, 0, 0)) != FNULL) { 510*7c478bd9Sstevel@tonic-gate if (np->n_left == NNULL) { 511*7c478bd9Sstevel@tonic-gate ret = nextrecord(linebuf, fp); 512*7c478bd9Sstevel@tonic-gate } else { 513*7c478bd9Sstevel@tonic-gate cp = emalloc(NLINE * sizeof(wchar_t)); 514*7c478bd9Sstevel@tonic-gate ret = nextrecord(cp, fp); 515*7c478bd9Sstevel@tonic-gate np = np->n_left; 516*7c478bd9Sstevel@tonic-gate len = wcslen(cp); 517*7c478bd9Sstevel@tonic-gate cp = erealloc(cp, (len+1)*sizeof(wchar_t)); 518*7c478bd9Sstevel@tonic-gate if (isleaf(np->n_flags)) { 519*7c478bd9Sstevel@tonic-gate if (np->n_type == PARM) 520*7c478bd9Sstevel@tonic-gate np = np->n_next; 521*7c478bd9Sstevel@tonic-gate strassign(np, cp, FNOALLOC, len); 522*7c478bd9Sstevel@tonic-gate } else 523*7c478bd9Sstevel@tonic-gate (void)assign(np, stringnode(cp, FNOALLOC, len)); 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate } else 526*7c478bd9Sstevel@tonic-gate ret = -1; 527*7c478bd9Sstevel@tonic-gate return (intnode(ret)); 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate /* 531*7c478bd9Sstevel@tonic-gate * Open a file. Flag is non-zero for output. 532*7c478bd9Sstevel@tonic-gate */ 533*7c478bd9Sstevel@tonic-gate static FILE * 534*7c478bd9Sstevel@tonic-gate openfile(NODE *np, int flag, int fatal) 535*7c478bd9Sstevel@tonic-gate { 536*7c478bd9Sstevel@tonic-gate register OFILE *op; 537*7c478bd9Sstevel@tonic-gate register char *cp; 538*7c478bd9Sstevel@tonic-gate register FILE *fp; 539*7c478bd9Sstevel@tonic-gate register int type; 540*7c478bd9Sstevel@tonic-gate register OFILE *fop; 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate if (np == NNULL) { 543*7c478bd9Sstevel@tonic-gate if (flag) 544*7c478bd9Sstevel@tonic-gate return (stdout); 545*7c478bd9Sstevel@tonic-gate if (awkinfp == FNULL) 546*7c478bd9Sstevel@tonic-gate awkinfp = newfile(); 547*7c478bd9Sstevel@tonic-gate return (awkinfp); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate if ((type = np->n_type) == APPEND) 550*7c478bd9Sstevel@tonic-gate type = WRITE; 551*7c478bd9Sstevel@tonic-gate cp = mbunconvert(exprstring(np->n_left)); 552*7c478bd9Sstevel@tonic-gate fop = (OFILE *)NULL; 553*7c478bd9Sstevel@tonic-gate for (op = &ofiles[0]; op < &ofiles[NIOSTREAM]; op++) { 554*7c478bd9Sstevel@tonic-gate if (op->f_fp == FNULL) { 555*7c478bd9Sstevel@tonic-gate if (fop == (OFILE *)NULL) 556*7c478bd9Sstevel@tonic-gate fop = op; 557*7c478bd9Sstevel@tonic-gate continue; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate if (op->f_mode == type 560*7c478bd9Sstevel@tonic-gate && strcmp(op->f_name, cp)==0) 561*7c478bd9Sstevel@tonic-gate return (op->f_fp); 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate if (fop == (OFILE *)NULL) 564*7c478bd9Sstevel@tonic-gate awkerr(gettext("too many open streams to %s onto \"%s\""), 565*7c478bd9Sstevel@tonic-gate flag ? "print/printf" : "getline", cp); 566*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 567*7c478bd9Sstevel@tonic-gate op = fop; 568*7c478bd9Sstevel@tonic-gate if (cp[0]=='-' && cp[1]=='\0') { 569*7c478bd9Sstevel@tonic-gate fp = flag ? stdout : stdin; 570*7c478bd9Sstevel@tonic-gate } else { 571*7c478bd9Sstevel@tonic-gate switch (np->n_type) { 572*7c478bd9Sstevel@tonic-gate case WRITE: 573*7c478bd9Sstevel@tonic-gate if ((fp = fopen(cp, w)) != FNULL) { 574*7c478bd9Sstevel@tonic-gate if (isatty(fileno(fp))) 575*7c478bd9Sstevel@tonic-gate (void) setvbuf(fp, 0, _IONBF, 0); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate break; 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate case APPEND: 580*7c478bd9Sstevel@tonic-gate fp = fopen(cp, "a"); 581*7c478bd9Sstevel@tonic-gate break; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate case PIPE: 584*7c478bd9Sstevel@tonic-gate fp = popen(cp, w); 585*7c478bd9Sstevel@tonic-gate (void) setvbuf(fp, (char *) 0, _IOLBF, 0); 586*7c478bd9Sstevel@tonic-gate break; 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate case PIPESYM: 589*7c478bd9Sstevel@tonic-gate fp = popen(cp, r); 590*7c478bd9Sstevel@tonic-gate break; 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate case LT: 593*7c478bd9Sstevel@tonic-gate fp = fopen(cp, r); 594*7c478bd9Sstevel@tonic-gate break; 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate default: 597*7c478bd9Sstevel@tonic-gate awkerr(interr, "openfile"); 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate if (fp != FNULL) { 601*7c478bd9Sstevel@tonic-gate op->f_name = strdup(cp); 602*7c478bd9Sstevel@tonic-gate op->f_fp = fp; 603*7c478bd9Sstevel@tonic-gate op->f_mode = type; 604*7c478bd9Sstevel@tonic-gate } else if (fatal) { 605*7c478bd9Sstevel@tonic-gate awkperr(flag ? gettext("output file \"%s\"") : 606*7c478bd9Sstevel@tonic-gate gettext("input file \"%s\""), cp); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate return (fp); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate /* 612*7c478bd9Sstevel@tonic-gate * Close a stream. 613*7c478bd9Sstevel@tonic-gate */ 614*7c478bd9Sstevel@tonic-gate void 615*7c478bd9Sstevel@tonic-gate awkclose(OFILE *op) 616*7c478bd9Sstevel@tonic-gate { 617*7c478bd9Sstevel@tonic-gate if (op->f_mode==PIPE || op->f_mode==PIPESYM) 618*7c478bd9Sstevel@tonic-gate (void)pclose(op->f_fp); 619*7c478bd9Sstevel@tonic-gate else if (fclose(op->f_fp) == EOF) 620*7c478bd9Sstevel@tonic-gate awkperr("error on stream \"%s\"", op->f_name); 621*7c478bd9Sstevel@tonic-gate op->f_fp = FNULL; 622*7c478bd9Sstevel@tonic-gate free(op->f_name); 623*7c478bd9Sstevel@tonic-gate op->f_name = NULL; 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate /* 627*7c478bd9Sstevel@tonic-gate * Internal routine common to printf, sprintf. 628*7c478bd9Sstevel@tonic-gate * The node is that describing the arguments. 629*7c478bd9Sstevel@tonic-gate * Returns the number of characters written to file 630*7c478bd9Sstevel@tonic-gate * pointer `fp' or the length of the string return 631*7c478bd9Sstevel@tonic-gate * in cp. If cp is NULL then the file pointer is used. If 632*7c478bd9Sstevel@tonic-gate * cp points to a string pointer, a pointer to an allocated 633*7c478bd9Sstevel@tonic-gate * buffer will be returned in it. 634*7c478bd9Sstevel@tonic-gate */ 635*7c478bd9Sstevel@tonic-gate size_t 636*7c478bd9Sstevel@tonic-gate xprintf(NODE *np, FILE *fp, wchar_t **cp) 637*7c478bd9Sstevel@tonic-gate { 638*7c478bd9Sstevel@tonic-gate register wchar_t *fmt; 639*7c478bd9Sstevel@tonic-gate register int c; 640*7c478bd9Sstevel@tonic-gate wchar_t *bptr = (wchar_t *)NULL; 641*7c478bd9Sstevel@tonic-gate char fmtbuf[40]; 642*7c478bd9Sstevel@tonic-gate register size_t length = 0; 643*7c478bd9Sstevel@tonic-gate register char *ofmtp; 644*7c478bd9Sstevel@tonic-gate register NODE *fnp; 645*7c478bd9Sstevel@tonic-gate register wchar_t *fmtsave; 646*7c478bd9Sstevel@tonic-gate int slen; 647*7c478bd9Sstevel@tonic-gate int cplen; 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate fnp = getlist(&np); 650*7c478bd9Sstevel@tonic-gate if (isleaf(fnp->n_flags) && fnp->n_type==PARM) 651*7c478bd9Sstevel@tonic-gate fnp = fnp->n_next; 652*7c478bd9Sstevel@tonic-gate if (isstring(fnp->n_flags)) { 653*7c478bd9Sstevel@tonic-gate fmt = fnp->n_string; 654*7c478bd9Sstevel@tonic-gate fmtsave = NULL; 655*7c478bd9Sstevel@tonic-gate } else 656*7c478bd9Sstevel@tonic-gate fmtsave = fmt = (wchar_t *)strsave(exprstring(fnp)); 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate /* 659*7c478bd9Sstevel@tonic-gate * if a char * pointer has been passed in then allocate an initial 660*7c478bd9Sstevel@tonic-gate * buffer for the string. Make it LINE_MAX plus the length of 661*7c478bd9Sstevel@tonic-gate * the format string but do reallocs only based LINE_MAX. 662*7c478bd9Sstevel@tonic-gate */ 663*7c478bd9Sstevel@tonic-gate if (cp != (wchar_t **)NULL) { 664*7c478bd9Sstevel@tonic-gate cplen = LINE_MAX; 665*7c478bd9Sstevel@tonic-gate bptr = *cp = emalloc(sizeof(wchar_t) * (cplen + wcslen(fmt))); 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate while ((c = *fmt++) != '\0') { 669*7c478bd9Sstevel@tonic-gate if (c != '%') { 670*7c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 671*7c478bd9Sstevel@tonic-gate awk_putwc(c, fp); 672*7c478bd9Sstevel@tonic-gate else 673*7c478bd9Sstevel@tonic-gate *bptr++ = c; 674*7c478bd9Sstevel@tonic-gate ++length; 675*7c478bd9Sstevel@tonic-gate continue; 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate ofmtp = fmtbuf; 678*7c478bd9Sstevel@tonic-gate *ofmtp++ = (char)c; 679*7c478bd9Sstevel@tonic-gate nextc: 680*7c478bd9Sstevel@tonic-gate switch (c = *fmt++) { 681*7c478bd9Sstevel@tonic-gate case '%': 682*7c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 683*7c478bd9Sstevel@tonic-gate awk_putwc(c, fp); 684*7c478bd9Sstevel@tonic-gate else 685*7c478bd9Sstevel@tonic-gate *bptr++ = c; 686*7c478bd9Sstevel@tonic-gate ++length; 687*7c478bd9Sstevel@tonic-gate continue; 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate case 'c': 690*7c478bd9Sstevel@tonic-gate *ofmtp++ = 'w'; 691*7c478bd9Sstevel@tonic-gate *ofmtp++ = 'c'; 692*7c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 693*7c478bd9Sstevel@tonic-gate fnp = exprreduce(nextarg(&np)); 694*7c478bd9Sstevel@tonic-gate if (isnumber(fnp->n_flags)) 695*7c478bd9Sstevel@tonic-gate c = exprint(fnp); 696*7c478bd9Sstevel@tonic-gate else 697*7c478bd9Sstevel@tonic-gate c = *(wchar_t *)exprstring(fnp); 698*7c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 699*7c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, c); 700*7c478bd9Sstevel@tonic-gate else { 701*7c478bd9Sstevel@tonic-gate /* 702*7c478bd9Sstevel@tonic-gate * Make sure that the buffer is long 703*7c478bd9Sstevel@tonic-gate * enough to hold the formatted string. 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 0); 706*7c478bd9Sstevel@tonic-gate /* 707*7c478bd9Sstevel@tonic-gate * Since the call to adjust_buf() has already 708*7c478bd9Sstevel@tonic-gate * guaranteed that the buffer will be long 709*7c478bd9Sstevel@tonic-gate * enough, just pass in INT_MAX as 710*7c478bd9Sstevel@tonic-gate * the length. 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, c); 713*7c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 714*7c478bd9Sstevel@tonic-gate length += slen; 715*7c478bd9Sstevel@tonic-gate } 716*7c478bd9Sstevel@tonic-gate continue; 717*7c478bd9Sstevel@tonic-gate /* XXXX Is this bogus? Figure out what s & S mean - look at original code */ 718*7c478bd9Sstevel@tonic-gate case 's': 719*7c478bd9Sstevel@tonic-gate case 'S': 720*7c478bd9Sstevel@tonic-gate *ofmtp++ = 'w'; 721*7c478bd9Sstevel@tonic-gate *ofmtp++ = 's'; 722*7c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 723*7c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 724*7c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, 725*7c478bd9Sstevel@tonic-gate (wchar_t *)exprstring(nextarg(&np))); 726*7c478bd9Sstevel@tonic-gate else { 727*7c478bd9Sstevel@tonic-gate wchar_t *ts = exprstring(nextarg(&np)); 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 730*7c478bd9Sstevel@tonic-gate wcslen(ts)); 731*7c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, 732*7c478bd9Sstevel@tonic-gate ts); 733*7c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 734*7c478bd9Sstevel@tonic-gate length += slen; 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate continue; 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate case 'o': 739*7c478bd9Sstevel@tonic-gate case 'O': 740*7c478bd9Sstevel@tonic-gate case 'X': 741*7c478bd9Sstevel@tonic-gate case 'x': 742*7c478bd9Sstevel@tonic-gate case 'd': 743*7c478bd9Sstevel@tonic-gate case 'i': 744*7c478bd9Sstevel@tonic-gate case 'D': 745*7c478bd9Sstevel@tonic-gate case 'U': 746*7c478bd9Sstevel@tonic-gate case 'u': 747*7c478bd9Sstevel@tonic-gate *ofmtp++ = 'l'; 748*7c478bd9Sstevel@tonic-gate *ofmtp++ = 'l'; /* now dealing with long longs */ 749*7c478bd9Sstevel@tonic-gate *ofmtp++ = c; 750*7c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 751*7c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 752*7c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, 753*7c478bd9Sstevel@tonic-gate exprint(nextarg(&np))); 754*7c478bd9Sstevel@tonic-gate else { 755*7c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 0); 756*7c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, 757*7c478bd9Sstevel@tonic-gate exprint(nextarg(&np))); 758*7c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 759*7c478bd9Sstevel@tonic-gate length += slen; 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate continue; 762*7c478bd9Sstevel@tonic-gate 763*7c478bd9Sstevel@tonic-gate case 'e': 764*7c478bd9Sstevel@tonic-gate case 'E': 765*7c478bd9Sstevel@tonic-gate case 'f': 766*7c478bd9Sstevel@tonic-gate case 'F': 767*7c478bd9Sstevel@tonic-gate case 'g': 768*7c478bd9Sstevel@tonic-gate case 'G': 769*7c478bd9Sstevel@tonic-gate *ofmtp++ = c; 770*7c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 771*7c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 772*7c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, 773*7c478bd9Sstevel@tonic-gate exprreal(nextarg(&np))); 774*7c478bd9Sstevel@tonic-gate else { 775*7c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 0); 776*7c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, 777*7c478bd9Sstevel@tonic-gate exprreal(nextarg(&np))); 778*7c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 779*7c478bd9Sstevel@tonic-gate length += slen; 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate continue; 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate case 'l': 784*7c478bd9Sstevel@tonic-gate case 'L': 785*7c478bd9Sstevel@tonic-gate break; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate case '*': 788*7c478bd9Sstevel@tonic-gate #ifdef M_BSD_SPRINTF 789*7c478bd9Sstevel@tonic-gate sprintf(ofmtp, "%lld", (INT)exprint(nextarg(&np))); 790*7c478bd9Sstevel@tonic-gate ofmtp += strlen(ofmtp); 791*7c478bd9Sstevel@tonic-gate #else 792*7c478bd9Sstevel@tonic-gate ofmtp += sprintf(ofmtp, "%lld", (INT)exprint(nextarg(&np))); 793*7c478bd9Sstevel@tonic-gate #endif 794*7c478bd9Sstevel@tonic-gate break; 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate default: 797*7c478bd9Sstevel@tonic-gate if(c=='\0') { 798*7c478bd9Sstevel@tonic-gate *ofmtp = (wchar_t)NULL; 799*7c478bd9Sstevel@tonic-gate fprintf(fp,"%s",fmtbuf); 800*7c478bd9Sstevel@tonic-gate continue; 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate else { 803*7c478bd9Sstevel@tonic-gate *ofmtp++ = (wchar_t)c; 804*7c478bd9Sstevel@tonic-gate break; 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate } 807*7c478bd9Sstevel@tonic-gate goto nextc; 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate if (fmtsave != NULL) 810*7c478bd9Sstevel@tonic-gate free(fmtsave); 811*7c478bd9Sstevel@tonic-gate /* 812*7c478bd9Sstevel@tonic-gate * If printing to a character buffer then make sure it is 813*7c478bd9Sstevel@tonic-gate * null-terminated and only uses as much space as required. 814*7c478bd9Sstevel@tonic-gate */ 815*7c478bd9Sstevel@tonic-gate if (bptr != (wchar_t *)NULL) { 816*7c478bd9Sstevel@tonic-gate *bptr = '\0'; 817*7c478bd9Sstevel@tonic-gate *cp = erealloc(*cp, (length+1) * sizeof(wchar_t)); 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate return (length); 820*7c478bd9Sstevel@tonic-gate } 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate /* 823*7c478bd9Sstevel@tonic-gate * Return the next argument from the list. 824*7c478bd9Sstevel@tonic-gate */ 825*7c478bd9Sstevel@tonic-gate static NODE * 826*7c478bd9Sstevel@tonic-gate nextarg(NODE **npp) 827*7c478bd9Sstevel@tonic-gate { 828*7c478bd9Sstevel@tonic-gate register NODE *np; 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate if ((np = getlist(npp)) == NNULL) 831*7c478bd9Sstevel@tonic-gate awkerr(gettext("insufficient arguments to printf or sprintf")); 832*7c478bd9Sstevel@tonic-gate if (isleaf(np->n_flags) && np->n_type==PARM) 833*7c478bd9Sstevel@tonic-gate return (np->n_next); 834*7c478bd9Sstevel@tonic-gate return (np); 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate /* 839*7c478bd9Sstevel@tonic-gate * Check and adjust the length of the buffer that has been passed in 840*7c478bd9Sstevel@tonic-gate * to make sure that it has space to accomodate the sequence string 841*7c478bd9Sstevel@tonic-gate * described in fmtstr. This routine is used by xprintf() to allow 842*7c478bd9Sstevel@tonic-gate * for arbitrarily long sprintf() strings. 843*7c478bd9Sstevel@tonic-gate * 844*7c478bd9Sstevel@tonic-gate * bp = start of current buffer 845*7c478bd9Sstevel@tonic-gate * len = length of current buffer 846*7c478bd9Sstevel@tonic-gate * offset = offset in current buffer 847*7c478bd9Sstevel@tonic-gate * fmtstr = format string to check 848*7c478bd9Sstevel@tonic-gate * slen = size of string for %s formats 849*7c478bd9Sstevel@tonic-gate */ 850*7c478bd9Sstevel@tonic-gate static void 851*7c478bd9Sstevel@tonic-gate adjust_buf(wchar_t **bp, int *len, wchar_t **offset, char *fmtstr, size_t slen) 852*7c478bd9Sstevel@tonic-gate { 853*7c478bd9Sstevel@tonic-gate int ioff; 854*7c478bd9Sstevel@tonic-gate int width = 0; 855*7c478bd9Sstevel@tonic-gate int prec = 0; 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate do { 858*7c478bd9Sstevel@tonic-gate fmtstr++; 859*7c478bd9Sstevel@tonic-gate } while (strchr("-+ 0", *fmtstr) != (char *)0 || 860*7c478bd9Sstevel@tonic-gate *fmtstr == ('#')); 861*7c478bd9Sstevel@tonic-gate if (*fmtstr != '*') { 862*7c478bd9Sstevel@tonic-gate if (isdigit(*fmtstr)) { 863*7c478bd9Sstevel@tonic-gate width = *fmtstr-'0'; 864*7c478bd9Sstevel@tonic-gate while (isdigit(*++fmtstr)) 865*7c478bd9Sstevel@tonic-gate width = width * 10 + *fmtstr - '0'; 866*7c478bd9Sstevel@tonic-gate } 867*7c478bd9Sstevel@tonic-gate } else 868*7c478bd9Sstevel@tonic-gate fmtstr++; 869*7c478bd9Sstevel@tonic-gate if (*fmtstr == '.') { 870*7c478bd9Sstevel@tonic-gate if (*++fmtstr != '*') { 871*7c478bd9Sstevel@tonic-gate prec = *fmtstr-'0'; 872*7c478bd9Sstevel@tonic-gate while (isdigit(*++fmtstr)) 873*7c478bd9Sstevel@tonic-gate prec = prec * 10 + *fmtstr - '0'; 874*7c478bd9Sstevel@tonic-gate } else 875*7c478bd9Sstevel@tonic-gate fmtstr++; 876*7c478bd9Sstevel@tonic-gate } 877*7c478bd9Sstevel@tonic-gate if (strchr("Llh", *fmtstr) != (char *)0) 878*7c478bd9Sstevel@tonic-gate fmtstr++; 879*7c478bd9Sstevel@tonic-gate if (*fmtstr == 'S') 880*7c478bd9Sstevel@tonic-gate { 881*7c478bd9Sstevel@tonic-gate if (width && slen < width) 882*7c478bd9Sstevel@tonic-gate slen = width; 883*7c478bd9Sstevel@tonic-gate if (prec && slen > prec) 884*7c478bd9Sstevel@tonic-gate slen = prec; 885*7c478bd9Sstevel@tonic-gate width = slen+1; 886*7c478bd9Sstevel@tonic-gate } else 887*7c478bd9Sstevel@tonic-gate if (width == 0) 888*7c478bd9Sstevel@tonic-gate width = NUMSIZE; 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate if (*offset+ width > *bp+ *len) { 891*7c478bd9Sstevel@tonic-gate ioff = *offset-*bp; 892*7c478bd9Sstevel@tonic-gate *len += width+1; 893*7c478bd9Sstevel@tonic-gate *bp = erealloc(*bp, *len * sizeof(wchar_t)); 894*7c478bd9Sstevel@tonic-gate *offset = *bp+ioff; 895*7c478bd9Sstevel@tonic-gate } 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate static void 899*7c478bd9Sstevel@tonic-gate awk_putwc(wchar_t c, FILE *fp) 900*7c478bd9Sstevel@tonic-gate { 901*7c478bd9Sstevel@tonic-gate char mb[MB_LEN_MAX]; 902*7c478bd9Sstevel@tonic-gate size_t mbl; 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate if ((mbl = wctomb(mb, c)) > 0) { 905*7c478bd9Sstevel@tonic-gate mb[mbl] = '\0'; 906*7c478bd9Sstevel@tonic-gate (void)fputs(mb, fp); 907*7c478bd9Sstevel@tonic-gate } else 908*7c478bd9Sstevel@tonic-gate awkerr(gettext("invalid wide character %x"), c); 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate 911