master xplshn/aruu / cmd / posix / awk / main.c
  1/* ***************************************************************
  2 * copyright (c) lucent technologies 1997
  3 * all rights reserved
  4 *
  5 * permission to use, copy, modify, and distribute this software and
  6 * its documentation for any purpose and without fee is hereby
  7 * granted, provided that the above copyright notice appear in all
  8 * copies and that both that the copyright notice and this
  9 * permission notice and warranty disclaimer appear in supporting
 10 * documentation, and that the name lucent technologies or any of
 11 * its entities not be used in advertising or publicity pertaining
 12 * to distribution of the software without specific, written prior
 13 * permission
 14 *
 15 * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 17 * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
 18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 20 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 21 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 22 * THIS SOFTWARE
 23 * ************************************************************** */
 24
 25const char *version = "version 20260426";
 26
 27#define DEBUG
 28#include "awk.h"
 29#include <ctype.h>
 30#include <locale.h>
 31#include <signal.h>
 32#include <stdio.h>
 33#include <stdlib.h>
 34#include <string.h>
 35
 36extern char **environ;
 37extern int    nfields;
 38
 39int                 dbg        = 0;
 40Awkfloat            srand_seed = 1;
 41char               *cmdname;   /* gets argv[0] for error messages */
 42extern FILE        *yyin;      /* lex input file */
 43char               *lexprog;   /* points to program argument if it exists */
 44extern int          errorflag; /* non-zero if any syntax errors; set by yyerror */
 45enum compile_states compile_time = ERROR_PRINTING;
 46
 47static char **pfile;    /* program filenames from -f's */
 48static size_t maxpfile; /* max program filename */
 49static size_t npfile;   /* number of filenames */
 50static size_t curpfile; /* current filename */
 51
 52bool CSV = false; /* true for csv input */
 53
 54bool safe = false; /* true => "safe" mode */
 55
 56size_t awk_mb_cur_max = 1;
 57
 58static noreturn void
 59fpecatch(
 60    int n
 61#ifdef SA_SIGINFO
 62    ,
 63    siginfo_t *si,
 64    void      *uc
 65#endif
 66)
 67{
 68  (void)n;
 69#ifdef SA_SIGINFO
 70  (void)uc;
 71#endif
 72#ifdef SA_SIGINFO
 73  const char *mesg = NULL;
 74
 75  switch (si->si_code) {
 76    case FPE_INTDIV:
 77      mesg = "Integer divide by zero";
 78      break;
 79    case FPE_INTOVF:
 80      mesg = "Integer overflow";
 81      break;
 82    case FPE_FLTDIV:
 83      mesg = "Floating point divide by zero";
 84      break;
 85    case FPE_FLTOVF:
 86      mesg = "Floating point overflow";
 87      break;
 88    case FPE_FLTUND:
 89      mesg = "Floating point underflow";
 90      break;
 91    case FPE_FLTRES:
 92      mesg = "Floating point inexact result";
 93      break;
 94    case FPE_FLTINV:
 95      mesg = "Invalid Floating point operation";
 96      break;
 97    case FPE_FLTSUB:
 98      mesg = "Subscript out of range";
 99      break;
100    case 0:
101    default:
102      mesg = "Unknown error";
103      break;
104  }
105#endif
106  FATAL(
107      "floating point exception"
108#ifdef SA_SIGINFO
109      ": %s",
110      mesg
111#endif
112  );
113}
114
115/* can this work with recursive calls? i dont think so
116 * void segvcatch(int n)
117 * {
118 * fatal("segfault. do you have an unbounded recursive call?", n);
119 * }
120 */
121
122static const char *
123setfs(char *p)
124{
125  /* wart: t=>\t */
126  if (p[0] == 't' && p[1] == '\0')
127    return "\t";
128  return p;
129}
130
131static char *
132getarg(int *argc, char ***argv, const char *msg)
133{
134  if ((*argv)[1][2] != '\0') { /* arg is -fsomething */
135    return &(*argv)[1][2];
136  } else { /* arg is -f something */
137    (*argc)--;
138    (*argv)++;
139    if (*argc <= 1)
140      FATAL("%s", msg);
141    return (*argv)[1];
142  }
143}
144
145int
146main(int argc, char *argv[])
147{
148  const char *fs = NULL;
149  char       *fn, *vn;
150
151  setlocale(LC_CTYPE, "");
152  setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
153  awk_mb_cur_max = MB_CUR_MAX;
154  cmdname        = argv[0];
155  if (argc == 1) {
156    fprintf(
157        stderr,
158        "usage: %s [-F fs | --csv] [-v var=value] [-f progfile "
159        "| 'prog'] [file ...]\n",
160        cmdname
161    );
162    exit(1);
163  }
164#ifdef SA_SIGINFO
165  {
166    struct sigaction sa;
167    sa.sa_sigaction = fpecatch;
168    sa.sa_flags     = SA_SIGINFO;
169    sigemptyset(&sa.sa_mask);
170    (void)sigaction(SIGFPE, &sa, NULL);
171  }
172#else
173  (void)signal(SIGFPE, fpecatch);
174#endif
175  /* signal(sigsegv, segvcatch); experiment */
176
177  /* set and keep track of the random seed */
178  srand_seed = 1;
179  srandom((unsigned long)srand_seed);
180
181  yyin   = NULL;
182  symtab = makesymtab(NSYMTAB / NSYMTAB);
183  while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
184    if (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0) {
185      printf("awk %s\n", version);
186      return 0;
187    }
188    if (strcmp(argv[1], "--") == 0) { /* explicit end of args */
189      argc--;
190      argv++;
191      break;
192    }
193    if (strcmp(argv[1], "--csv") == 0) { /* turn on csv input processing */
194      CSV = true;
195      argc--;
196      argv++;
197      continue;
198    }
199    switch (argv[1][1]) {
200      case 's':
201        if (strcmp(argv[1], "-safe") == 0)
202          safe = true;
203        break;
204      case 'f': /* next argument is program filename */
205        fn = getarg(&argc, &argv, "no program filename");
206        if (npfile >= maxpfile) {
207          maxpfile += 20;
208          pfile = (char **)realloc(pfile, maxpfile * sizeof(*pfile));
209          if (pfile == NULL)
210            FATAL(
211                "error allocating space for -f "
212                "options"
213            );
214        }
215        pfile[npfile++] = fn;
216        break;
217      case 'F': /* set field separator */
218        fs = setfs(getarg(&argc, &argv, "no field separator"));
219        break;
220      case 'v': /* -v a=1 to be done NOW. one -v for each */
221        vn = getarg(&argc, &argv, "no variable name");
222        if (isclvar(vn))
223          setclvar(vn);
224        else
225          FATAL("invalid -v option argument: %s", vn);
226        break;
227      case 'd':
228        dbg = atoi(&argv[1][2]);
229        if (dbg == 0)
230          dbg = 1;
231        printf("awk %s\n", version);
232        break;
233      default:
234        WARNING("unknown option %s ignored", argv[1]);
235        break;
236    }
237    argc--;
238    argv++;
239  }
240
241  if (CSV && (fs != NULL || lookup("FS", symtab) != NULL))
242    WARNING("danger: don't set FS when --csv is in effect");
243
244  /* argv[1] is now the first argument */
245  if (npfile == 0) { /* no -f; first argument is program */
246    if (argc <= 1) {
247      if (dbg)
248        exit(0);
249      FATAL("no program given");
250    }
251    DPRINTF("program = |%s|\n", argv[1]);
252    lexprog = argv[1];
253    argc--;
254    argv++;
255  }
256  recinit(recsize);
257  syminit();
258  compile_time = COMPILING;
259  argv[0]      = cmdname; /* put prog name at front of arglist */
260  DPRINTF("argc=%d, argv[0]=%s\n", argc, argv[0]);
261  arginit(argc, argv);
262  if (!safe)
263    envinit(environ);
264  yyparse();
265#if 0
266	/* doing this would comply with POSIX, but is not compatible with
267	 * other awks and with what most users expect. so comment it out */
268	setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
269#endif
270  if (fs)
271    *FS = qstring(fs, '\0');
272  DPRINTF("errorflag=%d\n", errorflag);
273  if (errorflag == 0) {
274    compile_time = RUNNING;
275    run(winner);
276  } else
277    bracecheck();
278  return (errorflag);
279}
280
281int
282pgetc(void) /* get 1 character from awk program */
283{
284  int c;
285
286  for (;;) {
287    if (yyin == NULL) {
288      if (curpfile >= npfile)
289        return EOF;
290      if (strcmp(pfile[curpfile], "-") == 0)
291        yyin = stdin;
292      else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
293        FATAL("can't open file %s", pfile[curpfile]);
294      lineno = 1;
295    }
296    if ((c = getc(yyin)) != EOF)
297      return c;
298    if (yyin != stdin)
299      fclose(yyin);
300    yyin = NULL;
301    curpfile++;
302  }
303}
304
305char *
306cursource(void) /* current source file name */
307{
308  if (npfile > 0)
309    return pfile[curpfile < npfile ? curpfile : curpfile - 1];
310  else
311    return NULL;
312}