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