Subversion Repositories HelenOS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2714 cejka 1
/*  $NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $    */
2
 
3
/*-
4
 * Copyright (c) 1991, 1993
5
 *  The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Kenneth Almquist.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. All advertising materials mentioning features or use of this software
19
 *    must display the following acknowledgement:
20
 *  This product includes software developed by the University of
21
 *  California, Berkeley and its contributors.
22
 * 4. Neither the name of the University nor the names of its contributors
23
 *    may be used to endorse or promote products derived from this software
24
 *    without specific prior written permission.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
 * SUCH DAMAGE.
37
 */
38
 
39
#include <sys/cdefs.h>
40
#ifndef lint
41
#if 0
42
static char sccsid[] = "@(#)options.c   8.2 (Berkeley) 5/4/95";
43
#else
44
__RCSID("$NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $");
45
#endif
46
#endif /* not lint */
47
 
48
#include <signal.h>
49
#include <unistd.h>
50
#include <stdlib.h>
51
 
52
#include "shell.h"
53
#define DEFINE_OPTIONS
54
#include "options.h"
55
#undef DEFINE_OPTIONS
56
#include "nodes.h"  /* for other header files */
57
#include "eval.h"
58
#include "jobs.h"
59
#include "input.h"
60
#include "output.h"
61
#include "trap.h"
62
#include "var.h"
63
#include "memalloc.h"
64
#include "error.h"
65
#include "mystring.h"
66
#ifndef SMALL
67
#include "myhistedit.h"
68
#endif
69
 
70
char *arg0;         /* value of $0 */
71
struct shparam shellparam;  /* current positional parameters */
72
char **argptr;          /* argument list for builtin commands */
73
char *optarg;           /* set by nextopt (like getopt) */
74
char *optptr;           /* used by nextopt */
75
 
76
char *minusc;           /* argument to -c option */
77
 
78
 
79
STATIC void options (int);
80
STATIC void minus_o (char *, int);
81
STATIC void setoption (int, int);
82
STATIC int getopts (char *, char *, char **, int *, int *);
83
 
84
 
85
/*
86
 * Process the shell command line arguments.
87
 */
88
 
89
void
90
procargs(argc, argv)
91
    int argc;
92
    char **argv;
93
{
94
    int i;
95
 
96
    argptr = argv;
97
    if (argc > 0)
98
        argptr++;
99
    for (i = 0; i < NOPTS; i++)
100
        optlist[i].val = 2;
101
    options(1);
102
    if (*argptr == NULL && minusc == NULL)
103
        sflag = 1;
104
    if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
105
        iflag = 1;
106
    if (mflag == 2)
107
        mflag = iflag;
108
    for (i = 0; i < NOPTS; i++)
109
        if (optlist[i].val == 2)
110
            optlist[i].val = 0;
111
    arg0 = argv[0];
112
    if (sflag == 0 && minusc == NULL) {
113
        commandname = arg0 = *argptr++;
114
        setinputfile(commandname, 0);
115
    }
116
    /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
117
    if (argptr && minusc && *argptr)
118
            arg0 = *argptr++;
119
 
120
    shellparam.p = argptr;
121
    shellparam.optind = 1;
122
    shellparam.optoff = -1;
123
    /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
124
    while (*argptr) {
125
        shellparam.nparam++;
126
        argptr++;
127
    }
128
    optschanged();
129
}
130
 
131
 
132
void
133
optschanged()
134
{
135
    setinteractive(iflag);
136
#ifndef SMALL
137
    histedit();
138
#endif
139
    setjobctl(mflag);
140
}
141
 
142
/*
143
 * Process shell options.  The global variable argptr contains a pointer
144
 * to the argument list; we advance it past the options.
145
 */
146
 
147
STATIC void
148
options(cmdline)
149
    int cmdline;
150
{
151
    char *p;
152
    int val;
153
    int c;
154
 
155
    if (cmdline)
156
        minusc = NULL;
157
    while ((p = *argptr) != NULL) {
158
        argptr++;
159
        if ((c = *p++) == '-') {
160
            val = 1;
161
                        if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
162
                                if (!cmdline) {
163
                                        /* "-" means turn off -x and -v */
164
                                        if (p[0] == '\0')
165
                                                xflag = vflag = 0;
166
                                        /* "--" means reset params */
167
                                        else if (*argptr == NULL)
168
                        setparam(argptr);
169
                                }
170
                break;    /* "-" or  "--" terminates options */
171
            }
172
        } else if (c == '+') {
173
            val = 0;
174
        } else {
175
            argptr--;
176
            break;
177
        }
178
        while ((c = *p++) != '\0') {
179
            if (c == 'c' && cmdline) {
180
                char *q;
181
#ifdef NOHACK   /* removing this code allows sh -ce 'foo' for compat */
182
                if (*p == '\0')
183
#endif
184
                    q = *argptr++;
185
                if (q == NULL || minusc != NULL)
186
                    error("Bad -c option");
187
                minusc = q;
188
#ifdef NOHACK
189
                break;
190
#endif
191
            } else if (c == 'o') {
192
                minus_o(*argptr, val);
193
                if (*argptr)
194
                    argptr++;
195
            } else {
196
                setoption(c, val);
197
            }
198
        }
199
    }
