~ubuntu-branches/ubuntu/quantal/less/quantal

« back to all changes in this revision

Viewing changes to option.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Schoepf
  • Date: 2002-04-04 16:43:52 UTC
  • Revision ID: james.westby@ubuntu.com-20020404164352-qldq048yoc7x5sd5
Tags: upstream-374
ImportĀ upstreamĀ versionĀ 374

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1984-2000  Mark Nudelman
 
3
 *
 
4
 * You may distribute under the terms of either the GNU General Public
 
5
 * License or the Less License, as specified in the README file.
 
6
 *
 
7
 * For more information about less, or for information on how to 
 
8
 * contact the author, see the README file.
 
9
 */
 
10
 
 
11
 
 
12
/*
 
13
 * Process command line options.
 
14
 *
 
15
 * Each option is a single letter which controls a program variable.
 
16
 * The options have defaults which may be changed via
 
17
 * the command line option, toggled via the "-" command, 
 
18
 * or queried via the "_" command.
 
19
 */
 
20
 
 
21
#include "less.h"
 
22
#include "option.h"
 
23
 
 
24
static struct loption *pendopt;
 
25
public int plusoption = FALSE;
 
26
 
 
27
static char *propt();
 
28
static char *optstring();
 
29
static int flip_triple();
 
30
 
 
31
extern int screen_trashed;
 
32
extern char *every_first_cmd;
 
33
 
 
34
/* 
 
35
 * Scan an argument (either from the command line or from the 
 
36
 * LESS environment variable) and process it.
 
37
 */
 
38
        public void
 
39
scan_option(s)
 
40
        char *s;
 
41
{
 
42
        register struct loption *o;
 
43
        register int optc;
 
44
        char *optname;
 
45
        char *printopt;
 
46
        char *str;
 
47
        int set_default;
 
48
        int lc;
 
49
        int err;
 
50
        PARG parg;
 
51
 
 
52
        if (s == NULL)
 
53
                return;
 
54
 
 
55
        /*
 
56
         * If we have a pending option which requires an argument,
 
57
         * handle it now.
 
58
         * This happens if the previous option was, for example, "-P"
 
59
         * without a following string.  In that case, the current
 
60
         * option is simply the argument for the previous option.
 
61
         */
 
62
        if (pendopt != NULL)
 
63
        {
 
64
                switch (pendopt->otype & OTYPE)
 
65
                {
 
66
                case STRING:
 
67
                        (*pendopt->ofunc)(INIT, s);
 
68
                        break;
 
69
                case NUMBER:
 
70
                        printopt = propt(pendopt->oletter);
 
71
                        *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL);
 
72
                        break;
 
73
                }
 
74
                pendopt = NULL;
 
75
                return;
 
76
        }
 
77
 
 
78
        set_default = FALSE;
 
79
        optname = NULL;
 
80
 
 
81
        while (*s != '\0')
 
