Annotation of src/usr.bin/less/lesskey.c, Revision 1.1.1.2
1.1 etheisen 1: /*
1.1.1.2 ! millert 2: * Copyright (C) 1984-2002 Mark Nudelman
1.1 etheisen 3: *
1.1.1.2 ! millert 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.
! 6: *
! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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.1.1.2 ! 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;
228:
229: pathname = calloc(strlen(dirname) + strlen(filename) + 2, sizeof(char));
230: strcpy(pathname, dirname);
1.1.1.2 ! millert 231: strcat(pathname, PATHNAME_SEP);
1.1 etheisen 232: strcat(pathname, filename);
233: return (pathname);
234: }
235:
236: /*
237: * Figure out the name of a default file (in the user's HOME directory).
238: */
239: char *
240: homefile(filename)
241: char *filename;
242: {
243: char *p;
244: char *pathname;
245:
246: if ((p = getenv("HOME")) != NULL && *p != '\0')
247: pathname = mkpathname(p, filename);
248: #if OS2
249: else if ((p = getenv("INIT")) != NULL && *p != '\0')
250: pathname = mkpathname(p, filename);
251: #endif
252: else
253: {
254: fprintf(stderr, "cannot find $HOME - using current directory\n");
255: pathname = mkpathname(".", filename);
256: }
257: return (pathname);
258: }
259:
260: /*
261: * Parse command line arguments.
262: */
263: void
264: parse_args(argc, argv)
265: int argc;
266: char **argv;
267: {
1.1.1.2 ! millert 268: char *arg;
! 269:
1.1 etheisen 270: outfile = NULL;
1.1.1.2 ! millert 271: while (--argc > 0)
1.1 etheisen 272: {
1.1.1.2 ! millert 273: arg = *++argv;
! 274: if (arg[0] != '-')
! 275: /* Arg does not start with "-"; it's not an option. */
! 276: break;
! 277: if (arg[1] == '\0')
! 278: /* "-" means standard input. */
! 279: break;
! 280: if (arg[1] == '-' && arg[2] == '\0')
! 281: {
! 282: /* "--" means end of options. */
! 283: argc--;
! 284: argv++;
! 285: break;
! 286: }
! 287: switch (arg[1])
1.1 etheisen 288: {
1.1.1.2 ! millert 289: case '-':
! 290: if (strncmp(arg, "--output", 8) == 0)
! 291: {
! 292: if (arg[8] == '\0')
! 293: outfile = &arg[8];
! 294: else if (arg[8] == '=')
! 295: outfile = &arg[9];
! 296: else
! 297: usage();
! 298: goto opt_o;
! 299: }
! 300: if (strcmp(arg, "--version") == 0)
! 301: {
! 302: goto opt_V;
! 303: }
! 304: usage();
! 305: break;
1.1 etheisen 306: case 'o':
307: outfile = &argv[0][2];
1.1.1.2 ! millert 308: opt_o:
1.1 etheisen 309: if (*outfile == '\0')
310: {
311: if (--argc <= 0)
312: usage();
313: outfile = *(++argv);
314: }
315: break;
316: case 'V':
1.1.1.2 ! millert 317: opt_V:
1.1 etheisen 318: printf("lesskey version %s\n", version);
319: exit(0);
320: default:
321: usage();
322: }
323: }
324: if (argc > 1)
325: usage();
326: /*
327: * Open the input file, or use DEF_LESSKEYINFILE if none specified.
328: */
329: if (argc > 0)
330: infile = *argv;
331: else
332: infile = homefile(DEF_LESSKEYINFILE);
333: }
334:
335: /*
336: * Initialize data structures.
337: */
338: void
339: init_tables()
340: {
341: cmdtable.names = cmdnames;
342: cmdtable.pbuffer = cmdtable.buffer;
343:
344: edittable.names = editnames;
345: edittable.pbuffer = edittable.buffer;
1.1.1.2 ! millert 346:
! 347: vartable.names = NULL;
! 348: vartable.pbuffer = vartable.buffer;
1.1 etheisen 349: }
350:
351: /*
352: * Parse one character of a string.
353: */
1.1.1.2 ! millert 354: char *
! 355: tstr(pp, xlate)
1.1 etheisen 356: char **pp;
1.1.1.2 ! millert 357: int xlate;
1.1 etheisen 358: {
359: register char *p;
360: register char ch;
361: register int i;
1.1.1.2 ! millert 362: static char buf[10];
! 363: static char tstr_control_k[] =
! 364: { SK_SPECIAL_KEY, SK_CONTROL_K, 6, 1, 1, 1, '\0' };
1.1 etheisen 365:
366: p = *pp;
367: switch (*p)
368: {
369: case '\\':
370: ++p;
371: switch (*p)
372: {
373: case '0': case '1': case '2': case '3':
374: case '4': case '5': case '6': case '7':
375: /*
376: * Parse an octal number.
377: */
378: ch = 0;
379: i = 0;
380: do
381: ch = 8*ch + (*p - '0');
382: while (*++p >= '0' && *p <= '7' && ++i < 3);
383: *pp = p;
1.1.1.2 ! millert 384: if (xlate && ch == CONTROL('K'))
! 385: return tstr_control_k;
! 386: buf[0] = ch;
! 387: buf[1] = '\0';
! 388: return (buf);
1.1 etheisen 389: case 'b':
390: *pp = p+1;
1.1.1.2 ! millert 391: return ("\b");
1.1 etheisen 392: case 'e':
393: *pp = p+1;
1.1.1.2 ! millert 394: buf[0] = ESC;
! 395: buf[1] = '\0';
! 396: return (buf);
1.1 etheisen 397: case 'n':
398: *pp = p+1;
1.1.1.2 ! millert 399: return ("\n");
1.1 etheisen 400: case 'r':
401: *pp = p+1;
1.1.1.2 ! millert 402: return ("\r");
1.1 etheisen 403: case 't':
404: *pp = p+1;
1.1.1.2 ! millert 405: return ("\t");
! 406: case 'k':
! 407: if (xlate)
! 408: {
! 409: switch (*++p)
! 410: {
! 411: case 'u': ch = SK_UP_ARROW; break;
! 412: case 'd': ch = SK_DOWN_ARROW; break;
! 413: case 'r': ch = SK_RIGHT_ARROW; break;
! 414: case 'l': ch = SK_LEFT_ARROW; break;
! 415: case 'U': ch = SK_PAGE_UP; break;
! 416: case 'D': ch = SK_PAGE_DOWN; break;
! 417: case 'h': ch = SK_HOME; break;
! 418: case 'e': ch = SK_END; break;
! 419: case 'x': ch = SK_DELETE; break;
! 420: default:
! 421: error("illegal char after \\k");
! 422: *pp = p+1;
! 423: return ("");
! 424: }
! 425: *pp = p+1;
! 426: buf[0] = SK_SPECIAL_KEY;
! 427: buf[1] = ch;
! 428: buf[2] = 6;
! 429: buf[3] = 1;
! 430: buf[4] = 1;
! 431: buf[5] = 1;
! 432: buf[6] = '\0';
! 433: return (buf);
! 434: }
! 435: /* FALLTHRU */
1.1 etheisen 436: default:
437: /*
438: * Backslash followed by any other char
439: * just means that char.
440: */
441: *pp = p+1;
1.1.1.2 ! millert 442: buf[0] = *p;
! 443: buf[1] = '\0';
! 444: if (xlate && buf[0] == CONTROL('K'))
! 445: return tstr_control_k;
! 446: return (buf);
1.1 etheisen 447: }
448: case '^':
449: /*
450: * Carat means CONTROL.
451: */
452: *pp = p+2;
1.1.1.2 ! millert 453: buf[0] = CONTROL(p[1]);
! 454: buf[1] = '\0';
! 455: if (buf[0] == CONTROL('K'))
! 456: return tstr_control_k;
! 457: return (buf);
1.1 etheisen 458: }
459: *pp = p+1;
1.1.1.2 ! millert 460: buf[0] = *p;
! 461: buf[1] = '\0';
! 462: if (xlate && buf[0] == CONTROL('K'))
! 463: return tstr_control_k;
! 464: return (buf);
1.1 etheisen 465: }
466:
467: /*
468: * Skip leading spaces in a string.
469: */
470: public char *
471: skipsp(s)
472: register char *s;
473: {
474: while (*s == ' ' || *s == '\t')
475: s++;
476: return (s);
477: }
478:
479: /*
480: * Skip non-space characters in a string.
481: */
482: public char *
483: skipnsp(s)
484: register char *s;
485: {
486: while (*s != '\0' && *s != ' ' && *s != '\t')
487: s++;
488: return (s);
489: }
490:
491: /*
492: * Clean up an input line:
493: * strip off the trailing newline & any trailing # comment.
494: */
495: char *
496: clean_line(s)
497: char *s;
498: {
499: register int i;
500:
501: s = skipsp(s);
1.1.1.2 ! millert 502: for (i = 0; s[i] != '\n' && s[i] != '\r' && s[i] != '\0'; i++)
1.1 etheisen 503: if (s[i] == '#' && (i == 0 || s[i-1] != '\\'))
504: break;
505: s[i] = '\0';
506: return (s);
507: }
508:
509: /*
510: * Add a byte to the output command table.
511: */
512: void
513: add_cmd_char(c)
514: int c;
515: {
516: if (currtable->pbuffer >= currtable->buffer + MAX_USERCMD)
517: {
518: error("too many commands");
519: exit(1);
520: }
521: *(currtable->pbuffer)++ = c;
522: }
523:
524: /*
1.1.1.2 ! millert 525: * Add a string to the output command table.
! 526: */
! 527: void
! 528: add_cmd_str(s)
! 529: char *s;
! 530: {
! 531: for ( ; *s != '\0'; s++)
! 532: add_cmd_char(*s);
! 533: }
! 534:
! 535: /*
1.1 etheisen 536: * See if we have a special "control" line.
537: */
538: int
539: control_line(s)
540: char *s;
541: {
542: #define PREFIX(str,pat) (strncmp(str,pat,strlen(pat)-1) == 0)
543:
544: if (PREFIX(s, "#line-edit"))
545: {
546: currtable = &edittable;
547: return (1);
548: }
549: if (PREFIX(s, "#command"))
550: {
551: currtable = &cmdtable;
552: return (1);
553: }
1.1.1.2 ! millert 554: if (PREFIX(s, "#env"))
! 555: {
! 556: currtable = &vartable;
! 557: return (1);
! 558: }
1.1 etheisen 559: if (PREFIX(s, "#stop"))
560: {
561: add_cmd_char('\0');
562: add_cmd_char(A_END_LIST);
563: return (1);
564: }
565: return (0);
566: }
567:
568: /*
569: * Output some bytes.
570: */
571: void
572: fputbytes(fd, buf, len)
573: FILE *fd;
574: char *buf;
575: int len;
576: {
577: while (len-- > 0)
578: {
579: fwrite(buf, sizeof(char), 1, fd);
580: buf++;
581: }
582: }
583:
584: /*
585: * Output an integer, in special KRADIX form.
586: */
587: void
588: fputint(fd, val)
589: FILE *fd;
590: unsigned int val;
591: {
592: char c;
593:
594: if (val >= KRADIX*KRADIX)
595: {
596: fprintf(stderr, "error: integer too big (%d > %d)\n",
597: val, KRADIX*KRADIX);
598: exit(1);
599: }
600: c = val % KRADIX;
601: fwrite(&c, sizeof(char), 1, fd);
602: c = val / KRADIX;
603: fwrite(&c, sizeof(char), 1, fd);
604: }
605:
606: /*
607: * Find an action, given the name of the action.
608: */
609: int
610: findaction(actname)
611: char *actname;
612: {
613: int i;
614:
615: for (i = 0; currtable->names[i].cn_name != NULL; i++)
616: if (strcmp(currtable->names[i].cn_name, actname) == 0)
617: return (currtable->names[i].cn_action);
618: error("unknown action");
619: return (A_INVALID);
620: }
621:
622: void
623: error(s)
624: char *s;
625: {
626: fprintf(stderr, "line %d: %s\n", linenum, s);
627: errors++;
628: }
629:
630:
631: void
1.1.1.2 ! millert 632: parse_cmdline(p)
1.1 etheisen 633: char *p;
1.1.1.2 ! millert 634: {
1.1 etheisen 635: int cmdlen;
636: char *actname;
637: int action;
1.1.1.2 ! millert 638: char *s;
! 639: char c;
1.1 etheisen 640:
641: /*
642: * Parse the command string and store it in the current table.
643: */
644: cmdlen = 0;
645: do
646: {
1.1.1.2 ! millert 647: s = tstr(&p, 1);
! 648: cmdlen += strlen(s);
! 649: if (cmdlen > MAX_CMDLEN)
1.1 etheisen 650: error("command too long");
651: else
1.1.1.2 ! millert 652: add_cmd_str(s);
1.1 etheisen 653: } while (*p != ' ' && *p != '\t' && *p != '\0');
654: /*
655: * Terminate the command string with a null byte.
656: */
657: add_cmd_char('\0');
658:
659: /*
660: * Skip white space between the command string
661: * and the action name.
662: * Terminate the action name with a null byte.
663: */
664: p = skipsp(p);
665: if (*p == '\0')
666: {
667: error("missing action");
668: return;
669: }
670: actname = p;
671: p = skipnsp(p);
672: c = *p;
673: *p = '\0';
674:
675: /*
676: * Parse the action name and store it in the current table.
677: */
678: action = findaction(actname);
679:
680: /*
681: * See if an extra string follows the action name.
682: */
683: *p = c;
684: p = skipsp(p);
685: if (*p == '\0')
686: {
687: add_cmd_char(action);
688: } else
689: {
690: /*
691: * OR the special value A_EXTRA into the action byte.
692: * Put the extra string after the action byte.
693: */
694: add_cmd_char(action | A_EXTRA);
695: while (*p != '\0')
1.1.1.2 ! millert 696: add_cmd_str(tstr(&p, 0));
1.1 etheisen 697: add_cmd_char('\0');
698: }
699: }
700:
1.1.1.2 ! millert 701: void
! 702: parse_varline(p)
! 703: char *p;
! 704: {
! 705: char *s;
! 706:
! 707: do
! 708: {
! 709: s = tstr(&p, 0);
! 710: add_cmd_str(s);
! 711: } while (*p != ' ' && *p != '\t' && *p != '=' && *p != '\0');
! 712: /*
! 713: * Terminate the variable name with a null byte.
! 714: */
! 715: add_cmd_char('\0');
! 716:
! 717: p = skipsp(p);
! 718: if (*p++ != '=')
! 719: {
! 720: error("missing =");
! 721: return;
! 722: }
! 723:
! 724: add_cmd_char(EV_OK|A_EXTRA);
! 725:
! 726: p = skipsp(p);
! 727: while (*p != '\0')
! 728: {
! 729: s = tstr(&p, 0);
! 730: add_cmd_str(s);
! 731: }
! 732: add_cmd_char('\0');
! 733: }
! 734:
! 735: /*
! 736: * Parse a line from the lesskey file.
! 737: */
! 738: void
! 739: parse_line(line)
! 740: char *line;
! 741: {
! 742: char *p;
! 743:
! 744: /*
! 745: * See if it is a control line.
! 746: */
! 747: if (control_line(line))
! 748: return;
! 749: /*
! 750: * Skip leading white space.
! 751: * Replace the final newline with a null byte.
! 752: * Ignore blank lines and comments.
! 753: */
! 754: p = clean_line(line);
! 755: if (*p == '\0')
! 756: return;
! 757:
! 758: if (currtable == &vartable)
! 759: parse_varline(p);
! 760: else
! 761: parse_cmdline(p);
! 762: }
! 763:
! 764: int
1.1 etheisen 765: main(argc, argv)
766: int argc;
767: char *argv[];
768: {
769: FILE *desc;
770: FILE *out;
1.1.1.2 ! millert 771: char line[1024];
! 772:
! 773: #ifdef WIN32
! 774: if (getenv("HOME") == NULL)
! 775: {
! 776: /*
! 777: * If there is no HOME environment variable,
! 778: * try the concatenation of HOMEDRIVE + HOMEPATH.
! 779: */
! 780: char *drive = getenv("HOMEDRIVE");
! 781: char *path = getenv("HOMEPATH");
! 782: if (drive != NULL && path != NULL)
! 783: {
! 784: char *env = (char *) calloc(strlen(drive) +
! 785: strlen(path) + 6, sizeof(char));
! 786: strcpy(env, "HOME=");
! 787: strcat(env, drive);
! 788: strcat(env, path);
! 789: putenv(env);
! 790: }
! 791: }
! 792: #endif /* WIN32 */
1.1 etheisen 793:
794: /*
795: * Process command line arguments.
796: */
797: parse_args(argc, argv);
798: init_tables();
799:
800: /*
801: * Open the input file.
802: */
803: if (strcmp(infile, "-") == 0)
804: desc = stdin;
805: else if ((desc = fopen(infile, "r")) == NULL)
806: {
1.1.1.2 ! millert 807: #if HAVE_PERROR
1.1 etheisen 808: perror(infile);
1.1.1.2 ! millert 809: #else
! 810: fprintf(stderr, "Cannot open %s\n", infile);
! 811: #endif
! 812: usage();
1.1 etheisen 813: }
814:
815: /*
816: * Read and parse the input file, one line at a time.
817: */
818: errors = 0;
819: linenum = 0;
820: while (fgets(line, sizeof(line), desc) != NULL)
821: {
822: ++linenum;
823: parse_line(line);
824: }
825:
826: /*
827: * Write the output file.
828: * If no output file was specified, use "$HOME/.less"
829: */
830: if (errors > 0)
831: {
832: fprintf(stderr, "%d errors; no output produced\n", errors);
833: exit(1);
834: }
835:
836: if (outfile == NULL)
1.1.1.2 ! millert 837: outfile = getenv("LESSKEY");
! 838: if (outfile == NULL)
1.1 etheisen 839: outfile = homefile(LESSKEYFILE);
840: if ((out = fopen(outfile, "wb")) == NULL)
841: {
1.1.1.2 ! millert 842: #if HAVE_PERROR
1.1 etheisen 843: perror(outfile);
1.1.1.2 ! millert 844: #else
! 845: fprintf(stderr, "Cannot open %s\n", outfile);
! 846: #endif
1.1 etheisen 847: exit(1);
848: }
849:
850: /* File header */
851: fputbytes(out, fileheader, sizeof(fileheader));
852:
853: /* Command key section */
854: fputbytes(out, cmdsection, sizeof(cmdsection));
855: fputint(out, cmdtable.pbuffer - cmdtable.buffer);
856: fputbytes(out, (char *)cmdtable.buffer, cmdtable.pbuffer-cmdtable.buffer);
857: /* Edit key section */
858: fputbytes(out, editsection, sizeof(editsection));
859: fputint(out, edittable.pbuffer - edittable.buffer);
860: fputbytes(out, (char *)edittable.buffer, edittable.pbuffer-edittable.buffer);
861:
1.1.1.2 ! millert 862: /* Environment variable section */
! 863: fputbytes(out, varsection, sizeof(varsection));
! 864: fputint(out, vartable.pbuffer - vartable.buffer);
! 865: fputbytes(out, (char *)vartable.buffer, vartable.pbuffer-vartable.buffer);
! 866:
1.1 etheisen 867: /* File trailer */
868: fputbytes(out, endsection, sizeof(endsection));
869: fputbytes(out, filetrailer, sizeof(filetrailer));
1.1.1.2 ! millert 870: return (0);
1.1 etheisen 871: }