200
}
201
 
202
STATIC void
203
minus_o(name, val)
204
    char *name;
205
    int val;
206
{
207
    int i;
208
 
209
    if (name == NULL) {
210
        out1str("Current option settings\n");
211
        for (i = 0; i < NOPTS; i++)
212
            out1fmt("%-16s%s\n", optlist[i].name,
213
                optlist[i].val ? "on" : "off");
214
    } else {
215
        for (i = 0; i < NOPTS; i++)
216
            if (equal(name, optlist[i].name)) {
217
                setoption(optlist[i].letter, val);
218
                return;
219
            }
220
        error("Illegal option -o %s", name);
221
    }
222
}
223
 
224
 
225
STATIC void
226
setoption(flag, val)
227
    char flag;
228
    int val;
229
    {
230
    int i;
231
 
232
    for (i = 0; i < NOPTS; i++)
233
        if (optlist[i].letter == flag) {
234
            optlist[i].val = val;
235
            if (val) {
236
                /* #%$ hack for ksh semantics */
237
                if (flag == 'V')
238
                    Eflag = 0;
239
                else if (flag == 'E')
240
                    Vflag = 0;
241
            }
242
            return;
243
        }
244
    error("Illegal option -%c", flag);
245
    /* NOTREACHED */
246
}
247
 
248
 
249
 
250
#ifdef mkinit
251
INCLUDE "options.h"
252
 
253
SHELLPROC {
254
    int i;
255
 
256
    for (i = 0; i < NOPTS; i++)
257
        optlist[i].val = 0;
258
    optschanged();
259
 
260
}
261
#endif
262
 
263
 
264
/*
265
 * Set the shell parameters.
266
 */
267
 
268
void
269
setparam(argv)
270
    char **argv;
271
    {
272
    char **newparam;
273
    char **ap;
274
    int nparam;
275
 
276
    for (nparam = 0 ; argv[nparam] ; nparam++);
277
    ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
278
    while (*argv) {
279
        *ap++ = savestr(*argv++);
280
    }
281
    *ap = NULL;
282
    freeparam(&shellparam);
283
    shellparam.malloc = 1;
284
    shellparam.nparam = nparam;
285
    shellparam.p = newparam;
286
    shellparam.optind = 1;
287
    shellparam.optoff = -1;
288
}
289
 
290
 
291
/*
292
 * Free the list of positional parameters.
293
 */
294
 
295
void
296
freeparam(param)
297
    volatile struct shparam *param;
298
    {
299
    char **ap;
300
 
301
    if (param->malloc) {
302
        for (ap = param->p ; *ap ; ap++)
303
            ckfree(*ap);
304
        ckfree(param->p);
305
    }
306
}
307
 
308
 
309
 
310
/*
311
 * The shift builtin command.
312
 */
313
 
314
int
315
shiftcmd(argc, argv)
316
    int argc;
317
    char **argv;
318
{
319
    int n;
320
    char **ap1, **ap2;
321
 
322
    n = 1;
323
    if (argc > 1)
324
        n = number(argv[1]);
325
    if (n > shellparam.nparam)
326
        error("can't shift that many");
327
    INTOFF;
328
    shellparam.nparam -= n;
329
    for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
330
        if (shellparam.malloc)
331
            ckfree(*ap1);
332
    }
333
    ap2 = shellparam.p;
334
    while ((*ap2++ = *ap1++) != NULL);
335
    shellparam.optind = 1;
336
    shellparam.optoff = -1;
337
    INTON;
338
    return 0;
339
}
340
 
341
 
342
 
343
/*
344
 * The set command builtin.
345
 */
346
 
347
int
348
setcmd(argc, argv)
349
    int argc;
350
    char **argv;
351
{
352
    if (argc == 1)
353
        return showvarscmd(argc, argv);
354
    INTOFF;
355
    options(0);
356
    optschanged();
357
    if (*argptr != NULL) {
358
        setparam(argptr);
359
    }
360
    INTON;
361
    return 0;
362
}
363
 
364
 
365
void
366
getoptsreset(value)
367
    const char *value;
368
{
369
    shellparam.optind = number(value);
370
    shellparam.optoff = -1;
371
}
372
 
373
/*
374
 * The getopts builtin.  Shellparam.optnext points to the next argument
375
 * to be processed.  Shellparam.optptr points to the next character to
376
 * be processed in the current argument.  If shellparam.optnext is NULL,
377
 * then it's the first time getopts has been called.
378
 */
379
 
380
int
381
getoptscmd(argc, argv)
382
    int argc;
383
    char **argv;
