upgrade to 466 version
[platform/upstream/less.git] / optfunc.c
1 /*
2  * Copyright (C) 1984-2014  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 #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 command for the specified string.
366                  */
367                 if (less_is_more)
368                 {
369                         /*
370                          * In "more" mode, the -p argument is a command,
371                          * not a search string, so we don't need a slash.
372                          */
373                         every_first_cmd = save(s);
374                 } else
375                 {
376                         plusoption = TRUE;
377                         ungetsc(s);
378                          /*
379                           * {{ This won't work if the "/" command is
380                           *    changed or invalidated by a .lesskey file. }}
381                           */
382                         ungetsc("/");
383                 }
384                 break;
385         }
386 }
387
388 /*
389  * Handler for -P option.
390  */
391         public void
392 opt__P(type, s)
393         int type;
394         register char *s;
395 {
396         register char **proto;
397         PARG parg;
398
399         switch (type)
400         {
401         case INIT:
402         case TOGGLE:
403                 /*
404                  * Figure out which prototype string should be changed.
405                  */
406                 switch (*s)
407                 {
408                 case 's':  proto = &prproto[PR_SHORT];  s++;    break;
409                 case 'm':  proto = &prproto[PR_MEDIUM]; s++;    break;
410                 case 'M':  proto = &prproto[PR_LONG];   s++;    break;
411                 case '=':  proto = &eqproto;            s++;    break;
412                 case 'h':  proto = &hproto;             s++;    break;
413                 case 'w':  proto = &wproto;             s++;    break;
414                 default:   proto = &prproto[PR_SHORT];          break;
415                 }
416                 free(*proto);
417                 *proto = save(s);
418                 break;
419         case QUERY:
420                 parg.p_string = prproto[pr_type];
421                 error("%s", &parg);
422                 break;
423         }
424 }
425
426 /*
427  * Handler for the -b option.
428  */
429         /*ARGSUSED*/
430         public void
431 opt_b(type, s)
432         int type;
433         char *s;
434 {
435         switch (type)
436         {
437         case INIT:
438         case TOGGLE:
439                 /*
440                  * Set the new number of buffers.
441                  */
442                 ch_setbufspace(bufspace);
443                 break;
444         case QUERY:
445                 break;
446         }
447 }
448
449 /*
450  * Handler for the -i option.
451  */
452         /*ARGSUSED*/
453         public void
454 opt_i(type, s)
455         int type;
456         char *s;
457 {
458         switch (type)
459         {
460         case TOGGLE:
461                 chg_caseless();
462                 break;
463         case QUERY:
464         case INIT:
465                 break;
466         }
467 }
468
469 /*
470  * Handler for the -V option.
471  */
472         /*ARGSUSED*/
473         public void
474 opt__V(type, s)
475         int type;
476         char *s;
477 {
478         switch (type)
479         {
480         case TOGGLE:
481         case QUERY:
482                 dispversion();
483                 break;
484         case INIT:
485                 /*
486                  * Force output to stdout per GNU standard for --version output.
487                  */
488                 any_display = 1;
489                 putstr("less ");
490                 putstr(version);
491                 putstr(" (");
492 #if HAVE_GNU_REGEX
493                 putstr("GNU ");
494 #endif
495 #if HAVE_POSIX_REGCOMP
496                 putstr("POSIX ");
497 #endif
498 #if HAVE_PCRE
499                 putstr("PCRE ");
500 #endif
501 #if HAVE_RE_COMP
502                 putstr("BSD ");
503 #endif
504 #if HAVE_REGCMP
505                 putstr("V8 ");
506 #endif
507 #if HAVE_V8_REGCOMP
508                 putstr("Spencer V8 ");
509 #endif
510 #if !HAVE_GNU_REGEX && !HAVE_POSIX_REGCOMP && !HAVE_PCRE && !HAVE_RE_COMP && !HAVE_REGCMP && !HAVE_V8_REGCOMP
511                 putstr("no ");
512 #endif
513                 putstr("regular expressions)\n");
514                 putstr("Copyright (C) 1984-2014  Mark Nudelman\n\n");
515                 putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
516                 putstr("For information about the terms of redistribution,\n");
517                 putstr("see the file named README in the less distribution.\n");
518                 putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
519                 quit(QUIT_OK);
520                 break;
521         }
522 }
523
524 #if MSDOS_COMPILER
525 /*
526  * Parse an MSDOS color descriptor.
527  */
528         static void
529 colordesc(s, fg_color, bg_color)
530         char *s;
531         int *fg_color;
532         int *bg_color;
533 {
534         int fg, bg;
535         int err;
536         
537         fg = getnum(&s, "D", &err);
538         if (err)
539         {
540                 error("Missing fg color in -D", NULL_PARG);
541                 return;
542         }
543         if (*s != '.')
544                 bg = nm_bg_color;
545         else
546         {
547                 s++;
548                 bg = getnum(&s, "D", &err);
549                 if (err)
550                 {
551                         error("Missing bg color in -D", NULL_PARG);
552                         return;
553                 }
554         }
555         if (*s != '\0')
556                 error("Extra characters at end of -D option", NULL_PARG);
557         *fg_color = fg;
558         *bg_color = bg;
559 }
560
561 /*
562  * Handler for the -D option.
563  */
564         /*ARGSUSED*/
565         public void
566 opt_D(type, s)
567         int type;
568         char *s;
569 {
570         switch (type)
571         {
572         case INIT:
573         case TOGGLE:
574                 switch (*s++)
575                 {
576                 case 'n':
577                         colordesc(s, &nm_fg_color, &nm_bg_color);
578                         break;
579                 case 'd':
580                         colordesc(s, &bo_fg_color, &bo_bg_color);
581                         break;
582                 case 'u':
583                         colordesc(s, &ul_fg_color, &ul_bg_color);
584                         break;
585                 case 'k':
586                         colordesc(s, &bl_fg_color, &bl_bg_color);
587                         break;
588                 case 's':
589                         colordesc(s, &so_fg_color, &so_bg_color);
590                         break;
591                 default:
592                         error("-D must be followed by n, d, u, k or s", NULL_PARG);
593                         break;
594                 }
595                 if (type == TOGGLE)
596                 {
597                         at_enter(AT_STANDOUT);
598                         at_exit();
599                 }
600                 break;
601         case QUERY:
602                 break;
603         }
604 }
605 #endif
606
607 /*
608  * Handler for the -x option.
609  */
610         public void
611 opt_x(type, s)
612         int type;
613         register char *s;
614 {
615         extern int tabstops[];
616         extern int ntabstops;
617         extern int tabdefault;
618         char msg[60+(4*TABSTOP_MAX)];
619         int i;
620         PARG p;
621
622         switch (type)
623         {
624         case INIT:
625         case TOGGLE:
626                 /* Start at 1 because tabstops[0] is always zero. */
627                 for (i = 1;  i < TABSTOP_MAX;  )
628                 {
629                         int n = 0;
630                         s = skipsp(s);
631                         while (*s >= '0' && *s <= '9')
632                                 n = (10 * n) + (*s++ - '0');
633                         if (n > tabstops[i-1])
634                                 tabstops[i++] = n;
635                         s = skipsp(s);
636                         if (*s++ != ',')
637                                 break;
638                 }
639                 if (i < 2)
640                         return;
641                 ntabstops = i;
642                 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
643                 break;
644         case QUERY:
645                 strcpy(msg, "Tab stops ");
646                 if (ntabstops > 2)
647                 {
648                         for (i = 1;  i < ntabstops;  i++)
649                         {
650                                 if (i > 1)
651                                         strcat(msg, ",");
652                                 sprintf(msg+strlen(msg), "%d", tabstops[i]);
653                         }
654                         sprintf(msg+strlen(msg), " and then ");
655                 }
656                 sprintf(msg+strlen(msg), "every %d spaces",
657                         tabdefault);
658                 p.p_string = msg;
659                 error("%s", &p);
660                 break;
661         }
662 }
663
664
665 /*
666  * Handler for the -" option.
667  */
668         public void
669 opt_quote(type, s)
670         int type;
671         register char *s;
672 {
673         char buf[3];
674         PARG parg;
675
676         switch (type)
677         {
678         case INIT:
679         case TOGGLE:
680                 if (s[0] == '\0')
681                 {
682                         openquote = closequote = '\0';
683                         break;
684                 }
685                 if (s[1] != '\0' && s[2] != '\0')
686                 {
687                         error("-\" must be followed by 1 or 2 chars", NULL_PARG);
688                         return;
689                 }
690                 openquote = s[0];
691                 if (s[1] == '\0')
692                         closequote = openquote;
693                 else
694                         closequote = s[1];
695                 break;
696         case QUERY:
697                 buf[0] = openquote;
698                 buf[1] = closequote;
699                 buf[2] = '\0';
700                 parg.p_string = buf;
701                 error("quotes %s", &parg);
702                 break;
703         }
704 }
705
706 /*
707  * "-?" means display a help message.
708  * If from the command line, exit immediately.
709  */
710         /*ARGSUSED*/
711         public void
712 opt_query(type, s)
713         int type;
714         char *s;
715 {
716         switch (type)
717         {
718         case QUERY:
719         case TOGGLE:
720                 error("Use \"h\" for help", NULL_PARG);
721                 break;
722         case INIT:
723                 dohelp = 1;
724         }
725 }
726
727 /*
728  * Get the "screen window" size.
729  */
730         public int
731 get_swindow()
732 {
733         if (swindow > 0)
734                 return (swindow);
735         return (sc_height + swindow);
736 }
737