KDB => KADB
[unix-history] / usr / src / usr.bin / more / option.c
CommitLineData
bfe13c81
KB
1/*
2 * Copyright (c) 1988 Mark Nudleman
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Mark Nudleman.
8 *
9 * Redistribution and use in source and binary forms are permitted
10 * provided that the above copyright notice and this paragraph are
11 * duplicated in all such forms and that any documentation,
12 * advertising materials, and other materials related to such
13 * distribution and use acknowledge that the software was developed
14 * by the University of California, Berkeley. The name of the
15 * University may not be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
bdd98443 23static char sccsid[] = "@(#)option.c 5.4 (Berkeley) %G%";
bfe13c81
KB
24#endif /* not lint */
25
26/*
27 * Process command line options.
28 * Each option is a single letter which controls a program variable.
29 * The options have defaults which may be changed via
30 * the command line option, or toggled via the "-" command.
31 */
32
33#include "less.h"
34
35#define toupper(c) ((c)-'a'+'A')
36
37#define END_OPTION_STRING ('$')
38
39/*
40 * Types of options.
41 */
42#define BOOL 01 /* Boolean option: 0 or 1 */
43#define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */
44#define NUMBER 04 /* Numeric option */
45#define REPAINT 040 /* Repaint screen after toggling option */
46#define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */
47
48/*
49 * Variables controlled by command line options.
50 */
51public int clean_data; /* Can we assume the data is "clean"?
52 (That is, free of nulls, etc) */
53public int quiet; /* Should we suppress the audible bell? */
54public int how_search; /* Where should forward searches start? */
55public int top_scroll; /* Repaint screen from top?
56 (alternative is scroll from bottom) */
57public int pr_type; /* Type of prompt (short, medium, long) */
58public int bs_mode; /* How to process backspaces */
59public int know_dumb; /* Don't complain about dumb terminals */
60public int quit_at_eof; /* Quit after hitting end of file twice */
61public int squeeze; /* Squeeze multiple blank lines into one */
62public int tabstop; /* Tab settings */
63public int back_scroll; /* Repaint screen on backwards movement */
64public int twiddle; /* Display "~" for lines after EOF */
65public int caseless; /* Do "caseless" searches */
66public int linenums; /* Use line numbers */
67public int cbufs; /* Current number of buffers */
68public int autobuf;
69public int plusoption;
70
71extern char *prproto[];
72extern char *eqproto;
73extern int nbufs;
74extern int sc_window;
75extern int ispipe;
76extern char *first_cmd;
77extern char *every_first_cmd;
bfe13c81
KB
78extern char *tagfile;
79extern char *tagpattern;
80public int tagoption = 0;
bfe13c81
KB
81
82static char *opt_P();
83
84static struct option
85{
86 char oletter; /* The controlling letter (a-z) */
87 char otype; /* Type of the option */
88 int odefault; /* Default value */
89 int *ovar; /* Pointer to the associated variable */
90 char *odesc[3]; /* Description of each value */
91} option[] =
92{
93 { 'a', TRIPLE, 0, &how_search,
94 { "Forward search starts at second REAL line displayed",
95 "Forward search starts at bottom of screen",
96 "Forward search starts at second SCREEN line displayed"
97 }
98 },
99 { 'b', NUMBER, 10, &cbufs,
100 { "%d buffers",
101 NULL, NULL
102 }
103 },
104 { 'B', BOOL, 1, &autobuf,
105 { "Don't automatically allocate buffers",
106 "Automatically allocate buffers when needed",
107 NULL
108 }
109 },
110 { 'c', TRIPLE, 0, &top_scroll,
111 { "Repaint by scrolling from bottom of screen",
112 "Repaint by clearing each line",
113 "Repaint by painting from top of screen"
114 }
115 },
116 { 'd', BOOL|NO_TOGGLE, 0, &know_dumb,
117 { NULL, NULL, NULL}
118 },
119 { 'e', TRIPLE, 0, &quit_at_eof,
120 { "Don't quit at end-of-file",
121 "Quit at end-of-file",
122 "Quit immediately at end-of-file"
123 }
124 },
125 { 'h', NUMBER, -1, &back_scroll,
126 { "Backwards scroll limit is %d lines",
127 NULL, NULL
128 }
129 },
130 { 'i', BOOL, 0, &caseless,
131 { "Case is significant in searches",
132 "Ignore case in searches",
133 NULL
134 }
135 },
136 { 'm', TRIPLE, 0, &pr_type,
137 { "Short prompt",
138 "Medium prompt",
139 "Long prompt"
140 }
141 },
142 { 'n', BOOL, 1, &linenums,
143 { "Don't use line numbers",
144 "Use line numbers",
145 NULL
146 }
147 },
148 { 'q', TRIPLE, 0, &quiet,
149 { "Ring the bell for errors AND at eof/bof",
150 "Ring the bell for errors but not at eof/bof",
151 "Never ring the bell"
152 }
153 },
154 { 's', BOOL|REPAINT, 0, &squeeze,
155 { "Don't squeeze multiple blank lines",
156 "Squeeze multiple blank lines",
157 NULL
158 }
159 },
160 { 'u', TRIPLE|REPAINT, 0, &bs_mode,
161 { "Underlined text displayed in underline mode",
162 "Backspaces cause overstrike",
163 "Backspaces print as ^H"
164 }
165 },
166 { 'w', BOOL|REPAINT, 1, &twiddle,
167 { "Display nothing for lines after end-of-file",
168 "Display ~ for lines after end-of-file",
169 NULL
170 }
171 },
172 { 'x', NUMBER|REPAINT, 8, &tabstop,
173 { "Tab stops every %d spaces",
174 NULL, NULL
175 }
176 },
177 { 'z', NUMBER|REPAINT, -1, &sc_window,
178 { "Scroll window size is %d lines",
179 NULL, NULL
180 }
181 },
182 { '\0' }
183};
184
185/*
186 * Initialize each option to its default value.
187 */
188 public void
189init_option()
190{
191 register struct option *o;
192
193 first_cmd = every_first_cmd = NULL;
194
195 for (o = option; o->oletter != '\0'; o++)
196 {
197 /*
198 * Set each variable to its default.
199 */
200 *(o->ovar) = o->odefault;
201 }
202}
203
204/*
205 * Toggle command line flags from within the program.
206 * Used by the "-" and "_" commands.
207 * If do_toggle is zero, just report the current setting, without changing it.
208 */
209 public void
210toggle_option(s, do_toggle)
211 char *s;
212 int do_toggle;
213{
214 int c;
215 register struct option *o;
216 char *msg;
217 int n;
218 int dorepaint;
bdd98443 219 char message[100], *strcat();
bfe13c81
KB
220
221 c = *s++;
222
223 switch (c)
224 {
225 case 'P':
226 /*
227 * Special case for -P.
228 */
229 if (*s == '\0')
230 error(prproto[pr_type]);
231 else
232 (void) opt_P(s);
233 return;
bfe13c81
KB
234 case 't':
235 /*
236 * Special case for -t.
237 */
238 if (*s == '\0')
239 {
240 error("no tag");
241 return;
242 }
243 findtag(s);
244 if (tagfile != NULL)
245 {
246 edit(tagfile);
247 (void) tagsearch();
248 }
249 return;
bfe13c81
KB
250 }
251
252 msg = NULL;
253 for (o = option; o->oletter != '\0'; o++)
254 {
255 if (o->otype & NO_TOGGLE)
256 continue;
257 dorepaint = (o->otype & REPAINT);
258 if ((o->otype & BOOL) && (o->oletter == c))
259 {
260 /*
261 * Boolean option:
262 * just toggle it.
263 */
264 if (do_toggle)
265 *(o->ovar) = ! *(o->ovar);
266 } else if ((o->otype & TRIPLE) && (o->oletter == c))
267 {
268 /*
269 * Triple-valued option with lower case letter:
270 * make it 1 unless already 1, then make it 0.
271 */
272 if (do_toggle)
273 *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1;
274 } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
275 {
276 /*
277 * Triple-valued option with upper case letter:
278 * make it 2 unless already 2, then make it 0.
279 */
280 if (do_toggle)
281 *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2;
282 } else if ((o->otype & NUMBER) && (o->oletter == c))
283 {
284 n = getnum(&s, '\0');
285 if (n < 0)
286 {
287 /*
288 * No number; just a query.
289 * No need to repaint screen.
290 */
291 dorepaint = 0;
292 } else
293 {
294 /*
295 * Number follows the option letter.
296 * Set the variable to that number.
297 */
298 if (do_toggle)
299 *(o->ovar) = n;
300 }
301
302 /*
303 * Special case for -b.
304 * Call ch_init to set new number of buffers.
305 */
306 if (o->ovar == &cbufs)
307 ch_init(cbufs, 1);
308
bdd98443 309 (void)sprintf(message, o->odesc[0],
bfe13c81
KB
310 (o->ovar == &back_scroll) ?
311 get_back_scroll() : *(o->ovar));
312 msg = message;
313 } else
314 continue;
315
316 /*
317 * Print a message describing the new setting.
318 */
319 if (msg == NULL)
320 msg = o->odesc[*(o->ovar)];
321 error(msg);
322
323 if (do_toggle && dorepaint)
324 repaint();
325 return;
326 }
327
328 if (control_char(c))
bdd98443 329 (void)sprintf(message, "-^%c", carat_char(c));
bfe13c81 330 else
bdd98443
KB
331 (void)sprintf(message, "-%c", c);
332 (void)strcat(message, ": no such flag.");
bfe13c81
KB
333 error(message);
334}
335
336/*
337 * Determine if an option is a single character option (BOOL or TRIPLE),
338 * or if it a multi-character option (NUMBER).
339 */
340 public int
341single_char_option(c)
342 int c;
343{
344 register struct option *o;
345
346 if (c == 'P')
347 return (0);
bfe13c81
KB
348 if (c == 't')
349 return (0);
bfe13c81
KB
350 for (o = option; o->oletter != '\0'; o++)
351 if (o->oletter == c)
352 return (o->otype & (BOOL|TRIPLE));
353 return (1);
354}
355
356/*
357 * Scan to end of string or to an END_OPTION_STRING character.
358 * In the latter case, replace the char with a null char.
359 * Return a pointer to the remainder of the string, if any.
360 */
361 static char *
362optstring(s, c)
363 char *s;
364 int c;
365{
366 register char *p;
367 char message[80];
368
369 if (*s == '\0')
370 {
bdd98443 371 (void)sprintf(message, "string is required after -%c", c);
bfe13c81
KB
372 error(message);
373 exit(1);
374 }
375 for (p = s; *p != '\0'; p++)
376 if (*p == END_OPTION_STRING)
377 {
378 *p = '\0';
379 return (p+1);
380 }
381 return (p);
382}
383
384/*
385 * Scan an argument (either from command line or from LESS environment
386 * variable) and process it.
387 */
388 public void
389scan_option(s)
390 char *s;
391{
392 register struct option *o;
393 register int c;
394 int set_default;
395 char message[80];
396
397 if (s == NULL)
398 return;
399
400 set_default = 0;
401 next:
402 if (*s == '\0')
403 return;
404 switch (c = *s++)
405 {
406 case ' ':
407 case '\t':
408 case END_OPTION_STRING:
409 goto next;
410 case '-':
411 if (set_default = (*s == '+'))
412 s++;
413 goto next;
414 case '+':
415 plusoption = 1;
416 if (*s == '+')
417 every_first_cmd = save(++s);
418 first_cmd = s;
419 s = optstring(s, c);
420 goto next;
bfe13c81
KB
421 case 't':
422 {
423 char *p;
424 tagoption = 1;
425 p = s;
426 s = optstring(s, c);
427 findtag(p);
428 goto next;
429 }
bfe13c81
KB
430 case 'P':
431 s = opt_P(s);
432 goto next;
433 case '0': case '1': case '2': case '3': case '4':
434 case '5': case '6': case '7': case '8': case '9':
435 /*
436 * Handle special "more" compatibility form "-number"
437 * (instead of -znumber) to set the scrolling window size.
438 */
439 s--;
440 c = 'z';
441 break;
442 }
443
444 for (o = option; o->oletter != '\0'; o++)
445 {
446 if ((o->otype & BOOL) && (o->oletter == c))
447 {
448 if (set_default)
449 *(o->ovar) = o->odefault;
450 else
451 *(o->ovar) = ! o->odefault;
452 goto next;
453 } else if ((o->otype & TRIPLE) && (o->oletter == c))
454 {
455 if (set_default)
456 *(o->ovar) = o->odefault;
457 else
458 *(o->ovar) = (o->odefault == 1) ? 0 : 1;
459 goto next;
460 } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
461 {
462 if (set_default)
463 *(o->ovar) = o->odefault;
464 else
465 *(o->ovar) = (o->odefault == 2) ? 0 : 2;
466 goto next;
467 } else if ((o->otype & NUMBER) && (o->oletter == c))
468 {
469 *(o->ovar) = getnum(&s, c);
470 goto next;
471 }
472 }
473
bdd98443 474 (void)sprintf(message, "\"-%c\": invalid flag", c);
bfe13c81
KB
475 error(message);
476 exit(1);
477}
478
479/*
480 * Special case for -P.
481 */
482 static char *
483opt_P(s)
484 register char *s;
485{
486 register char *es;
487 register char **proto;
488
489 es = optstring(s, 'P');
490
491 /*
492 * Figure out which prototype string should be changed.
493 */
494 switch (*s)
495 {
496 case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
497 case 'M': proto = &prproto[PR_LONG]; s++; break;
498 case '=': proto = &eqproto; s++; break;
499 default: proto = &prproto[pr_type]; break;
500 }
501
502 free(*proto);
503 *proto = save(s);
504
505 return (es);
506}
507
508/*
509 * Translate a string into a number.
510 * Like atoi(), but takes a pointer to a char *, and updates
511 * the char * to point after the translated number.
512 */
513 public int
514getnum(sp, c)
515 char **sp;
516 int c;
517{
518 register char *s;
519 register int n;
520 char message[80];
521
522 s = *sp;
523 if (*s < '0' || *s > '9')
524 {
525 if (c == '\0')
526 return (-1);
bdd98443 527 (void)sprintf(message, "number is required after -%c", c);
bfe13c81
KB
528 error(message);
529 exit(1);
530 }
531
532 n = 0;
533 while (*s >= '0' && *s <= '9')
534 n = 10 * n + *s++ - '0';
535 *sp = s;
536 return (n);
537}