384
{
385
    char **optbase;
386
 
387
    if (argc < 3)
388
        error("Usage: getopts optstring var [arg]");
389
    else if (argc == 3) {
390
        optbase = shellparam.p;
391
        if (shellparam.optind > shellparam.nparam + 1) {
392
            shellparam.optind = 1;
393
            shellparam.optoff = -1;
394
        }
395
    }
396
    else {
397
        optbase = &argv[3];
398
        if (shellparam.optind > argc - 2) {
399
            shellparam.optind = 1;
400
            shellparam.optoff = -1;
401
        }
402
    }
403
 
404
    return getopts(argv[1], argv[2], optbase, &shellparam.optind,
405
               &shellparam.optoff);
406
}
407
 
408
STATIC int
409
getopts(optstr, optvar, optfirst, optind, optoff)
410
    char *optstr;
411
    char *optvar;
412
    char **optfirst;
413
    int *optind;
414
    int *optoff;
415
{
416
    char *p, *q;
417
    char c = '?';
418
    int done = 0;
419
    int err = 0;
420
    char s[10];
421
    char **optnext = optfirst + *optind - 1;
422
 
423
    if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
424
        strlen(*(optnext - 1)) < *optoff)
425
        p = NULL;
426
    else
427
        p = *(optnext - 1) + *optoff;
428
    if (p == NULL || *p == '\0') {
429
        /* Current word is done, advance */
430
        if (optnext == NULL)
431
            return 1;
432
        p = *optnext;
433
        if (p == NULL || *p != '-' || *++p == '\0') {
434
atend:
435
            *optind = optnext - optfirst + 1;
436
            p = NULL;
437
            done = 1;
438
            goto out;
439
        }
440
        optnext++;
441
        if (p[0] == '-' && p[1] == '\0')    /* check for "--" */
442
            goto atend;
443
    }
444
 
445
    c = *p++;
446
    for (q = optstr; *q != c; ) {
447
        if (*q == '\0') {
448
            if (optstr[0] == ':') {
449
                s[0] = c;
450
                s[1] = '\0';
451
                err |= setvarsafe("OPTARG", s, 0);
452
            }
453
            else {
454
                outfmt(&errout, "Illegal option -%c\n", c);
455
                (void) unsetvar("OPTARG");
456
            }
457
            c = '?';
458
            goto bad;
459
        }
460
        if (*++q == ':')
461
            q++;
462
    }
463
 
464
    if (*++q == ':') {
465
        if (*p == '\0' && (p = *optnext) == NULL) {
466
            if (optstr[0] == ':') {
467
                s[0] = c;
468
                s[1] = '\0';
469
                err |= setvarsafe("OPTARG", s, 0);
470
                c = ':';
471
            }
472
            else {
473
                outfmt(&errout, "No arg for -%c option\n", c);
474
                (void) unsetvar("OPTARG");
475
                c = '?';
476
            }
477
            goto bad;
478
        }
479
 
480
        if (p == *optnext)
481
            optnext++;
482
        setvarsafe("OPTARG", p, 0);
483
        p = NULL;
484
    }
485
    else
486
        setvarsafe("OPTARG", "", 0);
487
    *optind = optnext - optfirst + 1;
488
    goto out;
489
 
490
bad:
491
    *optind = 1;
492
    p = NULL;
493
out:
494
    *optoff = p ? p - *(optnext - 1) : -1;
495
    fmtstr(s, sizeof(s), "%d", *optind);
496
    err |= setvarsafe("OPTIND", s, VNOFUNC);
497
    s[0] = c;
498
    s[1] = '\0';
499
    err |= setvarsafe(optvar, s, 0);
500
    if (err) {
501
        *optind = 1;
502
        *optoff = -1;
503
        flushall();
504
        exraise(EXERROR);
505
    }
506
    return done;
507
}
508
 
509
/*
510
 * XXX - should get rid of.  have all builtins use getopt(3).  the
511
 * library getopt must have the BSD extension static variable "optreset"
512
 * otherwise it can't be used within the shell safely.
513
 *
514
 * Standard option processing (a la getopt) for builtin routines.  The
515
 * only argument that is passed to nextopt is the option string; the
516
 * other arguments are unnecessary.  It return the character, or '\0' on
517
 * end of input.
518
 */
519
 
520
int
521
nextopt(optstring)
522
    const char *optstring;
523
    {
524
    char *p;
525
    const char *q;
526
    char c;
527
 
528
    if ((p = optptr) == NULL || *p == '\0') {
529
        p = *argptr;
530
        if (p == NULL || *p != '-' || *++p == '\0')
531
            return '\0';
532
        argptr++;
533
        if (p[0] == '-' && p[1] == '\0')    /* check for "--" */
534
            return '\0';
535
    }
536
    c = *p++;
537
    for (q = optstring ; *q != c ; ) {
538
        if (*q == '\0')
539
            error("Illegal option -%c", c);
540
        if (*++q == ':')
541
            q++;
542
    }
543
    if (*++q == ':') {
544
        if (*p == '\0' && (p = *argptr++) == NULL)
545
            error("No arg for -%c option", c);
546
        optarg = p;
547
        p = NULL;
548
    }
549
    optptr = p;
550
    return c;
551
}