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