82
        {
 
83
                /*
 
84
                 * Check some special cases first.
 
85
                 */
 
86
                switch (optc = *s++)
 
87
                {
 
88
                case ' ':
 
89
                case '\t':
 
90
                case END_OPTION_STRING:
 
91
                        continue;
 
92
                case '-':
 
93
                        /*
 
94
                         * "--" indicates an option name instead of a letter.
 
95
                         */
 
96
                        if (*s == '-')
 
97
                        {
 
98
                                optname = ++s;
 
99
                                break;
 
100
                        }
 
101
                        /*
 
102
                         * "-+" means set these options back to their defaults.
 
103
                         * (They may have been set otherwise by previous 
 
104
                         * options.)
 
105
                         */
 
106
                        set_default = (*s == '+');
 
107
                        if (set_default)
 
108
                                s++;
 
109
                        continue;
 
110
                case '+':
 
111
                        /*
 
112
                         * An option prefixed by a "+" is ungotten, so 
 
113
                         * that it is interpreted as less commands 
 
114
                         * processed at the start of the first input file.
 
115
                         * "++" means process the commands at the start of
 
116
                         * EVERY input file.
 
117
                         */
 
118
                        plusoption = TRUE;
 
119
                        s = optstring(s, &str, propt('+'), NULL);
 
120
                        if (*str == '+')
 
121
                                every_first_cmd = save(++str);
 
122
                        else
 
123
                                ungetsc(str);
 
124
                        continue;
 
125
                case '0':  case '1':  case '2':  case '3':  case '4':
 
126
                case '5':  case '6':  case '7':  case '8':  case '9':
 
127
                        /*
 
128
                         * Special "more" compatibility form "-<number>"
 
129
                         * instead of -z<number> to set the scrolling 
 
130
                         * window size.
 
131
                         */
 
132
                        s--;
 
133
                        optc = 'z';
 
134
                        break;
 
135
                }
 
136
 
 
137
                /*
 
138
                 * Not a special case.
 
139
                 * Look up the option letter in the option table.
 
140
                 */
 
141
                err = 0;
 
142
                if (optname == NULL)
 
143
                {
 
144
                        printopt = propt(optc);
 
145
                        lc = SIMPLE_IS_LOWER(optc);
 
146
                        o = findopt(optc);
 
147
                } else
 
148
                {
 
149
                        printopt = optname;
 
150
                        lc = SIMPLE_IS_LOWER(optname[0]);
 
151
                        o = findopt_name(&optname, NULL, &err);
 
152
                        s = optname;
 
153
                        optname = NULL;
 
154
                        if (*s == '\0' || *s == ' ')
 
155
                        {
 
156
                                /*
 
157
                                 * The option name matches exactly.
 
158
                                 */
 
159
                                ;
 
160
                        } else if (*s == '=')
 
161
                        {
 
162
                                /*
 
163
                                 * The option name is followed by "=value".
 
164
                                 */
 
165
                                if (o != NULL &&
 
166
                                    (o->otype & OTYPE) != STRING &&
 
167
                                    (o->otype & OTYPE) != NUMBER)
 
168
                                {
 
169
                                        parg.p_string = printopt;
 
170
                                        error("The %s option should not be followed by =",
 
171
                                                &parg);
 
172
                                        quit(QUIT_ERROR);
 
173
                                }
 
174
                                s++;
 
175
                        } else
 
176
                        {
 
177
                                /*
 
178
                                 * The specified name is longer than the
 
179
                                 * real option name.
 
180
                                 */
 
181
                                o = NULL;
 
182
                        }
 
183
                }
 
184
                if (o == NULL)
 
185
                {
 
186
                        parg.p_string = printopt;
 
187
                        if (err == OPT_AMBIG)
 
188
                                error("%s is an ambiguous abbreviation (\"less --help\" for help)",
 
189
                                        &parg);
 
190
                        else
 
191
                                error("There is no %s option (\"less --help\" for help)",
 
192
                                        &parg);
 
193
                        quit(QUIT_ERROR);
 
194
                }
 
195
 
 
196
                str = NULL;
 
197
                switch (o->otype & OTYPE)
 
198
                {
 
199
                case BOOL:
 
200
                        if (set_default)
 
201
                                *(o->ovar) = o->odefault;
 
202
                        else
 
203
                                *(o->ovar) = ! o->odefault;
 
204
                        break;
 
205
                case TRIPLE:
 
206
                        if (set_default)
 
207
                                *(o->ovar) = o->odefault;
 
208
                        else
 
209
                                *(o->ovar) = flip_triple(o->odefault, lc);
 
210
                        break;
 
211
                case STRING:
 
212
                        if (*s == '\0')
 
213
                        {
 
214
                                /*
 
215
                                 * Set pendopt and return.
 
216
                                 * We will get the string next time
 
217
                                 * scan_option is called.
 
218
                                 */
 
219
                                pendopt = o;
 
220
                                return;
 
221
                        }
 
222
                        /*
 
223
                         * Don't do anything here.
 
224
                         * All processing of STRING options is done by 
 
225
                         * the handling function.
 
226
                         */
 
227
                        s = optstring(s, &str, printopt, o->odesc[1]);
 
228
                        break;
 
229
                case NUMBER:
 
230
                        if (*s == '\0')
 
231
                        {
 
232
                                pendopt = o;
 
233
                                return;
 
234
                        }
 
235
                        *(o->ovar) = getnum(&s, printopt, (int*)NULL);
 
236
                        break;
 
237
                }
 
238
                /*
 
239
                 * If the option has a handling function, call it.
 
240
                 */
 
241
                if (o->ofunc != NULL)
 
242
                        (*o->ofunc)(INIT, str);
 
243
        }
 
