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