options.c revision 8855
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 353044Sdg * 368855Srgrimes * $Id: options.c,v 1.2 1994/09/24 02:58:04 davidg Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 401556Srgrimesstatic char sccsid[] = "@(#)options.c 8.1 (Berkeley) 5/31/93"; 411556Srgrimes#endif /* not lint */ 421556Srgrimes 431556Srgrimes#include "shell.h" 441556Srgrimes#define DEFINE_OPTIONS 451556Srgrimes#include "options.h" 461556Srgrimes#undef DEFINE_OPTIONS 471556Srgrimes#include "nodes.h" /* for other header files */ 481556Srgrimes#include "eval.h" 491556Srgrimes#include "jobs.h" 501556Srgrimes#include "input.h" 511556Srgrimes#include "output.h" 521556Srgrimes#include "trap.h" 531556Srgrimes#include "var.h" 541556Srgrimes#include "memalloc.h" 551556Srgrimes#include "error.h" 561556Srgrimes#include "mystring.h" 571556Srgrimes 581556Srgrimeschar *arg0; /* value of $0 */ 591556Srgrimesstruct shparam shellparam; /* current positional parameters */ 601556Srgrimeschar **argptr; /* argument list for builtin commands */ 611556Srgrimeschar *optarg; /* set by nextopt (like getopt) */ 621556Srgrimeschar *optptr; /* used by nextopt */ 631556Srgrimes 641556Srgrimeschar *minusc; /* argument to -c option */ 651556Srgrimes 661556Srgrimes 671556Srgrimes#ifdef __STDC__ 681556SrgrimesSTATIC void options(int); 691556SrgrimesSTATIC void setoption(int, int); 701556SrgrimesSTATIC void minus_o(char *, int); 711556Srgrimes#else 721556SrgrimesSTATIC void options(); 731556SrgrimesSTATIC void setoption(); 741556SrgrimesSTATIC void minus_o(); 751556Srgrimes#endif 761556Srgrimes 771556Srgrimes 781556Srgrimes 791556Srgrimes/* 801556Srgrimes * Process the shell command line arguments. 811556Srgrimes */ 821556Srgrimes 831556Srgrimesvoid 841556Srgrimesprocargs(argc, argv) 851556Srgrimes char **argv; 861556Srgrimes { 871556Srgrimes int i; 881556Srgrimes 891556Srgrimes argptr = argv; 901556Srgrimes if (argc > 0) 911556Srgrimes argptr++; 921556Srgrimes for (i = 0; i < NOPTS; i++) 931556Srgrimes optlist[i].val = 2; 941556Srgrimes options(1); 951556Srgrimes if (*argptr == NULL && minusc == NULL) 961556Srgrimes sflag = 1; 971556Srgrimes if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 981556Srgrimes iflag = 1; 991556Srgrimes if (mflag == 2) 1001556Srgrimes mflag = iflag; 1011556Srgrimes for (i = 0; i < NOPTS; i++) 1021556Srgrimes if (optlist[i].val == 2) 1031556Srgrimes optlist[i].val = 0; 1041556Srgrimes arg0 = argv[0]; 1051556Srgrimes if (sflag == 0 && minusc == NULL) { 1061556Srgrimes commandname = arg0 = *argptr++; 1071556Srgrimes setinputfile(commandname, 0); 1081556Srgrimes } 1091556Srgrimes shellparam.p = argptr; 1101556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1111556Srgrimes while (*argptr) { 1121556Srgrimes shellparam.nparam++; 1131556Srgrimes argptr++; 1141556Srgrimes } 1151556Srgrimes optschanged(); 1161556Srgrimes} 1171556Srgrimes 1181556Srgrimes 1191556Srgrimesoptschanged() { 1201556Srgrimes setinteractive(iflag); 1211556Srgrimes histedit(); 1221556Srgrimes setjobctl(mflag); 1231556Srgrimes} 1241556Srgrimes 1251556Srgrimes/* 1261556Srgrimes * Process shell options. The global variable argptr contains a pointer 1271556Srgrimes * to the argument list; we advance it past the options. 1281556Srgrimes */ 1291556Srgrimes 1301556SrgrimesSTATIC void 1311556Srgrimesoptions(cmdline) { 1321556Srgrimes register char *p; 1331556Srgrimes int val; 1341556Srgrimes int c; 1351556Srgrimes 1361556Srgrimes if (cmdline) 1371556Srgrimes minusc = NULL; 1381556Srgrimes while ((p = *argptr) != NULL) { 1391556Srgrimes argptr++; 1401556Srgrimes if ((c = *p++) == '-') { 1411556Srgrimes val = 1; 1421556Srgrimes if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') { 1431556Srgrimes if (!cmdline) { 1441556Srgrimes /* "-" means turn off -x and -v */ 1451556Srgrimes if (p[0] == '\0') 1461556Srgrimes xflag = vflag = 0; 1471556Srgrimes /* "--" means reset params */ 1481556Srgrimes else if (*argptr == NULL) 1491556Srgrimes setparam(argptr); 1501556Srgrimes } 1511556Srgrimes break; /* "-" or "--" terminates options */ 1521556Srgrimes } 1531556Srgrimes } else if (c == '+') { 1541556Srgrimes val = 0; 1551556Srgrimes } else { 1561556Srgrimes argptr--; 1571556Srgrimes break; 1581556Srgrimes } 1591556Srgrimes while ((c = *p++) != '\0') { 1601556Srgrimes if (c == 'c' && cmdline) { 1611556Srgrimes char *q; 1621556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1631556Srgrimes if (*p == '\0') 1641556Srgrimes#endif 1651556Srgrimes q = *argptr++; 1661556Srgrimes if (q == NULL || minusc != NULL) 1671556Srgrimes error("Bad -c option"); 1681556Srgrimes minusc = q; 1691556Srgrimes#ifdef NOHACK 1701556Srgrimes break; 1711556Srgrimes#endif 1721556Srgrimes } else if (c == 'o') { 1731556Srgrimes minus_o(*argptr, val); 1741556Srgrimes if (*argptr) 1751556Srgrimes argptr++; 1761556Srgrimes } else { 1771556Srgrimes setoption(c, val); 1781556Srgrimes } 1791556Srgrimes } 1801556Srgrimes } 1811556Srgrimes} 1821556Srgrimes 1831556SrgrimesSTATIC void 1841556Srgrimesminus_o(name, val) 1851556Srgrimes char *name; 1861556Srgrimes int val; 1871556Srgrimes{ 1881556Srgrimes int i; 1891556Srgrimes 1901556Srgrimes if (name == NULL) { 1911556Srgrimes out1str("Current option settings\n"); 1921556Srgrimes for (i = 0; i < NOPTS; i++) 1931556Srgrimes out1fmt("%-16s%s\n", optlist[i].name, 1941556Srgrimes optlist[i].val ? "on" : "off"); 1951556Srgrimes } else { 1961556Srgrimes for (i = 0; i < NOPTS; i++) 1971556Srgrimes if (equal(name, optlist[i].name)) { 1981556Srgrimes setoption(optlist[i].letter, val); 1991556Srgrimes return; 2001556Srgrimes } 2011556Srgrimes error("Illegal option -o %s", name); 2021556Srgrimes } 2031556Srgrimes} 2041556Srgrimes 2058855Srgrimes 2061556SrgrimesSTATIC void 2071556Srgrimessetoption(flag, val) 2081556Srgrimes char flag; 2091556Srgrimes int val; 2101556Srgrimes { 2111556Srgrimes int i; 2121556Srgrimes 2131556Srgrimes for (i = 0; i < NOPTS; i++) 2141556Srgrimes if (optlist[i].letter == flag) { 2151556Srgrimes optlist[i].val = val; 2161556Srgrimes if (val) { 2171556Srgrimes /* #%$ hack for ksh semantics */ 2181556Srgrimes if (flag == 'V') 2191556Srgrimes Eflag = 0; 2201556Srgrimes else if (flag == 'E') 2211556Srgrimes Vflag = 0; 2221556Srgrimes } 2231556Srgrimes return; 2241556Srgrimes } 2251556Srgrimes error("Illegal option -%c", flag); 2261556Srgrimes} 2271556Srgrimes 2281556Srgrimes 2291556Srgrimes 2301556Srgrimes#ifdef mkinit 2311556SrgrimesINCLUDE "options.h" 2321556Srgrimes 2331556SrgrimesSHELLPROC { 2341556Srgrimes int i; 2351556Srgrimes 2361556Srgrimes for (i = 0; i < NOPTS; i++) 2371556Srgrimes optlist[i].val = 0; 2381556Srgrimes optschanged(); 2391556Srgrimes 2401556Srgrimes} 2411556Srgrimes#endif 2421556Srgrimes 2431556Srgrimes 2441556Srgrimes/* 2451556Srgrimes * Set the shell parameters. 2461556Srgrimes */ 2471556Srgrimes 2481556Srgrimesvoid 2491556Srgrimessetparam(argv) 2501556Srgrimes char **argv; 2511556Srgrimes { 2521556Srgrimes char **newparam; 2531556Srgrimes char **ap; 2541556Srgrimes int nparam; 2551556Srgrimes 2561556Srgrimes for (nparam = 0 ; argv[nparam] ; nparam++); 2571556Srgrimes ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 2581556Srgrimes while (*argv) { 2591556Srgrimes *ap++ = savestr(*argv++); 2601556Srgrimes } 2611556Srgrimes *ap = NULL; 2621556Srgrimes freeparam(&shellparam); 2631556Srgrimes shellparam.malloc = 1; 2641556Srgrimes shellparam.nparam = nparam; 2651556Srgrimes shellparam.p = newparam; 2661556Srgrimes shellparam.optnext = NULL; 2671556Srgrimes} 2681556Srgrimes 2691556Srgrimes 2701556Srgrimes/* 2711556Srgrimes * Free the list of positional parameters. 2721556Srgrimes */ 2731556Srgrimes 2741556Srgrimesvoid 2751556Srgrimesfreeparam(param) 2761556Srgrimes struct shparam *param; 2771556Srgrimes { 2781556Srgrimes char **ap; 2791556Srgrimes 2801556Srgrimes if (param->malloc) { 2811556Srgrimes for (ap = param->p ; *ap ; ap++) 2821556Srgrimes ckfree(*ap); 2831556Srgrimes ckfree(param->p); 2841556Srgrimes } 2851556Srgrimes} 2861556Srgrimes 2871556Srgrimes 2881556Srgrimes 2891556Srgrimes/* 2901556Srgrimes * The shift builtin command. 2911556Srgrimes */ 2921556Srgrimes 2931556Srgrimesshiftcmd(argc, argv) char **argv; { 2941556Srgrimes int n; 2951556Srgrimes char **ap1, **ap2; 2961556Srgrimes 2971556Srgrimes n = 1; 2981556Srgrimes if (argc > 1) 2991556Srgrimes n = number(argv[1]); 3001556Srgrimes if (n > shellparam.nparam) 3011556Srgrimes error("can't shift that many"); 3021556Srgrimes INTOFF; 3031556Srgrimes shellparam.nparam -= n; 3041556Srgrimes for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 3051556Srgrimes if (shellparam.malloc) 3061556Srgrimes ckfree(*ap1); 3071556Srgrimes } 3081556Srgrimes ap2 = shellparam.p; 3091556Srgrimes while ((*ap2++ = *ap1++) != NULL); 3101556Srgrimes shellparam.optnext = NULL; 3111556Srgrimes INTON; 3121556Srgrimes return 0; 3131556Srgrimes} 3141556Srgrimes 3151556Srgrimes 3161556Srgrimes 3171556Srgrimes/* 3181556Srgrimes * The set command builtin. 3191556Srgrimes */ 3201556Srgrimes 3211556Srgrimessetcmd(argc, argv) char **argv; { 3221556Srgrimes if (argc == 1) 3231556Srgrimes return showvarscmd(argc, argv); 3241556Srgrimes INTOFF; 3251556Srgrimes options(0); 3261556Srgrimes optschanged(); 3271556Srgrimes if (*argptr != NULL) { 3281556Srgrimes setparam(argptr); 3291556Srgrimes } 3301556Srgrimes INTON; 3311556Srgrimes return 0; 3321556Srgrimes} 3331556Srgrimes 3341556Srgrimes 3351556Srgrimes/* 3361556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 3371556Srgrimes * to be processed. Shellparam.optptr points to the next character to 3381556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 3391556Srgrimes * then it's the first time getopts has been called. 3401556Srgrimes */ 3411556Srgrimes 3421556Srgrimesgetoptscmd(argc, argv) char **argv; { 3431556Srgrimes register char *p, *q; 3441556Srgrimes char c; 3451556Srgrimes char s[10]; 3461556Srgrimes 3471556Srgrimes if (argc != 3) 3481556Srgrimes error("Usage: getopts optstring var"); 3491556Srgrimes if (shellparam.optnext == NULL) { 3501556Srgrimes shellparam.optnext = shellparam.p; 3511556Srgrimes shellparam.optptr = NULL; 3521556Srgrimes } 3531556Srgrimes if ((p = shellparam.optptr) == NULL || *p == '\0') { 3541556Srgrimes p = *shellparam.optnext; 3551556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 3561556Srgrimesatend: 3571556Srgrimes fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 3581556Srgrimes setvar("OPTIND", s, 0); 3591556Srgrimes shellparam.optnext = NULL; 3601556Srgrimes return 1; 3611556Srgrimes } 3621556Srgrimes shellparam.optnext++; 3631556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 3641556Srgrimes goto atend; 3651556Srgrimes } 3661556Srgrimes c = *p++; 3671556Srgrimes for (q = argv[1] ; *q != c ; ) { 3681556Srgrimes if (*q == '\0') { 3691556Srgrimes out1fmt("Illegal option -%c\n", c); 3701556Srgrimes c = '?'; 3711556Srgrimes goto out; 3721556Srgrimes } 3731556Srgrimes if (*++q == ':') 3741556Srgrimes q++; 3751556Srgrimes } 3761556Srgrimes if (*++q == ':') { 3771556Srgrimes if (*p == '\0' && (p = *shellparam.optnext) == NULL) { 3781556Srgrimes out1fmt("No arg for -%c option\n", c); 3791556Srgrimes c = '?'; 3801556Srgrimes goto out; 3811556Srgrimes } 3821556Srgrimes shellparam.optnext++; 3831556Srgrimes setvar("OPTARG", p, 0); 3841556Srgrimes p = NULL; 3851556Srgrimes } 3861556Srgrimesout: 3871556Srgrimes shellparam.optptr = p; 3881556Srgrimes s[0] = c; 3891556Srgrimes s[1] = '\0'; 3901556Srgrimes setvar(argv[2], s, 0); 3911556Srgrimes return 0; 3921556Srgrimes} 3931556Srgrimes 3941556Srgrimes/* 3951556Srgrimes * XXX - should get rid of. have all builtins use getopt(3). the 3961556Srgrimes * library getopt must have the BSD extension static variable "optreset" 3971556Srgrimes * otherwise it can't be used within the shell safely. 3981556Srgrimes * 3991556Srgrimes * Standard option processing (a la getopt) for builtin routines. The 4001556Srgrimes * only argument that is passed to nextopt is the option string; the 4011556Srgrimes * other arguments are unnecessary. It return the character, or '\0' on 4021556Srgrimes * end of input. 4031556Srgrimes */ 4041556Srgrimes 4051556Srgrimesint 4061556Srgrimesnextopt(optstring) 4071556Srgrimes char *optstring; 4081556Srgrimes { 4091556Srgrimes register char *p, *q; 4101556Srgrimes char c; 4111556Srgrimes 4121556Srgrimes if ((p = optptr) == NULL || *p == '\0') { 4131556Srgrimes p = *argptr; 4141556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 4151556Srgrimes return '\0'; 4161556Srgrimes argptr++; 4171556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4181556Srgrimes return '\0'; 4191556Srgrimes } 4201556Srgrimes c = *p++; 4211556Srgrimes for (q = optstring ; *q != c ; ) { 4221556Srgrimes if (*q == '\0') 4231556Srgrimes error("Illegal option -%c", c); 4241556Srgrimes if (*++q == ':') 4251556Srgrimes q++; 4261556Srgrimes } 4271556Srgrimes if (*++q == ':') { 4281556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 4291556Srgrimes error("No arg for -%c option", c); 4301556Srgrimes optarg = p; 4311556Srgrimes p = NULL; 4321556Srgrimes } 4331556Srgrimes optptr = p; 4341556Srgrimes return c; 4351556Srgrimes} 436