Annotation of src/usr.bin/less/optfunc.c, Revision 1.13
1.1 etheisen 1: /*
1.9 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.11 nicm 3: * Modified for use with illumos by Garrett D'Amore.
4: * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.1 etheisen 5: *
1.4 millert 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.
1.1 etheisen 8: *
1.9 shadchin 9: * For more information, see the README file.
1.1 etheisen 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:
1.4 millert 31: extern int bufspace;
1.1 etheisen 32: extern int pr_type;
33: extern int plusoption;
34: extern int swindow;
1.7 shadchin 35: extern int sc_width;
1.1 etheisen 36: extern int sc_height;
1.4 millert 37: extern int secure;
1.7 shadchin 38: extern int dohelp;
1.1 etheisen 39: extern int any_display;
1.4 millert 40: extern char openquote;
41: extern char closequote;
1.1 etheisen 42: extern char *prproto[];
43: extern char *eqproto;
1.4 millert 44: extern char *hproto;
45: extern char *wproto;
1.1 etheisen 46: extern IFILE curr_ifile;
1.4 millert 47: extern char version[];
1.7 shadchin 48: extern int jump_sline;
49: extern int jump_sline_fraction;
50: extern int less_is_more;
1.1 etheisen 51: extern char *namelogfile;
52: extern int force_logfile;
53: extern int logfile;
1.10 nicm 54: char *tagoption = NULL;
1.1 etheisen 55: extern char *tags;
56:
1.10 nicm 57: int shift_count; /* Number of positions to shift horizontally */
58: static int shift_count_fraction = -1;
1.1 etheisen 59:
60: /*
61: * Handler for -o option.
62: */
1.10 nicm 63: void
64: opt_o(int type, char *s)
1.1 etheisen 65: {
66: PARG parg;
67:
1.10 nicm 68: if (secure) {
1.13 ! deraadt 69: error("log file support is not available", NULL);
1.4 millert 70: return;
71: }
1.10 nicm 72: switch (type) {
1.1 etheisen 73: case INIT:
74: namelogfile = s;
75: break;
76: case TOGGLE:
1.10 nicm 77: if (ch_getflags() & CH_CANSEEK) {
1.13 ! deraadt 78: error("Input is not a pipe", NULL);
1.1 etheisen 79: return;
80: }
1.10 nicm 81: if (logfile >= 0) {
1.13 ! deraadt 82: error("Log file is already in use", NULL);
1.1 etheisen 83: return;
84: }
85: s = skipsp(s);
1.4 millert 86: namelogfile = lglob(s);
1.1 etheisen 87: use_logfile(namelogfile);
88: sync_logfile();
89: break;
90: case QUERY:
1.10 nicm 91: if (logfile < 0) {
1.13 ! deraadt 92: error("No log file", NULL);
1.10 nicm 93: } else {
1.1 etheisen 94: parg.p_string = namelogfile;
95: error("Log file \"%s\"", &parg);
96: }
97: break;
98: }
99: }
100:
101: /*
102: * Handler for -O option.
103: */
1.10 nicm 104: void
105: opt__O(int type, char *s)
1.1 etheisen 106: {
107: force_logfile = TRUE;
108: opt_o(type, s);
109: }
110:
111: /*
1.7 shadchin 112: * Handlers for -j option.
1.1 etheisen 113: */
1.10 nicm 114: void
115: opt_j(int type, char *s)
1.1 etheisen 116: {
1.7 shadchin 117: PARG parg;
118: char buf[16];
119: int len;
1.1 etheisen 120: int err;
1.7 shadchin 121:
1.10 nicm 122: switch (type) {
1.7 shadchin 123: case INIT:
124: case TOGGLE:
1.10 nicm 125: if (*s == '.') {
1.7 shadchin 126: s++;
127: jump_sline_fraction = getfraction(&s, "j", &err);
128: if (err)
1.13 ! deraadt 129: error("Invalid line fraction", NULL);
1.7 shadchin 130: else
131: calc_jump_sline();
1.10 nicm 132: } else {
1.7 shadchin 133: int sline = getnum(&s, "j", &err);
1.10 nicm 134: if (err) {
1.13 ! deraadt 135: error("Invalid line number", NULL);
1.10 nicm 136: } else {
1.7 shadchin 137: jump_sline = sline;
138: jump_sline_fraction = -1;
139: }
140: }
141: break;
142: case QUERY:
1.10 nicm 143: if (jump_sline_fraction < 0) {
1.7 shadchin 144: parg.p_int = jump_sline;
145: error("Position target at screen line %d", &parg);
1.10 nicm 146: } else {
147: (void) snprintf(buf, sizeof (buf), ".%06d",
148: jump_sline_fraction);
1.7 shadchin 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);
155: }
156: break;
157: }
158: }
159:
1.10 nicm 160: void
161: calc_jump_sline(void)
1.7 shadchin 162: {
163: if (jump_sline_fraction < 0)
164: return;
165: jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
166: }
167:
168: /*
169: * Handlers for -# option.
170: */
1.10 nicm 171: void
172: opt_shift(int type, char *s)
1.7 shadchin 173: {
174: PARG parg;
175: char buf[16];
176: int len;
177: int err;
178:
1.10 nicm 179: switch (type) {
1.1 etheisen 180: case INIT:
1.7 shadchin 181: case TOGGLE:
1.10 nicm 182: if (*s == '.') {
1.7 shadchin 183: s++;
184: shift_count_fraction = getfraction(&s, "#", &err);
185: if (err)
1.13 ! deraadt 186: error("Invalid column fraction", NULL);
1.7 shadchin 187: else
188: calc_shift_count();
1.10 nicm 189: } else {
1.7 shadchin 190: int hs = getnum(&s, "#", &err);
1.10 nicm 191: if (err) {
1.13 ! deraadt 192: error("Invalid column number", NULL);
1.10 nicm 193: } else {
1.7 shadchin 194: shift_count = hs;
195: shift_count_fraction = -1;
196: }
197: }
198: break;
199: case QUERY:
1.10 nicm 200: if (shift_count_fraction < 0) {
1.7 shadchin 201: parg.p_int = shift_count;
202: error("Horizontal shift %d columns", &parg);
1.10 nicm 203: } else {
1.7 shadchin 204:
1.10 nicm 205: (void) snprintf(buf, sizeof (buf), ".%06d",
206: shift_count_fraction);
1.7 shadchin 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);
1.1 etheisen 213: }
214: break;
215: }
216: }
1.10 nicm 217:
218: void
219: calc_shift_count(void)
1.7 shadchin 220: {
221: if (shift_count_fraction < 0)
222: return;
223: shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
224: }
1.1 etheisen 225:
1.10 nicm 226: void
227: opt_k(int type, char *s)
1.1 etheisen 228: {
229: PARG parg;
230:
1.10 nicm 231: switch (type) {
1.1 etheisen 232: case INIT:
1.10 nicm 233: if (lesskey(s, 0)) {
1.1 etheisen 234: parg.p_string = s;
235: error("Cannot use lesskey file \"%s\"", &parg);
236: }
237: break;
238: }
239: }
240:
241: /*
242: * Handler for -t option.
243: */
1.10 nicm 244: void
245: opt_t(int type, char *s)
1.1 etheisen 246: {
247: IFILE save_ifile;
1.10 nicm 248: off_t pos;
1.1 etheisen 249:
1.10 nicm 250: switch (type) {
1.1 etheisen 251: case INIT:
252: tagoption = s;
253: /* Do the rest in main() */
254: break;
255: case TOGGLE:
1.10 nicm 256: if (secure) {
1.13 ! deraadt 257: error("tags support is not available", NULL);
1.4 millert 258: break;
259: }
1.1 etheisen 260: findtag(skipsp(s));
1.4 millert 261: save_ifile = save_curr_ifile();
1.7 shadchin 262: /*
263: * Try to open the file containing the tag
264: * and search for the tag in that file.
265: */
1.10 nicm 266: if (edit_tagfile() || (pos = tagsearch()) == -1) {
1.7 shadchin 267: /* Failed: reopen the old file. */
1.4 millert 268: reedit_ifile(save_ifile);
1.1 etheisen 269: break;
270: }
1.4 millert 271: unsave_ifile(save_ifile);
1.1 etheisen 272: jump_loc(pos, jump_sline);
273: break;
274: }
275: }
276:
277: /*
278: * Handler for -T option.
279: */
1.10 nicm 280: void
281: opt__T(int type, char *s)
1.1 etheisen 282: {
283: PARG parg;
284:
1.10 nicm 285: switch (type) {
1.1 etheisen 286: case INIT:
287: tags = s;
288: break;
289: case TOGGLE:
290: s = skipsp(s);
1.4 millert 291: tags = lglob(s);
1.1 etheisen 292: break;
293: case QUERY:
294: parg.p_string = tags;
295: error("Tags file \"%s\"", &parg);
296: break;
297: }
298: }
299:
300: /*
301: * Handler for -p option.
302: */
1.10 nicm 303: void
304: opt_p(int type, char *s)
1.1 etheisen 305: {
1.10 nicm 306: switch (type) {
1.1 etheisen 307: case INIT:
308: /*
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. }}
312: */
1.10 nicm 313: plusoption = TRUE;
314: ungetsc(s);
315: /*
316: * In "more" mode, the -p argument is a command,
317: * not a search string, so we don't need a slash.
318: */
319: if (!less_is_more)
1.7 shadchin 320: ungetsc("/");
1.1 etheisen 321: break;
322: }
323: }
324:
325: /*
326: * Handler for -P option.
327: */
1.10 nicm 328: void
329: opt__P(int type, char *s)
1.1 etheisen 330: {
1.10 nicm 331: char **proto;
1.1 etheisen 332: PARG parg;
333:
1.10 nicm 334: switch (type) {
1.1 etheisen 335: case INIT:
336: case TOGGLE:
337: /*
338: * Figure out which prototype string should be changed.
339: */
1.10 nicm 340: switch (*s) {
1.4 millert 341: case 's': proto = &prproto[PR_SHORT]; s++; break;
1.1 etheisen 342: case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
343: case 'M': proto = &prproto[PR_LONG]; s++; break;
344: case '=': proto = &eqproto; s++; break;
1.4 millert 345: case 'h': proto = &hproto; s++; break;
346: case 'w': proto = &wproto; s++; break;
1.1 etheisen 347: default: proto = &prproto[PR_SHORT]; break;
348: }
349: free(*proto);
1.12 tedu 350: *proto = estrdup(s);
1.1 etheisen 351: break;
352: case QUERY:
353: parg.p_string = prproto[pr_type];
354: error("%s", &parg);
355: break;
356: }
357: }
358:
359: /*
360: * Handler for the -b option.
361: */
1.10 nicm 362: /*ARGSUSED*/
363: void
364: opt_b(int type, char *s)
1.1 etheisen 365: {
1.10 nicm 366: switch (type) {
1.4 millert 367: case INIT:
1.1 etheisen 368: case TOGGLE:
369: /*
1.4 millert 370: * Set the new number of buffers.
1.1 etheisen 371: */
1.4 millert 372: ch_setbufspace(bufspace);
1.1 etheisen 373: break;
1.4 millert 374: case QUERY:
1.1 etheisen 375: break;
376: }
377: }
378:
379: /*
380: * Handler for the -i option.
381: */
1.10 nicm 382: /*ARGSUSED*/
383: void
384: opt_i(int type, char *s)
1.1 etheisen 385: {
1.10 nicm 386: switch (type) {
1.1 etheisen 387: case TOGGLE:
388: chg_caseless();
389: break;
390: case QUERY:
391: case INIT:
392: break;
393: }
394: }
395:
396: /*
397: * Handler for the -V option.
398: */
1.10 nicm 399: /*ARGSUSED*/
400: void
401: opt__V(int type, char *s)
1.1 etheisen 402: {
1.10 nicm 403: switch (type) {
1.1 etheisen 404: case TOGGLE:
405: case QUERY:
1.4 millert 406: dispversion();
407: break;
1.1 etheisen 408: case INIT:
1.4 millert 409: /*
410: * Force output to stdout per GNU standard for --version output.
411: */
412: any_display = 1;
413: putstr("less ");
414: putstr(version);
1.9 shadchin 415: putstr(" (");
416: putstr("POSIX ");
417: putstr("regular expressions)\n");
1.11 nicm 418: putstr("Copyright (C) 1984-2012 Mark Nudelman\n");
419: putstr("Modified for use with illumos by Garrett D'Amore.\n");
420: putstr("Copyright 2014 Garrett D'Amore\n\n");
1.10 nicm 421: putstr("less comes with NO WARRANTY, ");
422: putstr("to the extent permitted by law.\n");
1.4 millert 423: putstr("For information about the terms of redistribution,\n");
424: putstr("see the file named README in the less distribution.\n");
425: putstr("Homepage: http://www.greenwoodsoftware.com/less\n");
1.10 nicm 426: putstr("\n");
1.4 millert 427: quit(QUIT_OK);
1.1 etheisen 428: break;
429: }
430: }
431:
432: /*
1.4 millert 433: * Handler for the -x option.
434: */
1.10 nicm 435: void
436: opt_x(int type, char *s)
1.4 millert 437: {
438: extern int tabstops[];
439: extern int ntabstops;
440: extern int tabdefault;
441: char msg[60+(4*TABSTOP_MAX)];
442: int i;
443: PARG p;
444:
1.10 nicm 445: switch (type) {
1.4 millert 446: case INIT:
447: case TOGGLE:
448: /* Start at 1 because tabstops[0] is always zero. */
1.10 nicm 449: for (i = 1; i < TABSTOP_MAX; ) {
1.4 millert 450: int n = 0;
451: s = skipsp(s);
452: while (*s >= '0' && *s <= '9')
453: n = (10 * n) + (*s++ - '0');
454: if (n > tabstops[i-1])
455: tabstops[i++] = n;
456: s = skipsp(s);
457: if (*s++ != ',')
458: break;
459: }
460: if (i < 2)
461: return;
462: ntabstops = i;
463: tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
464: break;
465: case QUERY:
1.10 nicm 466: (void) strlcpy(msg, "Tab stops ", sizeof(msg));
467: if (ntabstops > 2) {
468: for (i = 1; i < ntabstops; i++) {
1.4 millert 469: if (i > 1)
470: strlcat(msg, ",", sizeof(msg));
1.10 nicm 471: (void) snprintf(msg+strlen(msg),
1.4 millert 472: sizeof(msg)-strlen(msg), "%d", tabstops[i]);
473: }
1.10 nicm 474: (void) snprintf(msg+strlen(msg), sizeof(msg)-strlen(msg),
1.4 millert 475: " and then ");
476: }
1.10 nicm 477: (void) snprintf(msg+strlen(msg), sizeof(msg)-strlen(msg),
1.7 shadchin 478: "every %d spaces", tabdefault);
1.4 millert 479: p.p_string = msg;
480: error("%s", &p);
481: break;
482: }
483: }
484:
485:
486: /*
487: * Handler for the -" option.
488: */
1.10 nicm 489: void
490: opt_quote(int type, char *s)
1.4 millert 491: {
492: char buf[3];
493: PARG parg;
494:
1.10 nicm 495: switch (type) {
1.4 millert 496: case INIT:
497: case TOGGLE:
1.10 nicm 498: if (s[0] == '\0') {
1.4 millert 499: openquote = closequote = '\0';
500: break;
501: }
1.10 nicm 502: if (s[1] != '\0' && s[2] != '\0') {
503: error("-\" must be followed by 1 or 2 chars",
1.13 ! deraadt 504: NULL);
1.4 millert 505: return;
506: }
507: openquote = s[0];
508: if (s[1] == '\0')
509: closequote = openquote;
510: else
511: closequote = s[1];
512: break;
513: case QUERY:
514: buf[0] = openquote;
515: buf[1] = closequote;
516: buf[2] = '\0';
517: parg.p_string = buf;
518: error("quotes %s", &parg);
519: break;
520: }
521: }
522:
523: /*
1.1 etheisen 524: * "-?" means display a help message.
525: * If from the command line, exit immediately.
526: */
1.10 nicm 527: /*ARGSUSED*/
528: void
529: opt_query(int type, char *s)
1.1 etheisen 530: {
1.10 nicm 531: switch (type) {
1.1 etheisen 532: case QUERY:
533: case TOGGLE:
1.13 ! deraadt 534: error("Use \"h\" for help", NULL);
1.1 etheisen 535: break;
536: case INIT:
1.7 shadchin 537: dohelp = 1;
1.1 etheisen 538: }
539: }
540:
541: /*
542: * Get the "screen window" size.
543: */
1.10 nicm 544: int
545: get_swindow(void)
1.1 etheisen 546: {
547: if (swindow > 0)
548: return (swindow);
549: return (sc_height + swindow);
550: }