Annotation of src/usr.bin/less/lesskey.c, Revision 1.9
1.1 etheisen 1: /*
1.7 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.9 ! nicm 3: * Modified for use with illumos by Garrett D'Amore.
! 4: * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.5 millert 5: *
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.7 shadchin 9: * For more information, see the README file.
1.8 nicm 10: */
1.1 etheisen 11:
12: /*
13: * lesskey [-o output] [input]
14: *
1.8 nicm 15: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1.1 etheisen 16: *
17: * Make a .less file.
18: * If no input file is specified, standard input is used.
19: * If no output file is specified, $HOME/.less is used.
20: *
21: * The .less file is used to specify (to "less") user-defined
22: * key bindings. Basically any sequence of 1 to MAX_CMDLEN
23: * keystrokes may be bound to an existing less function.
24: *
1.8 nicm 25: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1.1 etheisen 26: *
1.8 nicm 27: * The input file is an ascii file consisting of a
1.1 etheisen 28: * sequence of lines of the form:
29: * string <whitespace> action [chars] <newline>
30: *
31: * "string" is a sequence of command characters which form
32: * the new user-defined command. The command
33: * characters may be:
34: * 1. The actual character itself.
35: * 2. A character preceded by ^ to specify a
36: * control character (e.g. ^X means control-X).
37: * 3. A backslash followed by one to three octal digits
38: * to specify a character by its octal value.
39: * 4. A backslash followed by b, e, n, r or t
40: * to specify \b, ESC, \n, \r or \t, respectively.
1.8 nicm 41: * 5. Any character (other than those mentioned above) preceded
1.1 etheisen 42: * by a \ to specify the character itself (characters which
43: * must be preceded by \ include ^, \, and whitespace.
44: * "action" is the name of a "less" action, from the table below.
45: * "chars" is an optional sequence of characters which is treated
46: * as keyboard input after the command is executed.
47: *
1.8 nicm 48: * Blank lines and lines which start with # are ignored,
1.1 etheisen 49: * except for the special control lines:
1.5 millert 50: * #command Signals the beginning of the command
51: * keys section.
1.1 etheisen 52: * #line-edit Signals the beginning of the line-editing
53: * keys section.
1.5 millert 54: * #env Signals the beginning of the environment
55: * variable section.
1.1 etheisen 56: * #stop Stops command parsing in less;
57: * causes all default keys to be disabled.
58: *
1.8 nicm 59: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1.1 etheisen 60: *
61: * The output file is a non-ascii file, consisting of a header,
62: * one or more sections, and a trailer.
63: * Each section begins with a section header, a section length word
64: * and the section data. Normally there are three sections:
65: * CMD_SECTION Definition of command keys.
66: * EDIT_SECTION Definition of editing keys.
1.8 nicm 67: * END_SECTION A special section header, with no
1.1 etheisen 68: * length word or section data.
69: *
70: * Section data consists of zero or more byte sequences of the form:
71: * string <0> <action>
72: * or
73: * string <0> <action|A_EXTRA> chars <0>
74: *
75: * "string" is the command string.
76: * "<0>" is one null byte.
77: * "<action>" is one byte containing the action code (the A_xxx value).
78: * If action is ORed with A_EXTRA, the action byte is followed
79: * by the null-terminated "chars" string.
80: *
1.8 nicm 81: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1.1 etheisen 82: */
83:
84: #include "less.h"
85: #include "lesskey.h"
86: #include "cmd.h"
87:
88: struct cmdname
89: {
90: char *cn_name;
91: int cn_action;
92: };
93:
1.8 nicm 94: static void lkerr(char *s);
95:
96: struct cmdname cmdnames[] =
1.1 etheisen 97: {
1.8 nicm 98: { "back-bracket", A_B_BRACKET },
99: { "back-line", A_B_LINE },
100: { "back-line-force", A_BF_LINE },
101: { "back-screen", A_B_SCREEN },
102: { "back-scroll", A_B_SCROLL },
103: { "back-search", A_B_SEARCH },
104: { "back-window", A_B_WINDOW },
105: { "debug", A_DEBUG },
106: { "digit", A_DIGIT },
107: { "display-flag", A_DISP_OPTION },
108: { "display-option", A_DISP_OPTION },
109: { "end", A_GOEND },
110: { "examine", A_EXAMINE },
111: { "filter", A_FILTER },
112: { "first-cmd", A_FIRSTCMD },
113: { "firstcmd", A_FIRSTCMD },
114: { "flush-repaint", A_FREPAINT },
115: { "forw-bracket", A_F_BRACKET },
116: { "forw-forever", A_F_FOREVER },
117: { "forw-until-hilite", A_F_UNTIL_HILITE },
118: { "forw-line", A_F_LINE },
119: { "forw-line-force", A_FF_LINE },
120: { "forw-screen", A_F_SCREEN },
121: { "forw-screen-force", A_FF_SCREEN },
122: { "forw-scroll", A_F_SCROLL },
123: { "forw-search", A_F_SEARCH },
124: { "forw-skip", A_F_SKIP },
125: { "forw-window", A_F_WINDOW },
126: { "goto-end", A_GOEND },
127: { "goto-line", A_GOLINE },
128: { "goto-mark", A_GOMARK },
129: { "help", A_HELP },
130: { "index-file", A_INDEX_FILE },
131: { "invalid", A_UINVALID },
132: { "left-scroll", A_LSHIFT },
133: { "next-file", A_NEXT_FILE },
134: { "next-tag", A_NEXT_TAG },
135: { "noaction", A_NOACTION },
136: { "percent", A_PERCENT },
137: { "pipe", A_PIPE },
138: { "prev-file", A_PREV_FILE },
139: { "prev-tag", A_PREV_TAG },
140: { "quit", A_QUIT },
141: { "remove-file", A_REMOVE_FILE },
142: { "repaint", A_REPAINT },
143: { "repaint-flush", A_FREPAINT },
144: { "repeat-search", A_AGAIN_SEARCH },
145: { "repeat-search-all", A_T_AGAIN_SEARCH },
146: { "reverse-search", A_REVERSE_SEARCH },
147: { "reverse-search-all", A_T_REVERSE_SEARCH },
148: { "right-scroll", A_RSHIFT },
149: { "set-mark", A_SETMARK },
150: { "shell", A_SHELL },
151: { "status", A_STAT },
152: { "toggle-flag", A_OPT_TOGGLE },
153: { "toggle-option", A_OPT_TOGGLE },
154: { "undo-hilite", A_UNDO_SEARCH },
155: { "version", A_VERSION },
156: { "visual", A_VISUAL },
157: { NULL, 0 }
1.1 etheisen 158: };
159:
1.8 nicm 160: struct cmdname editnames[] = {
1.5 millert 161: { "back-complete", EC_B_COMPLETE },
162: { "backspace", EC_BACKSPACE },
163: { "delete", EC_DELETE },
164: { "down", EC_DOWN },
165: { "end", EC_END },
166: { "expand", EC_EXPAND },
167: { "forw-complete", EC_F_COMPLETE },
168: { "home", EC_HOME },
169: { "insert", EC_INSERT },
170: { "invalid", EC_UINVALID },
171: { "kill-line", EC_LINEKILL },
1.6 shadchin 172: { "abort", EC_ABORT },
1.5 millert 173: { "left", EC_LEFT },
174: { "literal", EC_LITERAL },
175: { "right", EC_RIGHT },
176: { "up", EC_UP },
177: { "word-backspace", EC_W_BACKSPACE },
178: { "word-delete", EC_W_DELETE },
179: { "word-left", EC_W_LEFT },
180: { "word-right", EC_W_RIGHT },
181: { NULL, 0 }
1.1 etheisen 182: };
183:
184: struct table
185: {
186: struct cmdname *names;
187: char *pbuffer;
188: char buffer[MAX_USERCMD];
189: };
190:
191: struct table cmdtable;
192: struct table edittable;
1.5 millert 193: struct table vartable;
1.1 etheisen 194: struct table *currtable = &cmdtable;
195:
196: char fileheader[] = {
1.8 nicm 197: C0_LESSKEY_MAGIC,
198: C1_LESSKEY_MAGIC,
199: C2_LESSKEY_MAGIC,
1.1 etheisen 200: C3_LESSKEY_MAGIC
201: };
202: char filetrailer[] = {
1.8 nicm 203: C0_END_LESSKEY_MAGIC,
204: C1_END_LESSKEY_MAGIC,
1.1 etheisen 205: C2_END_LESSKEY_MAGIC
206: };
207: char cmdsection[1] = { CMD_SECTION };
208: char editsection[1] = { EDIT_SECTION };
1.5 millert 209: char varsection[1] = { VAR_SECTION };
1.1 etheisen 210: char endsection[1] = { END_SECTION };
211:
212: char *infile = NULL;
1.8 nicm 213: char *outfile = NULL;
1.1 etheisen 214:
215: int linenum;
216: int errors;
217:
218: extern char version[];
219:
1.8 nicm 220: void
221: usage(void)
1.5 millert 222: {
1.8 nicm 223: (void) fprintf(stderr, "usage: lesskey [-o output] [input]\n");
1.5 millert 224: exit(1);
225: }
226:
1.8 nicm 227: char *
228: mkpathname(char *dirname, char *filename)
1.1 etheisen 229: {
230: char *pathname;
1.4 deraadt 231: size_t len;
1.1 etheisen 232:
1.4 deraadt 233: len = strlen(dirname) + strlen(filename) + 2;
1.8 nicm 234: pathname = calloc(1, len);
235: if (pathname == NULL) {
236: fprintf(stderr, "mkpathname: out of memory\n");
237: exit(1);
238: }
239: (void) snprintf(pathname, len, "%s/%s", dirname, filename);
1.1 etheisen 240: return (pathname);
241: }
242:
243: /*
244: * Figure out the name of a default file (in the user's HOME directory).
245: */
1.8 nicm 246: char *
247: homefile(char *filename)
1.1 etheisen 248: {
249: char *p;
250: char *pathname;
251:
1.8 nicm 252: if ((p = getenv("HOME")) != NULL && *p != '\0') {
1.1 etheisen 253: pathname = mkpathname(p, filename);
1.8 nicm 254: } else {
255: (void) fprintf(stderr, "cannot find $HOME - "
256: "using current directory\n");
1.1 etheisen 257: pathname = mkpathname(".", filename);
258: }
259: return (pathname);
260: }
261:
262: /*
263: * Parse command line arguments.
264: */
1.8 nicm 265: void
266: parse_args(int argc, char **argv)
1.1 etheisen 267: {
1.5 millert 268: char *arg;
269:
1.1 etheisen 270: outfile = NULL;
1.8 nicm 271: while (--argc > 0) {
1.5 millert 272: arg = *++argv;
273: if (arg[0] != '-')
274: /* Arg does not start with "-"; it's not an option. */
275: break;
276: if (arg[1] == '\0')
277: /* "-" means standard input. */
278: break;
1.8 nicm 279: if (arg[1] == '-' && arg[2] == '\0') {
1.5 millert 280: /* "--" means end of options. */
281: argc--;
282: argv++;
283: break;
284: }
1.8 nicm 285: switch (arg[1]) {
1.5 millert 286: case '-':
1.8 nicm 287: if (strncmp(arg, "--output", 8) == 0) {
1.5 millert 288: if (arg[8] == '\0')
289: outfile = &arg[8];
290: else if (arg[8] == '=')
291: outfile = &arg[9];
292: else
293: usage();
294: goto opt_o;
295: }
1.8 nicm 296: if (strcmp(arg, "--version") == 0) {
1.5 millert 297: goto opt_V;
298: }
299: usage();
300: break;
1.1 etheisen 301: case 'o':
302: outfile = &argv[0][2];
1.5 millert 303: opt_o:
1.8 nicm 304: if (*outfile == '\0') {
1.1 etheisen 305: if (--argc <= 0)
306: usage();
307: outfile = *(++argv);
308: }
309: break;
310: case 'V':
1.5 millert 311: opt_V:
1.8 nicm 312: (void) printf("lesskey version %s\n", version);
1.1 etheisen 313: exit(0);
314: default:
315: usage();
316: }
317: }
318: if (argc > 1)
319: usage();
320: /*
321: * Open the input file, or use DEF_LESSKEYINFILE if none specified.
322: */
323: if (argc > 0)
324: infile = *argv;
325: else
326: infile = homefile(DEF_LESSKEYINFILE);
327: }
328:
329: /*
330: * Initialize data structures.
331: */
1.8 nicm 332: void
333: init_tables(void)
1.1 etheisen 334: {
335: cmdtable.names = cmdnames;
336: cmdtable.pbuffer = cmdtable.buffer;
337:
338: edittable.names = editnames;
339: edittable.pbuffer = edittable.buffer;
1.5 millert 340:
341: vartable.names = NULL;
342: vartable.pbuffer = vartable.buffer;
1.1 etheisen 343: }
344:
345: /*
346: * Parse one character of a string.
347: */
1.8 nicm 348: char *
349: tstr(char **pp, int xlate)
350: {
351: char *p;
352: char ch;
353: int i;
1.5 millert 354: static char buf[10];
355: static char tstr_control_k[] =
356: { SK_SPECIAL_KEY, SK_CONTROL_K, 6, 1, 1, 1, '\0' };
1.1 etheisen 357:
358: p = *pp;
1.8 nicm 359: switch (*p) {
1.1 etheisen 360: case '\\':
361: ++p;
1.8 nicm 362: switch (*p) {
1.1 etheisen 363: case '0': case '1': case '2': case '3':
364: case '4': case '5': case '6': case '7':
365: /*
366: * Parse an octal number.
367: */
368: ch = 0;
369: i = 0;
370: do
371: ch = 8*ch + (*p - '0');
1.8 nicm 372: while (*++p >= '0' && *p <= '7' && ++i < 3)
373: ;
1.1 etheisen 374: *pp = p;
1.5 millert 375: if (xlate && ch == CONTROL('K'))
1.8 nicm 376: return (tstr_control_k);
1.5 millert 377: buf[0] = ch;
378: buf[1] = '\0';
379: return (buf);
1.1 etheisen 380: case 'b':
381: *pp = p+1;
1.5 millert 382: return ("\b");
1.1 etheisen 383: case 'e':
384: *pp = p+1;
1.5 millert 385: buf[0] = ESC;
386: buf[1] = '\0';
387: return (buf);
1.1 etheisen 388: case 'n':
389: *pp = p+1;
1.5 millert 390: return ("\n");
1.1 etheisen 391: case 'r':
392: *pp = p+1;
1.5 millert 393: return ("\r");
1.1 etheisen 394: case 't':
395: *pp = p+1;
1.5 millert 396: return ("\t");
397: case 'k':
1.8 nicm 398: if (xlate) {
399: switch (*++p) {
1.5 millert 400: case 'u': ch = SK_UP_ARROW; break;
401: case 'd': ch = SK_DOWN_ARROW; break;
402: case 'r': ch = SK_RIGHT_ARROW; break;
403: case 'l': ch = SK_LEFT_ARROW; break;
404: case 'U': ch = SK_PAGE_UP; break;
405: case 'D': ch = SK_PAGE_DOWN; break;
406: case 'h': ch = SK_HOME; break;
407: case 'e': ch = SK_END; break;
408: case 'x': ch = SK_DELETE; break;
409: default:
1.8 nicm 410: lkerr("illegal char after \\k");
1.5 millert 411: *pp = p+1;
412: return ("");
413: }
414: *pp = p+1;
415: buf[0] = SK_SPECIAL_KEY;
416: buf[1] = ch;
417: buf[2] = 6;
418: buf[3] = 1;
419: buf[4] = 1;
420: buf[5] = 1;
421: buf[6] = '\0';
422: return (buf);
423: }
424: /* FALLTHRU */
1.1 etheisen 425: default:
426: /*
1.8 nicm 427: * Backslash followed by any other char
1.1 etheisen 428: * just means that char.
429: */
430: *pp = p+1;
1.5 millert 431: buf[0] = *p;
432: buf[1] = '\0';
433: if (xlate && buf[0] == CONTROL('K'))
1.8 nicm 434: return (tstr_control_k);
1.5 millert 435: return (buf);
1.1 etheisen 436: }
437: case '^':
438: /*
1.7 shadchin 439: * Caret means CONTROL.
1.1 etheisen 440: */
441: *pp = p+2;
1.5 millert 442: buf[0] = CONTROL(p[1]);
443: buf[1] = '\0';
444: if (buf[0] == CONTROL('K'))
1.8 nicm 445: return (tstr_control_k);
1.5 millert 446: return (buf);
1.1 etheisen 447: }
448: *pp = p+1;
1.5 millert 449: buf[0] = *p;
450: buf[1] = '\0';
451: if (xlate && buf[0] == CONTROL('K'))
1.8 nicm 452: return (tstr_control_k);
1.5 millert 453: return (buf);
1.1 etheisen 454: }
455:
456: /*
457: * Skip leading spaces in a string.
458: */
1.8 nicm 459: char *
460: skipsp(char *s)
1.1 etheisen 461: {
1.8 nicm 462: while (*s == ' ' || *s == '\t')
1.1 etheisen 463: s++;
464: return (s);
465: }
466:
467: /*
468: * Skip non-space characters in a string.
469: */
1.8 nicm 470: char *
471: skipnsp(char *s)
1.1 etheisen 472: {
473: while (*s != '\0' && *s != ' ' && *s != '\t')
474: s++;
475: return (s);
476: }
477:
478: /*
479: * Clean up an input line:
480: * strip off the trailing newline & any trailing # comment.
481: */
1.8 nicm 482: char *
483: clean_line(char *s)
1.1 etheisen 484: {
1.8 nicm 485: int i;
1.1 etheisen 486:
487: s = skipsp(s);
1.5 millert 488: for (i = 0; s[i] != '\n' && s[i] != '\r' && s[i] != '\0'; i++)
1.1 etheisen 489: if (s[i] == '#' && (i == 0 || s[i-1] != '\\'))
490: break;
491: s[i] = '\0';
492: return (s);
493: }
494:
495: /*
496: * Add a byte to the output command table.
497: */
1.8 nicm 498: void
499: add_cmd_char(int c)
500: {
501: if (currtable->pbuffer >= currtable->buffer + MAX_USERCMD) {
502: lkerr("too many commands");
1.1 etheisen 503: exit(1);
504: }
1.8 nicm 505: *(currtable->pbuffer)++ = (char)c;
1.1 etheisen 506: }
507:
508: /*
1.5 millert 509: * Add a string to the output command table.
510: */
1.8 nicm 511: void
512: add_cmd_str(char *s)
1.5 millert 513: {
1.8 nicm 514: for (; *s != '\0'; s++)
1.5 millert 515: add_cmd_char(*s);
516: }
517:
518: /*
1.1 etheisen 519: * See if we have a special "control" line.
520: */
1.8 nicm 521: int
522: control_line(char *s)
1.1 etheisen 523: {
1.8 nicm 524: #define PREFIX(str, pat) (strncmp(str, pat, strlen(pat)) == 0)
1.1 etheisen 525:
1.8 nicm 526: if (PREFIX(s, "#line-edit")) {
1.1 etheisen 527: currtable = &edittable;
528: return (1);
529: }
1.8 nicm 530: if (PREFIX(s, "#command")) {
1.1 etheisen 531: currtable = &cmdtable;
532: return (1);
533: }
1.8 nicm 534: if (PREFIX(s, "#env")) {
1.5 millert 535: currtable = &vartable;
536: return (1);
537: }
1.8 nicm 538: if (PREFIX(s, "#stop")) {
1.1 etheisen 539: add_cmd_char('\0');
540: add_cmd_char(A_END_LIST);
541: return (1);
542: }
543: return (0);
544: }
545:
546: /*
547: * Output some bytes.
548: */
1.8 nicm 549: void
550: fputbytes(FILE *fd, char *buf, int len)
551: {
552: while (len-- > 0) {
553: (void) fwrite(buf, sizeof (char), 1, fd);
1.1 etheisen 554: buf++;
555: }
556: }
557:
558: /*
559: * Output an integer, in special KRADIX form.
560: */
1.8 nicm 561: void
562: fputint(FILE *fd, unsigned int val)
1.1 etheisen 563: {
564: char c;
565:
1.8 nicm 566: if (val >= KRADIX*KRADIX) {
567: (void) fprintf(stderr, "error: integer too big (%d > %d)\n",
568: val, KRADIX*KRADIX);
1.1 etheisen 569: exit(1);
570: }
571: c = val % KRADIX;
1.8 nicm 572: (void) fwrite(&c, sizeof (char), 1, fd);
1.1 etheisen 573: c = val / KRADIX;
1.8 nicm 574: (void) fwrite(&c, sizeof (char), 1, fd);
1.1 etheisen 575: }
576:
577: /*
578: * Find an action, given the name of the action.
579: */
1.8 nicm 580: int
581: findaction(char *actname)
1.1 etheisen 582: {
583: int i;
584:
585: for (i = 0; currtable->names[i].cn_name != NULL; i++)
586: if (strcmp(currtable->names[i].cn_name, actname) == 0)
587: return (currtable->names[i].cn_action);
1.8 nicm 588: lkerr("unknown action");
1.1 etheisen 589: return (A_INVALID);
590: }
591:
1.8 nicm 592: void
593: lkerr(char *s)
1.1 etheisen 594: {
1.8 nicm 595: (void) fprintf(stderr, "line %d: %s\n", linenum, s);
1.1 etheisen 596: errors++;
597: }
598:
599:
1.8 nicm 600: void
601: parse_cmdline(char *p)
1.1 etheisen 602: {
603: int cmdlen;
604: char *actname;
605: int action;
1.5 millert 606: char *s;
607: char c;
1.1 etheisen 608:
609: /*
610: * Parse the command string and store it in the current table.
611: */
612: cmdlen = 0;
1.8 nicm 613: do {
1.5 millert 614: s = tstr(&p, 1);
615: cmdlen += strlen(s);
616: if (cmdlen > MAX_CMDLEN)
1.8 nicm 617: lkerr("command too long");
1.1 etheisen 618: else
1.5 millert 619: add_cmd_str(s);
1.1 etheisen 620: } while (*p != ' ' && *p != '\t' && *p != '\0');
621: /*
622: * Terminate the command string with a null byte.
623: */
624: add_cmd_char('\0');
625:
626: /*
627: * Skip white space between the command string
628: * and the action name.
629: * Terminate the action name with a null byte.
630: */
631: p = skipsp(p);
1.8 nicm 632: if (*p == '\0') {
633: lkerr("missing action");
1.1 etheisen 634: return;
635: }
636: actname = p;
637: p = skipnsp(p);
638: c = *p;
639: *p = '\0';
640:
641: /*
642: * Parse the action name and store it in the current table.
643: */
644: action = findaction(actname);
645:
646: /*
647: * See if an extra string follows the action name.
648: */
649: *p = c;
650: p = skipsp(p);
1.8 nicm 651: if (*p == '\0') {
1.1 etheisen 652: add_cmd_char(action);
1.8 nicm 653: } else {
1.1 etheisen 654: /*
655: * OR the special value A_EXTRA into the action byte.
656: * Put the extra string after the action byte.
657: */
658: add_cmd_char(action | A_EXTRA);
659: while (*p != '\0')
1.5 millert 660: add_cmd_str(tstr(&p, 0));
1.1 etheisen 661: add_cmd_char('\0');
662: }
663: }
664:
1.8 nicm 665: void
666: parse_varline(char *p)
1.5 millert 667: {
668: char *s;
669:
1.8 nicm 670: do {
1.5 millert 671: s = tstr(&p, 0);
672: add_cmd_str(s);
673: } while (*p != ' ' && *p != '\t' && *p != '=' && *p != '\0');
674: /*
675: * Terminate the variable name with a null byte.
676: */
677: add_cmd_char('\0');
678:
679: p = skipsp(p);
1.8 nicm 680: if (*p++ != '=') {
681: lkerr("missing =");
1.5 millert 682: return;
683: }
684:
685: add_cmd_char(EV_OK|A_EXTRA);
686:
687: p = skipsp(p);
1.8 nicm 688: while (*p != '\0') {
1.5 millert 689: s = tstr(&p, 0);
690: add_cmd_str(s);
691: }
692: add_cmd_char('\0');
693: }
694:
695: /*
696: * Parse a line from the lesskey file.
697: */
1.8 nicm 698: void
699: parse_line(char *line)
1.5 millert 700: {
701: char *p;
702:
703: /*
704: * See if it is a control line.
705: */
706: if (control_line(line))
707: return;
708: /*
709: * Skip leading white space.
710: * Replace the final newline with a null byte.
711: * Ignore blank lines and comments.
712: */
713: p = clean_line(line);
714: if (*p == '\0')
715: return;
716:
717: if (currtable == &vartable)
718: parse_varline(p);
719: else
720: parse_cmdline(p);
721: }
722:
1.8 nicm 723: int
724: main(int argc, char **argv)
1.1 etheisen 725: {
726: FILE *desc;
727: FILE *out;
1.5 millert 728: char line[1024];
729:
1.1 etheisen 730: /*
731: * Process command line arguments.
732: */
733: parse_args(argc, argv);
734: init_tables();
735:
736: /*
737: * Open the input file.
738: */
739: if (strcmp(infile, "-") == 0)
740: desc = stdin;
1.8 nicm 741: else if ((desc = fopen(infile, "r")) == NULL) {
1.1 etheisen 742: perror(infile);
1.5 millert 743: usage();
1.1 etheisen 744: }
745:
746: /*
747: * Read and parse the input file, one line at a time.
748: */
749: errors = 0;
750: linenum = 0;
1.8 nicm 751: while (fgets(line, sizeof (line), desc) != NULL) {
1.1 etheisen 752: ++linenum;
753: parse_line(line);
754: }
755:
756: /*
757: * Write the output file.
758: * If no output file was specified, use "$HOME/.less"
759: */
1.8 nicm 760: if (errors > 0) {
761: (void) fprintf(stderr, "%d errors; no output produced\n",
762: errors);
1.1 etheisen 763: exit(1);
764: }
765:
766: if (outfile == NULL)
1.5 millert 767: outfile = getenv("LESSKEY");
768: if (outfile == NULL)
1.1 etheisen 769: outfile = homefile(LESSKEYFILE);
1.8 nicm 770: if ((out = fopen(outfile, "wb")) == NULL) {
1.1 etheisen 771: perror(outfile);
772: exit(1);
773: }
774:
775: /* File header */
1.8 nicm 776: fputbytes(out, fileheader, sizeof (fileheader));
1.1 etheisen 777:
778: /* Command key section */
1.8 nicm 779: fputbytes(out, cmdsection, sizeof (cmdsection));
1.1 etheisen 780: fputint(out, cmdtable.pbuffer - cmdtable.buffer);
1.8 nicm 781: fputbytes(out, (char *)cmdtable.buffer,
782: cmdtable.pbuffer-cmdtable.buffer);
783:
1.1 etheisen 784: /* Edit key section */
1.8 nicm 785: fputbytes(out, editsection, sizeof (editsection));
1.1 etheisen 786: fputint(out, edittable.pbuffer - edittable.buffer);
1.8 nicm 787: fputbytes(out, (char *)edittable.buffer,
788: edittable.pbuffer-edittable.buffer);
1.1 etheisen 789:
1.5 millert 790: /* Environment variable section */
1.8 nicm 791: fputbytes(out, varsection, sizeof (varsection));
1.5 millert 792: fputint(out, vartable.pbuffer - vartable.buffer);
1.8 nicm 793: fputbytes(out, (char *)vartable.buffer,
794: vartable.pbuffer-vartable.buffer);
1.5 millert 795:
1.1 etheisen 796: /* File trailer */
1.8 nicm 797: fputbytes(out, endsection, sizeof (endsection));
798: fputbytes(out, filetrailer, sizeof (filetrailer));
1.5 millert 799: return (0);
1.1 etheisen 800: }