options.c revision 17987
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 * 3617987Speter * $Id: options.c,v 1.6 1995/10/09 17:56:32 joerg Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 4017987Speterstatic char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; 411556Srgrimes#endif /* not lint */ 421556Srgrimes 4317987Speter#include <signal.h> 4417987Speter#include <unistd.h> 4517987Speter#include <stdlib.h> 4617987Speter 471556Srgrimes#include "shell.h" 481556Srgrimes#define DEFINE_OPTIONS 491556Srgrimes#include "options.h" 501556Srgrimes#undef DEFINE_OPTIONS 511556Srgrimes#include "nodes.h" /* for other header files */ 521556Srgrimes#include "eval.h" 531556Srgrimes#include "jobs.h" 541556Srgrimes#include "input.h" 551556Srgrimes#include "output.h" 561556Srgrimes#include "trap.h" 571556Srgrimes#include "var.h" 581556Srgrimes#include "memalloc.h" 591556Srgrimes#include "error.h" 601556Srgrimes#include "mystring.h" 6117987Speter#ifndef NO_HISTORY 6217987Speter#include "myhistedit.h" 6317987Speter#endif 641556Srgrimes 651556Srgrimeschar *arg0; /* value of $0 */ 661556Srgrimesstruct shparam shellparam; /* current positional parameters */ 671556Srgrimeschar **argptr; /* argument list for builtin commands */ 681556Srgrimeschar *optarg; /* set by nextopt (like getopt) */ 691556Srgrimeschar *optptr; /* used by nextopt */ 701556Srgrimes 711556Srgrimeschar *minusc; /* argument to -c option */ 721556Srgrimes 731556Srgrimes 7417987SpeterSTATIC void options __P((int)); 7517987SpeterSTATIC void minus_o __P((char *, int)); 7617987SpeterSTATIC void setoption __P((int, int)); 771556Srgrimes 781556Srgrimes 791556Srgrimes/* 801556Srgrimes * Process the shell command line arguments. 811556Srgrimes */ 821556Srgrimes 831556Srgrimesvoid 841556Srgrimesprocargs(argc, argv) 8517987Speter int argc; 861556Srgrimes char **argv; 8717987Speter{ 881556Srgrimes int i; 891556Srgrimes 901556Srgrimes argptr = argv; 911556Srgrimes if (argc > 0) 921556Srgrimes argptr++; 931556Srgrimes for (i = 0; i < NOPTS; i++) 941556Srgrimes optlist[i].val = 2; 951556Srgrimes options(1); 961556Srgrimes if (*argptr == NULL && minusc == NULL) 971556Srgrimes sflag = 1; 981556Srgrimes if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 991556Srgrimes iflag = 1; 1001556Srgrimes if (mflag == 2) 1011556Srgrimes mflag = iflag; 1021556Srgrimes for (i = 0; i < NOPTS; i++) 1031556Srgrimes if (optlist[i].val == 2) 1041556Srgrimes optlist[i].val = 0; 1051556Srgrimes arg0 = argv[0]; 1061556Srgrimes if (sflag == 0 && minusc == NULL) { 1071556Srgrimes commandname = arg0 = *argptr++; 1081556Srgrimes setinputfile(commandname, 0); 1091556Srgrimes } 11011377Sjoerg if (*argptr && minusc) 11111111Sjoerg /* Posix.2: first arg after -c cmd is $0, remainder $1... */ 11211111Sjoerg arg0 = *argptr++; 1131556Srgrimes shellparam.p = argptr; 1141556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1151556Srgrimes while (*argptr) { 1161556Srgrimes shellparam.nparam++; 1171556Srgrimes argptr++; 1181556Srgrimes } 1191556Srgrimes optschanged(); 1201556Srgrimes} 1211556Srgrimes 1221556Srgrimes 12317987Spetervoid 12417987Speteroptschanged() 12517987Speter{ 1261556Srgrimes setinteractive(iflag); 12717987Speter#ifndef NO_HISTORY 1281556Srgrimes histedit(); 12917987Speter#endif 1301556Srgrimes setjobctl(mflag); 1311556Srgrimes} 1321556Srgrimes 1331556Srgrimes/* 1341556Srgrimes * Process shell options. The global variable argptr contains a pointer 1351556Srgrimes * to the argument list; we advance it past the options. 1361556Srgrimes */ 1371556Srgrimes 1381556SrgrimesSTATIC void 13917987Speteroptions(cmdline) 14017987Speter int cmdline; 14117987Speter{ 1421556Srgrimes register char *p; 1431556Srgrimes int val; 1441556Srgrimes int c; 1451556Srgrimes 1461556Srgrimes if (cmdline) 1471556Srgrimes minusc = NULL; 1481556Srgrimes while ((p = *argptr) != NULL) { 1491556Srgrimes argptr++; 1501556Srgrimes if ((c = *p++) == '-') { 1511556Srgrimes val = 1; 15217987Speter if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { 1531556Srgrimes if (!cmdline) { 1541556Srgrimes /* "-" means turn off -x and -v */ 1551556Srgrimes if (p[0] == '\0') 1561556Srgrimes xflag = vflag = 0; 1571556Srgrimes /* "--" means reset params */ 1581556Srgrimes else if (*argptr == NULL) 15917987Speter setparam(argptr); 1601556Srgrimes } 1611556Srgrimes break; /* "-" or "--" terminates options */ 1621556Srgrimes } 1631556Srgrimes } else if (c == '+') { 1641556Srgrimes val = 0; 1651556Srgrimes } else { 1661556Srgrimes argptr--; 1671556Srgrimes break; 1681556Srgrimes } 1691556Srgrimes while ((c = *p++) != '\0') { 1701556Srgrimes if (c == 'c' && cmdline) { 1711556Srgrimes char *q; 1721556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1731556Srgrimes if (*p == '\0') 1741556Srgrimes#endif 1751556Srgrimes q = *argptr++; 1761556Srgrimes if (q == NULL || minusc != NULL) 1771556Srgrimes error("Bad -c option"); 1781556Srgrimes minusc = q; 1791556Srgrimes#ifdef NOHACK 1801556Srgrimes break; 1811556Srgrimes#endif 1821556Srgrimes } else if (c == 'o') { 1831556Srgrimes minus_o(*argptr, val); 1841556Srgrimes if (*argptr) 1851556Srgrimes argptr++; 1861556Srgrimes } else { 1871556Srgrimes setoption(c, val); 1881556Srgrimes } 1891556Srgrimes } 1901556Srgrimes } 1911556Srgrimes} 1921556Srgrimes 1931556SrgrimesSTATIC void 1941556Srgrimesminus_o(name, val) 1951556Srgrimes char *name; 1961556Srgrimes int val; 1971556Srgrimes{ 1981556Srgrimes int i; 1991556Srgrimes 2001556Srgrimes if (name == NULL) { 2011556Srgrimes out1str("Current option settings\n"); 2021556Srgrimes for (i = 0; i < NOPTS; i++) 2031556Srgrimes out1fmt("%-16s%s\n", optlist[i].name, 2041556Srgrimes optlist[i].val ? "on" : "off"); 2051556Srgrimes } else { 2061556Srgrimes for (i = 0; i < NOPTS; i++) 2071556Srgrimes if (equal(name, optlist[i].name)) { 2081556Srgrimes setoption(optlist[i].letter, val); 2091556Srgrimes return; 2101556Srgrimes } 2111556Srgrimes error("Illegal option -o %s", name); 2121556Srgrimes } 2131556Srgrimes} 2141556Srgrimes 2158855Srgrimes 2161556SrgrimesSTATIC void 2171556Srgrimessetoption(flag, val) 2181556Srgrimes char flag; 2191556Srgrimes int val; 2201556Srgrimes { 2211556Srgrimes int i; 2221556Srgrimes 2231556Srgrimes for (i = 0; i < NOPTS; i++) 2241556Srgrimes if (optlist[i].letter == flag) { 2251556Srgrimes optlist[i].val = val; 2261556Srgrimes if (val) { 2271556Srgrimes /* #%$ hack for ksh semantics */ 2281556Srgrimes if (flag == 'V') 2291556Srgrimes Eflag = 0; 2301556Srgrimes else if (flag == 'E') 2311556Srgrimes Vflag = 0; 2321556Srgrimes } 2331556Srgrimes return; 2341556Srgrimes } 2351556Srgrimes error("Illegal option -%c", flag); 2361556Srgrimes} 2371556Srgrimes 2381556Srgrimes 2391556Srgrimes 2401556Srgrimes#ifdef mkinit 2411556SrgrimesINCLUDE "options.h" 2421556Srgrimes 2431556SrgrimesSHELLPROC { 2441556Srgrimes int i; 2451556Srgrimes 2461556Srgrimes for (i = 0; i < NOPTS; i++) 2471556Srgrimes optlist[i].val = 0; 2481556Srgrimes optschanged(); 2491556Srgrimes 2501556Srgrimes} 2511556Srgrimes#endif 2521556Srgrimes 2531556Srgrimes 2541556Srgrimes/* 2551556Srgrimes * Set the shell parameters. 2561556Srgrimes */ 2571556Srgrimes 2581556Srgrimesvoid 2591556Srgrimessetparam(argv) 2601556Srgrimes char **argv; 2611556Srgrimes { 2621556Srgrimes char **newparam; 2631556Srgrimes char **ap; 2641556Srgrimes int nparam; 2651556Srgrimes 2661556Srgrimes for (nparam = 0 ; argv[nparam] ; nparam++); 2671556Srgrimes ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 2681556Srgrimes while (*argv) { 2691556Srgrimes *ap++ = savestr(*argv++); 2701556Srgrimes } 2711556Srgrimes *ap = NULL; 2721556Srgrimes freeparam(&shellparam); 2731556Srgrimes shellparam.malloc = 1; 2741556Srgrimes shellparam.nparam = nparam; 2751556Srgrimes shellparam.p = newparam; 2761556Srgrimes shellparam.optnext = NULL; 2771556Srgrimes} 2781556Srgrimes 2791556Srgrimes 2801556Srgrimes/* 2811556Srgrimes * Free the list of positional parameters. 2821556Srgrimes */ 2831556Srgrimes 2841556Srgrimesvoid 2851556Srgrimesfreeparam(param) 2861556Srgrimes struct shparam *param; 2871556Srgrimes { 2881556Srgrimes char **ap; 2891556Srgrimes 2901556Srgrimes if (param->malloc) { 2911556Srgrimes for (ap = param->p ; *ap ; ap++) 2921556Srgrimes ckfree(*ap); 2931556Srgrimes ckfree(param->p); 2941556Srgrimes } 2951556Srgrimes} 2961556Srgrimes 2971556Srgrimes 2981556Srgrimes 2991556Srgrimes/* 3001556Srgrimes * The shift builtin command. 3011556Srgrimes */ 3021556Srgrimes 30317987Speterint 30417987Spetershiftcmd(argc, argv) 30517987Speter int argc; 30617987Speter char **argv; 30717987Speter{ 3081556Srgrimes int n; 3091556Srgrimes char **ap1, **ap2; 3101556Srgrimes 3111556Srgrimes n = 1; 3121556Srgrimes if (argc > 1) 3131556Srgrimes n = number(argv[1]); 3141556Srgrimes if (n > shellparam.nparam) 3151556Srgrimes error("can't shift that many"); 3161556Srgrimes INTOFF; 3171556Srgrimes shellparam.nparam -= n; 3181556Srgrimes for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 3191556Srgrimes if (shellparam.malloc) 3201556Srgrimes ckfree(*ap1); 3211556Srgrimes } 3221556Srgrimes ap2 = shellparam.p; 3231556Srgrimes while ((*ap2++ = *ap1++) != NULL); 3241556Srgrimes shellparam.optnext = NULL; 3251556Srgrimes INTON; 3261556Srgrimes return 0; 3271556Srgrimes} 3281556Srgrimes 3291556Srgrimes 3301556Srgrimes 3311556Srgrimes/* 3321556Srgrimes * The set command builtin. 3331556Srgrimes */ 3341556Srgrimes 33517987Speterint 33617987Spetersetcmd(argc, argv) 33717987Speter int argc; 33817987Speter char **argv; 33917987Speter{ 3401556Srgrimes if (argc == 1) 3411556Srgrimes return showvarscmd(argc, argv); 3421556Srgrimes INTOFF; 3431556Srgrimes options(0); 3441556Srgrimes optschanged(); 3451556Srgrimes if (*argptr != NULL) { 3461556Srgrimes setparam(argptr); 3471556Srgrimes } 3481556Srgrimes INTON; 3491556Srgrimes return 0; 3501556Srgrimes} 3511556Srgrimes 3521556Srgrimes 3531556Srgrimes/* 3541556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 3551556Srgrimes * to be processed. Shellparam.optptr points to the next character to 3561556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 3571556Srgrimes * then it's the first time getopts has been called. 3581556Srgrimes */ 3591556Srgrimes 36017987Speterint 36117987Spetergetoptscmd(argc, argv) 36217987Speter int argc; 36317987Speter char **argv; 36417987Speter{ 3651556Srgrimes register char *p, *q; 3661556Srgrimes char c; 3671556Srgrimes char s[10]; 3681556Srgrimes 3691556Srgrimes if (argc != 3) 3701556Srgrimes error("Usage: getopts optstring var"); 3711556Srgrimes if (shellparam.optnext == NULL) { 3721556Srgrimes shellparam.optnext = shellparam.p; 3731556Srgrimes shellparam.optptr = NULL; 3741556Srgrimes } 3751556Srgrimes if ((p = shellparam.optptr) == NULL || *p == '\0') { 3761556Srgrimes p = *shellparam.optnext; 3771556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 3781556Srgrimesatend: 3791556Srgrimes fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 3801556Srgrimes setvar("OPTIND", s, 0); 3811556Srgrimes shellparam.optnext = NULL; 3821556Srgrimes return 1; 3831556Srgrimes } 3841556Srgrimes shellparam.optnext++; 3851556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 3861556Srgrimes goto atend; 3871556Srgrimes } 3881556Srgrimes c = *p++; 3891556Srgrimes for (q = argv[1] ; *q != c ; ) { 3901556Srgrimes if (*q == '\0') { 3911556Srgrimes out1fmt("Illegal option -%c\n", c); 3921556Srgrimes c = '?'; 3931556Srgrimes goto out; 3941556Srgrimes } 3951556Srgrimes if (*++q == ':') 3961556Srgrimes q++; 3971556Srgrimes } 3981556Srgrimes if (*++q == ':') { 3999974Sjoerg if (*p == '\0' && (p = *shellparam.optnext++) == NULL) { 4001556Srgrimes out1fmt("No arg for -%c option\n", c); 4011556Srgrimes c = '?'; 4021556Srgrimes goto out; 4031556Srgrimes } 4041556Srgrimes setvar("OPTARG", p, 0); 4051556Srgrimes p = NULL; 4061556Srgrimes } 4071556Srgrimesout: 4081556Srgrimes shellparam.optptr = p; 4091556Srgrimes s[0] = c; 4101556Srgrimes s[1] = '\0'; 4111556Srgrimes setvar(argv[2], s, 0); 4121556Srgrimes return 0; 4131556Srgrimes} 4141556Srgrimes 4151556Srgrimes/* 4161556Srgrimes * XXX - should get rid of. have all builtins use getopt(3). the 4171556Srgrimes * library getopt must have the BSD extension static variable "optreset" 4181556Srgrimes * otherwise it can't be used within the shell safely. 4191556Srgrimes * 4201556Srgrimes * Standard option processing (a la getopt) for builtin routines. The 4211556Srgrimes * only argument that is passed to nextopt is the option string; the 4221556Srgrimes * other arguments are unnecessary. It return the character, or '\0' on 4231556Srgrimes * end of input. 4241556Srgrimes */ 4251556Srgrimes 4261556Srgrimesint 4271556Srgrimesnextopt(optstring) 4281556Srgrimes char *optstring; 4291556Srgrimes { 4301556Srgrimes register char *p, *q; 4311556Srgrimes char c; 4321556Srgrimes 4331556Srgrimes if ((p = optptr) == NULL || *p == '\0') { 4341556Srgrimes p = *argptr; 4351556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 4361556Srgrimes return '\0'; 4371556Srgrimes argptr++; 4381556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4391556Srgrimes return '\0'; 4401556Srgrimes } 4411556Srgrimes c = *p++; 4421556Srgrimes for (q = optstring ; *q != c ; ) { 4431556Srgrimes if (*q == '\0') 4441556Srgrimes error("Illegal option -%c", c); 4451556Srgrimes if (*++q == ':') 4461556Srgrimes q++; 4471556Srgrimes } 4481556Srgrimes if (*++q == ':') { 4491556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 4501556Srgrimes error("No arg for -%c option", c); 4511556Srgrimes optarg = p; 4521556Srgrimes p = NULL; 4531556Srgrimes } 4541556Srgrimes optptr = p; 4551556Srgrimes return c; 4561556Srgrimes} 457