Import of less version 394
[dragonfly.git] / contrib / less-394 / optfunc.c
1 /*
2  * Copyright (C) 1984-2005  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  * Handling functions for command line options.
14  *
15  * Most options are handled by the generic code in option.c.
16  * But all string options, and a few non-string options, require
17  * special handling specific to the particular option.
18  * This special processing is done by the "handling functions" in this file.
19  *
20  * Each handling function is passed a "type" and, if it is a string
21  * option, the string which should be "assigned" to the option.
22  * The type may be one of:
23  *      INIT    The option is being initialized from the command line.
24  *      TOGGLE  The option is being changed from within the program.
25  *      QUERY   The setting of the option is merely being queried.
26  */
27
28 #include "less.h"
29 #include "option.h"
30
31 extern int nbufs;
32 extern int bufspace;
33 extern int pr_type;
34 extern int plusoption;
35 extern int swindow;
36 extern int sc_height;
37 extern int secure;
38 extern int dohelp;
39 extern int any_display;
40 extern int less_is_more;
41 extern char openquote;
42 extern char closequote;
43 extern char *prproto[];
44 extern char *eqproto;
45 extern char *hproto;
46 extern char *wproto;
47 extern IFILE curr_ifile;
48 extern char version[];
49 #if LOGFILE
50 extern char *namelogfile;
51 extern int force_logfile;
52 extern int logfile;
53 #endif
54 #if TAGS
55 public char *tagoption = NULL;
56 extern char *tags;
57 extern int jump_sline;
58 #endif
59 #if MSDOS_COMPILER
60 extern int nm_fg_color, nm_bg_color;
61 extern int bo_fg_color, bo_bg_color;
62 extern int ul_fg_color, ul_bg_color;
63 extern int so_fg_color, so_bg_color;
64 extern int bl_fg_color, bl_bg_color;
65 #endif
66
67
68 #if LOGFILE
69 /*
70  * Handler for -o option.
71  */
72         public void
73 opt_o(type, s)
74         int type;
75         char *s;
76 {
77         PARG parg;
78
79         if (secure)
80         {
81                 error("log file support is not available", NULL_PARG);
82                 return;
83         }
84         switch (type)
85         {
86         case INIT:
87                 namelogfile = s;
88                 break;
89         case TOGGLE:
90                 if (ch_getflags() & CH_CANSEEK)
91                 {
92                         error("Input is not a pipe", NULL_PARG);
93                         return;
94                 }
95                 if (logfile >= 0)
96                 {
97                         error("Log file is already in use", NULL_PARG);
98                         return;
99                 }
100                 s = skipsp(s);
101                 namelogfile = lglob(s);
102                 use_logfile(namelogfile);
103                 sync_logfile();
104                 break;
105         case QUERY:
106                 if (logfile < 0)
107                         error("No log file", NULL_PARG);
108                 else
109                 {
110                         parg.p_string = namelogfile;
111                         error("Log file \"%s\"", &parg);
112                 }
113                 break;
114         }
115 }
116
117 /*
118  * Handler for -O option.
119  */
120         public void
121 opt__O(type, s)
122         int type;
123         char *s;
124 {
125         force_logfile = TRUE;
126         opt_o(type, s);
127 }
128 #endif
129
130 /*
131  * Handlers for -l option.
132  */
133         public void
134 opt_l(type, s)
135         int type;
136         char *s;
137 {
138         int err;
139         int n;
140         char *t;
141         
142         switch (type)
143         {
144         case INIT:
145                 t = s;
146                 n = getnum(&t, "l", &err);
147                 if (err || n <= 0)
148                 {
149                         error("Line number is required after -l", NULL_PARG);
150                         return;
151                 }
152                 plusoption = TRUE;
153                 ungetsc(s);
154                 break;
155         }
156 }
157
158 #if USERFILE
159         public void
160 opt_k(type, s)
161         int type;
162         char *s;
163 {
164         PARG parg;
165
166         switch (type)
167         {
168         case INIT:
169                 if (lesskey(s, 0))
170                 {
171                         parg.p_string = s;
172                         error("Cannot use lesskey file \"%s\"", &parg);
173                 }
174                 break;
175         }
176 }
177 #endif
178
179 #if TAGS
180 /*
181  * Handler for -t option.
182  */
183         public void
184 opt_t(type, s)
185         int type;
186         char *s;
187 {
188         IFILE save_ifile;
189         POSITION pos;
190
191         switch (type)
192         {
193         case INIT:
194                 tagoption = s;
195                 /* Do the rest in main() */
196                 break;
197         case TOGGLE:
198                 if (secure)
199                 {
200                         error("tags support is not available", NULL_PARG);
201                         break;
202                 }
203                 findtag(skipsp(s));
204                 save_ifile = save_curr_ifile();
205                 /*
206                  * Try to open the file containing the tag
207                  * and search for the tag in that file.
208                  */
209                 if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION)
210                 {
211                         /* Failed: reopen the old file. */
212                         reedit_ifile(save_ifile);
213                         break;
214                 }
215                 unsave_ifile(save_ifile);
216                 jump_loc(pos, jump_sline);
217                 break;
218         }
219 }
220
221 /*
222  * Handler for -T option.
223  */
224         public void
225 opt__T(type, s)
226         int type;
227         char *s;
228 {
229         PARG parg;
230
231         switch (type)
232         {
233         case INIT:
234                 tags = s;
235                 break;
236         case TOGGLE:
237                 s = skipsp(s);
238                 tags = lglob(s);
239                 break;
240         case QUERY:
241                 parg.p_string = tags;
242                 error("Tags file \"%s\"", &parg);
243                 break;
244         }
245 }
246 #endif
247
248 /*
249  * Handler for -p option.
250  */
251         public void
252 opt_p(type, s)
253         int type;
254         register char *s;
255 {
256         switch (type)
257         {
258         case INIT:
259                 /*
260                  * Unget a search command for the specified string.
261                  * {{ This won't work if the "/" command is
262                  *    changed or invalidated by a .lesskey file. }}
263                  */
264                 plusoption = TRUE;
265                 ungetsc(s);
266                 /*
267                  * In "more" mode, the -p argument is a command,
268                  * not a search string, so we don't need a slash.
269                  */
270                 if (!less_is_more);
271                         ungetsc("/");
272                 break;
273         }
274 }
275
276 /*
277  * Handler for -P option.
278  */
279         public void
280 opt__P(type, s)
281         int type;
282         register char *s;
283 {
284         register char **proto;
285         PARG parg;
286
287         switch (type)
288         {
289         case INIT:
290         case TOGGLE:
291                 /*
292                  * Figure out which prototype string should be changed.
293                  */
294                 switch (*s)
295                 {
296                 case 's':  proto = &prproto[PR_SHORT];  s++;    break;
297                 case 'm':  proto = &prproto[PR_MEDIUM]; s++;    break;
298                 case 'M':  proto = &prproto[PR_LONG];   s++;    break;
299                 case '=':  proto = &eqproto;            s++;    break;
300                 case 'h':  proto = &hproto;             s++;    break;
301                 case 'w':  proto = &wproto;             s++;    break;
302                 default:   proto = &prproto[PR_SHORT];          break;
303                 }
304                 free(*proto);
305                 *proto = save(s);
306                 break;
307         case QUERY:
308                 parg.p_string = prproto[pr_type];
309                 error("%s", &parg);
310                 break;
311         }
312 }
313
314 /*
315  * Handler for the -b option.
316  */
317         /*ARGSUSED*/
318         public void
319 opt_b(type, s)
320         int type;
321         char *s;
322 {
323         switch (type)
324         {
325         case INIT:
326         case TOGGLE:
327                 /*
328                  * Set the new number of buffers.
329                  */
330                 ch_setbufspace(bufspace);
331                 break;
332         case QUERY:
333                 break;
334         }
335 }
336
337 /*
338  * Handler for the -i option.
339  */
340         /*ARGSUSED*/
341         public void
342 opt_i(type, s)
343         int type;
344         char *s;
345 {
346         switch (type)
347         {
348         case TOGGLE:
349                 chg_caseless();
350                 break;
351         case QUERY:
352         case INIT:
353                 break;
354         }
355 }
356
357 /*
358  * Handler for the -V option.
359  */
360         /*ARGSUSED*/
361         public void
362 opt__V(type, s)
363         int type;
364         char *s;
365 {
366         switch (type)
367         {
368         case TOGGLE:
369         case QUERY:
370                 dispversion();
371                 break;
372         case INIT:
373                 /*
374                  * Force output to stdout per GNU standard for --version output.
375                  */
376                 any_display = 1;
377                 putstr("less ");
378                 putstr(version);
379                 putstr("\nCopyright (C) 1984-2005 Mark Nudelman\n\n");
380                 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
381                 putstr("For information about the terms of redistribution,\n");
382                 putstr("see the file named README in the less distribution.\n");
383                 putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
384                 quit(QUIT_OK);
385                 break;
386         }
387 }
388
389 #if MSDOS_COMPILER
390 /*
391  * Parse an MSDOS color descriptor.
392  */
393         static void
394 colordesc(s, fg_color, bg_color)
395         char *s;
396         int *fg_color;
397         int *bg_color;
398 {
399         int fg, bg;
400         int err;
401         
402         fg = getnum(&s, "D", &err);
403         if (err)
404         {
405                 error("Missing fg color in -D", NULL_PARG);
406                 return;
407         }
408         if (*s != '.')
409                 bg = 0;
410         else
411         {
412                 s++;
413                 bg = getnum(&s, "D", &err);
414                 if (err)
415                 {
416                         error("Missing fg color in -D", NULL_PARG);
417                         return;
418                 }
419         }
420         if (*s != '\0')
421                 error("Extra characters at end of -D option", NULL_PARG);
422         *fg_color = fg;
423         *bg_color = bg;
424 }
425
426 /*
427  * Handler for the -D option.
428  */
429         /*ARGSUSED*/
430         public void
431 opt_D(type, s)
432         int type;
433         char *s;
434 {
435         switch (type)
436         {
437         case INIT:
438         case TOGGLE:
439                 switch (*s++)
440                 {
441                 case 'n':
442                         colordesc(s, &nm_fg_color, &nm_bg_color);
443                         break;
444                 case 'd':
445                         colordesc(s, &bo_fg_color, &bo_bg_color);
446                         break;
447                 case 'u':
448                         colordesc(s, &ul_fg_color, &ul_bg_color);
449                         break;
450                 case 'k':
451                         colordesc(s, &bl_fg_color, &bl_bg_color);
452                         break;
453                 case 's':
454                         colordesc(s, &so_fg_color, &so_bg_color);
455                         break;
456                 default:
457                         error("-D must be followed by n, d, u, k or s", NULL_PARG);
458                         break;
459                 }
460                 if (type == TOGGLE)
461                 {
462                         at_enter(AT_STANDOUT);
463                         at_exit();
464                 }
465                 break;
466         case QUERY:
467                 break;
468         }
469 }
470 #endif
471
472 /*
473  * Handler for the -x option.
474  */
475         public void
476 opt_x(type, s)
477         int type;
478         register char *s;
479 {
480         extern int tabstops[];
481         extern int ntabstops;
482         extern int tabdefault;
483         char msg[60+(4*TABSTOP_MAX)];
484         int i;
485         PARG p;
486
487         switch (type)
488         {
489         case INIT:
490         case TOGGLE:
491                 /* Start at 1 because tabstops[0] is always zero. */
492                 for (i = 1;  i < TABSTOP_MAX;  )
493                 {
494                         int n = 0;
495                         s = skipsp(s);
496                         while (*s >= '0' && *s <= '9')
497                                 n = (10 * n) + (*s++ - '0');
498                         if (n > tabstops[i-1])
499                                 tabstops[i++] = n;
500                         s = skipsp(s);
501                         if (*s++ != ',')
502                                 break;
503                 }
504                 if (i < 2)
505                         return;
506                 ntabstops = i;
507                 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
508                 break;
509         case QUERY:
510                 strcpy(msg, "Tab stops ");
511                 if (ntabstops > 2)
512                 {
513                         for (i = 1;  i < ntabstops;  i++)
514                         {
515                                 if (i > 1)
516                                         strcat(msg, ",");
517                                 sprintf(msg+strlen(msg), "%d", tabstops[i]);
518                         }
519                         sprintf(msg+strlen(msg), " and then ");
520                 }
521                 sprintf(msg+strlen(msg), "every %d spaces",
522                         tabdefault);
523                 p.p_string = msg;
524                 error("%s", &p);
525                 break;
526         }
527 }
528
529
530 /*
531  * Handler for the -" option.
532  */
533         public void
534 opt_quote(type, s)
535         int type;
536         register char *s;
537 {
538         char buf[3];
539         PARG parg;
540
541         switch (type)
542         {
543         case INIT:
544         case TOGGLE:
545                 if (s[0] == '\0')
546                 {
547                         openquote = closequote = '\0';
548                         break;
549                 }
550                 if (s[1] != '\0' && s[2] != '\0')
551                 {
552                         error("-\" must be followed by 1 or 2 chars", NULL_PARG);
553                         return;
554                 }
555                 openquote = s[0];
556                 if (s[1] == '\0')
557                         closequote = openquote;
558                 else
559                         closequote = s[1];
560                 break;
561         case QUERY:
562                 buf[0] = openquote;
563                 buf[1] = closequote;
564                 buf[2] = '\0';
565                 parg.p_string = buf;
566                 error("quotes %s", &parg);
567                 break;
568         }
569 }
570
571 /*
572  * "-?" means display a help message.
573  * If from the command line, exit immediately.
574  */
575         /*ARGSUSED*/
576         public void
577 opt_query(type, s)
578         int type;
579         char *s;
580 {
581         switch (type)
582         {
583         case QUERY:
584         case TOGGLE:
585                 error("Use \"h\" for help", NULL_PARG);
586                 break;
587         case INIT:
588                 dohelp = 1;
589         }
590 }
591
592 /*
593  * Get the "screen window" size.
594  */
595         public int
596 get_swindow()
597 {
598         if (swindow > 0)
599                 return (swindow);
600         return (sc_height + swindow);
601 }
602