244
}
 
245
 
 
246
/*
 
247
 * Toggle command line flags from within the program.
 
248
 * Used by the "-" and "_" commands.
 
249
 * how_toggle may be:
 
250
 *      OPT_NO_TOGGLE   just report the current setting, without changing it.
 
251
 *      OPT_TOGGLE      invert the current setting
 
252
 *      OPT_UNSET       set to the default value
 
253
 *      OPT_SET         set to the inverse of the default value
 
254
 */
 
255
        public void
 
256
toggle_option(c, s, how_toggle)
 
257
        int c;
 
258
        char *s;
 
259
        int how_toggle;
 
260
{
 
261
        register struct loption *o;
 
262
        register int num;
 
263
        int no_prompt;
 
264
        int err;
 
265
        PARG parg;
 
266
 
 
267
        no_prompt = (how_toggle & OPT_NO_PROMPT);
 
268
        how_toggle &= ~OPT_NO_PROMPT;
 
269
 
 
270
        /*
 
271
         * Look up the option letter in the option table.
 
272
         */
 
273
        o = findopt(c);
 
274
        if (o == NULL)
 
275
        {
 
276
                parg.p_string = propt(c);
 
277
                error("There is no %s option", &parg);
 
278
                return;
 
279
        }
 
280
 
 
281
        if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE))
 
282
        {
 
283
                parg.p_string = propt(c);
 
284
                error("Cannot change the %s option", &parg);
 
285
                return;
 
286
        } 
 
287
 
 
288
        if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY))
 
289
        {
 
290
                parg.p_string = propt(c);
 
291
                error("Cannot query the %s option", &parg);
 
292
                return;
 
293
        } 
 
294
 
 
295
        /*
 
296
         * Check for something which appears to be a do_toggle
 
297
         * (because the "-" command was used), but really is not.
 
298
         * This could be a string option with no string, or
 
299
         * a number option with no number.
 
300
         */
 
301
        switch (o->otype & OTYPE)
 
302
        {
 
303
        case STRING:
 
304
        case NUMBER:
 
305
                if (how_toggle == OPT_TOGGLE && *s == '\0')
 
306
                        how_toggle = OPT_NO_TOGGLE;
 
307
                break;
 
308
        }
 
309
 
 
310
#if HILITE_SEARCH
 
311
        if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
 
312
                repaint_hilite(0);
 
313
#endif
 
314
 
 
315
        /*
 
316
         * Now actually toggle (change) the variable.
 
317
         */
 
318
        if (how_toggle != OPT_NO_TOGGLE)
 
319
        {
 
320
                switch (o->otype & OTYPE)
 
321
                {
 
322
                case BOOL:
 
323
                        /*
 
324
                         * Boolean.
 
325
                         */
 
326
                        switch (how_toggle)
 
327
                        {
 
328
                        case OPT_TOGGLE:
 
329
                                *(o->ovar) = ! *(o->ovar);
 
330
                                break;
 
331
                        case OPT_UNSET:
 
332
                                *(o->ovar) = o->odefault;
 
333
                                break;
 
334
                        case OPT_SET:
 
335
                                *(o->ovar) = ! o->odefault;
 
336
                                break;
 
337
                        }
 
338
                        break;
 
339
                case TRIPLE:
 
340
                        /*
 
341
                         * Triple:
 
342
                         *      If user gave the lower case letter, then switch 
 
343
                         *      to 1 unless already 1, in which case make it 0.
 
344
                         *      If user gave the upper case letter, then switch
 
345
                         *      to 2 unless already 2, in which case make it 0.
 
346
                         */
 
347
                        switch (how_toggle)
 
348
                        {
 
349
                        case OPT_TOGGLE:
 
350
                                *(o->ovar) = flip_triple(*(o->ovar), 
 
351
                                                islower(c));
 
352
                                break;
 
353
                        case OPT_UNSET:
 
354
                                *(o->ovar) = o->odefault;
 
355
                                break;
 
356
                        case OPT_SET:
 
357
                                *(o->ovar) = flip_triple(o->odefault,
 
358
                                                islower(c));
 
359
                                break;
 
360
                        }
 
361
                        break;
 
362
                case STRING:
 
363
                        /*
 
364
                         * String: don't do anything here.
 
365
                         *      The handling function will do everything.
 
366
                         */
 
367
                        switch (how_toggle)
 
368
                        {
 
369
                        case OPT_SET:
 
370
                        case OPT_UNSET:
 
371
                                error("Cannot use \"-+\" or \"--\" for a string option",
 
372
                                        NULL_PARG);
 
373
                                return;
 
374
                        }
 
375
                        break;
 
376
                case NUMBER:
 
377
                        /*
 
378
                         * Number: set the variable to the given number.
 
379
                         */
 
380
                        switch (how_toggle)
 
381
                        {
 
382
                        case OPT_TOGGLE:
 
383
                                num = getnum(&s, '\0', &err);
 
384
                                if (!err)
 
385
                                        *(o->ovar) = num;
 
386
                                break;
 
387
                        case OPT_UNSET:
 
388
                                *(o->ovar) = o->odefault;
 
389
                                break;
 
390
                        case OPT_SET:
 
391
                                error("Can't use \"-!\" for a numeric option",
 
392
                                        NULL_PARG);
 
393
                                return;
 
394
                        }
 
395
                        break;
 
396
                }
 
397
        }
 
