1: /* 2: * Process command line options. 3: * Each option is a single letter which controls a program variable. 4: * The options have defaults which may be changed via 5: * the command line option, or toggled via the "-" command. 6: */ 7: 8: #include "less.h" 9: 10: #define toupper(c) ((c)-'a'+'A') 11: 12: /* 13: * Types of options. 14: */ 15: #define BOOL 01 /* Boolean option: 0 or 1 */ 16: #define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */ 17: #define NUMBER 04 /* Numeric option */ 18: #define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */ 19: 20: /* 21: * Variables controlled by command line options. 22: */ 23: public int p_nbufs, f_nbufs; /* Number of buffers. There are two values, 24: one used for input from a pipe and 25: the other for input from a file. */ 26: public int clean_data; /* Can we assume the data is "clean"? 27: (That is, free of nulls, etc) */ 28: public int quiet; /* Should we suppress the audible bell? */ 29: public int top_search; /* Should forward searches start at the top 30: of the screen? (alternative is bottom) */ 31: public int top_scroll; /* Repaint screen from top? 32: (alternative is scroll from bottom) */ 33: public int pr_type; /* Type of prompt (short, medium, long) */ 34: public int bs_mode; /* How to process backspaces */ 35: public int know_dumb; /* Don't complain about dumb terminals */ 36: public int quit_at_eof; /* Quit after hitting end of file twice */ 37: public int squeeze; /* Squeeze multiple blank lines into one */ 38: public int tabstop; /* Tab settings */ 39: public int back_scroll; /* Repaint screen on backwards movement */ 40: public int twiddle; /* Display "~" for lines after EOF */ 41: 42: extern int nbufs; 43: extern char *first_cmd; 44: extern char *every_first_cmd; 45: 46: #define DEF_F_NBUFS 5 /* Default for f_nbufs */ 47: #define DEF_P_NBUFS 12 /* Default for p_nbufs */ 48: 49: static struct option 50: { 51: char oletter; /* The controlling letter (a-z) */ 52: char otype; /* Type of the option */ 53: int odefault; /* Default value */ 54: int *ovar; /* Pointer to the associated variable */ 55: char *odesc[3]; /* Description of each value */ 56: } option[] = 57: { 58: { 'c', BOOL, 0, &clean_data, 59: { "Don't assume data is clean", 60: "Assume data is clean", 61: NULL 62: } 63: }, 64: { 'd', BOOL|NO_TOGGLE, 0, &know_dumb, 65: { NULL, NULL, NULL} 66: }, 67: { 'e', BOOL, 0, &quit_at_eof, 68: { "Don't quit at end-of-file", 69: "Quit at end-of-file", 70: NULL 71: } 72: }, 73: { 'h', NUMBER, -1, &back_scroll, 74: { "Backwards scroll limit is %d lines", 75: NULL, NULL 76: } 77: }, 78: { 'p', BOOL, 0, &top_scroll, 79: { "Repaint by scrolling from bottom of screen", 80: "Repaint by painting from top of screen", 81: NULL 82: } 83: }, 84: { 'x', NUMBER, 8, &tabstop, 85: { "Tab stops every %d spaces", 86: NULL, NULL 87: } 88: }, 89: { 's', BOOL, 0, &squeeze, 90: { "Don't squeeze multiple blank lines", 91: "Squeeze multiple blank lines", 92: NULL 93: } 94: }, 95: { 't', BOOL, 1, &top_search, 96: { "Forward search starts from bottom of screen", 97: "Forward search starts from top of screen", 98: NULL 99: } 100: }, 101: { 'w', BOOL, 1, &twiddle, 102: { "Display nothing for lines after end-of-file", 103: "Display ~ for lines after end-of-file", 104: NULL 105: } 106: }, 107: { 'm', TRIPLE, 0, &pr_type, 108: { "Prompt with a colon", 109: "Prompt with a message", 110: "Prompt with a verbose message" 111: } 112: }, 113: { 'q', TRIPLE, 0, &quiet, 114: { "Ring the bell for errors AND at eof/bof", 115: "Ring the bell for errors but not at eof/bof", 116: "Never ring the bell" 117: } 118: }, 119: { 'u', TRIPLE, 0, &bs_mode, 120: { "Underlined text displayed in underline mode", 121: "All backspaces cause overstrike", 122: "Backspaces print as ^H" 123: } 124: }, 125: { '\0' } 126: }; 127: 128: public char all_options[64]; /* List of all valid options */ 129: 130: /* 131: * Initialize each option to its default value. 132: */ 133: public void 134: init_option() 135: { 136: register struct option *o; 137: register char *p; 138: 139: /* 140: * First do special cases, not in option table. 141: */ 142: first_cmd = every_first_cmd = NULL; 143: f_nbufs = DEF_F_NBUFS; /* -bf */ 144: p_nbufs = DEF_P_NBUFS; /* -bp */ 145: 146: p = all_options; 147: *p++ = 'b'; 148: 149: for (o = option; o->oletter != '\0'; o++) 150: { 151: /* 152: * Set each variable to its default. 153: * Also make a list of all options, in "all_options". 154: */ 155: *(o->ovar) = o->odefault; 156: *p++ = o->oletter; 157: if (o->otype & TRIPLE) 158: *p++ = toupper(o->oletter); 159: } 160: *p = '\0'; 161: } 162: 163: /* 164: * Toggle command line flags from within the program. 165: * Used by the "-" command. 166: */ 167: public void 168: toggle_option(c) 169: int c; 170: { 171: register struct option *o; 172: char message[100]; 173: char buf[5]; 174: 175: /* 176: * First check for special cases not handled by the option table. 177: */ 178: switch (c) 179: { 180: case 'b': 181: sprintf(message, "%d buffers", nbufs); 182: error(message); 183: return; 184: } 185: 186: 187: for (o = option; o->oletter != '\0'; o++) 188: { 189: if ((o->otype & BOOL) && (o->oletter == c) && 190: (o->otype & NO_TOGGLE) == 0) 191: { 192: /* 193: * Boolean option: 194: * just toggle it. 195: */ 196: *(o->ovar) = ! *(o->ovar); 197: error(o->odesc[*(o->ovar)]); 198: return; 199: } else if ((o->otype & TRIPLE) && (o->oletter == c) && 200: (o->otype & NO_TOGGLE) == 0) 201: { 202: /* 203: * Triple-valued option with lower case letter: 204: * make it 1 unless already 1, then make it 0. 205: */ 206: *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1; 207: error(o->odesc[*(o->ovar)]); 208: return; 209: } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c) && 210: (o->otype & NO_TOGGLE) == 0) 211: { 212: /* 213: * Triple-valued option with upper case letter: 214: * make it 2 unless already 2, then make it 0. 215: */ 216: *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2; 217: error(o->odesc[*(o->ovar)]); 218: return; 219: } else if ((o->otype & NUMBER) && (o->oletter == c) && 220: (o->otype & NO_TOGGLE) == 0) 221: { 222: sprintf(message, o->odesc[0], *(o->ovar)); 223: error(message); 224: return; 225: } 226: } 227: 228: if (control_char(c)) 229: sprintf(buf, "^%c", carat_char(c)); 230: else 231: sprintf(buf, "%c", c); 232: sprintf(message, "\"-%s\": no such flag. Use one of \"%s\"", 233: buf, all_options); 234: error(message); 235: } 236: 237: /* 238: * Scan an argument (either from command line or from LESS environment 239: * variable) and process it. 240: */ 241: public void 242: scan_option(s) 243: char *s; 244: { 245: register struct option *o; 246: register int c; 247: 248: if (s == NULL) 249: return; 250: 251: next: 252: if (*s == '\0') 253: return; 254: switch (c = *s++) 255: { 256: case '-': 257: case ' ': 258: case '\t': 259: goto next; 260: case '+': 261: if (*s == '+') 262: every_first_cmd = ++s; 263: first_cmd = s; 264: return; 265: case 'b': 266: switch (*s) 267: { 268: case 'f': 269: s++; 270: f_nbufs = getnum(&s, 'b'); 271: break; 272: case 'p': 273: s++; 274: p_nbufs = getnum(&s, 'b'); 275: break; 276: default: 277: f_nbufs = p_nbufs = getnum(&s, 'b'); 278: break; 279: } 280: goto next; 281: } 282: 283: for (o = option; o->oletter != '\0'; o++) 284: { 285: if ((o->otype & BOOL) && (o->oletter == c)) 286: { 287: *(o->ovar) = ! o->odefault; 288: goto next; 289: } else if ((o->otype & TRIPLE) && (o->oletter == c)) 290: { 291: *(o->ovar) = (o->odefault == 1) ? 0 : 1; 292: goto next; 293: } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c)) 294: { 295: *(o->ovar) = (o->odefault == 2) ? 0 : 2; 296: goto next; 297: } else if ((o->otype & NUMBER) && (o->oletter == c)) 298: { 299: *(o->ovar) = getnum(&s, c); 300: goto next; 301: } 302: } 303: 304: printf("\"-%c\": invalid flag\n", c); 305: exit(1); 306: } 307: 308: /* 309: * Translate a string into a number. 310: * Like atoi(), but takes a pointer to a char *, and updates 311: * the char * to point after the translated number. 312: */ 313: static int 314: getnum(sp, c) 315: char **sp; 316: int c; 317: { 318: register char *s; 319: register int n; 320: 321: s = *sp; 322: if (*s < '0' || *s > '9') 323: { 324: printf("number is required after -%c\n", c); 325: exit(1); 326: } 327: 328: n = 0; 329: while (*s >= '0' && *s <= '9') 330: n = 10 * n + *s++ - '0'; 331: *sp = s; 332: return (n); 333: }