home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gawk-2.15.6-base.tgz / gawk-2.15.6-base.tar / fsf / gawk / main.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  21KB  |  829 lines

  1. /*
  2.  * main.c -- Expression tree constructors and main program for gawk. 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27. #include "getopt.h"
  28. #include "patchlevel.h"
  29.  
  30. static void usage P((int exitval));
  31. static void copyleft P((void));
  32. static void cmdline_fs P((char *str));
  33. static void init_args P((int argc0, int argc, char *argv0, char **argv));
  34. static void init_vars P((void));
  35. static void pre_assign P((char *v));
  36. SIGTYPE catchsig P((int sig, int code));
  37. static void gawk_option P((char *optstr));
  38. static void nostalgia P((void));
  39. static void version P((void));
  40. char *gawk_name P((char *filespec));
  41.  
  42. #ifdef MSDOS
  43. extern int isatty P((int));
  44. #endif
  45.  
  46. extern void resetup P((void));
  47.  
  48. /* These nodes store all the special variables AWK uses */
  49. NODE *FS_node, *NF_node, *RS_node, *NR_node;
  50. NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
  51. NODE *CONVFMT_node;
  52. NODE *ERRNO_node;
  53. NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
  54. NODE *ENVIRON_node, *IGNORECASE_node;
  55. NODE *ARGC_node, *ARGV_node, *ARGIND_node;
  56. NODE *FIELDWIDTHS_node;
  57.  
  58. long NF;
  59. long NR;
  60. long FNR;
  61. int IGNORECASE;
  62. char *RS;
  63. char *OFS;
  64. char *ORS;
  65. char *OFMT;
  66.  
  67. /*
  68.  * CONVFMT is a convenience pointer for the current number to string format.
  69.  * We must supply an initial value to avoid recursion problems of
  70.  *    set_CONVFMT -> fmt_index -> r_force_string: gets NULL CONVFMT
  71.  * Fun, fun, fun, fun.
  72.  */
  73. char *CONVFMT = "%.6g";
  74.  
  75. int errcount = 0;    /* error counter, used by yyerror() */
  76.  
  77. /* The global null string */
  78. NODE *Nnull_string;
  79.  
  80. /* The name the program was invoked under, for error messages */
  81. const char *myname;
  82.  
  83. /* A block of AWK code to be run before running the program */
  84. NODE *begin_block = 0;
  85.  
  86. /* A block of AWK code to be run after the last input file */
  87. NODE *end_block = 0;
  88.  
  89. int exiting = 0;        /* Was an "exit" statement executed? */
  90. int exit_val = 0;        /* optional exit value */
  91.  
  92. #if defined(YYDEBUG) || defined(DEBUG)
  93. extern int yydebug;
  94. #endif
  95.  
  96. struct src *srcfiles = NULL;    /* source file name(s) */
  97. int numfiles = -1;        /* how many source files */
  98.  
  99. int do_unix = 0;        /* turn off gnu extensions */
  100. int do_posix = 0;        /* turn off gnu and unix extensions */
  101. int do_lint = 0;        /* provide warnings about questionable stuff */
  102. int do_nostalgia = 0;        /* provide a blast from the past */
  103.  
  104. int in_begin_rule = 0;        /* we're in a BEGIN rule */
  105. int in_end_rule = 0;        /* we're in a END rule */
  106.  
  107. int output_is_tty = 0;        /* control flushing of output */
  108.  
  109. extern char *version_string;    /* current version, for printing */
  110.  
  111. /* The parse tree is stored here.  */
  112. NODE *expression_value;
  113.  
  114. static struct option optab[] = {
  115.     { "compat",        no_argument,        & do_unix,    1 },
  116.     { "lint",        no_argument,        & do_lint,    1 },
  117.     { "posix",        no_argument,        & do_posix,    1 },
  118.     { "nostalgia",        no_argument,        & do_nostalgia,    1 },
  119.     { "copyleft",        no_argument,        NULL,        'C' },
  120.     { "copyright",        no_argument,        NULL,        'C' },
  121.     { "field-separator",    required_argument,    NULL,        'F' },
  122.     { "file",        required_argument,    NULL,        'f' },
  123.     { "assign",        required_argument,    NULL,        'v' },
  124.     { "version",        no_argument,        NULL,        'V' },
  125.     { "usage",        no_argument,        NULL,        'u' },
  126.     { "help",        no_argument,        NULL,        'u' },
  127.     { "source",        required_argument,    NULL,        's' },
  128. #ifdef DEBUG
  129.     { "parsedebug",        no_argument,        NULL,        'D' },
  130. #endif
  131.     { 0, 0, 0, 0 }
  132. };
  133.  
  134. int
  135. main(argc, argv)
  136. int argc;
  137. char **argv;
  138. {
  139.     int c;
  140.     char *scan;
  141.     /* the + on the front tells GNU getopt not to rearrange argv */
  142.     const char *optlist = "+F:f:v:W:m:";
  143.     int stopped_early = 0;
  144.     int old_optind;
  145.     extern int optind;
  146.     extern int opterr;
  147.     extern char *optarg;
  148.  
  149. #ifdef __EMX__
  150.     _response(&argc, &argv);
  151.     _wildcard(&argc, &argv);
  152.     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
  153. #endif
  154.  
  155.     (void) signal(SIGFPE,  (SIGTYPE (*) P((int))) catchsig);
  156.     (void) signal(SIGSEGV, (SIGTYPE (*) P((int))) catchsig);
  157. #ifdef SIGBUS
  158.     (void) signal(SIGBUS,  (SIGTYPE (*) P((int))) catchsig);
  159. #endif
  160.  
  161.     myname = gawk_name(argv[0]);
  162.         argv[0] = (char *)myname;
  163. #ifdef VMS
  164.     vms_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
  165. #endif
  166.  
  167.     /* remove sccs gunk */
  168.     if (strncmp(version_string, "@(#)", 4) == 0)
  169.         version_string += 4;
  170.  
  171.     if (argc < 2)
  172.         usage(1);
  173.  
  174.     /* initialize the null string */
  175.     Nnull_string = make_string("", 0);
  176.     Nnull_string->numbr = 0.0;
  177.     Nnull_string->type = Node_val;
  178.     Nnull_string->flags = (PERM|STR|STRING|NUM|NUMBER);
  179.  
  180.     /*
  181.      * Tell the regex routines how they should work.
  182.      * Do this before initializing variables, since
  183.      * they could want to do a regexp compile.
  184.      */
  185.     resetup();
  186.  
  187.     /* Set up the special variables */
  188.     /*
  189.      * Note that this must be done BEFORE arg parsing else -F
  190.      * breaks horribly 
  191.      */
  192.     init_vars();
  193.  
  194.     /* worst case */
  195.     emalloc(srcfiles, struct src *, argc * sizeof(struct src), "main");
  196.     memset(srcfiles, '\0', argc * sizeof(struct src));
  197.  
  198.     /* we do error messages ourselves on invalid options */
  199.     opterr = 0;
  200.  
  201.     /* option processing. ready, set, go! */
  202.     for (optopt = 0, old_optind = 1;
  203.          (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
  204.          optopt = 0, old_optind = optind) {
  205.         if (do_posix)
  206.             opterr = 1;
  207.         switch (c) {
  208.         case 'F':
  209.             cmdline_fs(optarg);
  210.             break;
  211.  
  212.         case 'f':
  213.             /*
  214.              * a la MKS awk, allow multiple -f options.
  215.              * this makes function libraries real easy.
  216.              * most of the magic is in the scanner.
  217.              */
  218.             /* The following is to allow for whitespace at the end
  219.              * of a #! /bin/gawk line in an executable file
  220.              */
  221.             scan = optarg;
  222.             while (isspace(*scan))
  223.                 scan++;
  224.             ++numfiles;
  225.             srcfiles[numfiles].stype = SOURCEFILE;
  226.             if (*scan == '\0')
  227.                 srcfiles[numfiles].val = argv[optind++];
  228.             else
  229.                 srcfiles[numfiles].val = optarg;
  230.             break;
  231.  
  232.         case 'v':
  233.             pre_assign(optarg);
  234.             break;
  235.  
  236.         case 'm':
  237.             /*
  238.              * Research awk extension.
  239.              *    -mf=nnn        set # fields, gawk ignores
  240.              *    -mr=nnn        set record length, ditto
  241.              */
  242.             if (do_lint)
  243.                 warning("-m[fr] option irrelevant");
  244.             if ((optarg[0] != 'r' && optarg[0] != 'f')
  245.                 || optarg[1] != '=')
  246.                 warning("-m option usage: -m[fn]=nnn");
  247.             break;
  248.  
  249.         case 'W':       /* gawk specific options */
  250.             gawk_option(optarg);
  251.             break;
  252.  
  253.         /* These can only come from long form options */
  254.         case 'V':
  255.             version();
  256.             break;
  257.  
  258.         case 'C':
  259.             copyleft();
  260.             break;
  261.  
  262.         case 'u':
  263.             usage(0);
  264.             break;
  265.  
  266.         case 's':
  267.             if (optarg[0] == '\0')
  268.                 warning("empty argument to --source ignored");
  269.             else {
  270.                 srcfiles[++numfiles].stype = CMDLINE;
  271.                 srcfiles[numfiles].val = optarg;
  272.             }
  273.             break;
  274.  
  275. #ifdef DEBUG
  276.         case 'D':
  277.             yydebug = 2;
  278.             break;
  279. #endif
  280.  
  281.         case 0:
  282.             /*
  283.              * getopt_long found an option that sets a variable
  284.              * instead of returning a letter. Do nothing, just
  285.              * cycle around for the next one.
  286.              */
  287.             break;
  288.  
  289.         case '?':
  290.         default:
  291.             /*
  292.              * New behavior.  If not posix, an unrecognized
  293.              * option stops argument processing so that it can
  294.              * go into ARGV for the awk program to see. This
  295.              * makes use of ``#! /bin/gawk -f'' easier.
  296.              *
  297.              * However, it's never simple. If optopt is set,
  298.              * an option that requires an argument didn't get the
  299.              * argument. We care because if opterr is 0, then
  300.              * getopt_long won't print the error message for us.
  301.              */
  302.             if (! do_posix
  303.                 && (optopt == 0 || strchr(optlist, optopt) == NULL)) {
  304.                 /*
  305.                  * can't just do optind--. In case of an
  306.                  * option with >=2 letters, getopt_long
  307.                  * won't have incremented optind.
  308.                  */
  309.                 optind = old_optind;
  310.                 stopped_early = 1;
  311.                 goto out;
  312.             } else if (optopt)
  313.                 /* Use 1003.2 required message format */
  314.                 fprintf (stderr,
  315.                 "%s: option requires an argument -- %c\n",
  316.                     myname, optopt);
  317.             /* else
  318.                 let getopt print error message for us */
  319.             break;
  320.         }
  321.     }
  322. out:
  323.  
  324.     if (do_nostalgia)
  325.         nostalgia();
  326.  
  327.     /* check for POSIXLY_CORRECT environment variable */
  328.     if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
  329.         do_posix = 1;
  330.         if (do_lint)
  331.             warning(
  332.     "environment variable `POSIXLY_CORRECT' set: turning on --posix");
  333.     }
  334.  
  335.     /* POSIX compliance also implies no Unix extensions either */
  336.     if (do_posix)
  337.         do_unix = 1;
  338.  
  339. #ifdef DEBUG
  340.     setbuf(stdout, (char *) NULL);    /* make debugging easier */
  341. #endif
  342.     if (isatty(fileno(stdout)))
  343.         output_is_tty = 1;
  344.     /* No -f or --source options, use next arg */
  345.     if (numfiles == -1) {
  346.         if (optind > argc - 1 || stopped_early) /* no args left or no program */
  347.             usage(1);
  348.         srcfiles[++numfiles].stype = CMDLINE;
  349.         srcfiles[numfiles].val = argv[optind];
  350.         optind++;
  351.     }
  352.     init_args(optind, argc, (char *) myname, argv);
  353.     (void) tokexpand();
  354.  
  355.     /* Read in the program */
  356.     if (yyparse() || errcount)
  357.         exit(1);
  358.     /* recover any space from C based alloca */
  359.     (void) alloca(0);
  360.  
  361.     /* Set up the field variables */
  362.     init_fields();
  363.  
  364.     if (do_lint && begin_block == NULL && expression_value == NULL
  365.          && end_block == NULL)
  366.         warning("no program");
  367.  
  368.     if (begin_block) {
  369.         in_begin_rule = 1;
  370.         (void) interpret(begin_block);
  371.     }
  372.     in_begin_rule = 0;
  373.     if (!exiting && (expression_value || end_block))
  374.         do_input();
  375.     if (end_block) {
  376.         in_end_rule = 1;
  377.         (void) interpret(end_block);
  378.     }
  379.     in_end_rule = 0;
  380.     if (close_io() != 0 && exit_val == 0)
  381.         exit_val = 1;
  382.     exit(exit_val);        /* more portable */
  383.     return exit_val;    /* to suppress warnings */
  384. }
  385.  
  386. /* usage --- print usage information and exit */
  387.  
  388. static void
  389. usage(exitval)
  390. int exitval;
  391. {
  392.     const char *opt1 = " -f progfile [--]";
  393. #if defined(MSDOS) || defined(OS2) || defined(VMS)
  394.     const char *opt2 = " [--] \"program\"";
  395. #else
  396.     const char *opt2 = " [--] 'program'";
  397. #endif
  398.     const char *regops = " [POSIX or GNU style options]";
  399.  
  400.     fprintf(stderr, "Usage:\t%s%s%s file ...\n\t%s%s%s file ...\n",
  401.         myname, regops, opt1, myname, regops, opt2);
  402.  
  403.     /* GNU long options info. Gack. */
  404.     fputs("POSIX options:\t\tGNU long options:\n", stderr);
  405.     fputs("\t-f progfile\t\t--file=progfile\n", stderr);
  406.     fputs("\t-F fs\t\t\t--field-separator=fs\n", stderr);
  407.     fputs("\t-v var=val\t\t--assign=var=val\n", stderr);
  408.     fputs("\t-m[fr]=val\n", stderr);
  409.     fputs("\t-W compat\t\t--compat\n", stderr);
  410.     fputs("\t-W copyleft\t\t--copyleft\n", stderr);
  411.     fputs("\t-W copyright\t\t--copyright\n", stderr);
  412.     fputs("\t-W help\t\t\t--help\n", stderr);
  413.     fputs("\t-W lint\t\t\t--lint\n", stderr);
  414. #ifdef NOSTALGIA
  415.     fputs("\t-W nostalgia\t\t--nostalgia\n", stderr);
  416. #endif
  417. #ifdef DEBUG
  418.     fputs("\t-W parsedebug\t\t--parsedebug\n", stderr);
  419. #endif
  420.     fputs("\t-W posix\t\t--posix\n", stderr);
  421.     fputs("\t-W source=program-text\t--source=program-text\n", stderr);
  422.     fputs("\t-W usage\t\t--usage\n", stderr);
  423.     fputs("\t-W version\t\t--version\n", stderr);
  424.     exit(exitval);
  425. }
  426.  
  427. static void
  428. copyleft ()
  429. {
  430.     static char blurb_part1[] =
  431. "Copyright (C) 1989, 1991, 1992, Free Software Foundation.\n\
  432. \n\
  433. This program is free software; you can redistribute it and/or modify\n\
  434. it under the terms of the GNU General Public License as published by\n\
  435. the Free Software Foundation; either version 2 of the License, or\n\
  436. (at your option) any later version.\n\
  437. \n";
  438.     static char blurb_part2[] =
  439. "This program is distributed in the hope that it will be useful,\n\
  440. but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  441. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  442. GNU General Public License for more details.\n\
  443. \n";
  444.     static char blurb_part3[] =
  445. "You should have received a copy of the GNU General Public License\n\
  446. along with this program; if not, write to the Free Software\n\
  447. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
  448.  
  449.     fputs(blurb_part1, stderr);
  450.     fputs(blurb_part2, stderr);
  451.     fputs(blurb_part3, stderr);
  452.     fflush(stderr);
  453. }
  454.  
  455. static void
  456. cmdline_fs(str)
  457. char *str;
  458. {
  459.     register NODE **tmp;
  460.     /* int len = strlen(str); *//* don't do that - we want to
  461.                                    avoid mismatched types */
  462.  
  463.     tmp = get_lhs(FS_node, (Func_ptr *) 0);
  464.     unref(*tmp);
  465.     /*
  466.      * Only if in full compatibility mode check for the stupid special
  467.      * case so -F\t works as documented in awk even though the shell
  468.      * hands us -Ft.  Bleah!
  469.      *
  470.      * Thankfully, Posix didn't propogate this "feature".
  471.      */
  472.     if (str[0] == 't' && str[1] == '\0') {
  473.         if (do_lint)
  474.             warning("-Ft does not set FS to tab in POSIX awk");
  475.         if (do_unix && ! do_posix)
  476.             str[0] = '\t';
  477.     }
  478.     *tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
  479.     set_FS();
  480. }
  481.  
  482. static void
  483. init_args(argc0, argc, argv0, argv)
  484. int argc0, argc;
  485. char *argv0;
  486. char **argv;
  487. {
  488.     int i, j;
  489.     NODE **aptr;
  490.  
  491.     ARGV_node = install("ARGV", node(Nnull_string, Node_var, (NODE *)NULL));
  492.     aptr = assoc_lookup(ARGV_node, tmp_number(0.0));
  493.     *aptr = make_string(argv0, strlen(argv0));
  494.     (*aptr)->flags |= MAYBE_NUM;
  495.     for (i = argc0, j = 1; i < argc; i++) {
  496.         aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j));
  497.         *aptr = make_string(argv[i], strlen(argv[i]));
  498.         (*aptr)->flags |= MAYBE_NUM;
  499.         j++;
  500.     }
  501.     ARGC_node = install("ARGC",
  502.             node(make_number((AWKNUM) j), Node_var, (NODE *) NULL));
  503. }
  504.  
  505. /*
  506.  * Set all the special variables to their initial values.
  507.  * Note that some of the variables that have set_FOO routines should
  508.  * *N*O*T* have those routines called upon initialization, and thus
  509.  * they have NULL entries in that field. This is notably true of FS
  510.  * and IGNORECASE.
  511.  */
  512. struct varinit {
  513.     NODE **spec;
  514.     const char *name;
  515.     NODETYPE type;
  516.     const char *strval;
  517.     AWKNUM numval;
  518.     Func_ptr assign;
  519. };
  520. static struct varinit varinit[] = {
  521. {&CONVFMT_node,    "CONVFMT",    Node_CONVFMT,        "%.6g",    0,  set_CONVFMT },
  522. {&NF_node,    "NF",        Node_NF,        0,    -1, set_NF },
  523. {&FIELDWIDTHS_node, "FIELDWIDTHS", Node_FIELDWIDTHS,    "",    0,  0 },
  524. {&NR_node,    "NR",        Node_NR,        0,    0,  set_NR },
  525. {&FNR_node,    "FNR",        Node_FNR,        0,    0,  set_FNR },
  526. {&FS_node,    "FS",        Node_FS,        " ",    0,  0 },
  527. {&RS_node,    "RS",        Node_RS,        "\n",    0,  set_RS },
  528. {&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE,    0,    0,  0 },
  529. {&FILENAME_node, "FILENAME",    Node_var,        "",    0,  0 },
  530. {&OFS_node,    "OFS",        Node_OFS,        " ",    0,  set_OFS },
  531. {&ORS_node,    "ORS",        Node_ORS,        "\n",    0,  set_ORS },
  532. {&OFMT_node,    "OFMT",        Node_OFMT,        "%.6g",    0,  set_OFMT },
  533. {&RLENGTH_node, "RLENGTH",    Node_var,        0,    0,  0 },
  534. {&RSTART_node,    "RSTART",    Node_var,        0,    0,  0 },
  535. {&SUBSEP_node,    "SUBSEP",    Node_var,        "\034",    0,  0 },
  536. {&ARGIND_node,    "ARGIND",    Node_var,        0,    0,  0 },
  537. {&ERRNO_node,    "ERRNO",    Node_var,        0,    0,  0 },
  538. {0,        0,        Node_illegal,        0,    0,  0 },
  539. };
  540.  
  541. static void
  542. init_vars()
  543. {
  544.     register struct varinit *vp;
  545.  
  546.     for (vp = varinit; vp->name; vp++) {
  547.         *(vp->spec) = install((char *) vp->name,
  548.           node(vp->strval == 0 ? make_number(vp->numval)
  549.                 : make_string((char *) vp->strval,
  550.                     strlen(vp->strval)),
  551.                vp->type, (NODE *) NULL));
  552.         if (vp->assign)
  553.             (*(vp->assign))();
  554.     }
  555. }
  556.  
  557. void
  558. load_environ()
  559. {
  560. #if !defined(MSDOS) && !defined(OS2) && !(defined(VMS) && defined(__DECC))
  561.     extern char **environ;
  562. #endif
  563.     register char *var, *val;
  564.     NODE **aptr;
  565.     register int i;
  566.  
  567.     ENVIRON_node = install("ENVIRON", 
  568.             node(Nnull_string, Node_var, (NODE *) NULL));
  569.     for (i = 0; environ[i]; i++) {
  570.         static char nullstr[] = "";
  571.  
  572.         var = environ[i];
  573.         val = strchr(var, '=');
  574.         if (val)
  575.             *val++ = '\0';
  576.         else
  577.             val = nullstr;
  578.         aptr = assoc_lookup(ENVIRON_node, tmp_string(var, strlen (var)));
  579.         *aptr = make_string(val, strlen (val));
  580.         (*aptr)->flags |= MAYBE_NUM;
  581.  
  582.         /* restore '=' so that system() gets a valid environment */
  583.         if (val != nullstr)
  584.             *--val = '=';
  585.     }
  586. }
  587.  
  588. /* Process a command-line assignment */
  589. char *
  590. arg_assign(arg)
  591. char *arg;
  592. {
  593.     char *cp, *cp2;
  594.     int badvar;
  595.     Func_ptr after_assign = NULL;
  596.     NODE *var;
  597.     NODE *it;
  598.     NODE **lhs;
  599.  
  600.     cp = strchr(arg, '=');
  601.     if (cp != NULL) {
  602.         *cp++ = '\0';
  603.         /* first check that the variable name has valid syntax */
  604.         badvar = 0;
  605.         if (! isalpha(arg[0]) && arg[0] != '_')
  606.             badvar = 1;
  607.         else
  608.             for (cp2 = arg+1; *cp2; cp2++)
  609.                 if (! isalnum(*cp2) && *cp2 != '_') {
  610.                     badvar = 1;
  611.                     break;
  612.                 }
  613.         if (badvar)
  614.             fatal("illegal name `%s' in variable assignment", arg);
  615.  
  616.         /*
  617.          * Recent versions of nawk expand escapes inside assignments.
  618.          * This makes sense, so we do it too.
  619.          */
  620.         it = make_str_node(cp, strlen(cp), SCAN);
  621.         it->flags |= MAYBE_NUM;
  622.         var = variable(arg, 0);
  623.         lhs = get_lhs(var, &after_assign);
  624.         unref(*lhs);
  625.         *lhs = it;
  626.         if (after_assign)
  627.             (*after_assign)();
  628.         *--cp = '=';    /* restore original text of ARGV */
  629.     }
  630.     return cp;
  631. }
  632.  
  633. static void
  634. pre_assign(v)
  635. char *v;
  636. {
  637.     if (!arg_assign(v)) {
  638.         fprintf (stderr,
  639.             "%s: '%s' argument to -v not in 'var=value' form\n",
  640.                 myname, v);
  641.         usage(1);
  642.     }
  643. }
  644.  
  645. SIGTYPE
  646. catchsig(sig, code)
  647. int sig, code;
  648. {
  649. #ifdef lint
  650.     code = 0; sig = code; code = sig;
  651. #endif
  652.     if (sig == SIGFPE) {
  653.         fatal("floating point exception");
  654.     } else if (sig == SIGSEGV
  655. #ifdef SIGBUS
  656.             || sig == SIGBUS
  657. #endif
  658.     ) {
  659.         msg("fatal error: internal error");
  660.         /* fatal won't abort() if not compiled for debugging */
  661.         abort();
  662.     } else
  663.         cant_happen();
  664.     /* NOTREACHED */
  665. }
  666.  
  667. /* gawk_option --- do gawk specific things */
  668.  
  669. static void
  670. gawk_option(optstr)
  671. char *optstr;
  672. {
  673.     char *cp;
  674.  
  675.     for (cp = optstr; *cp; cp++) {
  676.         switch (*cp) {
  677.         case ' ':
  678.         case '\t':
  679.         case ',':
  680.             break;
  681.         case 'v':
  682.         case 'V':
  683.             /* print version */
  684.             if (strncasecmp(cp, "version", 7) != 0)
  685.                 goto unknown;
  686.             else
  687.                 cp += 6;
  688.             version();
  689.             break;
  690.         case 'c':
  691.         case 'C':
  692.             if (strncasecmp(cp, "copyright", 9) == 0) {
  693.                 cp += 8;
  694.                 copyleft();
  695.             } else if (strncasecmp(cp, "copyleft", 8) == 0) {
  696.                 cp += 7;
  697.                 copyleft();
  698.             } else if (strncasecmp(cp, "compat", 6) == 0) {
  699.                 cp += 5;
  700.                 do_unix = 1;
  701.             } else
  702.                 goto unknown;
  703.             break;
  704.         case 'n':
  705.         case 'N':
  706.             /*
  707.              * Undocumented feature,
  708.              * inspired by nostalgia, and a T-shirt
  709.              */
  710.             if (strncasecmp(cp, "nostalgia", 9) != 0)
  711.                 goto unknown;
  712.             nostalgia();
  713.             break;
  714.         case 'p':
  715.         case 'P':
  716. #ifdef DEBUG
  717.             if (strncasecmp(cp, "parsedebug", 10) == 0) {
  718.                 cp += 9;
  719.                 yydebug = 2;
  720.                 break;
  721.             }
  722. #endif
  723.             if (strncasecmp(cp, "posix", 5) != 0)
  724.                 goto unknown;
  725.             cp += 4;
  726.             do_posix = do_unix = 1;
  727.             break;
  728.         case 'l':
  729.         case 'L':
  730.             if (strncasecmp(cp, "lint", 4) != 0)
  731.                 goto unknown;
  732.             cp += 3;
  733.             do_lint = 1;
  734.             break;
  735.         case 'H':
  736.         case 'h':
  737.             if (strncasecmp(cp, "help", 4) != 0)
  738.                 goto unknown;
  739.             cp += 3;
  740.             usage(0);
  741.             break;
  742.         case 'U':
  743.         case 'u':
  744.             if (strncasecmp(cp, "usage", 5) != 0)
  745.                 goto unknown;
  746.             cp += 4;
  747.             usage(0);
  748.             break;
  749.         case 's':
  750.         case 'S':
  751.             if (strncasecmp(cp, "source=", 7) != 0)
  752.                 goto unknown;
  753.             cp += 7;
  754.             if (cp[0] == '\0')
  755.                 warning("empty argument to -Wsource ignored");
  756.             else {
  757.                 srcfiles[++numfiles].stype = CMDLINE;
  758.                 srcfiles[numfiles].val = cp;
  759.                 return;
  760.             }
  761.             break;
  762.         default:
  763.         unknown:
  764.             fprintf(stderr, "'%c' -- unknown option, ignored\n",
  765.                 *cp);
  766.             break;
  767.         }
  768.     }
  769. }
  770.  
  771. /* nostalgia --- print the famous error message and die */
  772.  
  773. static void
  774. nostalgia()
  775. {
  776.     fprintf(stderr, "awk: bailing out near line 1\n");
  777.     abort();
  778. }
  779.  
  780. /* version --- print version message */
  781.  
  782. static void
  783. version()
  784. {
  785.     fprintf(stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
  786.     /* per GNU coding standards, exit successfully, do nothing else */
  787.     exit(0);
  788. }
  789.  
  790. /* this mess will improve in 2.16 */
  791. char *
  792. gawk_name(filespec)
  793. char *filespec;
  794. {
  795.     char *p;
  796.     
  797. #ifdef VMS    /* "device:[root.][directory.subdir]GAWK.EXE;n" -> "GAWK" */
  798.     char *q;
  799.  
  800.     p = strrchr(filespec, ']');  /* directory punctuation */
  801.     q = strrchr(filespec, '>');  /* alternate <international> punct */
  802.  
  803.     if (p == NULL || q > p) p = q;
  804.     p = strdup(p == NULL ? filespec : (p + 1));
  805.     if ((q = strrchr(p, '.')) != NULL)  *q = '\0';  /* strip .typ;vers */
  806.  
  807.     return p;
  808. #endif /*VMS*/
  809.  
  810. #if defined(MSDOS) || defined(OS2) || defined(atarist)
  811.     char *q;
  812.  
  813.     for (p = filespec; (p = strchr(p, '\\')); *p = '/')
  814.         ;
  815.     p = filespec;
  816.     if ((q = strrchr(p, '/')))
  817.         p = q + 1;
  818.     if ((q = strchr(p, '.')))
  819.         *q = '\0';
  820.     strlwr(p);
  821.  
  822.     return (p == NULL ? filespec : p);
  823. #endif /* MSDOS || atarist */
  824.  
  825.     /* "path/name" -> "name" */
  826.     p = strrchr(filespec, '/');
  827.     return (p == NULL ? filespec : p + 1);
  828. }
  829.