import less(1)
[unleashed/tickless.git] / bin / less / optfunc.c
blobddd3712320b38f276179ed191650ad11d4090c16
1 /*
2 * Copyright (C) 1984-2012 Mark Nudelman
3 * Modified for use with illumos by Garrett D'Amore.
4 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
6 * You may distribute under the terms of either the GNU General Public
7 * License or the Less License, as specified in the README file.
9 * For more information, see the README file.
13 * Handling functions for command line options.
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.
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.
28 #include "less.h"
29 #include "option.h"
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 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 extern char *namelogfile;
52 extern int force_logfile;
53 extern int logfile;
54 char *tagoption = NULL;
55 extern char *tags;
57 int shift_count; /* Number of positions to shift horizontally */
58 static int shift_count_fraction = -1;
61 * Handler for -o option.
63 void
64 opt_o(int type, char *s)
66 PARG parg;
68 if (secure) {
69 error("log file support is not available", NULL);
70 return;
72 switch (type) {
73 case INIT:
74 namelogfile = s;
75 break;
76 case TOGGLE:
77 if (ch_getflags() & CH_CANSEEK) {
78 error("Input is not a pipe", NULL);
79 return;
81 if (logfile >= 0) {
82 error("Log file is already in use", NULL);
83 return;
85 s = skipsp(s);
86 namelogfile = lglob(s);
87 use_logfile(namelogfile);
88 sync_logfile();
89 break;
90 case QUERY:
91 if (logfile < 0) {
92 error("No log file", NULL);
93 } else {
94 parg.p_string = namelogfile;
95 error("Log file \"%s\"", &parg);
97 break;
102 * Handler for -O option.
104 void
105 opt__O(int type, char *s)
107 force_logfile = TRUE;
108 opt_o(type, s);
112 * Handlers for -j option.
114 void
115 opt_j(int type, char *s)
117 PARG parg;
118 char buf[16];
119 int len;
120 int err;
122 switch (type) {
123 case INIT:
124 case TOGGLE:
125 if (*s == '.') {
126 s++;
127 jump_sline_fraction = getfraction(&s, "j", &err);
128 if (err)
129 error("Invalid line fraction", NULL);
130 else
131 calc_jump_sline();
132 } else {
133 int sline = getnum(&s, "j", &err);
134 if (err) {
135 error("Invalid line number", NULL);
136 } else {
137 jump_sline = sline;
138 jump_sline_fraction = -1;
141 break;
142 case QUERY:
143 if (jump_sline_fraction < 0) {
144 parg.p_int = jump_sline;
145 error("Position target at screen line %d", &parg);
146 } else {
147 (void) snprintf(buf, sizeof (buf), ".%06d",
148 jump_sline_fraction);
149 len = strlen(buf);
150 while (len > 2 && buf[len-1] == '0')
151 len--;
152 buf[len] = '\0';
153 parg.p_string = buf;
154 error("Position target at screen position %s", &parg);
156 break;
160 void
161 calc_jump_sline(void)
163 if (jump_sline_fraction < 0)
164 return;
165 jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
169 * Handlers for -# option.
171 void
172 opt_shift(int type, char *s)
174 PARG parg;
175 char buf[16];
176 int len;
177 int err;
179 switch (type) {
180 case INIT:
181 case TOGGLE:
182 if (*s == '.') {
183 s++;
184 shift_count_fraction = getfraction(&s, "#", &err);
185 if (err)
186 error("Invalid column fraction", NULL);
187 else
188 calc_shift_count();
189 } else {
190 int hs = getnum(&s, "#", &err);
191 if (err) {
192 error("Invalid column number", NULL);
193 } else {
194 shift_count = hs;
195 shift_count_fraction = -1;
198 break;
199 case QUERY:
200 if (shift_count_fraction < 0) {
201 parg.p_int = shift_count;
202 error("Horizontal shift %d columns", &parg);
203 } else {
205 (void) snprintf(buf, sizeof (buf), ".%06d",
206 shift_count_fraction);
207 len = strlen(buf);
208 while (len > 2 && buf[len-1] == '0')
209 len--;
210 buf[len] = '\0';
211 parg.p_string = buf;
212 error("Horizontal shift %s of screen width", &parg);
214 break;
218 void
219 calc_shift_count(void)
221 if (shift_count_fraction < 0)
222 return;
223 shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
226 void
227 opt_k(int type, char *s)
229 PARG parg;
231 switch (type) {
232 case INIT:
233 if (lesskey(s, 0)) {
234 parg.p_string = s;
235 error("Cannot use lesskey file \"%s\"", &parg);
237 break;
242 * Handler for -t option.
244 void
245 opt_t(int type, char *s)
247 IFILE save_ifile;
248 off_t pos;
250 switch (type) {
251 case INIT:
252 tagoption = s;
253 /* Do the rest in main() */
254 break;
255 case TOGGLE:
256 if (secure) {
257 error("tags support is not available", NULL);
258 break;
260 findtag(skipsp(s));
261 save_ifile = save_curr_ifile();
263 * Try to open the file containing the tag
264 * and search for the tag in that file.
266 if (edit_tagfile() || (pos = tagsearch()) == -1) {
267 /* Failed: reopen the old file. */
268 reedit_ifile(save_ifile);
269 break;
271 unsave_ifile(save_ifile);
272 jump_loc(pos, jump_sline);
273 break;
278 * Handler for -T option.
280 void
281 opt__T(int type, char *s)
283 PARG parg;
285 switch (type) {
286 case INIT:
287 tags = s;
288 break;
289 case TOGGLE:
290 s = skipsp(s);
291 tags = lglob(s);
292 break;
293 case QUERY:
294 parg.p_string = tags;
295 error("Tags file \"%s\"", &parg);
296 break;
301 * Handler for -p option.
303 void
304 opt_p(int type, char *s)
306 switch (type) {
307 case INIT:
309 * Unget a search command for the specified string.
310 * {{ This won't work if the "/" command is
311 * changed or invalidated by a .lesskey file. }}
313 plusoption = TRUE;
314 ungetsc(s);
316 * In "more" mode, the -p argument is a command,
317 * not a search string, so we don't need a slash.
319 if (!less_is_more)
320 ungetsc("/");
321 break;
326 * Handler for -P option.
328 void
329 opt__P(int type, char *s)
331 char **proto;
332 PARG parg;
334 switch (type) {
335 case INIT:
336 case TOGGLE:
338 * Figure out which prototype string should be changed.
340 switch (*s) {
341 case 's': proto = &prproto[PR_SHORT]; s++; break;
342 case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
343 case 'M': proto = &prproto[PR_LONG]; s++; break;
344 case '=': proto = &eqproto; s++; break;
345 case 'h': proto = &hproto; s++; break;
346 case 'w': proto = &wproto; s++; break;
347 default: proto = &prproto[PR_SHORT]; break;
349 free(*proto);
350 *proto = estrdup(s);
351 break;
352 case QUERY:
353 parg.p_string = prproto[pr_type];
354 error("%s", &parg);
355 break;
360 * Handler for the -b option.
362 void
363 opt_b(int type, char *s)
365 switch (type) {
366 case INIT:
367 case TOGGLE:
369 * Set the new number of buffers.
371 ch_setbufspace(bufspace);
372 break;
373 case QUERY:
374 break;
379 * Handler for the -i option.
381 void
382 opt_i(int type, char *s)
384 switch (type) {
385 case TOGGLE:
386 chg_caseless();
387 break;
388 case QUERY:
389 case INIT:
390 break;
395 * Handler for the -V option.
397 void
398 opt__V(int type, char *s)
400 switch (type) {
401 case TOGGLE:
402 case QUERY:
403 dispversion();
404 break;
405 case INIT:
407 * Force output to stdout per GNU standard for --version output.
409 any_display = 1;
410 putstr("less ");
411 putstr(version);
412 putstr(" (");
413 putstr("POSIX ");
414 putstr("regular expressions)\n");
415 putstr("Copyright (C) 1984-2012 Mark Nudelman\n");
416 putstr("Modified for use with illumos by Garrett D'Amore.\n");
417 putstr("Copyright 2014 Garrett D'Amore\n\n");
418 putstr("less comes with NO WARRANTY, ");
419 putstr("to the extent permitted by law.\n");
420 putstr("For information about the terms of redistribution,\n");
421 putstr("see the file named README in the less distribution.\n");
422 putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
423 putstr("\n");
424 quit(QUIT_OK);
425 break;
430 * Handler for the -x option.
432 void
433 opt_x(int type, char *s)
435 extern int tabstops[];
436 extern int ntabstops;
437 extern int tabdefault;
438 char tabs[60+(4*TABSTOP_MAX)];
439 int i;
440 PARG p;
442 switch (type) {
443 case INIT:
444 case TOGGLE:
445 /* Start at 1 because tabstops[0] is always zero. */
446 for (i = 1; i < TABSTOP_MAX; ) {
447 int n = 0;
448 s = skipsp(s);
449 while (*s >= '0' && *s <= '9')
450 n = (10 * n) + (*s++ - '0');
451 if (n > tabstops[i-1])
452 tabstops[i++] = n;
453 s = skipsp(s);
454 if (*s++ != ',')
455 break;
457 if (i < 2)
458 return;
459 ntabstops = i;
460 tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
461 break;
462 case QUERY:
463 (void) strlcpy(tabs, "Tab stops ", sizeof(tabs));
464 if (ntabstops > 2) {
465 for (i = 1; i < ntabstops; i++) {
466 if (i > 1)
467 strlcat(tabs, ",", sizeof(tabs));
468 (void) snprintf(tabs+strlen(tabs),
469 sizeof(tabs)-strlen(tabs),
470 "%d", tabstops[i]);
472 (void) snprintf(tabs+strlen(tabs),
473 sizeof(tabs)-strlen(tabs), " and then ");
475 (void) snprintf(tabs+strlen(tabs), sizeof(tabs)-strlen(tabs),
476 "every %d spaces", tabdefault);
477 p.p_string = tabs;
478 error("%s", &p);
479 break;
485 * Handler for the -" option.
487 void
488 opt_quote(int type, char *s)
490 char buf[3];
491 PARG parg;
493 switch (type) {
494 case INIT:
495 case TOGGLE:
496 if (s[0] == '\0') {
497 openquote = closequote = '\0';
498 break;
500 if (s[1] != '\0' && s[2] != '\0') {
501 error("-\" must be followed by 1 or 2 chars",
502 NULL);
503 return;
505 openquote = s[0];
506 if (s[1] == '\0')
507 closequote = openquote;
508 else
509 closequote = s[1];
510 break;
511 case QUERY:
512 buf[0] = openquote;
513 buf[1] = closequote;
514 buf[2] = '\0';
515 parg.p_string = buf;
516 error("quotes %s", &parg);
517 break;
522 * "-?" means display a help message.
523 * If from the command line, exit immediately.
525 void
526 opt_query(int type, char *s)
528 switch (type) {
529 case QUERY:
530 case TOGGLE:
531 error("Use \"h\" for help", NULL);
532 break;
533 case INIT:
534 dohelp = 1;
539 * Get the "screen window" size.
542 get_swindow(void)
544 if (swindow > 0)
545 return (swindow);
546 return (sc_height + swindow);