398
 
 
399
        /*
 
400
         * Call the handling function for any special action 
 
401
         * specific to this option.
 
402
         */
 
403
        if (o->ofunc != NULL)
 
404
                (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s);
 
405
 
 
406
#if HILITE_SEARCH
 
407
        if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT))
 
408
                chg_hilite();
 
409
#endif
 
410
 
 
411
        if (!no_prompt)
 
412
        {
 
413
                /*
 
414
                 * Print a message describing the new setting.
 
415
                 */
 
416
                switch (o->otype & OTYPE)
 
417
                {
 
418
                case BOOL:
 
419
                case TRIPLE:
 
420
                        /*
 
421
                         * Print the odesc message.
 
422
                         */
 
423
                        error(o->odesc[*(o->ovar)], NULL_PARG);
 
424
                        break;
 
425
                case NUMBER:
 
426
                        /*
 
427
                         * The message is in odesc[1] and has a %d for 
 
428
                         * the value of the variable.
 
429
                         */
 
430
                        parg.p_int = *(o->ovar);
 
431
                        error(o->odesc[1], &parg);
 
432
                        break;
 
433
                case STRING:
 
434
                        /*
 
435
                         * Message was already printed by the handling function.
 
436
                         */
 
437
                        break;
 
438
                }
 
439
        }
 
440
 
 
441
        if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT))
 
442
                screen_trashed = TRUE;
 
443
}
 
444
 
 
445
/*
 
446
 * "Toggle" a triple-valued option.
 
447
 */
 
448
        static int
 
449
flip_triple(val, lc)
 
450
        int val;
 
451
        int lc;
 
452
{
 
453
        if (lc)
 
454
                return ((val == OPT_ON) ? OPT_OFF : OPT_ON);
 
455
        else
 
456
                return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS);
 
457
}
 
458
 
 
459
/*
 
460
 * Return a string suitable for printing as the "name" of an option.
 
461
 * For example, if the option letter is 'x', just return "-x".
 
462
 */
 
463
        static char *
 
464
propt(c)
 
465
        int c;
 
466
{
 
467
        static char buf[8];
 
468
 
 
469
        sprintf(buf, "-%s", prchar(c));
 
470
        return (buf);
 
471
}
 
472
 
 
473
/*
 
474
 * Determine if an option is a single character option (BOOL or TRIPLE),
 
475
 * or if it a multi-character option (NUMBER).
 
476
 */
 
477
        public int
 
478
single_char_option(c)
 
479
        int c;
 
480
{
 
481
        register struct loption *o;
 
482
 
 
483
        o = findopt(c);
 
484
        if (o == NULL)
 
485
                return (TRUE);
 
486
        return ((o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) != 0);
 
487
}
 
488
 
 
489
/*
 
490
 * Return the prompt to be used for a given option letter.
 
491
 * Only string and number valued options have prompts.
 
492
 */
 
493
        public char *
 
494
opt_prompt(c)
 
495
        int c;
 
