147135Sbostic /*-
260698Sbostic * Copyright (c) 1991, 1993
360698Sbostic * The Regents of the University of California. All rights reserved.
447135Sbostic *
547135Sbostic * This code is derived from software contributed to Berkeley by
647135Sbostic * Kenneth Almquist.
747135Sbostic *
847135Sbostic * %sccs.include.redist.c%
947135Sbostic */
1047135Sbostic
1147135Sbostic #ifndef lint
12*69272Schristos static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 05/04/95";
1347135Sbostic #endif /* not lint */
1447135Sbostic
15*69272Schristos #include <signal.h>
16*69272Schristos #include <unistd.h>
17*69272Schristos #include <stdlib.h>
18*69272Schristos
1947135Sbostic #include "shell.h"
2047135Sbostic #define DEFINE_OPTIONS
2147135Sbostic #include "options.h"
2247135Sbostic #undef DEFINE_OPTIONS
2347135Sbostic #include "nodes.h" /* for other header files */
2447135Sbostic #include "eval.h"
2547135Sbostic #include "jobs.h"
2647135Sbostic #include "input.h"
2747135Sbostic #include "output.h"
2847135Sbostic #include "trap.h"
2947135Sbostic #include "var.h"
3047135Sbostic #include "memalloc.h"
3147135Sbostic #include "error.h"
3247135Sbostic #include "mystring.h"
33*69272Schristos #ifndef NO_HISTORY
34*69272Schristos #include "myhistedit.h"
35*69272Schristos #endif
3647135Sbostic
3747135Sbostic char *arg0; /* value of $0 */
3847135Sbostic struct shparam shellparam; /* current positional parameters */
3947135Sbostic char **argptr; /* argument list for builtin commands */
4047135Sbostic char *optarg; /* set by nextopt (like getopt) */
4147135Sbostic char *optptr; /* used by nextopt */
4247135Sbostic
4347135Sbostic char *minusc; /* argument to -c option */
4447135Sbostic
4547135Sbostic
46*69272Schristos STATIC void options __P((int));
47*69272Schristos STATIC void minus_o __P((char *, int));
48*69272Schristos STATIC void setoption __P((int, int));
4947135Sbostic
5047135Sbostic
5147135Sbostic /*
5247135Sbostic * Process the shell command line arguments.
5347135Sbostic */
5447135Sbostic
5547135Sbostic void
procargs(argc,argv)5647135Sbostic procargs(argc, argv)
57*69272Schristos int argc;
5847135Sbostic char **argv;
59*69272Schristos {
6055229Smarc int i;
6147135Sbostic
6247135Sbostic argptr = argv;
6347135Sbostic if (argc > 0)
6447135Sbostic argptr++;
6555229Smarc for (i = 0; i < NOPTS; i++)
6655229Smarc optlist[i].val = 2;
6747135Sbostic options(1);
6847135Sbostic if (*argptr == NULL && minusc == NULL)
6947135Sbostic sflag = 1;
7047135Sbostic if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
7147135Sbostic iflag = 1;
7255229Smarc if (mflag == 2)
7355229Smarc mflag = iflag;
7455229Smarc for (i = 0; i < NOPTS; i++)
7555229Smarc if (optlist[i].val == 2)
7655229Smarc optlist[i].val = 0;
7747135Sbostic arg0 = argv[0];
7847135Sbostic if (sflag == 0 && minusc == NULL) {
7947135Sbostic commandname = arg0 = *argptr++;
8047135Sbostic setinputfile(commandname, 0);
8147135Sbostic }
8247135Sbostic shellparam.p = argptr;
8347135Sbostic /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8447135Sbostic while (*argptr) {
8547135Sbostic shellparam.nparam++;
8647135Sbostic argptr++;
8747135Sbostic }
8855229Smarc optschanged();
8955229Smarc }
9055229Smarc
9155229Smarc
92*69272Schristos void
optschanged()93*69272Schristos optschanged()
94*69272Schristos {
9547135Sbostic setinteractive(iflag);
96*69272Schristos #ifndef NO_HISTORY
9754377Smarc histedit();
98*69272Schristos #endif
9955229Smarc setjobctl(mflag);
10047135Sbostic }
10147135Sbostic
10247135Sbostic /*
10347135Sbostic * Process shell options. The global variable argptr contains a pointer
10447135Sbostic * to the argument list; we advance it past the options.
10547135Sbostic */
10647135Sbostic
10747135Sbostic STATIC void
options(cmdline)108*69272Schristos options(cmdline)
109*69272Schristos int cmdline;
110*69272Schristos {
11147135Sbostic register char *p;
11247135Sbostic int val;
11347135Sbostic int c;
11447135Sbostic
11547299Smarc if (cmdline)
11647299Smarc minusc = NULL;
11747135Sbostic while ((p = *argptr) != NULL) {
11847135Sbostic argptr++;
11947135Sbostic if ((c = *p++) == '-') {
12047135Sbostic val = 1;
121*69272Schristos if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
12247299Smarc if (!cmdline) {
12347299Smarc /* "-" means turn off -x and -v */
12447299Smarc if (p[0] == '\0')
12547299Smarc xflag = vflag = 0;
12647299Smarc /* "--" means reset params */
12747299Smarc else if (*argptr == NULL)
128*69272Schristos setparam(argptr);
12947299Smarc }
13047135Sbostic break; /* "-" or "--" terminates options */
13147299Smarc }
13247135Sbostic } else if (c == '+') {
13347135Sbostic val = 0;
13447135Sbostic } else {
13547135Sbostic argptr--;
13647135Sbostic break;
13747135Sbostic }
13847135Sbostic while ((c = *p++) != '\0') {
13947135Sbostic if (c == 'c' && cmdline) {
14047135Sbostic char *q;
14147299Smarc #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
14247135Sbostic if (*p == '\0')
14347135Sbostic #endif
14447135Sbostic q = *argptr++;
14547135Sbostic if (q == NULL || minusc != NULL)
14647135Sbostic error("Bad -c option");
14747135Sbostic minusc = q;
14847135Sbostic #ifdef NOHACK
14947135Sbostic break;
15047135Sbostic #endif
15155229Smarc } else if (c == 'o') {
15255229Smarc minus_o(*argptr, val);
15355229Smarc if (*argptr)
15455229Smarc argptr++;
15547135Sbostic } else {
15647135Sbostic setoption(c, val);
15747135Sbostic }
15847135Sbostic }
15947135Sbostic }
16047135Sbostic }
16147135Sbostic
16255229Smarc STATIC void
minus_o(name,val)16355229Smarc minus_o(name, val)
16455229Smarc char *name;
16555229Smarc int val;
16655229Smarc {
16755229Smarc int i;
16847135Sbostic
16955229Smarc if (name == NULL) {
17055229Smarc out1str("Current option settings\n");
17155229Smarc for (i = 0; i < NOPTS; i++)
17255229Smarc out1fmt("%-16s%s\n", optlist[i].name,
17355229Smarc optlist[i].val ? "on" : "off");
17455229Smarc } else {
17555229Smarc for (i = 0; i < NOPTS; i++)
17655229Smarc if (equal(name, optlist[i].name)) {
17755229Smarc setoption(optlist[i].letter, val);
17855229Smarc return;
17955229Smarc }
18055229Smarc error("Illegal option -o %s", name);
18155229Smarc }
18255229Smarc }
18355229Smarc
18455229Smarc
18547135Sbostic STATIC void
setoption(flag,val)18647135Sbostic setoption(flag, val)
18747135Sbostic char flag;
18847135Sbostic int val;
18947135Sbostic {
19055229Smarc int i;
19147135Sbostic
19255229Smarc for (i = 0; i < NOPTS; i++)
19355229Smarc if (optlist[i].letter == flag) {
19455229Smarc optlist[i].val = val;
19555229Smarc if (val) {
19655229Smarc /* #%$ hack for ksh semantics */
19755229Smarc if (flag == 'V')
19855229Smarc Eflag = 0;
19955229Smarc else if (flag == 'E')
20055229Smarc Vflag = 0;
20155229Smarc }
20255229Smarc return;
20355229Smarc }
20455229Smarc error("Illegal option -%c", flag);
20547135Sbostic }
20647135Sbostic
20747135Sbostic
20847135Sbostic
20947135Sbostic #ifdef mkinit
21047135Sbostic INCLUDE "options.h"
21147135Sbostic
21247135Sbostic SHELLPROC {
21355229Smarc int i;
21447135Sbostic
21555229Smarc for (i = 0; i < NOPTS; i++)
21655229Smarc optlist[i].val = 0;
21755229Smarc optschanged();
21855229Smarc
21947135Sbostic }
22047135Sbostic #endif
22147135Sbostic
22247135Sbostic
22347135Sbostic /*
22447135Sbostic * Set the shell parameters.
22547135Sbostic */
22647135Sbostic
22747135Sbostic void
setparam(argv)22847135Sbostic setparam(argv)
22947135Sbostic char **argv;
23047135Sbostic {
23147135Sbostic char **newparam;
23247135Sbostic char **ap;
23347135Sbostic int nparam;
23447135Sbostic
23547135Sbostic for (nparam = 0 ; argv[nparam] ; nparam++);
23647135Sbostic ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
23747135Sbostic while (*argv) {
23847135Sbostic *ap++ = savestr(*argv++);
23947135Sbostic }
24047135Sbostic *ap = NULL;
24147135Sbostic freeparam(&shellparam);
24247135Sbostic shellparam.malloc = 1;
24347135Sbostic shellparam.nparam = nparam;
24447135Sbostic shellparam.p = newparam;
24547135Sbostic shellparam.optnext = NULL;
24647135Sbostic }
24747135Sbostic
24847135Sbostic
24947135Sbostic /*
25047135Sbostic * Free the list of positional parameters.
25147135Sbostic */
25247135Sbostic
25347135Sbostic void
freeparam(param)25447135Sbostic freeparam(param)
25547135Sbostic struct shparam *param;
25647135Sbostic {
25747135Sbostic char **ap;
25847135Sbostic
25947135Sbostic if (param->malloc) {
26047135Sbostic for (ap = param->p ; *ap ; ap++)
26147135Sbostic ckfree(*ap);
26247135Sbostic ckfree(param->p);
26347135Sbostic }
26447135Sbostic }
26547135Sbostic
26647135Sbostic
26747135Sbostic
26847135Sbostic /*
26947135Sbostic * The shift builtin command.
27047135Sbostic */
27147135Sbostic
272*69272Schristos int
shiftcmd(argc,argv)273*69272Schristos shiftcmd(argc, argv)
274*69272Schristos int argc;
275*69272Schristos char **argv;
276*69272Schristos {
27747135Sbostic int n;
27847135Sbostic char **ap1, **ap2;
27947135Sbostic
28047135Sbostic n = 1;
28147135Sbostic if (argc > 1)
28247135Sbostic n = number(argv[1]);
28347135Sbostic if (n > shellparam.nparam)
28455301Smarc error("can't shift that many");
28547135Sbostic INTOFF;
28647135Sbostic shellparam.nparam -= n;
28747135Sbostic for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
28847135Sbostic if (shellparam.malloc)
28947135Sbostic ckfree(*ap1);
29047135Sbostic }
29147135Sbostic ap2 = shellparam.p;
29247135Sbostic while ((*ap2++ = *ap1++) != NULL);
29347135Sbostic shellparam.optnext = NULL;
29447135Sbostic INTON;
29547135Sbostic return 0;
29647135Sbostic }
29747135Sbostic
29847135Sbostic
29947135Sbostic
30047135Sbostic /*
30147135Sbostic * The set command builtin.
30247135Sbostic */
30347135Sbostic
304*69272Schristos int
setcmd(argc,argv)305*69272Schristos setcmd(argc, argv)
306*69272Schristos int argc;
307*69272Schristos char **argv;
308*69272Schristos {
30947135Sbostic if (argc == 1)
31047135Sbostic return showvarscmd(argc, argv);
31147135Sbostic INTOFF;
31247135Sbostic options(0);
31355229Smarc optschanged();
31447135Sbostic if (*argptr != NULL) {
31547135Sbostic setparam(argptr);
31647135Sbostic }
31747135Sbostic INTON;
31847135Sbostic return 0;
31947135Sbostic }
32047135Sbostic
32147135Sbostic
32247135Sbostic /*
32347135Sbostic * The getopts builtin. Shellparam.optnext points to the next argument
32447135Sbostic * to be processed. Shellparam.optptr points to the next character to
32547135Sbostic * be processed in the current argument. If shellparam.optnext is NULL,
32647135Sbostic * then it's the first time getopts has been called.
32747135Sbostic */
32847135Sbostic
329*69272Schristos int
getoptscmd(argc,argv)330*69272Schristos getoptscmd(argc, argv)
331*69272Schristos int argc;
332*69272Schristos char **argv;
333*69272Schristos {
33447135Sbostic register char *p, *q;
33547135Sbostic char c;
33647135Sbostic char s[10];
33747135Sbostic
33847135Sbostic if (argc != 3)
33947135Sbostic error("Usage: getopts optstring var");
34047135Sbostic if (shellparam.optnext == NULL) {
34147135Sbostic shellparam.optnext = shellparam.p;
34247135Sbostic shellparam.optptr = NULL;
34347135Sbostic }
34447135Sbostic if ((p = shellparam.optptr) == NULL || *p == '\0') {
34547135Sbostic p = *shellparam.optnext;
34647135Sbostic if (p == NULL || *p != '-' || *++p == '\0') {
34747135Sbostic atend:
34847135Sbostic fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1);
34947135Sbostic setvar("OPTIND", s, 0);
35047135Sbostic shellparam.optnext = NULL;
35147135Sbostic return 1;
35247135Sbostic }
35347135Sbostic shellparam.optnext++;
35447135Sbostic if (p[0] == '-' && p[1] == '\0') /* check for "--" */
35547135Sbostic goto atend;
35647135Sbostic }
35747135Sbostic c = *p++;
35847135Sbostic for (q = argv[1] ; *q != c ; ) {
35947135Sbostic if (*q == '\0') {
36047135Sbostic out1fmt("Illegal option -%c\n", c);
36147135Sbostic c = '?';
36247135Sbostic goto out;
36347135Sbostic }
36447135Sbostic if (*++q == ':')
36547135Sbostic q++;
36647135Sbostic }
36747135Sbostic if (*++q == ':') {
36847135Sbostic if (*p == '\0' && (p = *shellparam.optnext) == NULL) {
36947135Sbostic out1fmt("No arg for -%c option\n", c);
37047135Sbostic c = '?';
37147135Sbostic goto out;
37247135Sbostic }
37347135Sbostic shellparam.optnext++;
37447135Sbostic setvar("OPTARG", p, 0);
37547135Sbostic p = NULL;
37647135Sbostic }
37747135Sbostic out:
37847135Sbostic shellparam.optptr = p;
37947135Sbostic s[0] = c;
38047135Sbostic s[1] = '\0';
38147135Sbostic setvar(argv[2], s, 0);
38247135Sbostic return 0;
38347135Sbostic }
38447135Sbostic
38547135Sbostic /*
38655229Smarc * XXX - should get rid of. have all builtins use getopt(3). the
38755229Smarc * library getopt must have the BSD extension static variable "optreset"
38855229Smarc * otherwise it can't be used within the shell safely.
38955229Smarc *
39047135Sbostic * Standard option processing (a la getopt) for builtin routines. The
39147135Sbostic * only argument that is passed to nextopt is the option string; the
39247299Smarc * other arguments are unnecessary. It return the character, or '\0' on
39347299Smarc * end of input.
39447135Sbostic */
39547135Sbostic
39647135Sbostic int
nextopt(optstring)39747135Sbostic nextopt(optstring)
39847135Sbostic char *optstring;
39947135Sbostic {
40047135Sbostic register char *p, *q;
40147135Sbostic char c;
40247135Sbostic
40347135Sbostic if ((p = optptr) == NULL || *p == '\0') {
40447135Sbostic p = *argptr;
40547135Sbostic if (p == NULL || *p != '-' || *++p == '\0')
40647299Smarc return '\0';
40747135Sbostic argptr++;
40847135Sbostic if (p[0] == '-' && p[1] == '\0') /* check for "--" */
40947299Smarc return '\0';
41047135Sbostic }
41147135Sbostic c = *p++;
41247135Sbostic for (q = optstring ; *q != c ; ) {
41347135Sbostic if (*q == '\0')
41447135Sbostic error("Illegal option -%c", c);
41547135Sbostic if (*++q == ':')
41647135Sbostic q++;
41747135Sbostic }
41847135Sbostic if (*++q == ':') {
41947135Sbostic if (*p == '\0' && (p = *argptr++) == NULL)
42047135Sbostic error("No arg for -%c option", c);
42147135Sbostic optarg = p;
42247135Sbostic p = NULL;
42347135Sbostic }
42447135Sbostic optptr = p;
42547135Sbostic return c;
42647135Sbostic }
427