17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*79777a7dSnakanon * Common Development and Distribution License (the "License"). 6*79777a7dSnakanon * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*79777a7dSnakanon * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23cb4658fbSceastha * Use is subject to license terms. 24cb4658fbSceastha */ 25cb4658fbSceastha 26cb4658fbSceastha /* 277c478bd9Sstevel@tonic-gate * Copyright 1986, 1994 by Mortice Kern Systems Inc. All rights reserved. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 317c478bd9Sstevel@tonic-gate 32cb4658fbSceastha /* 33cb4658fbSceastha * awk -- process input files, field extraction, output 34cb4658fbSceastha * 35cb4658fbSceastha * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes 36cb4658fbSceastha */ 37cb4658fbSceastha 387c478bd9Sstevel@tonic-gate #include "awk.h" 397c478bd9Sstevel@tonic-gate #include "y.tab.h" 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate static FILE *awkinfp; /* Input file pointer */ 427c478bd9Sstevel@tonic-gate static int reclen; /* Length of last record */ 437c478bd9Sstevel@tonic-gate static int exstat; /* Exit status */ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate static FILE *openfile(NODE *np, int flag, int fatal); 467c478bd9Sstevel@tonic-gate static FILE *newfile(void); 477c478bd9Sstevel@tonic-gate static NODE *nextarg(NODE **npp); 487c478bd9Sstevel@tonic-gate static void adjust_buf(wchar_t **, int *, wchar_t **, char *, size_t); 497c478bd9Sstevel@tonic-gate static void awk_putwc(wchar_t, FILE *); 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate /* 527c478bd9Sstevel@tonic-gate * mainline for awk execution 537c478bd9Sstevel@tonic-gate */ 547c478bd9Sstevel@tonic-gate void 557c478bd9Sstevel@tonic-gate awk() 567c478bd9Sstevel@tonic-gate { 577c478bd9Sstevel@tonic-gate running = 1; 587c478bd9Sstevel@tonic-gate dobegin(); 597c478bd9Sstevel@tonic-gate while (nextrecord(linebuf, awkinfp) > 0) 607c478bd9Sstevel@tonic-gate execute(yytree); 617c478bd9Sstevel@tonic-gate doend(exstat); 627c478bd9Sstevel@tonic-gate } 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate /* 657c478bd9Sstevel@tonic-gate * "cp" is the buffer to fill. There is a special case if this buffer is 667c478bd9Sstevel@tonic-gate * "linebuf" ($0) 677c478bd9Sstevel@tonic-gate * Return 1 if OK, zero on EOF, -1 on error. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate int 707c478bd9Sstevel@tonic-gate nextrecord(wchar_t *cp, FILE *fp) 717c478bd9Sstevel@tonic-gate { 727c478bd9Sstevel@tonic-gate wchar_t *ep = cp; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate nextfile: 757c478bd9Sstevel@tonic-gate if (fp == FNULL && (fp = newfile()) == FNULL) 767c478bd9Sstevel@tonic-gate return (0); 777c478bd9Sstevel@tonic-gate if ((*awkrecord)(ep, NLINE, fp) == NULL) { 787c478bd9Sstevel@tonic-gate if (fp == awkinfp) { 797c478bd9Sstevel@tonic-gate if (fp != stdin) 807c478bd9Sstevel@tonic-gate (void) fclose(awkinfp); 817c478bd9Sstevel@tonic-gate awkinfp = fp = FNULL; 827c478bd9Sstevel@tonic-gate goto nextfile; 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate if (ferror(fp)) 857c478bd9Sstevel@tonic-gate return (-1); 867c478bd9Sstevel@tonic-gate return (0); 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate if (fp == awkinfp) { 897c478bd9Sstevel@tonic-gate if (varNR->n_flags & FINT) 90cb4658fbSceastha ++varNR->n_int; 91cb4658fbSceastha else 927c478bd9Sstevel@tonic-gate (void) exprreduce(incNR); 937c478bd9Sstevel@tonic-gate if (varFNR->n_flags & FINT) 94cb4658fbSceastha ++varFNR->n_int; 95cb4658fbSceastha else 967c478bd9Sstevel@tonic-gate (void) exprreduce(incFNR); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate if (cp == linebuf) { 997c478bd9Sstevel@tonic-gate lbuflen = reclen; 1007c478bd9Sstevel@tonic-gate splitdone = 0; 1017c478bd9Sstevel@tonic-gate if (needsplit) 1027c478bd9Sstevel@tonic-gate fieldsplit(); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate /* if record length is too long then bail out */ 1057c478bd9Sstevel@tonic-gate if (reclen > NLINE - 2) { 1067c478bd9Sstevel@tonic-gate awkerr(gettext("Record too long (LIMIT: %d bytes)"), 1077c478bd9Sstevel@tonic-gate NLINE - 1); 1087c478bd9Sstevel@tonic-gate /* Not Reached */ 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate return (1); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 114cb4658fbSceastha * isclvar() 115cb4658fbSceastha * 116cb4658fbSceastha * Returns 1 if the input string, arg, is a variable assignment, 117cb4658fbSceastha * otherwise returns 0. 118cb4658fbSceastha * 119cb4658fbSceastha * An argument to awk can be either a pathname of a file, or a variable 120cb4658fbSceastha * assignment. An operand that begins with an undersore or alphabetic 121cb4658fbSceastha * character from the portable character set, followed by a sequence of 122cb4658fbSceastha * underscores, digits, and alphabetics from the portable character set, 123cb4658fbSceastha * followed by the '=' character, shall specify a variable assignment 124cb4658fbSceastha * rather than a pathname. 125cb4658fbSceastha */ 126cb4658fbSceastha int 127cb4658fbSceastha isclvar(wchar_t *arg) 128cb4658fbSceastha { 129cb4658fbSceastha wchar_t *tmpptr = arg; 130cb4658fbSceastha 131cb4658fbSceastha if (tmpptr != NULL) { 132cb4658fbSceastha 133cb4658fbSceastha /* Begins with an underscore or alphabetic character */ 134cb4658fbSceastha if (iswalpha(*tmpptr) || *tmpptr == '_') { 135cb4658fbSceastha 136cb4658fbSceastha /* 137cb4658fbSceastha * followed by a sequence of underscores, digits, 138cb4658fbSceastha * and alphabetics 139cb4658fbSceastha */ 140cb4658fbSceastha for (tmpptr++; *tmpptr; tmpptr++) { 141baaf2753Sceastha if (!(iswalnum(*tmpptr) || (*tmpptr == '_'))) { 142cb4658fbSceastha break; 143cb4658fbSceastha } 144cb4658fbSceastha } 145cb4658fbSceastha return (*tmpptr == '='); 146cb4658fbSceastha } 147cb4658fbSceastha } 148cb4658fbSceastha 149cb4658fbSceastha return (0); 150cb4658fbSceastha } 151cb4658fbSceastha 152cb4658fbSceastha /* 1537c478bd9Sstevel@tonic-gate * Return the next file from the command line. 1547c478bd9Sstevel@tonic-gate * Return FNULL when no more files. 1557c478bd9Sstevel@tonic-gate * Sets awkinfp variable to the new current input file. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate static FILE * 1587c478bd9Sstevel@tonic-gate newfile() 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate static int argindex = 1; 1617c478bd9Sstevel@tonic-gate static int filedone; 162cb4658fbSceastha wchar_t *ap; 163cb4658fbSceastha int argc; 1647c478bd9Sstevel@tonic-gate wchar_t *arg; 1657c478bd9Sstevel@tonic-gate extern void strescape(wchar_t *); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate argc = (int)exprint(varARGC); 1687c478bd9Sstevel@tonic-gate for (;;) { 1697c478bd9Sstevel@tonic-gate if (argindex >= argc) { 1707c478bd9Sstevel@tonic-gate if (filedone) 1717c478bd9Sstevel@tonic-gate return (FNULL); 1727c478bd9Sstevel@tonic-gate ++filedone; 1737c478bd9Sstevel@tonic-gate awkinfp = stdin; 1747c478bd9Sstevel@tonic-gate arg = M_MB_L("-"); 1757c478bd9Sstevel@tonic-gate break; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate constant->n_int = argindex++; 1787c478bd9Sstevel@tonic-gate arg = (wchar_t *)exprstring(ARGVsubi); 179cb4658fbSceastha /* 180cb4658fbSceastha * If the argument contains a '=', determine if the 181cb4658fbSceastha * argument needs to be treated as a variable assignment 182cb4658fbSceastha * or as the pathname of a file. 183cb4658fbSceastha */ 184cb4658fbSceastha if (((ap = wcschr(arg, '=')) != NULL) && isclvar(arg)) { 1857c478bd9Sstevel@tonic-gate *ap = '\0'; 1867c478bd9Sstevel@tonic-gate strescape(ap+1); 1877c478bd9Sstevel@tonic-gate strassign(vlook(arg), linebuf, FALLOC|FSENSE, 1887c478bd9Sstevel@tonic-gate wcslen(linebuf)); 1897c478bd9Sstevel@tonic-gate *ap = '='; 1907c478bd9Sstevel@tonic-gate continue; 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate if (arg[0] == '\0') 1937c478bd9Sstevel@tonic-gate continue; 1947c478bd9Sstevel@tonic-gate ++filedone; 1957c478bd9Sstevel@tonic-gate if (arg[0] == '-' && arg[1] == '\0') { 1967c478bd9Sstevel@tonic-gate awkinfp = stdin; 1977c478bd9Sstevel@tonic-gate break; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate if ((awkinfp = fopen(mbunconvert(arg), r)) == FNULL) { 2007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("input file \"%s\""), 2017c478bd9Sstevel@tonic-gate mbunconvert(arg)); 2027c478bd9Sstevel@tonic-gate exstat = 1; 2037c478bd9Sstevel@tonic-gate continue; 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate break; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate strassign(varFILENAME, arg, FALLOC, wcslen(arg)); 2087c478bd9Sstevel@tonic-gate if (varFNR->n_flags & FINT) 209cb4658fbSceastha varFNR->n_int = 0; 210cb4658fbSceastha else 2117c478bd9Sstevel@tonic-gate (void) exprreduce(clrFNR); 2127c478bd9Sstevel@tonic-gate return (awkinfp); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Default record reading code 2177c478bd9Sstevel@tonic-gate * Uses fgets for potential speedups found in some (e.g. MKS) 2187c478bd9Sstevel@tonic-gate * stdio packages. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate wchar_t * 2217c478bd9Sstevel@tonic-gate defrecord(wchar_t *bp, int lim, FILE *fp) 2227c478bd9Sstevel@tonic-gate { 223cb4658fbSceastha wchar_t *endp; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate if (fgetws(bp, lim, fp) == NULL) { 2267c478bd9Sstevel@tonic-gate *bp = '\0'; 2277c478bd9Sstevel@tonic-gate return (NULL); 2287c478bd9Sstevel@tonic-gate } 229cb4658fbSceastha /* 230cb4658fbSceastha * XXXX 231cb4658fbSceastha * switch (fgetws(bp, lim, fp)) { 232cb4658fbSceastha * case M_FGETS_EOF: 233cb4658fbSceastha * *bp = '\0'; 234cb4658fbSceastha * return (NULL); 235cb4658fbSceastha * case M_FGETS_BINARY: 236cb4658fbSceastha * awkerr(gettext("file is binary")); 237cb4658fbSceastha * case M_FGETS_LONG: 238cb4658fbSceastha * awkerr(gettext("line too long: limit %d"), 239cb4658fbSceastha * lim); 240cb4658fbSceastha * case M_FGETS_ERROR: 241cb4658fbSceastha * awkperr(gettext("error reading file")); 242cb4658fbSceastha * } 2437c478bd9Sstevel@tonic-gate */ 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (*(endp = (bp + (reclen = wcslen(bp))-1)) == '\n') { 2467c478bd9Sstevel@tonic-gate *endp = '\0'; 2477c478bd9Sstevel@tonic-gate reclen--; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate return (bp); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * Read a record separated by one character in the RS. 2547c478bd9Sstevel@tonic-gate * Compatible calling sequence with fgets, but don't include 2557c478bd9Sstevel@tonic-gate * record separator character in string. 2567c478bd9Sstevel@tonic-gate */ 2577c478bd9Sstevel@tonic-gate wchar_t * 2587c478bd9Sstevel@tonic-gate charrecord(wchar_t *abp, int alim, FILE *fp) 2597c478bd9Sstevel@tonic-gate { 260cb4658fbSceastha wchar_t *bp; 261cb4658fbSceastha wint_t c; 262cb4658fbSceastha int limit = alim; 263cb4658fbSceastha wint_t endc; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate bp = abp; 2667c478bd9Sstevel@tonic-gate endc = *(wchar_t *)varRS->n_string; 2677c478bd9Sstevel@tonic-gate while (--limit > 0 && (c = getwc(fp)) != endc && c != WEOF) 2687c478bd9Sstevel@tonic-gate *bp++ = c; 2697c478bd9Sstevel@tonic-gate *bp = '\0'; 2707c478bd9Sstevel@tonic-gate reclen = bp-abp; 2717c478bd9Sstevel@tonic-gate return (c == WEOF && bp == abp ? NULL : abp); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Special routine for multiple line records. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate wchar_t * 2787c478bd9Sstevel@tonic-gate multirecord(wchar_t *abp, int limit, FILE *fp) 2797c478bd9Sstevel@tonic-gate { 280cb4658fbSceastha wchar_t *bp; 281cb4658fbSceastha int c; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate while ((c = getwc(fp)) == '\n') 2847c478bd9Sstevel@tonic-gate ; 2857c478bd9Sstevel@tonic-gate bp = abp; 2867c478bd9Sstevel@tonic-gate if (c != WEOF) do { 2877c478bd9Sstevel@tonic-gate if (--limit == 0) 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate if (c == '\n' && bp[-1] == '\n') 2907c478bd9Sstevel@tonic-gate break; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate *bp++ = c; 2937c478bd9Sstevel@tonic-gate } while ((c = getwc(fp)) != WEOF); 2947c478bd9Sstevel@tonic-gate *bp = '\0'; 2957c478bd9Sstevel@tonic-gate if (bp > abp) 2967c478bd9Sstevel@tonic-gate *--bp = '\0'; 2977c478bd9Sstevel@tonic-gate reclen = bp-abp; 2987c478bd9Sstevel@tonic-gate return (c == WEOF && bp == abp ? NULL : abp); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* 3027c478bd9Sstevel@tonic-gate * Look for fields separated by spaces, tabs or newlines. 3037c478bd9Sstevel@tonic-gate * Extract the next field, given pointer to start address. 3047c478bd9Sstevel@tonic-gate * Return pointer to beginning of field or NULL. 3057c478bd9Sstevel@tonic-gate * Reset end of field reference, which is the beginning of the 3067c478bd9Sstevel@tonic-gate * next field. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate wchar_t * 3097c478bd9Sstevel@tonic-gate whitefield(wchar_t **endp) 3107c478bd9Sstevel@tonic-gate { 311cb4658fbSceastha wchar_t *sp; 312cb4658fbSceastha wchar_t *ep; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate sp = *endp; 3157c478bd9Sstevel@tonic-gate while (*sp == ' ' || *sp == '\t' || *sp == '\n') 3167c478bd9Sstevel@tonic-gate ++sp; 3177c478bd9Sstevel@tonic-gate if (*sp == '\0') 3187c478bd9Sstevel@tonic-gate return (NULL); 319cb4658fbSceastha for (ep = sp; *ep != ' ' && *ep != '\0' && *ep != '\t' && 320cb4658fbSceastha *ep != '\n'; ++ep) 3217c478bd9Sstevel@tonic-gate ; 3227c478bd9Sstevel@tonic-gate *endp = ep; 3237c478bd9Sstevel@tonic-gate return (sp); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * Look for fields separated by non-whitespace characters. 3287c478bd9Sstevel@tonic-gate * Same calling sequence as whitefield(). 3297c478bd9Sstevel@tonic-gate */ 3307c478bd9Sstevel@tonic-gate wchar_t * 3317c478bd9Sstevel@tonic-gate blackfield(wchar_t **endp) 3327c478bd9Sstevel@tonic-gate { 333cb4658fbSceastha wchar_t *cp; 334cb4658fbSceastha int endc; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate endc = *(wchar_t *)varFS->n_string; 3377c478bd9Sstevel@tonic-gate cp = *endp; 3387c478bd9Sstevel@tonic-gate if (*cp == '\0') 3397c478bd9Sstevel@tonic-gate return (NULL); 3407c478bd9Sstevel@tonic-gate if (*cp == endc && fcount != 0) 3417c478bd9Sstevel@tonic-gate cp++; 3427c478bd9Sstevel@tonic-gate if ((*endp = wcschr(cp, endc)) == NULL) 3437c478bd9Sstevel@tonic-gate *endp = wcschr(cp, '\0'); 3447c478bd9Sstevel@tonic-gate return (cp); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * This field separation routine uses the same logic as 3497c478bd9Sstevel@tonic-gate * blackfield but uses a regular expression to separate 3507c478bd9Sstevel@tonic-gate * the fields. 3517c478bd9Sstevel@tonic-gate */ 3527c478bd9Sstevel@tonic-gate wchar_t * 3537c478bd9Sstevel@tonic-gate refield(wchar_t **endpp) 3547c478bd9Sstevel@tonic-gate { 355cb4658fbSceastha wchar_t *cp, *start; 356cb4658fbSceastha int flags; 3577c478bd9Sstevel@tonic-gate static REGWMATCH_T match[10]; 3587c478bd9Sstevel@tonic-gate int result; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate cp = *endpp; 3617c478bd9Sstevel@tonic-gate if (*cp == '\0') { 3627c478bd9Sstevel@tonic-gate match[0].rm_ep = NULL; 3637c478bd9Sstevel@tonic-gate return (NULL); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate if (match[0].rm_ep != NULL) { 3667c478bd9Sstevel@tonic-gate flags = REG_NOTBOL; 3677c478bd9Sstevel@tonic-gate cp = (wchar_t *)match[0].rm_ep; 3687c478bd9Sstevel@tonic-gate } else 3697c478bd9Sstevel@tonic-gate flags = 0; 3707c478bd9Sstevel@tonic-gate start = cp; 3717c478bd9Sstevel@tonic-gate again: 3727c478bd9Sstevel@tonic-gate switch ((result = REGWEXEC(resep, cp, 10, match, flags))) { 3737c478bd9Sstevel@tonic-gate case REG_OK: 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Check to see if a null string was matched. If this is the 3767c478bd9Sstevel@tonic-gate * case, then move the current pointer beyond this position. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate if (match[0].rm_sp == match[0].rm_ep) { 3797c478bd9Sstevel@tonic-gate cp = (wchar_t *)match[0].rm_sp; 3807c478bd9Sstevel@tonic-gate if (*cp++ != '\0') { 3817c478bd9Sstevel@tonic-gate goto again; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate *endpp = (wchar_t *)match[0].rm_sp; 3857c478bd9Sstevel@tonic-gate break; 3867c478bd9Sstevel@tonic-gate case REG_NOMATCH: 3877c478bd9Sstevel@tonic-gate match[0].rm_ep = NULL; 3887c478bd9Sstevel@tonic-gate *endpp = wcschr(cp, '\0'); 3897c478bd9Sstevel@tonic-gate break; 3907c478bd9Sstevel@tonic-gate default: 391*79777a7dSnakanon (void) REGWERROR(result, resep, (char *)linebuf, 392cb4658fbSceastha sizeof (linebuf)); 3937c478bd9Sstevel@tonic-gate awkerr(gettext("error splitting record: %s"), 3947c478bd9Sstevel@tonic-gate (char *)linebuf); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate return (start); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * do begin processing 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate void 4037c478bd9Sstevel@tonic-gate dobegin() 4047c478bd9Sstevel@tonic-gate { 405cb4658fbSceastha /* 4067c478bd9Sstevel@tonic-gate * Free all keyword nodes to save space. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate NODE *np; 4107c478bd9Sstevel@tonic-gate int nbuck; 411cb4658fbSceastha NODE *knp; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate np = NNULL; 4147c478bd9Sstevel@tonic-gate nbuck = 0; 4157c478bd9Sstevel@tonic-gate while ((knp = symwalk(&nbuck, &np)) != NNULL) 4167c478bd9Sstevel@tonic-gate if (knp->n_type == KEYWORD) 4177c478bd9Sstevel@tonic-gate delsymtab(knp, 1); 4187c478bd9Sstevel@tonic-gate } 419cb4658fbSceastha /* 4207c478bd9Sstevel@tonic-gate * Copy ENVIRON array only if needed. 4217c478bd9Sstevel@tonic-gate * Note the convoluted work to assign to an array 4227c478bd9Sstevel@tonic-gate * and that the temporary nodes will be freed by 4237c478bd9Sstevel@tonic-gate * freetemps() because we are "running". 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate if (needenviron) { 426cb4658fbSceastha char **app; 427cb4658fbSceastha wchar_t *name, *value; 428cb4658fbSceastha NODE *namep = stringnode(_null, FSTATIC, 0); 429cb4658fbSceastha NODE *valuep = stringnode(_null, FSTATIC, 0); 430cb4658fbSceastha NODE *ENVsubname = node(INDEX, varENVIRON, namep); 4317c478bd9Sstevel@tonic-gate extern char **environ; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* (void) m_setenv(); XXX what's this do? */ 434cb4658fbSceastha for (app = environ; *app != NULL; /* empty */) { 4357c478bd9Sstevel@tonic-gate name = mbstowcsdup(*app++); 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate if ((value = wcschr(name, '=')) != NULL) { 4387c478bd9Sstevel@tonic-gate *value++ = '\0'; 4397c478bd9Sstevel@tonic-gate valuep->n_strlen = wcslen(value); 4407c478bd9Sstevel@tonic-gate valuep->n_string = value; 4417c478bd9Sstevel@tonic-gate } else { 4427c478bd9Sstevel@tonic-gate valuep->n_strlen = 0; 4437c478bd9Sstevel@tonic-gate valuep->n_string = _null; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate namep->n_strlen = wcslen(namep->n_string = name); 4467c478bd9Sstevel@tonic-gate (void) assign(ENVsubname, valuep); 4477c478bd9Sstevel@tonic-gate if (value != NULL) 4487c478bd9Sstevel@tonic-gate value[-1] = '='; 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate phase = BEGIN; 4527c478bd9Sstevel@tonic-gate execute(yytree); 4537c478bd9Sstevel@tonic-gate phase = 0; 4547c478bd9Sstevel@tonic-gate if (npattern == 0) 4557c478bd9Sstevel@tonic-gate doend(0); 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * Delete all pattern/action rules that are BEGIN at this 4587c478bd9Sstevel@tonic-gate * point to save space. 4597c478bd9Sstevel@tonic-gate * NOTE: this is not yet implemented. 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * Do end processing. 4657c478bd9Sstevel@tonic-gate * Exit with a status 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate void 4687c478bd9Sstevel@tonic-gate doend(int s) 4697c478bd9Sstevel@tonic-gate { 470cb4658fbSceastha OFILE *op; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (phase != END) { 4737c478bd9Sstevel@tonic-gate phase = END; 4747c478bd9Sstevel@tonic-gate awkinfp = stdin; 4757c478bd9Sstevel@tonic-gate execute(yytree); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate for (op = &ofiles[0]; op < &ofiles[NIOSTREAM]; op++) 4787c478bd9Sstevel@tonic-gate if (op->f_fp != FNULL) 4797c478bd9Sstevel@tonic-gate awkclose(op); 4807c478bd9Sstevel@tonic-gate if (awkinfp == stdin) 4817c478bd9Sstevel@tonic-gate (void) fflush(awkinfp); 4827c478bd9Sstevel@tonic-gate exit(s); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * Print statement. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate void 4897c478bd9Sstevel@tonic-gate s_print(NODE *np) 4907c478bd9Sstevel@tonic-gate { 491cb4658fbSceastha FILE *fp; 4927c478bd9Sstevel@tonic-gate NODE *listp; 493cb4658fbSceastha char *ofs; 494cb4658fbSceastha int notfirst = 0; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate fp = openfile(np->n_right, 1, 1); 4977c478bd9Sstevel@tonic-gate if (np->n_left == NNULL) 4987c478bd9Sstevel@tonic-gate (void) fputs(mbunconvert(linebuf), fp); 4997c478bd9Sstevel@tonic-gate else { 5007c478bd9Sstevel@tonic-gate ofs = wcstombsdup((isstring(varOFS->n_flags)) ? 5017c478bd9Sstevel@tonic-gate (wchar_t *)varOFS->n_string : 5027c478bd9Sstevel@tonic-gate (wchar_t *)exprstring(varOFS)); 5037c478bd9Sstevel@tonic-gate listp = np->n_left; 5047c478bd9Sstevel@tonic-gate while ((np = getlist(&listp)) != NNULL) { 5057c478bd9Sstevel@tonic-gate if (notfirst++) 5067c478bd9Sstevel@tonic-gate (void) fputs(ofs, fp); 5077c478bd9Sstevel@tonic-gate np = exprreduce(np); 5087c478bd9Sstevel@tonic-gate if (np->n_flags & FINT) 5097c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%lld", (INT)np->n_int); 5107c478bd9Sstevel@tonic-gate else if (isstring(np->n_flags)) 511cb4658fbSceastha (void) fprintf(fp, "%S", np->n_string); 5127c478bd9Sstevel@tonic-gate else 5137c478bd9Sstevel@tonic-gate (void) fprintf(fp, 5147c478bd9Sstevel@tonic-gate mbunconvert((wchar_t *)exprstring(varOFMT)), 5157c478bd9Sstevel@tonic-gate (double)np->n_real); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate free(ofs); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate (void) fputs(mbunconvert(isstring(varORS->n_flags) ? 5207c478bd9Sstevel@tonic-gate (wchar_t *)varORS->n_string : (wchar_t *)exprstring(varORS)), 5217c478bd9Sstevel@tonic-gate fp); 5227c478bd9Sstevel@tonic-gate if (ferror(fp)) 5237c478bd9Sstevel@tonic-gate awkperr("error on print"); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * printf statement. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate void 5307c478bd9Sstevel@tonic-gate s_prf(NODE *np) 5317c478bd9Sstevel@tonic-gate { 532cb4658fbSceastha FILE *fp; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate fp = openfile(np->n_right, 1, 1); 5357c478bd9Sstevel@tonic-gate (void) xprintf(np->n_left, fp, (wchar_t **)NULL); 5367c478bd9Sstevel@tonic-gate if (ferror(fp)) 5377c478bd9Sstevel@tonic-gate awkperr("error on printf"); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Get next input line. 5427c478bd9Sstevel@tonic-gate * Read into variable on left of node (or $0 if NULL). 5437c478bd9Sstevel@tonic-gate * Read from pipe or file on right of node (or from regular 5447c478bd9Sstevel@tonic-gate * input if NULL). 5457c478bd9Sstevel@tonic-gate * This is an oddball inasmuch as it is a function 5467c478bd9Sstevel@tonic-gate * but parses more like the keywords print, etc. 5477c478bd9Sstevel@tonic-gate */ 5487c478bd9Sstevel@tonic-gate NODE * 5497c478bd9Sstevel@tonic-gate f_getline(NODE *np) 5507c478bd9Sstevel@tonic-gate { 551cb4658fbSceastha wchar_t *cp; 552cb4658fbSceastha INT ret; 553cb4658fbSceastha FILE *fp; 554cb4658fbSceastha size_t len; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate if (np->n_right == NULL && phase == END) { 5577c478bd9Sstevel@tonic-gate /* Pretend we've reached end of (the non-existant) file. */ 558cb4658fbSceastha return (intnode(0)); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if ((fp = openfile(np->n_right, 0, 0)) != FNULL) { 5627c478bd9Sstevel@tonic-gate if (np->n_left == NNULL) { 5637c478bd9Sstevel@tonic-gate ret = nextrecord(linebuf, fp); 5647c478bd9Sstevel@tonic-gate } else { 5657c478bd9Sstevel@tonic-gate cp = emalloc(NLINE * sizeof (wchar_t)); 5667c478bd9Sstevel@tonic-gate ret = nextrecord(cp, fp); 5677c478bd9Sstevel@tonic-gate np = np->n_left; 5687c478bd9Sstevel@tonic-gate len = wcslen(cp); 5697c478bd9Sstevel@tonic-gate cp = erealloc(cp, (len+1)*sizeof (wchar_t)); 5707c478bd9Sstevel@tonic-gate if (isleaf(np->n_flags)) { 5717c478bd9Sstevel@tonic-gate if (np->n_type == PARM) 5727c478bd9Sstevel@tonic-gate np = np->n_next; 5737c478bd9Sstevel@tonic-gate strassign(np, cp, FNOALLOC, len); 5747c478bd9Sstevel@tonic-gate } else 575cb4658fbSceastha (void) assign(np, stringnode(cp, 576cb4658fbSceastha FNOALLOC, len)); 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate } else 5797c478bd9Sstevel@tonic-gate ret = -1; 5807c478bd9Sstevel@tonic-gate return (intnode(ret)); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * Open a file. Flag is non-zero for output. 5857c478bd9Sstevel@tonic-gate */ 5867c478bd9Sstevel@tonic-gate static FILE * 5877c478bd9Sstevel@tonic-gate openfile(NODE *np, int flag, int fatal) 5887c478bd9Sstevel@tonic-gate { 589cb4658fbSceastha OFILE *op; 590cb4658fbSceastha char *cp; 591cb4658fbSceastha FILE *fp; 592cb4658fbSceastha int type; 593cb4658fbSceastha OFILE *fop; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate if (np == NNULL) { 5967c478bd9Sstevel@tonic-gate if (flag) 5977c478bd9Sstevel@tonic-gate return (stdout); 5987c478bd9Sstevel@tonic-gate if (awkinfp == FNULL) 5997c478bd9Sstevel@tonic-gate awkinfp = newfile(); 6007c478bd9Sstevel@tonic-gate return (awkinfp); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate if ((type = np->n_type) == APPEND) 6037c478bd9Sstevel@tonic-gate type = WRITE; 6047c478bd9Sstevel@tonic-gate cp = mbunconvert(exprstring(np->n_left)); 6057c478bd9Sstevel@tonic-gate fop = (OFILE *)NULL; 6067c478bd9Sstevel@tonic-gate for (op = &ofiles[0]; op < &ofiles[NIOSTREAM]; op++) { 6077c478bd9Sstevel@tonic-gate if (op->f_fp == FNULL) { 6087c478bd9Sstevel@tonic-gate if (fop == (OFILE *)NULL) 6097c478bd9Sstevel@tonic-gate fop = op; 6107c478bd9Sstevel@tonic-gate continue; 6117c478bd9Sstevel@tonic-gate } 612cb4658fbSceastha if (op->f_mode == type && strcmp(op->f_name, cp) == 0) 6137c478bd9Sstevel@tonic-gate return (op->f_fp); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate if (fop == (OFILE *)NULL) 6167c478bd9Sstevel@tonic-gate awkerr(gettext("too many open streams to %s onto \"%s\""), 6177c478bd9Sstevel@tonic-gate flag ? "print/printf" : "getline", cp); 6187c478bd9Sstevel@tonic-gate (void) fflush(stdout); 6197c478bd9Sstevel@tonic-gate op = fop; 6207c478bd9Sstevel@tonic-gate if (cp[0] == '-' && cp[1] == '\0') { 6217c478bd9Sstevel@tonic-gate fp = flag ? stdout : stdin; 6227c478bd9Sstevel@tonic-gate } else { 6237c478bd9Sstevel@tonic-gate switch (np->n_type) { 6247c478bd9Sstevel@tonic-gate case WRITE: 6257c478bd9Sstevel@tonic-gate if ((fp = fopen(cp, w)) != FNULL) { 6267c478bd9Sstevel@tonic-gate if (isatty(fileno(fp))) 6277c478bd9Sstevel@tonic-gate (void) setvbuf(fp, 0, _IONBF, 0); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate break; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate case APPEND: 6327c478bd9Sstevel@tonic-gate fp = fopen(cp, "a"); 6337c478bd9Sstevel@tonic-gate break; 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate case PIPE: 6367c478bd9Sstevel@tonic-gate fp = popen(cp, w); 6377c478bd9Sstevel@tonic-gate (void) setvbuf(fp, (char *)0, _IOLBF, 0); 6387c478bd9Sstevel@tonic-gate break; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate case PIPESYM: 6417c478bd9Sstevel@tonic-gate fp = popen(cp, r); 6427c478bd9Sstevel@tonic-gate break; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate case LT: 6457c478bd9Sstevel@tonic-gate fp = fopen(cp, r); 6467c478bd9Sstevel@tonic-gate break; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate default: 6497c478bd9Sstevel@tonic-gate awkerr(interr, "openfile"); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate if (fp != FNULL) { 6537c478bd9Sstevel@tonic-gate op->f_name = strdup(cp); 6547c478bd9Sstevel@tonic-gate op->f_fp = fp; 6557c478bd9Sstevel@tonic-gate op->f_mode = type; 6567c478bd9Sstevel@tonic-gate } else if (fatal) { 6577c478bd9Sstevel@tonic-gate awkperr(flag ? gettext("output file \"%s\"") : 6587c478bd9Sstevel@tonic-gate gettext("input file \"%s\""), cp); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate return (fp); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Close a stream. 6657c478bd9Sstevel@tonic-gate */ 6667c478bd9Sstevel@tonic-gate void 6677c478bd9Sstevel@tonic-gate awkclose(OFILE *op) 6687c478bd9Sstevel@tonic-gate { 6697c478bd9Sstevel@tonic-gate if (op->f_mode == PIPE || op->f_mode == PIPESYM) 6707c478bd9Sstevel@tonic-gate (void) pclose(op->f_fp); 6717c478bd9Sstevel@tonic-gate else if (fclose(op->f_fp) == EOF) 6727c478bd9Sstevel@tonic-gate awkperr("error on stream \"%s\"", op->f_name); 6737c478bd9Sstevel@tonic-gate op->f_fp = FNULL; 6747c478bd9Sstevel@tonic-gate free(op->f_name); 6757c478bd9Sstevel@tonic-gate op->f_name = NULL; 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * Internal routine common to printf, sprintf. 6807c478bd9Sstevel@tonic-gate * The node is that describing the arguments. 6817c478bd9Sstevel@tonic-gate * Returns the number of characters written to file 6827c478bd9Sstevel@tonic-gate * pointer `fp' or the length of the string return 6837c478bd9Sstevel@tonic-gate * in cp. If cp is NULL then the file pointer is used. If 6847c478bd9Sstevel@tonic-gate * cp points to a string pointer, a pointer to an allocated 6857c478bd9Sstevel@tonic-gate * buffer will be returned in it. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate size_t 6887c478bd9Sstevel@tonic-gate xprintf(NODE *np, FILE *fp, wchar_t **cp) 6897c478bd9Sstevel@tonic-gate { 690cb4658fbSceastha wchar_t *fmt; 691cb4658fbSceastha int c; 6927c478bd9Sstevel@tonic-gate wchar_t *bptr = (wchar_t *)NULL; 6937c478bd9Sstevel@tonic-gate char fmtbuf[40]; 694cb4658fbSceastha size_t length = 0; 695cb4658fbSceastha char *ofmtp; 696cb4658fbSceastha NODE *fnp; 697cb4658fbSceastha wchar_t *fmtsave; 6987c478bd9Sstevel@tonic-gate int slen; 6997c478bd9Sstevel@tonic-gate int cplen; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate fnp = getlist(&np); 7027c478bd9Sstevel@tonic-gate if (isleaf(fnp->n_flags) && fnp->n_type == PARM) 7037c478bd9Sstevel@tonic-gate fnp = fnp->n_next; 7047c478bd9Sstevel@tonic-gate if (isstring(fnp->n_flags)) { 7057c478bd9Sstevel@tonic-gate fmt = fnp->n_string; 7067c478bd9Sstevel@tonic-gate fmtsave = NULL; 7077c478bd9Sstevel@tonic-gate } else 7087c478bd9Sstevel@tonic-gate fmtsave = fmt = (wchar_t *)strsave(exprstring(fnp)); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * if a char * pointer has been passed in then allocate an initial 7127c478bd9Sstevel@tonic-gate * buffer for the string. Make it LINE_MAX plus the length of 7137c478bd9Sstevel@tonic-gate * the format string but do reallocs only based LINE_MAX. 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate if (cp != (wchar_t **)NULL) { 7167c478bd9Sstevel@tonic-gate cplen = LINE_MAX; 7177c478bd9Sstevel@tonic-gate bptr = *cp = emalloc(sizeof (wchar_t) * (cplen + wcslen(fmt))); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate while ((c = *fmt++) != '\0') { 7217c478bd9Sstevel@tonic-gate if (c != '%') { 7227c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 7237c478bd9Sstevel@tonic-gate awk_putwc(c, fp); 7247c478bd9Sstevel@tonic-gate else 7257c478bd9Sstevel@tonic-gate *bptr++ = c; 7267c478bd9Sstevel@tonic-gate ++length; 7277c478bd9Sstevel@tonic-gate continue; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate ofmtp = fmtbuf; 7307c478bd9Sstevel@tonic-gate *ofmtp++ = (char)c; 7317c478bd9Sstevel@tonic-gate nextc: 7327c478bd9Sstevel@tonic-gate switch (c = *fmt++) { 7337c478bd9Sstevel@tonic-gate case '%': 7347c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 7357c478bd9Sstevel@tonic-gate awk_putwc(c, fp); 7367c478bd9Sstevel@tonic-gate else 7377c478bd9Sstevel@tonic-gate *bptr++ = c; 7387c478bd9Sstevel@tonic-gate ++length; 7397c478bd9Sstevel@tonic-gate continue; 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate case 'c': 7427c478bd9Sstevel@tonic-gate *ofmtp++ = 'w'; 7437c478bd9Sstevel@tonic-gate *ofmtp++ = 'c'; 7447c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 7457c478bd9Sstevel@tonic-gate fnp = exprreduce(nextarg(&np)); 7467c478bd9Sstevel@tonic-gate if (isnumber(fnp->n_flags)) 7477c478bd9Sstevel@tonic-gate c = exprint(fnp); 7487c478bd9Sstevel@tonic-gate else 7497c478bd9Sstevel@tonic-gate c = *(wchar_t *)exprstring(fnp); 7507c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 7517c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, c); 7527c478bd9Sstevel@tonic-gate else { 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * Make sure that the buffer is long 7557c478bd9Sstevel@tonic-gate * enough to hold the formatted string. 7567c478bd9Sstevel@tonic-gate */ 7577c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 0); 7587c478bd9Sstevel@tonic-gate /* 7597c478bd9Sstevel@tonic-gate * Since the call to adjust_buf() has already 7607c478bd9Sstevel@tonic-gate * guaranteed that the buffer will be long 7617c478bd9Sstevel@tonic-gate * enough, just pass in INT_MAX as 7627c478bd9Sstevel@tonic-gate * the length. 7637c478bd9Sstevel@tonic-gate */ 7647c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, c); 7657c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 7667c478bd9Sstevel@tonic-gate length += slen; 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate continue; 7697c478bd9Sstevel@tonic-gate /* XXXX Is this bogus? Figure out what s & S mean - look at original code */ 7707c478bd9Sstevel@tonic-gate case 's': 7717c478bd9Sstevel@tonic-gate case 'S': 7727c478bd9Sstevel@tonic-gate *ofmtp++ = 'w'; 7737c478bd9Sstevel@tonic-gate *ofmtp++ = 's'; 7747c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 7757c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 7767c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, 7777c478bd9Sstevel@tonic-gate (wchar_t *)exprstring(nextarg(&np))); 7787c478bd9Sstevel@tonic-gate else { 7797c478bd9Sstevel@tonic-gate wchar_t *ts = exprstring(nextarg(&np)); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 7827c478bd9Sstevel@tonic-gate wcslen(ts)); 7837c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, 7847c478bd9Sstevel@tonic-gate ts); 7857c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 7867c478bd9Sstevel@tonic-gate length += slen; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate continue; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate case 'o': 7917c478bd9Sstevel@tonic-gate case 'O': 7927c478bd9Sstevel@tonic-gate case 'X': 7937c478bd9Sstevel@tonic-gate case 'x': 7947c478bd9Sstevel@tonic-gate case 'd': 7957c478bd9Sstevel@tonic-gate case 'i': 7967c478bd9Sstevel@tonic-gate case 'D': 7977c478bd9Sstevel@tonic-gate case 'U': 7987c478bd9Sstevel@tonic-gate case 'u': 7997c478bd9Sstevel@tonic-gate *ofmtp++ = 'l'; 8007c478bd9Sstevel@tonic-gate *ofmtp++ = 'l'; /* now dealing with long longs */ 8017c478bd9Sstevel@tonic-gate *ofmtp++ = c; 8027c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 8037c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 8047c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, 8057c478bd9Sstevel@tonic-gate exprint(nextarg(&np))); 8067c478bd9Sstevel@tonic-gate else { 8077c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 0); 8087c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, 8097c478bd9Sstevel@tonic-gate exprint(nextarg(&np))); 8107c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 8117c478bd9Sstevel@tonic-gate length += slen; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate continue; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate case 'e': 8167c478bd9Sstevel@tonic-gate case 'E': 8177c478bd9Sstevel@tonic-gate case 'f': 8187c478bd9Sstevel@tonic-gate case 'F': 8197c478bd9Sstevel@tonic-gate case 'g': 8207c478bd9Sstevel@tonic-gate case 'G': 8217c478bd9Sstevel@tonic-gate *ofmtp++ = c; 8227c478bd9Sstevel@tonic-gate *ofmtp = '\0'; 8237c478bd9Sstevel@tonic-gate if (bptr == (wchar_t *)NULL) 8247c478bd9Sstevel@tonic-gate length += fprintf(fp, fmtbuf, 8257c478bd9Sstevel@tonic-gate exprreal(nextarg(&np))); 8267c478bd9Sstevel@tonic-gate else { 8277c478bd9Sstevel@tonic-gate adjust_buf(cp, &cplen, &bptr, fmtbuf, 0); 8287c478bd9Sstevel@tonic-gate (void) wsprintf(bptr, (const char *) fmtbuf, 8297c478bd9Sstevel@tonic-gate exprreal(nextarg(&np))); 8307c478bd9Sstevel@tonic-gate bptr += (slen = wcslen(bptr)); 8317c478bd9Sstevel@tonic-gate length += slen; 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate continue; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate case 'l': 8367c478bd9Sstevel@tonic-gate case 'L': 8377c478bd9Sstevel@tonic-gate break; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate case '*': 8407c478bd9Sstevel@tonic-gate #ifdef M_BSD_SPRINTF 8417c478bd9Sstevel@tonic-gate sprintf(ofmtp, "%lld", (INT)exprint(nextarg(&np))); 8427c478bd9Sstevel@tonic-gate ofmtp += strlen(ofmtp); 8437c478bd9Sstevel@tonic-gate #else 844cb4658fbSceastha ofmtp += sprintf(ofmtp, "%lld", 845cb4658fbSceastha (INT)exprint(nextarg(&np))); 8467c478bd9Sstevel@tonic-gate #endif 8477c478bd9Sstevel@tonic-gate break; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate default: 8507c478bd9Sstevel@tonic-gate if (c == '\0') { 8517c478bd9Sstevel@tonic-gate *ofmtp = (wchar_t)NULL; 852cb4658fbSceastha (void) fprintf(fp, "%s", fmtbuf); 8537c478bd9Sstevel@tonic-gate continue; 854cb4658fbSceastha } else { 8557c478bd9Sstevel@tonic-gate *ofmtp++ = (wchar_t)c; 8567c478bd9Sstevel@tonic-gate break; 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate goto nextc; 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate if (fmtsave != NULL) 8627c478bd9Sstevel@tonic-gate free(fmtsave); 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * If printing to a character buffer then make sure it is 8657c478bd9Sstevel@tonic-gate * null-terminated and only uses as much space as required. 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate if (bptr != (wchar_t *)NULL) { 8687c478bd9Sstevel@tonic-gate *bptr = '\0'; 8697c478bd9Sstevel@tonic-gate *cp = erealloc(*cp, (length+1) * sizeof (wchar_t)); 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate return (length); 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate /* 8757c478bd9Sstevel@tonic-gate * Return the next argument from the list. 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate static NODE * 8787c478bd9Sstevel@tonic-gate nextarg(NODE **npp) 8797c478bd9Sstevel@tonic-gate { 880cb4658fbSceastha NODE *np; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate if ((np = getlist(npp)) == NNULL) 8837c478bd9Sstevel@tonic-gate awkerr(gettext("insufficient arguments to printf or sprintf")); 8847c478bd9Sstevel@tonic-gate if (isleaf(np->n_flags) && np->n_type == PARM) 8857c478bd9Sstevel@tonic-gate return (np->n_next); 8867c478bd9Sstevel@tonic-gate return (np); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* 8917c478bd9Sstevel@tonic-gate * Check and adjust the length of the buffer that has been passed in 8927c478bd9Sstevel@tonic-gate * to make sure that it has space to accomodate the sequence string 8937c478bd9Sstevel@tonic-gate * described in fmtstr. This routine is used by xprintf() to allow 8947c478bd9Sstevel@tonic-gate * for arbitrarily long sprintf() strings. 8957c478bd9Sstevel@tonic-gate * 8967c478bd9Sstevel@tonic-gate * bp = start of current buffer 8977c478bd9Sstevel@tonic-gate * len = length of current buffer 8987c478bd9Sstevel@tonic-gate * offset = offset in current buffer 8997c478bd9Sstevel@tonic-gate * fmtstr = format string to check 9007c478bd9Sstevel@tonic-gate * slen = size of string for %s formats 9017c478bd9Sstevel@tonic-gate */ 9027c478bd9Sstevel@tonic-gate static void 9037c478bd9Sstevel@tonic-gate adjust_buf(wchar_t **bp, int *len, wchar_t **offset, char *fmtstr, size_t slen) 9047c478bd9Sstevel@tonic-gate { 9057c478bd9Sstevel@tonic-gate int ioff; 9067c478bd9Sstevel@tonic-gate int width = 0; 9077c478bd9Sstevel@tonic-gate int prec = 0; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate do { 9107c478bd9Sstevel@tonic-gate fmtstr++; 911cb4658fbSceastha } while (strchr("-+ 0", *fmtstr) != (char *)0 || *fmtstr == ('#')); 9127c478bd9Sstevel@tonic-gate if (*fmtstr != '*') { 9137c478bd9Sstevel@tonic-gate if (isdigit(*fmtstr)) { 9147c478bd9Sstevel@tonic-gate width = *fmtstr-'0'; 9157c478bd9Sstevel@tonic-gate while (isdigit(*++fmtstr)) 9167c478bd9Sstevel@tonic-gate width = width * 10 + *fmtstr - '0'; 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate } else 9197c478bd9Sstevel@tonic-gate fmtstr++; 9207c478bd9Sstevel@tonic-gate if (*fmtstr == '.') { 9217c478bd9Sstevel@tonic-gate if (*++fmtstr != '*') { 9227c478bd9Sstevel@tonic-gate prec = *fmtstr-'0'; 9237c478bd9Sstevel@tonic-gate while (isdigit(*++fmtstr)) 9247c478bd9Sstevel@tonic-gate prec = prec * 10 + *fmtstr - '0'; 9257c478bd9Sstevel@tonic-gate } else 9267c478bd9Sstevel@tonic-gate fmtstr++; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate if (strchr("Llh", *fmtstr) != (char *)0) 9297c478bd9Sstevel@tonic-gate fmtstr++; 930cb4658fbSceastha if (*fmtstr == 'S') { 9317c478bd9Sstevel@tonic-gate if (width && slen < width) 9327c478bd9Sstevel@tonic-gate slen = width; 9337c478bd9Sstevel@tonic-gate if (prec && slen > prec) 9347c478bd9Sstevel@tonic-gate slen = prec; 9357c478bd9Sstevel@tonic-gate width = slen+1; 9367c478bd9Sstevel@tonic-gate } else 9377c478bd9Sstevel@tonic-gate if (width == 0) 9387c478bd9Sstevel@tonic-gate width = NUMSIZE; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate if (*offset+ width > *bp+ *len) { 9417c478bd9Sstevel@tonic-gate ioff = *offset-*bp; 9427c478bd9Sstevel@tonic-gate *len += width+1; 9437c478bd9Sstevel@tonic-gate *bp = erealloc(*bp, *len * sizeof (wchar_t)); 9447c478bd9Sstevel@tonic-gate *offset = *bp+ioff; 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate static void 9497c478bd9Sstevel@tonic-gate awk_putwc(wchar_t c, FILE *fp) 9507c478bd9Sstevel@tonic-gate { 9517c478bd9Sstevel@tonic-gate char mb[MB_LEN_MAX]; 9527c478bd9Sstevel@tonic-gate size_t mbl; 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if ((mbl = wctomb(mb, c)) > 0) { 9557c478bd9Sstevel@tonic-gate mb[mbl] = '\0'; 9567c478bd9Sstevel@tonic-gate (void) fputs(mb, fp); 9577c478bd9Sstevel@tonic-gate } else 9587c478bd9Sstevel@tonic-gate awkerr(gettext("invalid wide character %x"), c); 9597c478bd9Sstevel@tonic-gate } 960