Subversion Repositories HelenOS

Rev

Rev 2714 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*  $NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $    */
  2.  
  3. /*-
  4.  * Copyright (c) 1991, 1993
  5.  *  The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Kenneth Almquist.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *  This product includes software developed by the University of
  21.  *  California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #include <sys/cdefs.h>
  40. #ifndef lint
  41. #if 0
  42. static char sccsid[] = "@(#)options.c   8.2 (Berkeley) 5/4/95";
  43. #else
  44. __RCSID("$NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $");
  45. #endif
  46. #endif /* not lint */
  47.  
  48. #include <signal.h>
  49. #include <unistd.h>
  50. #include <stdlib.h>
  51.  
  52. #include "shell.h"
  53. #define DEFINE_OPTIONS
  54. #include "options.h"
  55. #undef DEFINE_OPTIONS
  56. #include "nodes.h"  /* for other header files */
  57. #include "eval.h"
  58. #include "jobs.h"
  59. #include "input.h"
  60. #include "output.h"
  61. #include "trap.h"
  62. #include "var.h"
  63. #include "memalloc.h"
  64. #include "error.h"
  65. #include "mystring.h"
  66. #ifndef SMALL
  67. #include "myhistedit.h"
  68. #endif
  69.  
  70. char *arg0;         /* value of $0 */
  71. struct shparam shellparam;  /* current positional parameters */
  72. char **argptr;          /* argument list for builtin commands */
  73. char *optarg;           /* set by nextopt (like getopt) */
  74. char *optptr;           /* used by nextopt */
  75.  
  76. char *minusc;           /* argument to -c option */
  77.  
  78.  
  79. STATIC void options (int);
  80. STATIC void minus_o (char *, int);
  81. STATIC void setoption (int, int);
  82. STATIC int getopts (char *, char *, char **, int *, int *);
  83.  
  84.  
  85. /*
  86.  * Process the shell command line arguments.
  87.  */
  88.  
  89. void
  90. procargs(argc, argv)
  91.     int argc;
  92.     char **argv;
  93. {
  94.     int i;
  95.  
  96.     argptr = argv;
  97.     if (argc > 0)
  98.         argptr++;
  99.     for (i = 0; i < NOPTS; i++)
  100.         optlist[i].val = 2;
  101.     options(1);
  102.     if (*argptr == NULL && minusc == NULL)
  103.         sflag = 1;
  104.     if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
  105.         iflag = 1;
  106.     if (mflag == 2)
  107.         mflag = iflag;
  108.     for (i = 0; i < NOPTS; i++)
  109.         if (optlist[i].val == 2)
  110.             optlist[i].val = 0;
  111.     arg0 = argv[0];
  112.     if (sflag == 0 && minusc == NULL) {
  113.         commandname = arg0 = *argptr++;
  114.         setinputfile(commandname, 0);
  115.     }
  116.     /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
  117.     if (argptr && minusc && *argptr)
  118.             arg0 = *argptr++;
  119.  
  120.     shellparam.p = argptr;
  121.     shellparam.optind = 1;
  122.     shellparam.optoff = -1;
  123.     /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
  124.     while (*argptr) {
  125.         shellparam.nparam++;
  126.         argptr++;
  127.     }
  128.     optschanged();
  129. }
  130.  
  131.  
  132. void
  133. optschanged()
  134. {
  135.     setinteractive(iflag);
  136. #ifndef SMALL
  137.     histedit();
  138. #endif
  139.     setjobctl(mflag);
  140. }
  141.  
  142. /*
  143.  * Process shell options.  The global variable argptr contains a pointer
  144.  * to the argument list; we advance it past the options.
  145.  */
  146.  
  147. STATIC void
  148. options(cmdline)
  149.     int cmdline;
  150. {
  151.     char *p;
  152.     int val;
  153.     int c;
  154.  
  155.     if (cmdline)
  156.         minusc = NULL;
  157.     while ((p = *argptr) != NULL) {
  158.         argptr++;
  159.         if ((c = *p++) == '-') {
  160.             val = 1;
  161.                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
  162.                                 if (!cmdline) {
  163.                                         /* "-" means turn off -x and -v */
  164.                                         if (p[0] == '\0')
  165.                                                 xflag = vflag = 0;
  166.                                         /* "--" means reset params */
  167.                                         else if (*argptr == NULL)
  168.                         setparam(argptr);
  169.                                 }
  170.                 break;    /* "-" or  "--" terminates options */
  171.             }
  172.         } else if (c == '+') {
  173.             val = 0;
  174.         } else {
  175.             argptr--;
  176.             break;
  177.         }
  178.         while ((c = *p++) != '\0') {
  179.             if (c == 'c' && cmdline) {
  180.                 char *q;
  181. #ifdef NOHACK   /* removing this code allows sh -ce 'foo' for compat */
  182.                 if (*p == '\0')
  183. #endif
  184.                     q = *argptr++;
  185.                 if (q == NULL || minusc != NULL)
  186.                     error("Bad -c option");
  187.                 minusc = q;
  188. #ifdef NOHACK
  189.                 break;
  190. #endif
  191.             } else if (c == 'o') {
  192.                 minus_o(*argptr, val);
  193.                 if (*argptr)
  194.                     argptr++;
  195.             } else {
  196.                 setoption(c, val);
  197.             }
  198.         }
  199.     }
  200. }
  201.  
  202. STATIC void
  203. minus_o(name, val)
  204.     char *name;
  205.     int val;
  206. {
  207.     int i;
  208.  
  209.     if (name == NULL) {
  210.         out1str("Current option settings\n");
  211.         for (i = 0; i < NOPTS; i++)
  212.             out1fmt("%-16s%s\n", optlist[i].name,
  213.                 optlist[i].val ? "on" : "off");
  214.     } else {
  215.         for (i = 0; i < NOPTS; i++)
  216.             if (equal(name, optlist[i].name)) {
  217.                 setoption(optlist[i].letter, val);
  218.                 return;
  219.             }
  220.         error("Illegal option -o %s", name);
  221.     }
  222. }
  223.  
  224.  
  225. STATIC void
  226. setoption(flag, val)
  227.     char flag;
  228.     int val;
  229.     {
  230.     int i;
  231.  
  232.     for (i = 0; i < NOPTS; i++)
  233.         if (optlist[i].letter == flag) {
  234.             optlist[i].val = val;
  235.             if (val) {
  236.                 /* #%$ hack for ksh semantics */
  237.                 if (flag == 'V')
  238.                     Eflag = 0;
  239.                 else if (flag == 'E')
  240.                     Vflag = 0;
  241.             }
  242.             return;
  243.         }
  244.     error("Illegal option -%c", flag);
  245.     /* NOTREACHED */
  246. }
  247.  
  248.  
  249.  
  250. #ifdef mkinit
  251. INCLUDE "options.h"
  252.  
  253. SHELLPROC {
  254.     int i;
  255.  
  256.     for (i = 0; i < NOPTS; i++)
  257.         optlist[i].val = 0;
  258.     optschanged();
  259.  
  260. }
  261. #endif
  262.  
  263.  
  264. /*
  265.  * Set the shell parameters.
  266.  */
  267.  
  268. void
  269. setparam(argv)
  270.     char **argv;
  271.     {
  272.     char **newparam;
  273.     char **ap;
  274.     int nparam;
  275.  
  276.     for (nparam = 0 ; argv[nparam] ; nparam++);
  277.     ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
  278.     while (*argv) {
  279.         *ap++ = savestr(*argv++);
  280.     }
  281.     *ap = NULL;
  282.     freeparam(&shellparam);
  283.     shellparam.malloc = 1;
  284.     shellparam.nparam = nparam;
  285.     shellparam.p = newparam;
  286.     shellparam.optind = 1;
  287.     shellparam.optoff = -1;
  288. }
  289.  
  290.  
  291. /*
  292.  * Free the list of positional parameters.
  293.  */
  294.  
  295. void
  296. freeparam(param)
  297.     volatile struct shparam *param;
  298.     {
  299.     char **ap;
  300.  
  301.     if (param->malloc) {
  302.         for (ap = param->p ; *ap ; ap++)
  303.             ckfree(*ap);
  304.         ckfree(param->p);
  305.     }
  306. }
  307.  
  308.  
  309.  
  310. /*
  311.  * The shift builtin command.
  312.  */
  313.  
  314. int
  315. shiftcmd(argc, argv)
  316.     int argc;
  317.     char **argv;
  318. {
  319.     int n;
  320.     char **ap1, **ap2;
  321.  
  322.     n = 1;
  323.     if (argc > 1)
  324.         n = number(argv[1]);
  325.     if (n > shellparam.nparam)
  326.         error("can't shift that many");
  327.     INTOFF;
  328.     shellparam.nparam -= n;
  329.     for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
  330.         if (shellparam.malloc)
  331.             ckfree(*ap1);
  332.     }
  333.     ap2 = shellparam.p;
  334.     while ((*ap2++ = *ap1++) != NULL);
  335.     shellparam.optind = 1;
  336.     shellparam.optoff = -1;
  337.     INTON;
  338.     return 0;
  339. }
  340.  
  341.  
  342.  
  343. /*
  344.  * The set command builtin.
  345.  */
  346.  
  347. int
  348. setcmd(argc, argv)
  349.     int argc;
  350.     char **argv;
  351. {
  352.     if (argc == 1)
  353.         return showvarscmd(argc, argv);
  354.     INTOFF;
  355.     options(0);
  356.     optschanged();
  357.     if (*argptr != NULL) {
  358.         setparam(argptr);
  359.     }
  360.     INTON;
  361.     return 0;
  362. }
  363.  
  364.  
  365. void
  366. getoptsreset(value)
  367.     const char *value;
  368. {
  369.     shellparam.optind = number(value);
  370.     shellparam.optoff = -1;
  371. }
  372.  
  373. /*
  374.  * The getopts builtin.  Shellparam.optnext points to the next argument
  375.  * to be processed.  Shellparam.optptr points to the next character to
  376.  * be processed in the current argument.  If shellparam.optnext is NULL,
  377.  * then it's the first time getopts has been called.
  378.  */
  379.  
  380. int
  381. getoptscmd(argc, argv)
  382.     int argc;
  383.     char **argv;
  384. {
  385.     char **optbase;
  386.  
  387.     if (argc < 3)
  388.         error("Usage: getopts optstring var [arg]");
  389.     else if (argc == 3) {
  390.         optbase = shellparam.p;
  391.         if (shellparam.optind > shellparam.nparam + 1) {
  392.             shellparam.optind = 1;
  393.             shellparam.optoff = -1;
  394.         }
  395.     }
  396.     else {
  397.         optbase = &argv[3];
  398.         if (shellparam.optind > argc - 2) {
  399.             shellparam.optind = 1;
  400.             shellparam.optoff = -1;
  401.         }
  402.     }
  403.  
  404.     return getopts(argv[1], argv[2], optbase, &shellparam.optind,
  405.                &shellparam.optoff);
  406. }
  407.  
  408. STATIC int
  409. getopts(optstr, optvar, optfirst, optind, optoff)
  410.     char *optstr;
  411.     char *optvar;
  412.     char **optfirst;
  413.     int *optind;
  414.     int *optoff;
  415. {
  416.     char *p, *q;
  417.     char c = '?';
  418.     int done = 0;
  419.     int err = 0;
  420.     char s[10];
  421.     char **optnext = optfirst + *optind - 1;
  422.  
  423.     if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
  424.         strlen(*(optnext - 1)) < *optoff)
  425.         p = NULL;
  426.     else
  427.         p = *(optnext - 1) + *optoff;
  428.     if (p == NULL || *p == '\0') {
  429.         /* Current word is done, advance */
  430.         if (optnext == NULL)
  431.             return 1;
  432.         p = *optnext;
  433.         if (p == NULL || *p != '-' || *++p == '\0') {
  434. atend:
  435.             *optind = optnext - optfirst + 1;
  436.             p = NULL;
  437.             done = 1;
  438.             goto out;
  439.         }
  440.         optnext++;
  441.         if (p[0] == '-' && p[1] == '\0')    /* check for "--" */
  442.             goto atend;
  443.     }
  444.  
  445.     c = *p++;
  446.     for (q = optstr; *q != c; ) {
  447.         if (*q == '\0') {
  448.             if (optstr[0] == ':') {
  449.                 s[0] = c;
  450.                 s[1] = '\0';
  451.                 err |= setvarsafe("OPTARG", s, 0);
  452.             }
  453.             else {
  454.                 outfmt(&errout, "Illegal option -%c\n", c);
  455.                 (void) unsetvar("OPTARG");
  456.             }
  457.             c = '?';
  458.             goto bad;
  459.         }
  460.         if (*++q == ':')
  461.             q++;
  462.     }
  463.  
  464.     if (*++q == ':') {
  465.         if (*p == '\0' && (p = *optnext) == NULL) {
  466.             if (optstr[0] == ':') {
  467.                 s[0] = c;
  468.                 s[1] = '\0';
  469.                 err |= setvarsafe("OPTARG", s, 0);
  470.                 c = ':';
  471.             }
  472.             else {
  473.                 outfmt(&errout, "No arg for -%c option\n", c);
  474.                 (void) unsetvar("OPTARG");
  475.                 c = '?';
  476.             }
  477.             goto bad;
  478.         }
  479.  
  480.         if (p == *optnext)
  481.             optnext++;
  482.         setvarsafe("OPTARG", p, 0);
  483.         p = NULL;
  484.     }
  485.     else
  486.         setvarsafe("OPTARG", "", 0);
  487.     *optind = optnext - optfirst + 1;
  488.     goto out;
  489.  
  490. bad:
  491.     *optind = 1;
  492.     p = NULL;
  493. out:
  494.     *optoff = p ? p - *(optnext - 1) : -1;
  495.     fmtstr(s, sizeof(s), "%d", *optind);
  496.     err |= setvarsafe("OPTIND", s, VNOFUNC);
  497.     s[0] = c;
  498.     s[1] = '\0';
  499.     err |= setvarsafe(optvar, s, 0);
  500.     if (err) {
  501.         *optind = 1;
  502.         *optoff = -1;
  503.         flushall();
  504.         exraise(EXERROR);
  505.     }
  506.     return done;
  507. }
  508.  
  509. /*
  510.  * XXX - should get rid of.  have all builtins use getopt(3).  the
  511.  * library getopt must have the BSD extension static variable "optreset"
  512.  * otherwise it can't be used within the shell safely.
  513.  *
  514.  * Standard option processing (a la getopt) for builtin routines.  The
  515.  * only argument that is passed to nextopt is the option string; the
  516.  * other arguments are unnecessary.  It return the character, or '\0' on
  517.  * end of input.
  518.  */
  519.  
  520. int
  521. nextopt(optstring)
  522.     const char *optstring;
  523.     {
  524.     char *p;
  525.     const char *q;
  526.     char c;
  527.  
  528.     if ((p = optptr) == NULL || *p == '\0') {
  529.         p = *argptr;
  530.         if (p == NULL || *p != '-' || *++p == '\0')
  531.             return '\0';
  532.         argptr++;
  533.         if (p[0] == '-' && p[1] == '\0')    /* check for "--" */
  534.             return '\0';
  535.     }
  536.     c = *p++;
  537.     for (q = optstring ; *q != c ; ) {
  538.         if (*q == '\0')
  539.             error("Illegal option -%c", c);
  540.         if (*++q == ':')
  541.             q++;
  542.     }
  543.     if (*++q == ':') {
  544.         if (*p == '\0' && (p = *argptr++) == NULL)
  545.             error("No arg for -%c option", c);
  546.         optarg = p;
  547.         p = NULL;
  548.     }
  549.     optptr = p;
  550.     return c;
  551. }
  552.