496
{
 
497
        register struct loption *o;
 
498
 
 
499
        o = findopt(c);
 
500
        if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
 
501
                return (NULL);
 
502
        return (o->odesc[0]);
 
503
}
 
504
 
 
505
/*
 
506
 * Return whether or not there is a string option pending;
 
507
 * that is, if the previous option was a string-valued option letter 
 
508
 * (like -P) without a following string.
 
509
 * In that case, the current option is taken to be the string for
 
510
 * the previous option.
 
511
 */
 
512
        public int
 
513
isoptpending()
 
514
{
 
515
        return (pendopt != NULL);
 
516
}
 
517
 
 
518
/*
 
519
 * Print error message about missing string.
 
520
 */
 
521
        static void
 
522
nostring(printopt)
 
523
        char *printopt;
 
524
{
 
525
        PARG parg;
 
526
        parg.p_string = printopt;
 
527
        error("Value is required after %s", &parg);
 
528
}
 
529
 
 
530
/*
 
531
 * Print error message if a STRING type option is not followed by a string.
 
532
 */
 
533
        public void
 
534
nopendopt()
 
535
{
 
536
        nostring(propt(pendopt->oletter));
 
537
}
 
538
 
 
539
/*
 
540
 * Scan to end of string or to an END_OPTION_STRING character.
 
541
 * In the latter case, replace the char with a null char.
 
542
 * Return a pointer to the remainder of the string, if any.
 
543
 */
 
544
        static char *
 
545
optstring(s, p_str, printopt, validchars)
 
546
        char *s;
 
547
        char **p_str;
 
548
        char *printopt;
 
549
        char *validchars;
 
550
{
 
551
        register char *p;
 
552
 
 
553
        if (*s == '\0')
 
554
        {
 
555
                nostring(printopt);
 
556
                quit(QUIT_ERROR);
 
557
        }
 
558
        *p_str = s;
 
559
        for (p = s;  *p != '\0';  p++)
 
560
        {
 
561
                if (*p == END_OPTION_STRING ||
 
562
                    (validchars != NULL && strchr(validchars, *p) == NULL))
 
563
                {
 
564
                        switch (*p)
 
565
                        {
 
566
                        case END_OPTION_STRING:
 
567
                        case ' ':  case '\t':  case '-':
 
568
                                /* Replace the char with a null to terminate string. */
 
569
                                *p++ = '\0';
 
570
                                break;
 
571
                        default:
 
572
                                /* Cannot replace char; make a copy of the string. */
 
573
                                *p_str = (char *) ecalloc(p-s+1, sizeof(char));
 
574
                                strncpy(*p_str, s, p-s);
 
575
                                (*p_str)[p-s] = '\0';
 
576
                                break;
 
577
                        }
 
578
                        break;
 
579
                }
 
580
        }
 
581
        return (p);
 
582
}
 
583
 
 
584
/*
 
585
 * Translate a string into a number.
 
586
 * Like atoi(), but takes a pointer to a char *, and updates
 
587
 * the char * to point after the translated number.
 
588
 */
 
589
        public int
 
590
getnum(sp, printopt, errp)
 
591
        char **sp;
 
592
        char *printopt;
 
593
        int *errp;
 
594
{
 
595
        register char *s;
 
596
        register int n;
 
597
        register int neg;
 
598
        PARG parg;
 
599
 
 
600
        s = skipsp(*sp);
 
601
        neg = FALSE;
 
602
        if (*s == '-')
 
603
        {
 
604
                neg = TRUE;
 
605
                s++;
 
606
        }
 
607
        if (*s < '0' || *s > '9')
 
608
        {
 
609
                if (errp != NULL)
 
610
                {
 
611
                        *errp = TRUE;
 
612
                        return (-1);
 
613
                }
 
614
                parg.p_string = printopt;
 
615
                error("Number is required after %s", &parg);
 
616
                quit(QUIT_ERROR);
 
617
        }
 
618
 
 
619
        n = 0;
 
620
        while (*s >= '0' && *s <= '9')
 
621
                n = 10 * n + *s++ - '0';
 
622
        *sp = s;
 
623
        if (errp != NULL)
 
624
                *errp = FALSE;
 
625
        if (neg)
 
626
                n = -n;
 
627
        return (n);
 
628
}