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: #ifndef NRTC 65: { 'd', BOOL|NO_TOGGLE, 0, &know_dumb, 66: { NULL, NULL, NULL} 67: }, 68: #else NRTC 69: { 'd', BOOL|NO_TOGGLE, 1, &know_dumb, 70: { NULL, NULL, NULL} 71: }, 72: #endif NRTC 73: { 'e', BOOL, 0, &quit_at_eof, 74: { "Don't quit at end-of-file", 75: "Quit at end-of-file", 76: NULL 77: } 78: }, 79: { 'h', NUMBER, -1, &back_scroll, 80: { "Backwards scroll limit is %d lines", 81: NULL, NULL 82: } 83: }, 84: { 'p', BOOL, 0, &top_scroll, 85: { "Repaint by scrolling from bottom of screen", 86: "Repaint by painting from top of screen", 87: NULL 88: } 89: }, 90: { 'x', NUMBER, 8, &tabstop, 91: { "Tab stops every %d spaces", 92: NULL, NULL 93: } 94: }, 95: { 's', BOOL, 0, &squeeze, 96: { "Don't squeeze multiple blank lines", 97: "Squeeze multiple blank lines", 98: NULL 99: } 100: }, 101: { 't', BOOL, 1, &top_search, 102: { "Forward search starts from bottom of screen", 103: "Forward search starts from top of screen", 104: NULL 105: } 106: }, 107: { 'w', BOOL, 1, &twiddle, 108: { "Display nothing for lines after end-of-file", 109: "Display ~ for lines after end-of-file", 110: NULL 111: } 112: }, 113: { 'm', TRIPLE, 0, &pr_type, 114: { "Prompt with a colon", 115: "Prompt with a message", 116: "Prompt with a verbose message" 117: } 118: }, 119: { 'q', TRIPLE, 0, &quiet, 120: { "Ring the bell for errors AND at eof/bof", 121: "Ring the bell for errors but not at eof/bof", 122: "Never ring the bell" 123: } 124: }, 125: { 'u', TRIPLE, 0, &bs_mode, 126: { "Underlined text displayed in underline mode", 127: "All backspaces cause overstrike", 128: "Backspaces print as ^H" 129: } 130: }, 131: { '\0' } 132: }; 133: 134: public char all_options[64]; /* List of all valid options */ 135: 136: /* 137: * Initialize each option to its default value. 138: */ 139: public void 140: init_option() 141: { 142: register struct option *o; 143: register char *p; 144: 145: /* 146: * First do special cases, not in option table. 147: */ 148: first_cmd = every_first_cmd = NULL; 149: f_nbufs = DEF_F_NBUFS; /* -bf */ 150: p_nbufs = DEF_P_NBUFS; /* -bp */ 151: 152: p = all_options; 153: *p++ = 'b'; 154: 155: for (o = option; o->oletter != '\0'; o++) 156: { 157: /* 158: * Set each variable to its default. 159: * Also make a list of all options, in "all_options". 160: */ 161: *(o->ovar) = o->odefault; 162: *p++ = o->oletter; 163: if (o->otype & TRIPLE) 164: *p++ = toupper(o->oletter); 165: } 166: *p = '\0'; 167: } 168: 169: /* 170: * Toggle command line flags from within the program. 171: * Used by the "-" command. 172: */ 173: public void 174: toggle_option(c) 175: int c; 176: { 177: register struct option *o; 178: char message[100]; 179: char buf[5]; 180: 181: /* 182: * First check for special cases not handled by the option table. 183: */ 184: switch (c) 185: { 186: case 'b': 187: sprintf(message, "%d buffers", nbufs); 188: error(message); 189: return; 190: } 191: 192: 193: for (o = option; o->oletter != '\0'; o++) 194: { 195: if ((o->otype & BOOL) && (o->oletter == c) && 196: (o->otype & NO_TOGGLE) == 0) 197: { 198: /* 199: * Boolean option: 200: * just toggle it. 201: */ 202: *(o->ovar) = ! *(o->ovar); 203: error(o->odesc[*(o->ovar)]); 204: return; 205: } else if ((o->otype & TRIPLE) && (o->oletter == c) && 206: (o->otype & NO_TOGGLE) == 0) 207: { 208: /* 209: * Triple-valued option with lower case letter: 210: * make it 1 unless already 1, then make it 0. 211: */ 212: *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1; 213: error(o->odesc[*(o->ovar)]); 214: return; 215: } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c) && 216: (o->otype & NO_TOGGLE) == 0) 217: { 218: /* 219: * Triple-valued option with upper case letter: 220: * make it 2 unless already 2, then make it 0. 221: */ 222: *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2; 223: error(o->odesc[*(o->ovar)]); 224: return; 225: } else if ((o->otype & NUMBER) && (o->oletter == c) && 226: (o->otype & NO_TOGGLE) == 0) 227: { 228: sprintf(message, o->odesc[0], *(o->ovar)); 229: error(message); 230: return; 231: } 232: } 233: 234: if (control_char(c)) 235: sprintf(buf, "^%c", carat_char(c)); 236: else 237: sprintf(buf, "%c", c); 238: sprintf(message, "\"-%s\": no such flag. Use one of \"%s\"", 239: buf, all_options); 240: error(message); 241: } 242: 243: /* 244: * Scan an argument (either from command line or from LESS environment 245: * variable) and process it. 246: */ 247: public void 248: scan_option(s) 249: char *s; 250: { 251: register struct option *o; 252: register int c; 253: 254: if (s == NULL) 255: return; 256: 257: next: 258: if (*s == '\0') 259: return; 260: switch (c = *s++) 261: { 262: case '-': 263: case ' ': 264: case '\t': 265: goto next; 266: case '+': 267: if (*s == '+') 268: every_first_cmd = ++s; 269: first_cmd = s; 270: return; 271: case 'b': 272: switch (*s) 273: { 274: case 'f': 275: s++; 276: f_nbufs = getnum(&s, 'b'); 277: break; 278: case 'p': 279: s++; 280: p_nbufs = getnum(&s, 'b'); 281: break; 282: default: 283: f_nbufs = p_nbufs = getnum(&s, 'b'); 284: break; 285: } 286: goto next; 287: } 288: 289: for (o = option; o->oletter != '\0'; o++) 290: { 291: if ((o->otype & BOOL) && (o->oletter == c)) 292: { 293: *(o->ovar) = ! o->odefault; 294: goto next; 295: } else if ((o->otype & TRIPLE) && (o->oletter == c)) 296: { 297: *(o->ovar) = (o->odefault == 1) ? 0 : 1; 298: goto next; 299: } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c)) 300: { 301: *(o->ovar) = (o->odefault == 2) ? 0 : 2; 302: goto next; 303: } else if ((o->otype & NUMBER) && (o->oletter == c)) 304: { 305: *(o->ovar) = getnum(&s, c); 306: goto next; 307: } 308: } 309: 310: printf("\"-%c\": invalid flag\n", c); 311: exit(1); 312: } 313: 314: /* 315: * Translate a string into a number. 316: * Like atoi(), but takes a pointer to a char *, and updates 317: * the char * to point after the translated number. 318: */ 319: static int 320: getnum(sp, c) 321: char **sp; 322: int c; 323: { 324: register char *s; 325: register int n; 326: 327: s = *sp; 328: if (*s < '0' || *s > '9') 329: { 330: printf("number is required after -%c\n", c); 331: exit(1); 332: } 333: 334: n = 0; 335: while (*s >= '0' && *s <= '9') 336: n = 10 * n + *s++ - '0'; 337: *sp = s; 338: return (n); 339: }