master xplshn/aruu / cmd / posix / awk / main.c
  1/****************************************************************
  2Copyright (C) Lucent Technologies 1997
  3All Rights Reserved
  4
  5Permission to use, copy, modify, and distribute this software and
  6its documentation for any purpose and without fee is hereby
  7granted, provided that the above copyright notice appear in all
  8copies and that both that the copyright notice and this
  9permission notice and warranty disclaimer appear in supporting
 10documentation, and that the name Lucent Technologies or any of
 11its entities not be used in advertising or publicity pertaining
 12to distribution of the software without specific, written prior
 13permission.
 14
 15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
 17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
 18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 22THIS 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 don't think so.
116void 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}