147135Sbostic /*- 247135Sbostic * Copyright (c) 1991 The Regents of the University of California. 347135Sbostic * 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*55229Smarc static char sccsid[] = "@(#)options.c 5.4 (Berkeley) 07/15/92"; 1347135Sbostic #endif /* not lint */ 1447135Sbostic 1547135Sbostic #include "shell.h" 1647135Sbostic #define DEFINE_OPTIONS 1747135Sbostic #include "options.h" 1847135Sbostic #undef DEFINE_OPTIONS 1947135Sbostic #include "nodes.h" /* for other header files */ 2047135Sbostic #include "eval.h" 2147135Sbostic #include "jobs.h" 2247135Sbostic #include "input.h" 2347135Sbostic #include "output.h" 2447135Sbostic #include "trap.h" 2547135Sbostic #include "var.h" 2647135Sbostic #include "memalloc.h" 2747135Sbostic #include "error.h" 2847135Sbostic #include "mystring.h" 2947135Sbostic 3047135Sbostic char *arg0; /* value of $0 */ 3147135Sbostic struct shparam shellparam; /* current positional parameters */ 3247135Sbostic char **argptr; /* argument list for builtin commands */ 3347135Sbostic char *optarg; /* set by nextopt (like getopt) */ 3447135Sbostic char *optptr; /* used by nextopt */ 3547135Sbostic 3647135Sbostic char *minusc; /* argument to -c option */ 3747135Sbostic 3847135Sbostic 3947135Sbostic #ifdef __STDC__ 4047135Sbostic STATIC void options(int); 4147135Sbostic STATIC void setoption(int, int); 42*55229Smarc STATIC void minus_o(char *, int); 4347135Sbostic #else 4447135Sbostic STATIC void options(); 4547135Sbostic STATIC void setoption(); 46*55229Smarc STATIC void minus_o(); 4747135Sbostic #endif 4847135Sbostic 4947135Sbostic 5047135Sbostic 5147135Sbostic /* 5247135Sbostic * Process the shell command line arguments. 5347135Sbostic */ 5447135Sbostic 5547135Sbostic void 5647135Sbostic procargs(argc, argv) 5747135Sbostic char **argv; 5847135Sbostic { 59*55229Smarc int i; 6047135Sbostic 6147135Sbostic argptr = argv; 6247135Sbostic if (argc > 0) 6347135Sbostic argptr++; 64*55229Smarc for (i = 0; i < NOPTS; i++) 65*55229Smarc optlist[i].val = 2; 6647135Sbostic options(1); 6747135Sbostic if (*argptr == NULL && minusc == NULL) 6847135Sbostic sflag = 1; 6947135Sbostic if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 7047135Sbostic iflag = 1; 71*55229Smarc if (mflag == 2) 72*55229Smarc mflag = iflag; 73*55229Smarc for (i = 0; i < NOPTS; i++) 74*55229Smarc if (optlist[i].val == 2) 75*55229Smarc optlist[i].val = 0; 7647135Sbostic arg0 = argv[0]; 7747135Sbostic if (sflag == 0 && minusc == NULL) { 7847135Sbostic commandname = arg0 = *argptr++; 7947135Sbostic setinputfile(commandname, 0); 8047135Sbostic } 8147135Sbostic shellparam.p = argptr; 8247135Sbostic /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 8347135Sbostic while (*argptr) { 8447135Sbostic shellparam.nparam++; 8547135Sbostic argptr++; 8647135Sbostic } 87*55229Smarc optschanged(); 88*55229Smarc } 89*55229Smarc 90*55229Smarc 91*55229Smarc optschanged() { 9247135Sbostic setinteractive(iflag); 9354377Smarc histedit(); 94*55229Smarc setjobctl(mflag); 9547135Sbostic } 9647135Sbostic 9747135Sbostic /* 9847135Sbostic * Process shell options. The global variable argptr contains a pointer 9947135Sbostic * to the argument list; we advance it past the options. 10047135Sbostic */ 10147135Sbostic 10247135Sbostic STATIC void 10347135Sbostic options(cmdline) { 10447135Sbostic register char *p; 10547135Sbostic int val; 10647135Sbostic int c; 10747135Sbostic 10847299Smarc if (cmdline) 10947299Smarc minusc = NULL; 11047135Sbostic while ((p = *argptr) != NULL) { 11147135Sbostic argptr++; 11247135Sbostic if ((c = *p++) == '-') { 11347135Sbostic val = 1; 11447299Smarc if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') { 11547299Smarc if (!cmdline) { 11647299Smarc /* "-" means turn off -x and -v */ 11747299Smarc if (p[0] == '\0') 11847299Smarc xflag = vflag = 0; 11947299Smarc /* "--" means reset params */ 12047299Smarc else if (*argptr == NULL) 12147299Smarc setparam(argptr); 12247299Smarc } 12347135Sbostic break; /* "-" or "--" terminates options */ 12447299Smarc } 12547135Sbostic } else if (c == '+') { 12647135Sbostic val = 0; 12747135Sbostic } else { 12847135Sbostic argptr--; 12947135Sbostic break; 13047135Sbostic } 13147135Sbostic while ((c = *p++) != '\0') { 13247135Sbostic if (c == 'c' && cmdline) { 13347135Sbostic char *q; 13447299Smarc #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 13547135Sbostic if (*p == '\0') 13647135Sbostic #endif 13747135Sbostic q = *argptr++; 13847135Sbostic if (q == NULL || minusc != NULL) 13947135Sbostic error("Bad -c option"); 14047135Sbostic minusc = q; 14147135Sbostic #ifdef NOHACK 14247135Sbostic break; 14347135Sbostic #endif 144*55229Smarc } else if (c == 'o') { 145*55229Smarc minus_o(*argptr, val); 146*55229Smarc if (*argptr) 147*55229Smarc argptr++; 14847135Sbostic } else { 14947135Sbostic setoption(c, val); 15047135Sbostic } 15147135Sbostic } 15247135Sbostic } 15347135Sbostic } 15447135Sbostic 155*55229Smarc STATIC void 156*55229Smarc minus_o(name, val) 157*55229Smarc char *name; 158*55229Smarc int val; 159*55229Smarc { 160*55229Smarc int i; 16147135Sbostic 162*55229Smarc if (name == NULL) { 163*55229Smarc out1str("Current option settings\n"); 164*55229Smarc for (i = 0; i < NOPTS; i++) 165*55229Smarc out1fmt("%-16s%s\n", optlist[i].name, 166*55229Smarc optlist[i].val ? "on" : "off"); 167*55229Smarc } else { 168*55229Smarc for (i = 0; i < NOPTS; i++) 169*55229Smarc if (equal(name, optlist[i].name)) { 170*55229Smarc setoption(optlist[i].letter, val); 171*55229Smarc return; 172*55229Smarc } 173*55229Smarc error("Illegal option -o %s", name); 174*55229Smarc } 175*55229Smarc } 176*55229Smarc 177*55229Smarc 17847135Sbostic STATIC void 17947135Sbostic setoption(flag, val) 18047135Sbostic char flag; 18147135Sbostic int val; 18247135Sbostic { 183*55229Smarc int i; 18447135Sbostic 185*55229Smarc for (i = 0; i < NOPTS; i++) 186*55229Smarc if (optlist[i].letter == flag) { 187*55229Smarc optlist[i].val = val; 188*55229Smarc if (val) { 189*55229Smarc /* #%$ hack for ksh semantics */ 190*55229Smarc if (flag == 'V') 191*55229Smarc Eflag = 0; 192*55229Smarc else if (flag == 'E') 193*55229Smarc Vflag = 0; 194*55229Smarc } 195*55229Smarc return; 196*55229Smarc } 197*55229Smarc error("Illegal option -%c", flag); 19847135Sbostic } 19947135Sbostic 20047135Sbostic 20147135Sbostic 20247135Sbostic #ifdef mkinit 20347135Sbostic INCLUDE "options.h" 20447135Sbostic 20547135Sbostic SHELLPROC { 206*55229Smarc int i; 20747135Sbostic 208*55229Smarc for (i = 0; i < NOPTS; i++) 209*55229Smarc optlist[i].val = 0; 210*55229Smarc optschanged(); 211*55229Smarc 21247135Sbostic } 21347135Sbostic #endif 21447135Sbostic 21547135Sbostic 21647135Sbostic /* 21747135Sbostic * Set the shell parameters. 21847135Sbostic */ 21947135Sbostic 22047135Sbostic void 22147135Sbostic setparam(argv) 22247135Sbostic char **argv; 22347135Sbostic { 22447135Sbostic char **newparam; 22547135Sbostic char **ap; 22647135Sbostic int nparam; 22747135Sbostic 22847135Sbostic for (nparam = 0 ; argv[nparam] ; nparam++); 22947135Sbostic ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 23047135Sbostic while (*argv) { 23147135Sbostic *ap++ = savestr(*argv++); 23247135Sbostic } 23347135Sbostic *ap = NULL; 23447135Sbostic freeparam(&shellparam); 23547135Sbostic shellparam.malloc = 1; 23647135Sbostic shellparam.nparam = nparam; 23747135Sbostic shellparam.p = newparam; 23847135Sbostic shellparam.optnext = NULL; 23947135Sbostic } 24047135Sbostic 24147135Sbostic 24247135Sbostic /* 24347135Sbostic * Free the list of positional parameters. 24447135Sbostic */ 24547135Sbostic 24647135Sbostic void 24747135Sbostic freeparam(param) 24847135Sbostic struct shparam *param; 24947135Sbostic { 25047135Sbostic char **ap; 25147135Sbostic 25247135Sbostic if (param->malloc) { 25347135Sbostic for (ap = param->p ; *ap ; ap++) 25447135Sbostic ckfree(*ap); 25547135Sbostic ckfree(param->p); 25647135Sbostic } 25747135Sbostic } 25847135Sbostic 25947135Sbostic 26047135Sbostic 26147135Sbostic /* 26247135Sbostic * The shift builtin command. 26347135Sbostic */ 26447135Sbostic 26547135Sbostic shiftcmd(argc, argv) char **argv; { 26647135Sbostic int n; 26747135Sbostic char **ap1, **ap2; 26847135Sbostic 26947135Sbostic n = 1; 27047135Sbostic if (argc > 1) 27147135Sbostic n = number(argv[1]); 27247135Sbostic if (n > shellparam.nparam) 27347135Sbostic n = shellparam.nparam; 27447135Sbostic INTOFF; 27547135Sbostic shellparam.nparam -= n; 27647135Sbostic for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 27747135Sbostic if (shellparam.malloc) 27847135Sbostic ckfree(*ap1); 27947135Sbostic } 28047135Sbostic ap2 = shellparam.p; 28147135Sbostic while ((*ap2++ = *ap1++) != NULL); 28247135Sbostic shellparam.optnext = NULL; 28347135Sbostic INTON; 28447135Sbostic return 0; 28547135Sbostic } 28647135Sbostic 28747135Sbostic 28847135Sbostic 28947135Sbostic /* 29047135Sbostic * The set command builtin. 29147135Sbostic */ 29247135Sbostic 29347135Sbostic setcmd(argc, argv) char **argv; { 29447135Sbostic if (argc == 1) 29547135Sbostic return showvarscmd(argc, argv); 29647135Sbostic INTOFF; 29747135Sbostic options(0); 298*55229Smarc optschanged(); 29947135Sbostic if (*argptr != NULL) { 30047135Sbostic setparam(argptr); 30147135Sbostic } 30247135Sbostic INTON; 30347135Sbostic return 0; 30447135Sbostic } 30547135Sbostic 30647135Sbostic 30747135Sbostic /* 30847135Sbostic * The getopts builtin. Shellparam.optnext points to the next argument 30947135Sbostic * to be processed. Shellparam.optptr points to the next character to 31047135Sbostic * be processed in the current argument. If shellparam.optnext is NULL, 31147135Sbostic * then it's the first time getopts has been called. 31247135Sbostic */ 31347135Sbostic 31447135Sbostic getoptscmd(argc, argv) char **argv; { 31547135Sbostic register char *p, *q; 31647135Sbostic char c; 31747135Sbostic char s[10]; 31847135Sbostic 31947135Sbostic if (argc != 3) 32047135Sbostic error("Usage: getopts optstring var"); 32147135Sbostic if (shellparam.optnext == NULL) { 32247135Sbostic shellparam.optnext = shellparam.p; 32347135Sbostic shellparam.optptr = NULL; 32447135Sbostic } 32547135Sbostic if ((p = shellparam.optptr) == NULL || *p == '\0') { 32647135Sbostic p = *shellparam.optnext; 32747135Sbostic if (p == NULL || *p != '-' || *++p == '\0') { 32847135Sbostic atend: 32947135Sbostic fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 33047135Sbostic setvar("OPTIND", s, 0); 33147135Sbostic shellparam.optnext = NULL; 33247135Sbostic return 1; 33347135Sbostic } 33447135Sbostic shellparam.optnext++; 33547135Sbostic if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 33647135Sbostic goto atend; 33747135Sbostic } 33847135Sbostic c = *p++; 33947135Sbostic for (q = argv[1] ; *q != c ; ) { 34047135Sbostic if (*q == '\0') { 34147135Sbostic out1fmt("Illegal option -%c\n", c); 34247135Sbostic c = '?'; 34347135Sbostic goto out; 34447135Sbostic } 34547135Sbostic if (*++q == ':') 34647135Sbostic q++; 34747135Sbostic } 34847135Sbostic if (*++q == ':') { 34947135Sbostic if (*p == '\0' && (p = *shellparam.optnext) == NULL) { 35047135Sbostic out1fmt("No arg for -%c option\n", c); 35147135Sbostic c = '?'; 35247135Sbostic goto out; 35347135Sbostic } 35447135Sbostic shellparam.optnext++; 35547135Sbostic setvar("OPTARG", p, 0); 35647135Sbostic p = NULL; 35747135Sbostic } 35847135Sbostic out: 35947135Sbostic shellparam.optptr = p; 36047135Sbostic s[0] = c; 36147135Sbostic s[1] = '\0'; 36247135Sbostic setvar(argv[2], s, 0); 36347135Sbostic return 0; 36447135Sbostic } 36547135Sbostic 36647135Sbostic /* 367*55229Smarc * XXX - should get rid of. have all builtins use getopt(3). the 368*55229Smarc * library getopt must have the BSD extension static variable "optreset" 369*55229Smarc * otherwise it can't be used within the shell safely. 370*55229Smarc * 37147135Sbostic * Standard option processing (a la getopt) for builtin routines. The 37247135Sbostic * only argument that is passed to nextopt is the option string; the 37347299Smarc * other arguments are unnecessary. It return the character, or '\0' on 37447299Smarc * end of input. 37547135Sbostic */ 37647135Sbostic 37747135Sbostic int 37847135Sbostic nextopt(optstring) 37947135Sbostic char *optstring; 38047135Sbostic { 38147135Sbostic register char *p, *q; 38247135Sbostic char c; 38347135Sbostic 38447135Sbostic if ((p = optptr) == NULL || *p == '\0') { 38547135Sbostic p = *argptr; 38647135Sbostic if (p == NULL || *p != '-' || *++p == '\0') 38747299Smarc return '\0'; 38847135Sbostic argptr++; 38947135Sbostic if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 39047299Smarc return '\0'; 39147135Sbostic } 39247135Sbostic c = *p++; 39347135Sbostic for (q = optstring ; *q != c ; ) { 39447135Sbostic if (*q == '\0') 39547135Sbostic error("Illegal option -%c", c); 39647135Sbostic if (*++q == ':') 39747135Sbostic q++; 39847135Sbostic } 39947135Sbostic if (*++q == ':') { 40047135Sbostic if (*p == '\0' && (p = *argptr++) == NULL) 40147135Sbostic error("No arg for -%c option", c); 40247135Sbostic optarg = p; 40347135Sbostic p = NULL; 40447135Sbostic } 40547135Sbostic optptr = p; 40647135Sbostic return c; 40747135Sbostic } 408