options.c revision 11111
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 * 3611111Sjoerg * $Id: options.c,v 1.4 1995/08/06 19:35:33 joerg 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 } 10911111Sjoerg if (minusc) 11011111Sjoerg /* Posix.2: first arg after -c cmd is $0, remainder $1... */ 11111111Sjoerg arg0 = *argptr++; 1121556Srgrimes shellparam.p = argptr; 1131556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1141556Srgrimes while (*argptr) { 1151556Srgrimes shellparam.nparam++; 1161556Srgrimes argptr++; 1171556Srgrimes } 1181556Srgrimes optschanged(); 1191556Srgrimes} 1201556Srgrimes 1211556Srgrimes 1221556Srgrimesoptschanged() { 1231556Srgrimes setinteractive(iflag); 1241556Srgrimes histedit(); 1251556Srgrimes setjobctl(mflag); 1261556Srgrimes} 1271556Srgrimes 1281556Srgrimes/* 1291556Srgrimes * Process shell options. The global variable argptr contains a pointer 1301556Srgrimes * to the argument list; we advance it past the options. 1311556Srgrimes */ 1321556Srgrimes 1331556SrgrimesSTATIC void 1341556Srgrimesoptions(cmdline) { 1351556Srgrimes register char *p; 1361556Srgrimes int val; 1371556Srgrimes int c; 1381556Srgrimes 1391556Srgrimes if (cmdline) 1401556Srgrimes minusc = NULL; 1411556Srgrimes while ((p = *argptr) != NULL) { 1421556Srgrimes argptr++; 1431556Srgrimes if ((c = *p++) == '-') { 1441556Srgrimes val = 1; 1451556Srgrimes if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') { 1461556Srgrimes if (!cmdline) { 1471556Srgrimes /* "-" means turn off -x and -v */ 1481556Srgrimes if (p[0] == '\0') 1491556Srgrimes xflag = vflag = 0; 1501556Srgrimes /* "--" means reset params */ 1511556Srgrimes else if (*argptr == NULL) 1521556Srgrimes setparam(argptr); 1531556Srgrimes } 1541556Srgrimes break; /* "-" or "--" terminates options */ 1551556Srgrimes } 1561556Srgrimes } else if (c == '+') { 1571556Srgrimes val = 0; 1581556Srgrimes } else { 1591556Srgrimes argptr--; 1601556Srgrimes break; 1611556Srgrimes } 1621556Srgrimes while ((c = *p++) != '\0') { 1631556Srgrimes if (c == 'c' && cmdline) { 1641556Srgrimes char *q; 1651556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1661556Srgrimes if (*p == '\0') 1671556Srgrimes#endif 1681556Srgrimes q = *argptr++; 1691556Srgrimes if (q == NULL || minusc != NULL) 1701556Srgrimes error("Bad -c option"); 1711556Srgrimes minusc = q; 1721556Srgrimes#ifdef NOHACK 1731556Srgrimes break; 1741556Srgrimes#endif 1751556Srgrimes } else if (c == 'o') { 1761556Srgrimes minus_o(*argptr, val); 1771556Srgrimes if (*argptr) 1781556Srgrimes argptr++; 1791556Srgrimes } else { 1801556Srgrimes setoption(c, val); 1811556Srgrimes } 1821556Srgrimes } 1831556Srgrimes } 1841556Srgrimes} 1851556Srgrimes 1861556SrgrimesSTATIC void 1871556Srgrimesminus_o(name, val) 1881556Srgrimes char *name; 1891556Srgrimes int val; 1901556Srgrimes{ 1911556Srgrimes int i; 1921556Srgrimes 1931556Srgrimes if (name == NULL) { 1941556Srgrimes out1str("Current option settings\n"); 1951556Srgrimes for (i = 0; i < NOPTS; i++) 1961556Srgrimes out1fmt("%-16s%s\n", optlist[i].name, 1971556Srgrimes optlist[i].val ? "on" : "off"); 1981556Srgrimes } else { 1991556Srgrimes for (i = 0; i < NOPTS; i++) 2001556Srgrimes if (equal(name, optlist[i].name)) { 2011556Srgrimes setoption(optlist[i].letter, val); 2021556Srgrimes return; 2031556Srgrimes } 2041556Srgrimes error("Illegal option -o %s", name); 2051556Srgrimes } 2061556Srgrimes} 2071556Srgrimes 2088855Srgrimes 2091556SrgrimesSTATIC void 2101556Srgrimessetoption(flag, val) 2111556Srgrimes char flag; 2121556Srgrimes int val; 2131556Srgrimes { 2141556Srgrimes int i; 2151556Srgrimes 2161556Srgrimes for (i = 0; i < NOPTS; i++) 2171556Srgrimes if (optlist[i].letter == flag) { 2181556Srgrimes optlist[i].val = val; 2191556Srgrimes if (val) { 2201556Srgrimes /* #%$ hack for ksh semantics */ 2211556Srgrimes if (flag == 'V') 2221556Srgrimes Eflag = 0; 2231556Srgrimes else if (flag == 'E') 2241556Srgrimes Vflag = 0; 2251556Srgrimes } 2261556Srgrimes return; 2271556Srgrimes } 2281556Srgrimes error("Illegal option -%c", flag); 2291556Srgrimes} 2301556Srgrimes 2311556Srgrimes 2321556Srgrimes 2331556Srgrimes#ifdef mkinit 2341556SrgrimesINCLUDE "options.h" 2351556Srgrimes 2361556SrgrimesSHELLPROC { 2371556Srgrimes int i; 2381556Srgrimes 2391556Srgrimes for (i = 0; i < NOPTS; i++) 2401556Srgrimes optlist[i].val = 0; 2411556Srgrimes optschanged(); 2421556Srgrimes 2431556Srgrimes} 2441556Srgrimes#endif 2451556Srgrimes 2461556Srgrimes 2471556Srgrimes/* 2481556Srgrimes * Set the shell parameters. 2491556Srgrimes */ 2501556Srgrimes 2511556Srgrimesvoid 2521556Srgrimessetparam(argv) 2531556Srgrimes char **argv; 2541556Srgrimes { 2551556Srgrimes char **newparam; 2561556Srgrimes char **ap; 2571556Srgrimes int nparam; 2581556Srgrimes 2591556Srgrimes for (nparam = 0 ; argv[nparam] ; nparam++); 2601556Srgrimes ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 2611556Srgrimes while (*argv) { 2621556Srgrimes *ap++ = savestr(*argv++); 2631556Srgrimes } 2641556Srgrimes *ap = NULL; 2651556Srgrimes freeparam(&shellparam); 2661556Srgrimes shellparam.malloc = 1; 2671556Srgrimes shellparam.nparam = nparam; 2681556Srgrimes shellparam.p = newparam; 2691556Srgrimes shellparam.optnext = NULL; 2701556Srgrimes} 2711556Srgrimes 2721556Srgrimes 2731556Srgrimes/* 2741556Srgrimes * Free the list of positional parameters. 2751556Srgrimes */ 2761556Srgrimes 2771556Srgrimesvoid 2781556Srgrimesfreeparam(param) 2791556Srgrimes struct shparam *param; 2801556Srgrimes { 2811556Srgrimes char **ap; 2821556Srgrimes 2831556Srgrimes if (param->malloc) { 2841556Srgrimes for (ap = param->p ; *ap ; ap++) 2851556Srgrimes ckfree(*ap); 2861556Srgrimes ckfree(param->p); 2871556Srgrimes } 2881556Srgrimes} 2891556Srgrimes 2901556Srgrimes 2911556Srgrimes 2921556Srgrimes/* 2931556Srgrimes * The shift builtin command. 2941556Srgrimes */ 2951556Srgrimes 2961556Srgrimesshiftcmd(argc, argv) char **argv; { 2971556Srgrimes int n; 2981556Srgrimes char **ap1, **ap2; 2991556Srgrimes 3001556Srgrimes n = 1; 3011556Srgrimes if (argc > 1) 3021556Srgrimes n = number(argv[1]); 3031556Srgrimes if (n > shellparam.nparam) 3041556Srgrimes error("can't shift that many"); 3051556Srgrimes INTOFF; 3061556Srgrimes shellparam.nparam -= n; 3071556Srgrimes for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 3081556Srgrimes if (shellparam.malloc) 3091556Srgrimes ckfree(*ap1); 3101556Srgrimes } 3111556Srgrimes ap2 = shellparam.p; 3121556Srgrimes while ((*ap2++ = *ap1++) != NULL); 3131556Srgrimes shellparam.optnext = NULL; 3141556Srgrimes INTON; 3151556Srgrimes return 0; 3161556Srgrimes} 3171556Srgrimes 3181556Srgrimes 3191556Srgrimes 3201556Srgrimes/* 3211556Srgrimes * The set command builtin. 3221556Srgrimes */ 3231556Srgrimes 3241556Srgrimessetcmd(argc, argv) char **argv; { 3251556Srgrimes if (argc == 1) 3261556Srgrimes return showvarscmd(argc, argv); 3271556Srgrimes INTOFF; 3281556Srgrimes options(0); 3291556Srgrimes optschanged(); 3301556Srgrimes if (*argptr != NULL) { 3311556Srgrimes setparam(argptr); 3321556Srgrimes } 3331556Srgrimes INTON; 3341556Srgrimes return 0; 3351556Srgrimes} 3361556Srgrimes 3371556Srgrimes 3381556Srgrimes/* 3391556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 3401556Srgrimes * to be processed. Shellparam.optptr points to the next character to 3411556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 3421556Srgrimes * then it's the first time getopts has been called. 3431556Srgrimes */ 3441556Srgrimes 3451556Srgrimesgetoptscmd(argc, argv) char **argv; { 3461556Srgrimes register char *p, *q; 3471556Srgrimes char c; 3481556Srgrimes char s[10]; 3491556Srgrimes 3501556Srgrimes if (argc != 3) 3511556Srgrimes error("Usage: getopts optstring var"); 3521556Srgrimes if (shellparam.optnext == NULL) { 3531556Srgrimes shellparam.optnext = shellparam.p; 3541556Srgrimes shellparam.optptr = NULL; 3551556Srgrimes } 3561556Srgrimes if ((p = shellparam.optptr) == NULL || *p == '\0') { 3571556Srgrimes p = *shellparam.optnext; 3581556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 3591556Srgrimesatend: 3601556Srgrimes fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 3611556Srgrimes setvar("OPTIND", s, 0); 3621556Srgrimes shellparam.optnext = NULL; 3631556Srgrimes return 1; 3641556Srgrimes } 3651556Srgrimes shellparam.optnext++; 3661556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 3671556Srgrimes goto atend; 3681556Srgrimes } 3691556Srgrimes c = *p++; 3701556Srgrimes for (q = argv[1] ; *q != c ; ) { 3711556Srgrimes if (*q == '\0') { 3721556Srgrimes out1fmt("Illegal option -%c\n", c); 3731556Srgrimes c = '?'; 3741556Srgrimes goto out; 3751556Srgrimes } 3761556Srgrimes if (*++q == ':') 3771556Srgrimes q++; 3781556Srgrimes } 3791556Srgrimes if (*++q == ':') { 3809974Sjoerg if (*p == '\0' && (p = *shellparam.optnext++) == NULL) { 3811556Srgrimes out1fmt("No arg for -%c option\n", c); 3821556Srgrimes c = '?'; 3831556Srgrimes goto out; 3841556Srgrimes } 3851556Srgrimes setvar("OPTARG", p, 0); 3861556Srgrimes p = NULL; 3871556Srgrimes } 3881556Srgrimesout: 3891556Srgrimes shellparam.optptr = p; 3901556Srgrimes s[0] = c; 3911556Srgrimes s[1] = '\0'; 3921556Srgrimes setvar(argv[2], s, 0); 3931556Srgrimes return 0; 3941556Srgrimes} 3951556Srgrimes 3961556Srgrimes/* 3971556Srgrimes * XXX - should get rid of. have all builtins use getopt(3). the 3981556Srgrimes * library getopt must have the BSD extension static variable "optreset" 3991556Srgrimes * otherwise it can't be used within the shell safely. 4001556Srgrimes * 4011556Srgrimes * Standard option processing (a la getopt) for builtin routines. The 4021556Srgrimes * only argument that is passed to nextopt is the option string; the 4031556Srgrimes * other arguments are unnecessary. It return the character, or '\0' on 4041556Srgrimes * end of input. 4051556Srgrimes */ 4061556Srgrimes 4071556Srgrimesint 4081556Srgrimesnextopt(optstring) 4091556Srgrimes char *optstring; 4101556Srgrimes { 4111556Srgrimes register char *p, *q; 4121556Srgrimes char c; 4131556Srgrimes 4141556Srgrimes if ((p = optptr) == NULL || *p == '\0') { 4151556Srgrimes p = *argptr; 4161556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 4171556Srgrimes return '\0'; 4181556Srgrimes argptr++; 4191556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4201556Srgrimes return '\0'; 4211556Srgrimes } 4221556Srgrimes c = *p++; 4231556Srgrimes for (q = optstring ; *q != c ; ) { 4241556Srgrimes if (*q == '\0') 4251556Srgrimes error("Illegal option -%c", c); 4261556Srgrimes if (*++q == ':') 4271556Srgrimes q++; 4281556Srgrimes } 4291556Srgrimes if (*++q == ':') { 4301556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 4311556Srgrimes error("No arg for -%c option", c); 4321556Srgrimes optarg = p; 4331556Srgrimes p = NULL; 4341556Srgrimes } 4351556Srgrimes optptr = p; 4361556Srgrimes return c; 4371556Srgrimes} 438