/* * Copyright (C) 1984-2002 Mark Nudelman * * You may distribute under the terms of either the GNU General Public * License or the Less License, as specified in the README file. * * For more information about less, or for information on how to * contact the author, see the README file. */ /* * Handling functions for command line options. * * Most options are handled by the generic code in option.c. * But all string options, and a few non-string options, require * special handling specific to the particular option. * This special processing is done by the "handling functions" in this file. * * Each handling function is passed a "type" and, if it is a string * option, the string which should be "assigned" to the option. * The type may be one of: * INIT The option is being initialized from the command line. * TOGGLE The option is being changed from within the program. * QUERY The setting of the option is merely being queried. */ #include "less.h" #include "option.h" #ifndef SMALL_PROGRAM extern int nbufs; #endif extern int bufspace; extern int pr_type; extern int nohelp; extern int plusoption; extern int swindow; extern int sc_height; extern int secure; extern int any_display; extern char openquote; extern char closequote; extern char *prproto[]; extern char *eqproto; extern char *hproto; extern char *wproto; extern IFILE curr_ifile; extern char version[]; #if LOGFILE extern char *namelogfile; extern int force_logfile; extern int logfile; #endif #if TAGS public char *tagoption = NULL; extern char *tags; extern int jump_sline; #endif #if MSDOS_COMPILER extern int nm_fg_color, nm_bg_color; extern int bo_fg_color, bo_bg_color; extern int ul_fg_color, ul_bg_color; extern int so_fg_color, so_bg_color; extern int bl_fg_color, bl_bg_color; #endif #if LOGFILE /* * Handler for -o option. */ public void opt_o(type, s) int type; char *s; { PARG parg; if (secure) { error("log file support is not available", NULL_PARG); return; } switch (type) { case INIT: namelogfile = s; break; case TOGGLE: if (ch_getflags() & CH_CANSEEK) { error("Input is not a pipe", NULL_PARG); return; } if (logfile >= 0) { error("Log file is already in use", NULL_PARG); return; } s = skipsp(s); namelogfile = lglob(s); use_logfile(namelogfile); sync_logfile(); break; case QUERY: if (logfile < 0) error("No log file", NULL_PARG); else { parg.p_string = namelogfile; error("Log file \"%s\"", &parg); } break; } } /* * Handler for -O option. */ public void opt__O(type, s) int type; char *s; { force_logfile = TRUE; opt_o(type, s); } #endif /* * Handlers for -l option. */ public void opt_l(type, s) int type; char *s; { int err; int n; char *t; switch (type) { case INIT: t = s; n = getnum(&t, "l", &err); if (err || n <= 0) { error("Line number is required after -l", NULL_PARG); return; } plusoption = TRUE; ungetsc(s); break; } } #if USERFILE public void opt_k(type, s) int type; char *s; { PARG parg; switch (type) { case INIT: if (lesskey(s, 0)) { parg.p_string = s; error("Cannot use lesskey file \"%s\"", &parg); } break; } } #endif #if TAGS /* * Handler for -t option. */ public void opt_t(type, s) int type; char *s; { IFILE save_ifile; POSITION pos; switch (type) { case INIT: tagoption = s; /* Do the rest in main() */ break; case TOGGLE: if (secure) { error("tags support is not available", NULL_PARG); break; } findtag(skipsp(s)); save_ifile = save_curr_ifile(); if (edit_tagfile()) break; if ((pos = tagsearch()) == NULL_POSITION) { reedit_ifile(save_ifile); break; } unsave_ifile(save_ifile); jump_loc(pos, jump_sline); break; } } /* * Handler for -T option. */ public void opt__T(type, s) int type; char *s; { PARG parg; switch (type) { case INIT: tags = s; break; case TOGGLE: s = skipsp(s); tags = lglob(s); break; case QUERY: parg.p_string = tags; error("Tags file \"%s\"", &parg); break; } } #endif /* * Handler for -p option. */ public void opt_p(type, s) int type; register char *s; { switch (type) { case INIT: /* * Unget a search command for the specified string. * {{ This won't work if the "/" command is * changed or invalidated by a .lesskey file. }} */ plusoption = TRUE; ungetsc(s); ungetsc("/"); break; } } /* * Handler for -P option. */ public void opt__P(type, s) int type; register char *s; { register char **proto; PARG parg; switch (type) { case INIT: case TOGGLE: /* * Figure out which prototype string should be changed. */ switch (*s) { case 's': proto = &prproto[PR_SHORT]; s++; break; case 'm': proto = &prproto[PR_MEDIUM]; s++; break; case 'M': proto = &prproto[PR_LONG]; s++; break; case '=': proto = &eqproto; s++; break; case 'h': proto = &hproto; s++; break; case 'w': proto = &wproto; s++; break; default: proto = &prproto[PR_SHORT]; break; } free(*proto); *proto = save(s); break; case QUERY: parg.p_string = prproto[pr_type]; error("%s", &parg); break; } } /* * Handler for the -b option. */ /*ARGSUSED*/ public void opt_b(type, s) int type; char *s; { switch (type) { case INIT: case TOGGLE: /* * Set the new number of buffers. */ ch_setbufspace(bufspace); break; case QUERY: break; } } /* * Handler for the -i option. */ /*ARGSUSED*/ public void opt_i(type, s) int type; char *s; { switch (type) { case TOGGLE: chg_caseless(); break; case QUERY: case INIT: break; } } /* * Handler for the -V option. */ /*ARGSUSED*/ public void opt__V(type, s) int type; char *s; { switch (type) { case TOGGLE: case QUERY: dispversion(); break; case INIT: /* * Force output to stdout per GNU standard for --version output. */ any_display = 1; putstr("less "); putstr(version); putstr("\nCopyright (C) 2002 Mark Nudelman\n\n"); putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); putstr("For information about the terms of redistribution,\n"); putstr("see the file named README in the less distribution.\n"); putstr("Homepage: http://www.greenwoodsoftware.com/less\n"); quit(QUIT_OK); break; } } #if MSDOS_COMPILER /* * Parse an MSDOS color descriptor. */ static void colordesc(s, fg_color, bg_color) char *s; int *fg_color; int *bg_color; { int fg, bg; int err; fg = getnum(&s, "D", &err); if (err) { error("Missing fg color in -D", NULL_PARG); return; } if (*s != '.') bg = 0; else { s++; bg = getnum(&s, "D", &err); if (err) { error("Missing fg color in -D", NULL_PARG); return; } } if (*s != '\0') error("Extra characters at end of -D option", NULL_PARG); *fg_color = fg; *bg_color = bg; } /* * Handler for the -D option. */ /*ARGSUSED*/ public void opt_D(type, s) int type; char *s; { switch (type) { case INIT: case TOGGLE: switch (*s++) { case 'n': colordesc(s, &nm_fg_color, &nm_bg_color); break; case 'd': colordesc(s, &bo_fg_color, &bo_bg_color); break; case 'u': colordesc(s, &ul_fg_color, &ul_bg_color); break; case 'k': colordesc(s, &bl_fg_color, &bl_bg_color); break; case 's': colordesc(s, &so_fg_color, &so_bg_color); break; default: error("-D must be followed by n, d, u, k or s", NULL_PARG); break; } if (type == TOGGLE) { so_enter(); so_exit(); } break; case QUERY: break; } } #endif /* * Handler for the -x option. */ public void opt_x(type, s) int type; register char *s; { extern int tabstops[]; extern int ntabstops; extern int tabdefault; char msg[60+(4*TABSTOP_MAX)]; int i; PARG p; switch (type) { case INIT: case TOGGLE: /* Start at 1 because tabstops[0] is always zero. */ for (i = 1; i < TABSTOP_MAX; ) { int n = 0; s = skipsp(s); while (*s >= '0' && *s <= '9') n = (10 * n) + (*s++ - '0'); if (n > tabstops[i-1]) tabstops[i++] = n; s = skipsp(s); if (*s++ != ',') break; } if (i < 2) return; ntabstops = i; tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; break; case QUERY: strlcpy(msg, "Tab stops ", sizeof(msg)); if (ntabstops > 2) { for (i = 1; i < ntabstops; i++) { if (i > 1) strlcat(msg, ",", sizeof(msg)); snprintf(msg+strlen(msg), sizeof(msg)-strlen(msg), "%d", tabstops[i]); } snprintf(msg+strlen(msg), sizeof(msg)-strlen(msg), " and then "); } snprintf(msg+strlen(msg), sizeof(msg)-strlen(msg), "every %d spaces", tabdefault); p.p_string = msg; error("%s", &p); break; } } /* * Handler for the -" option. */ public void opt_quote(type, s) int type; register char *s; { char buf[3]; PARG parg; switch (type) { case INIT: case TOGGLE: if (s[0] == '\0') { openquote = closequote = '\0'; break; } if (s[1] != '\0' && s[2] != '\0') { error("-\" must be followed by 1 or 2 chars", NULL_PARG); return; } openquote = s[0]; if (s[1] == '\0') closequote = openquote; else closequote = s[1]; break; case QUERY: buf[0] = openquote; buf[1] = closequote; buf[2] = '\0'; parg.p_string = buf; error("quotes %s", &parg); break; } } /* * "-?" means display a help message. * If from the command line, exit immediately. */ /*ARGSUSED*/ public void opt_query(type, s) int type; char *s; { if (nohelp) return; switch (type) { case QUERY: case TOGGLE: error("Use \"h\" for help", NULL_PARG); break; case INIT: /* * This is "less -?". * It rather ungracefully grabs control, * does the initializations normally done in main, * shows the help file and exits. */ raw_mode(1); get_term(); open_getchr(); init(); any_display = TRUE; help(1); quit(QUIT_OK); /*NOTREACHED*/ } } /* * Get the "screen window" size. */ public int get_swindow() { if (swindow > 0) return (swindow); return (sc_height + swindow); }