1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright (C) Lucent Technologies 1997
  29  * All Rights Reserved
  30  *
  31  * Permission to use, copy, modify, and distribute this software and
  32  * its documentation for any purpose and without fee is hereby
  33  * granted, provided that the above copyright notice appear in all
  34  * copies and that both that the copyright notice and this
  35  * permission notice and warranty disclaimer appear in supporting
  36  * documentation, and that the name Lucent Technologies or any of
  37  * its entities not be used in advertising or publicity pertaining
  38  * to distribution of the software without specific, written prior
  39  * permission.
  40  *
  41  * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  42  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  43  * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
  44  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  45  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  46  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  47  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  48  * THIS SOFTWARE.
  49  */
  50 
  51 #include <signal.h>
  52 #include <locale.h>
  53 #include <stdarg.h>
  54 #include <errno.h>
  55 #include <values.h>
  56 #include <langinfo.h>
  57 #include "awk.h"
  58 #include "y.tab.h"
  59 
  60 char    *version = "version 20121220";
  61 
  62 int     dbg     = 0;
  63 Awkfloat        srand_seed = 1;
  64 uchar   *cmdname;       /* gets argv[0] for error messages */
  65 uchar   *lexprog;       /* points to program argument if it exists */
  66 int     compile_time = 2;       /* for error printing: */
  67                                 /* 2 = cmdline, 1 = compile, 0 = running */
  68 char    radixpoint = '.';
  69 
  70 #define MAX_PFILE       20      /* max number of -f's */
  71 
  72 static uchar    *pfile[MAX_PFILE];      /* program filenames from -f's */
  73 static int      npfile = 0;     /* number of filenames */
  74 static int      curpfile = 0;   /* current filename */
  75 
  76 int     safe = 0;       /* 1 => "safe" mode */
  77 
  78 int
  79 main(int argc, char *argv[], char *envp[])
  80 {
  81         const uchar *fs = NULL;
  82         char    *nl_radix;
  83         /*
  84          * At this point, numbers are still scanned as in
  85          * the POSIX locale.
  86          * (POSIX.2, volume 2, P867, L4742-4757)
  87          */
  88         (void) setlocale(LC_ALL, "");
  89         (void) setlocale(LC_NUMERIC, "C");
  90 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
  91 #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it weren't */
  92 #endif
  93         (void) textdomain(TEXT_DOMAIN);
  94         cmdname = (uchar *)argv[0];
  95         if (argc == 1) {
  96                 (void) fprintf(stderr, gettext(
  97                     "Usage: %s [-f programfile | 'program'] [-Ffieldsep] "
  98                     "[-v var=value] [files]\n"), cmdname);
  99                 exit(1);
 100         }
 101         (void) signal(SIGFPE, fpecatch);
 102 
 103         srand_seed = 1;
 104         srand((unsigned int)srand_seed);
 105 
 106         yyin = NULL;
 107         symtab = makesymtab(NSYMTAB/NSYMTAB);
 108         while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
 109                 if (strcmp(argv[1], "-version") == 0 ||
 110                     strcmp(argv[1], "--version") == 0) {
 111                         (void) printf("awk %s\n", version);
 112                         exit(0);
 113                         break;
 114                 }
 115                 if (strncmp(argv[1], "--", 2) == 0) {
 116                         /* explicit end of args */
 117                         argc--;
 118                         argv++;
 119                         break;
 120                 }
 121                 switch (argv[1][1]) {
 122                 case 's':
 123                         if (strcmp(argv[1], "-safe") == 0)
 124                                 safe = 1;
 125                         break;
 126                 case 'f':       /* next argument is program filename */
 127                         if (argv[1][2] != 0) {  /* arg is -fsomething */
 128                                 if (npfile >= MAX_PFILE - 1)
 129                                         FATAL("too many -f options");
 130                                 pfile[npfile++] = (uchar *)&argv[1][2];
 131                         } else {                /* arg is -f something */
 132                                 argc--; argv++;
 133                                 if (argc <= 1)
 134                                         FATAL("no program filename");
 135                                 if (npfile >= MAX_PFILE - 1)
 136                                         FATAL("too many -f options");
 137                                 pfile[npfile++] = (uchar *)argv[1];
 138                         }
 139                         break;
 140                 case 'F':       /* set field separator */
 141                         if (argv[1][2] != 0) {  /* arg is -Fsomething */
 142                                 /* wart: t=>\t */
 143                                 if (argv[1][2] == 't' && argv[1][3] == 0)
 144                                         fs = (uchar *) "\t";
 145                                 else if (argv[1][2] != 0)
 146                                         fs = (uchar *)&argv[1][2];
 147                         } else {                /* arg is -F something */
 148                                 argc--; argv++;
 149                                 /* wart: t=>\t */
 150                                 if (argc > 1 && argv[1][0] == 't' &&
 151                                     argv[1][1] == 0)
 152                                         fs = (uchar *) "\t";
 153                                 else if (argc > 1 && argv[1][0] != 0)
 154                                         fs = (uchar *)&argv[1][0];
 155                         }
 156                         if (fs == NULL || *fs == '\0')
 157                                 WARNING("field separator FS is empty");
 158                         break;
 159                 case 'v':       /* -v a=1 to be done NOW.  one -v for each */
 160                         if (argv[1][2] != 0) {  /* arg is -vsomething */
 161                                 if (isclvar((uchar *)&argv[1][2]))
 162                                         setclvar((uchar *)&argv[1][2]);
 163                                 else
 164                                         FATAL(
 165                                 "invalid -v option argument: %s", &argv[1][2]);
 166                         } else {        /* arg is -v something */
 167                                 argc--; argv++;
 168                                 if (argc <= 1)
 169                                         FATAL("no variable name");
 170                                 if (isclvar((uchar *)argv[1]))
 171                                         setclvar((uchar *)argv[1]);
 172                                 else
 173                                         FATAL(
 174                                 "invalid -v option argument: %s", argv[1]);
 175                         }
 176                         break;
 177                 case 'd':
 178                         dbg = atoi(&argv[1][2]);
 179                         if (dbg == 0)
 180                                 dbg = 1;
 181                         (void) printf("awk %s\n", version);
 182                         break;
 183                 default:
 184                         WARNING("unknown option %s ignored", argv[1]);
 185                         break;
 186                 }
 187                 argc--;
 188                 argv++;
 189         }
 190         /* argv[1] is now the first argument */
 191         if (npfile == 0) {      /* no -f; first argument is program */
 192                 if (argc <= 1) {
 193                         if (dbg)
 194                                 exit(0);
 195                         FATAL("no program given");
 196                 }
 197                 dprintf(("program = |%s|\n", argv[1]));
 198                 lexprog = (uchar *)argv[1];
 199                 argc--;
 200                 argv++;
 201         }
 202         recinit(record_size);
 203         syminit();
 204         compile_time = 1;
 205         argv[0] = (char *)cmdname;      /* put prog name at front of arglist */
 206         dprintf(("argc=%d, argv[0]=%s\n", argc, argv[0]));
 207         arginit(argc, (uchar **)argv);
 208         if (!safe)
 209                 envinit((uchar **)envp);
 210         (void) yyparse();
 211         if (fs)
 212                 *FS = qstring(fs, '\0');
 213         dprintf(("errorflag=%d\n", errorflag));
 214         /*
 215          * done parsing, so now activate the LC_NUMERIC
 216          */
 217         (void) setlocale(LC_ALL, "");
 218         nl_radix = nl_langinfo(RADIXCHAR);
 219         if (nl_radix)
 220                 radixpoint = *nl_radix;
 221 
 222         if (errorflag == 0) {
 223                 compile_time = 0;
 224                 run(winner);
 225         } else
 226                 bracecheck();
 227         return (errorflag);
 228 }
 229 
 230 int
 231 pgetc(void)             /* get 1 character from awk program */
 232 {
 233         int c;
 234 
 235         for (;;) {
 236                 if (yyin == NULL) {
 237                         if (curpfile >= npfile)
 238                                 return (EOF);
 239                         if (strcmp((char *)pfile[curpfile], "-") == 0)
 240                                 yyin = stdin;
 241                         else if ((yyin = fopen(
 242                             (char *)pfile[curpfile], "r")) == NULL)
 243                                 FATAL("can't open file %s", pfile[curpfile]);
 244                         lineno = 1;
 245                 }
 246                 if ((c = getc(yyin)) != EOF)
 247                         return (c);
 248                 if (yyin != stdin)
 249                         (void) fclose(yyin);
 250                 yyin = NULL;
 251                 curpfile++;
 252         }
 253 }
 254 
 255 uchar *
 256 cursource(void)         /* current source file name */
 257 {
 258         if (npfile > 0)
 259                 return (pfile[curpfile]);
 260         else
 261                 return (NULL);
 262 }