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