Annotation of src/usr.bin/less/decode.c, Revision 1.6
1.1 etheisen 1: /*
1.6 ! shadchin 2: * Copyright (C) 1984-2011 Mark Nudelman
1.1 etheisen 3: *
1.4 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.
1.1 etheisen 6: *
1.4 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: * Routines to decode user commands.
14: *
15: * This is all table driven.
16: * A command table is a sequence of command descriptors.
17: * Each command descriptor is a sequence of bytes with the following format:
18: * <c1><c2>...<cN><0><action>
19: * The characters c1,c2,...,cN are the command string; that is,
20: * the characters which the user must type.
21: * It is terminated by a null <0> byte.
22: * The byte after the null byte is the action code associated
23: * with the command string.
24: * If an action byte is OR-ed with A_EXTRA, this indicates
25: * that the option byte is followed by an extra string.
26: *
27: * There may be many command tables.
28: * The first (default) table is built-in.
29: * Other tables are read in from "lesskey" files.
30: * All the tables are linked together and are searched in order.
31: */
32:
33: #include "less.h"
34: #include "cmd.h"
35: #include "lesskey.h"
36:
1.6 ! shadchin 37: extern int erase_char, erase2_char, kill_char;
1.4 millert 38: extern int secure;
1.1 etheisen 39:
1.4 millert 40: #define SK(k) \
41: SK_SPECIAL_KEY, (k), 6, 1, 1, 1
1.1 etheisen 42: /*
43: * Command table is ordered roughly according to expected
44: * frequency of use, so the common commands are near the beginning.
45: */
1.4 millert 46:
1.1 etheisen 47: static unsigned char cmdtable[] =
48: {
49: '\r',0, A_F_LINE,
50: '\n',0, A_F_LINE,
51: 'e',0, A_F_LINE,
52: 'j',0, A_F_LINE,
1.4 millert 53: SK(SK_DOWN_ARROW),0, A_F_LINE,
1.1 etheisen 54: CONTROL('E'),0, A_F_LINE,
55: CONTROL('N'),0, A_F_LINE,
56: 'k',0, A_B_LINE,
57: 'y',0, A_B_LINE,
58: CONTROL('Y'),0, A_B_LINE,
1.4 millert 59: SK(SK_CONTROL_K),0, A_B_LINE,
1.1 etheisen 60: CONTROL('P'),0, A_B_LINE,
1.4 millert 61: SK(SK_UP_ARROW),0, A_B_LINE,
1.1 etheisen 62: 'J',0, A_FF_LINE,
63: 'K',0, A_BF_LINE,
64: 'Y',0, A_BF_LINE,
65: 'd',0, A_F_SCROLL,
66: CONTROL('D'),0, A_F_SCROLL,
67: 'u',0, A_B_SCROLL,
68: CONTROL('U'),0, A_B_SCROLL,
69: ' ',0, A_F_SCREEN,
70: 'f',0, A_F_SCREEN,
71: CONTROL('F'),0, A_F_SCREEN,
72: CONTROL('V'),0, A_F_SCREEN,
1.4 millert 73: SK(SK_PAGE_DOWN),0, A_F_SCREEN,
1.1 etheisen 74: 'b',0, A_B_SCREEN,
75: CONTROL('B'),0, A_B_SCREEN,
76: ESC,'v',0, A_B_SCREEN,
1.4 millert 77: SK(SK_PAGE_UP),0, A_B_SCREEN,
1.1 etheisen 78: 'z',0, A_F_WINDOW,
79: 'w',0, A_B_WINDOW,
1.4 millert 80: ESC,' ',0, A_FF_SCREEN,
1.1 etheisen 81: 'F',0, A_F_FOREVER,
82: 'R',0, A_FREPAINT,
83: 'r',0, A_REPAINT,
84: CONTROL('R'),0, A_REPAINT,
85: CONTROL('L'),0, A_REPAINT,
86: ESC,'u',0, A_UNDO_SEARCH,
87: 'g',0, A_GOLINE,
1.4 millert 88: SK(SK_HOME),0, A_GOLINE,
1.1 etheisen 89: '<',0, A_GOLINE,
90: ESC,'<',0, A_GOLINE,
91: 'p',0, A_PERCENT,
92: '%',0, A_PERCENT,
1.4 millert 93: ESC,'[',0, A_LSHIFT,
94: ESC,']',0, A_RSHIFT,
95: ESC,'(',0, A_LSHIFT,
96: ESC,')',0, A_RSHIFT,
97: SK(SK_RIGHT_ARROW),0, A_RSHIFT,
98: SK(SK_LEFT_ARROW),0, A_LSHIFT,
1.1 etheisen 99: '{',0, A_F_BRACKET|A_EXTRA, '{','}',0,
100: '}',0, A_B_BRACKET|A_EXTRA, '{','}',0,
101: '(',0, A_F_BRACKET|A_EXTRA, '(',')',0,
102: ')',0, A_B_BRACKET|A_EXTRA, '(',')',0,
103: '[',0, A_F_BRACKET|A_EXTRA, '[',']',0,
104: ']',0, A_B_BRACKET|A_EXTRA, '[',']',0,
105: ESC,CONTROL('F'),0, A_F_BRACKET,
106: ESC,CONTROL('B'),0, A_B_BRACKET,
107: 'G',0, A_GOEND,
108: ESC,'>',0, A_GOEND,
109: '>',0, A_GOEND,
1.4 millert 110: SK(SK_END),0, A_GOEND,
1.1 etheisen 111: 'P',0, A_GOPOS,
112:
113: '0',0, A_DIGIT,
114: '1',0, A_DIGIT,
115: '2',0, A_DIGIT,
116: '3',0, A_DIGIT,
117: '4',0, A_DIGIT,
118: '5',0, A_DIGIT,
119: '6',0, A_DIGIT,
120: '7',0, A_DIGIT,
121: '8',0, A_DIGIT,
122: '9',0, A_DIGIT,
1.6 ! shadchin 123: '.',0, A_DIGIT,
1.1 etheisen 124:
125: '=',0, A_STAT,
126: CONTROL('G'),0, A_STAT,
127: ':','f',0, A_STAT,
128: '/',0, A_F_SEARCH,
129: '?',0, A_B_SEARCH,
130: ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0,
131: ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0,
132: 'n',0, A_AGAIN_SEARCH,
133: ESC,'n',0, A_T_AGAIN_SEARCH,
134: 'N',0, A_REVERSE_SEARCH,
135: ESC,'N',0, A_T_REVERSE_SEARCH,
1.6 ! shadchin 136: '&',0, A_FILTER,
1.1 etheisen 137: 'm',0, A_SETMARK,
138: '\'',0, A_GOMARK,
139: CONTROL('X'),CONTROL('X'),0, A_GOMARK,
140: 'E',0, A_EXAMINE,
141: ':','e',0, A_EXAMINE,
142: CONTROL('X'),CONTROL('V'),0, A_EXAMINE,
143: ':','n',0, A_NEXT_FILE,
144: ':','p',0, A_PREV_FILE,
1.4 millert 145: 't',0, A_NEXT_TAG,
146: 'T',0, A_PREV_TAG,
1.1 etheisen 147: ':','x',0, A_INDEX_FILE,
1.4 millert 148: ':','d',0, A_REMOVE_FILE,
1.1 etheisen 149: '-',0, A_OPT_TOGGLE,
150: ':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0,
151: 's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0,
152: '_',0, A_DISP_OPTION,
153: '|',0, A_PIPE,
154: 'v',0, A_VISUAL,
155: '!',0, A_SHELL,
156: '+',0, A_FIRSTCMD,
157:
158: 'H',0, A_HELP,
159: 'h',0, A_HELP,
1.4 millert 160: SK(SK_F1),0, A_HELP,
1.1 etheisen 161: 'V',0, A_VERSION,
162: 'q',0, A_QUIT,
1.4 millert 163: 'Q',0, A_QUIT,
1.1 etheisen 164: ':','q',0, A_QUIT,
165: ':','Q',0, A_QUIT,
166: 'Z','Z',0, A_QUIT
167: };
168:
169: static unsigned char edittable[] =
170: {
1.4 millert 171: '\t',0, EC_F_COMPLETE, /* TAB */
172: '\17',0, EC_B_COMPLETE, /* BACKTAB */
173: SK(SK_BACKTAB),0, EC_B_COMPLETE, /* BACKTAB */
174: ESC,'\t',0, EC_B_COMPLETE, /* ESC TAB */
175: CONTROL('L'),0, EC_EXPAND, /* CTRL-L */
176: CONTROL('V'),0, EC_LITERAL, /* BACKSLASH */
177: CONTROL('A'),0, EC_LITERAL, /* BACKSLASH */
178: ESC,'l',0, EC_RIGHT, /* ESC l */
179: SK(SK_RIGHT_ARROW),0, EC_RIGHT, /* RIGHTARROW */
180: ESC,'h',0, EC_LEFT, /* ESC h */
181: SK(SK_LEFT_ARROW),0, EC_LEFT, /* LEFTARROW */
182: ESC,'b',0, EC_W_LEFT, /* ESC b */
183: ESC,SK(SK_LEFT_ARROW),0, EC_W_LEFT, /* ESC LEFTARROW */
184: SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */
185: ESC,'w',0, EC_W_RIGHT, /* ESC w */
186: ESC,SK(SK_RIGHT_ARROW),0, EC_W_RIGHT, /* ESC RIGHTARROW */
187: SK(SK_CTL_RIGHT_ARROW),0, EC_W_RIGHT, /* CTRL-RIGHTARROW */
188: ESC,'i',0, EC_INSERT, /* ESC i */
189: SK(SK_INSERT),0, EC_INSERT, /* INSERT */
190: ESC,'x',0, EC_DELETE, /* ESC x */
191: SK(SK_DELETE),0, EC_DELETE, /* DELETE */
192: ESC,'X',0, EC_W_DELETE, /* ESC X */
193: ESC,SK(SK_DELETE),0, EC_W_DELETE, /* ESC DELETE */
194: SK(SK_CTL_DELETE),0, EC_W_DELETE, /* CTRL-DELETE */
195: SK(SK_CTL_BACKSPACE),0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */
196: ESC,'\b',0, EC_W_BACKSPACE, /* ESC BACKSPACE */
197: ESC,'0',0, EC_HOME, /* ESC 0 */
198: SK(SK_HOME),0, EC_HOME, /* HOME */
199: ESC,'$',0, EC_END, /* ESC $ */
200: SK(SK_END),0, EC_END, /* END */
201: ESC,'k',0, EC_UP, /* ESC k */
202: SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */
203: ESC,'j',0, EC_DOWN, /* ESC j */
204: SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */
1.6 ! shadchin 205: CONTROL('G'),0, EC_ABORT, /* CTRL-G */
1.1 etheisen 206: };
207:
208: /*
209: * Structure to support a list of command tables.
210: */
211: struct tablelist
212: {
213: struct tablelist *t_next;
214: char *t_start;
215: char *t_end;
216: };
217:
218: /*
219: * List of command tables and list of line-edit tables.
220: */
221: static struct tablelist *list_fcmd_tables = NULL;
222: static struct tablelist *list_ecmd_tables = NULL;
1.4 millert 223: static struct tablelist *list_var_tables = NULL;
224: static struct tablelist *list_sysvar_tables = NULL;
1.1 etheisen 225:
226:
227: /*
1.4 millert 228: * Expand special key abbreviations in a command table.
229: */
230: static void
231: expand_special_keys(table, len)
232: char *table;
233: int len;
234: {
235: register char *fm;
236: register char *to;
237: register int a;
238: char *repl;
239: int klen;
240:
241: for (fm = table; fm < table + len; )
242: {
243: /*
244: * Rewrite each command in the table with any
245: * special key abbreviations expanded.
246: */
247: for (to = fm; *fm != '\0'; )
248: {
249: if (*fm != SK_SPECIAL_KEY)
250: {
251: *to++ = *fm++;
252: continue;
253: }
254: /*
255: * After SK_SPECIAL_KEY, next byte is the type
256: * of special key (one of the SK_* contants),
257: * and the byte after that is the number of bytes,
258: * N, reserved by the abbreviation (including the
259: * SK_SPECIAL_KEY and key type bytes).
260: * Replace all N bytes with the actual bytes
261: * output by the special key on this terminal.
262: */
263: repl = special_key_str(fm[1]);
264: klen = fm[2] & 0377;
265: fm += klen;
266: if (repl == NULL || (int) strlen(repl) > klen)
267: repl = "\377";
268: while (*repl != '\0')
269: *to++ = *repl++;
270: }
271: *to++ = '\0';
272: /*
273: * Fill any unused bytes between end of command and
274: * the action byte with A_SKIP.
275: */
276: while (to <= fm)
277: *to++ = A_SKIP;
278: fm++;
279: a = *fm++ & 0377;
280: if (a & A_EXTRA)
281: {
282: while (*fm++ != '\0')
283: continue;
284: }
285: }
286: }
287:
288: /*
1.1 etheisen 289: * Initialize the command lists.
290: */
291: public void
292: init_cmds()
293: {
294: /*
295: * Add the default command tables.
296: */
297: add_fcmd_table((char*)cmdtable, sizeof(cmdtable));
298: add_ecmd_table((char*)edittable, sizeof(edittable));
299: #if USERFILE
300: /*
1.4 millert 301: * For backwards compatibility,
302: * try to add tables in the OLD system lesskey file.
303: */
304: #ifdef BINDIR
305: add_hometable(NULL, BINDIR "/.sysless", 1);
306: #endif
307: /*
308: * Try to add the tables in the system lesskey file.
309: */
310: add_hometable("LESSKEY_SYSTEM", LESSKEYFILE_SYS, 1);
311: /*
1.1 etheisen 312: * Try to add the tables in the standard lesskey file "$HOME/.less".
313: */
1.4 millert 314: add_hometable("LESSKEY", LESSKEYFILE, 0);
1.1 etheisen 315: #endif
316: }
317:
318: /*
1.4 millert 319: * Add a command table.
1.1 etheisen 320: */
321: static int
322: add_cmd_table(tlist, buf, len)
323: struct tablelist **tlist;
324: char *buf;
325: int len;
326: {
1.4 millert 327: register struct tablelist *t;
1.1 etheisen 328:
329: if (len == 0)
330: return (0);
331: /*
332: * Allocate a tablelist structure, initialize it,
333: * and link it into the list of tables.
334: */
335: if ((t = (struct tablelist *)
336: calloc(1, sizeof(struct tablelist))) == NULL)
337: {
338: return (-1);
339: }
1.4 millert 340: expand_special_keys(buf, len);
1.1 etheisen 341: t->t_start = buf;
342: t->t_end = buf + len;
343: t->t_next = *tlist;
344: *tlist = t;
345: return (0);
346: }
347:
348: /*
349: * Add a command table.
350: */
351: public void
352: add_fcmd_table(buf, len)
353: char *buf;
354: int len;
355: {
356: if (add_cmd_table(&list_fcmd_tables, buf, len) < 0)
357: error("Warning: some commands disabled", NULL_PARG);
358: }
359:
360: /*
361: * Add an editing command table.
362: */
363: public void
364: add_ecmd_table(buf, len)
365: char *buf;
366: int len;
367: {
368: if (add_cmd_table(&list_ecmd_tables, buf, len) < 0)
369: error("Warning: some edit commands disabled", NULL_PARG);
370: }
371:
372: /*
1.4 millert 373: * Add an environment variable table.
374: */
375: static void
376: add_var_table(tlist, buf, len)
377: struct tablelist **tlist;
378: char *buf;
379: int len;
380: {
381: if (add_cmd_table(tlist, buf, len) < 0)
382: error("Warning: environment variables from lesskey file unavailable", NULL_PARG);
383: }
384:
385: /*
1.1 etheisen 386: * Search a single command table for the command string in cmd.
387: */
1.4 millert 388: static int
1.1 etheisen 389: cmd_search(cmd, table, endtable, sp)
390: char *cmd;
391: char *table;
392: char *endtable;
393: char **sp;
394: {
1.4 millert 395: register char *p;
396: register char *q;
397: register int a;
1.1 etheisen 398:
1.4 millert 399: *sp = NULL;
1.1 etheisen 400: for (p = table, q = cmd; p < endtable; p++, q++)
401: {
402: if (*p == *q)
403: {
404: /*
405: * Current characters match.
406: * If we're at the end of the string, we've found it.
407: * Return the action code, which is the character
408: * after the null at the end of the string
409: * in the command table.
410: */
411: if (*p == '\0')
412: {
413: a = *++p & 0377;
1.4 millert 414: while (a == A_SKIP)
415: a = *++p & 0377;
1.1 etheisen 416: if (a == A_END_LIST)
417: {
418: /*
419: * We get here only if the original
420: * cmd string passed in was empty ("").
421: * I don't think that can happen,
422: * but just in case ...
423: */
424: return (A_UINVALID);
425: }
426: /*
427: * Check for an "extra" string.
428: */
429: if (a & A_EXTRA)
430: {
431: *sp = ++p;
432: a &= ~A_EXTRA;
1.4 millert 433: }
1.1 etheisen 434: return (a);
435: }
436: } else if (*q == '\0')
437: {
438: /*
439: * Hit the end of the user's command,
440: * but not the end of the string in the command table.
441: * The user's command is incomplete.
442: */
443: return (A_PREFIX);
444: } else
445: {
446: /*
447: * Not a match.
448: * Skip ahead to the next command in the
449: * command table, and reset the pointer
450: * to the beginning of the user's command.
451: */
452: if (*p == '\0' && p[1] == A_END_LIST)
453: {
454: /*
455: * A_END_LIST is a special marker that tells
456: * us to abort the cmd search.
457: */
458: return (A_UINVALID);
459: }
1.4 millert 460: while (*p++ != '\0')
461: continue;
462: while (*p == A_SKIP)
463: p++;
1.1 etheisen 464: if (*p & A_EXTRA)
1.4 millert 465: while (*++p != '\0')
466: continue;
1.1 etheisen 467: q = cmd-1;
468: }
469: }
470: /*
471: * No match found in the entire command table.
472: */
473: return (A_INVALID);
474: }
475:
476: /*
477: * Decode a command character and return the associated action.
478: * The "extra" string, if any, is returned in sp.
479: */
480: static int
481: cmd_decode(tlist, cmd, sp)
482: struct tablelist *tlist;
483: char *cmd;
484: char **sp;
485: {
1.4 millert 486: register struct tablelist *t;
487: register int action = A_INVALID;
1.1 etheisen 488:
489: /*
490: * Search thru all the command tables.
491: * Stop when we find an action which is not A_INVALID.
492: */
493: for (t = tlist; t != NULL; t = t->t_next)
494: {
495: action = cmd_search(cmd, t->t_start, t->t_end, sp);
496: if (action != A_INVALID)
497: break;
498: }
1.4 millert 499: if (action == A_UINVALID)
500: action = A_INVALID;
1.1 etheisen 501: return (action);
502: }
503:
504: /*
505: * Decode a command from the cmdtables list.
506: */
507: public int
508: fcmd_decode(cmd, sp)
509: char *cmd;
510: char **sp;
511: {
512: return (cmd_decode(list_fcmd_tables, cmd, sp));
513: }
514:
515: /*
516: * Decode a command from the edittables list.
517: */
518: public int
519: ecmd_decode(cmd, sp)
520: char *cmd;
521: char **sp;
522: {
523: return (cmd_decode(list_ecmd_tables, cmd, sp));
524: }
525:
1.4 millert 526: /*
527: * Get the value of an environment variable.
528: * Looks first in the lesskey file, then in the real environment.
529: */
530: public char *
531: lgetenv(var)
532: char *var;
533: {
534: int a;
535: char *s;
536:
537: a = cmd_decode(list_var_tables, var, &s);
538: if (a == EV_OK)
539: return (s);
540: s = getenv(var);
541: if (s != NULL && *s != '\0')
542: return (s);
543: a = cmd_decode(list_sysvar_tables, var, &s);
544: if (a == EV_OK)
545: return (s);
546: return (NULL);
547: }
548:
1.1 etheisen 549: #if USERFILE
1.4 millert 550: /*
551: * Get an "integer" from a lesskey file.
552: * Integers are stored in a funny format:
553: * two bytes, low order first, in radix KRADIX.
554: */
1.1 etheisen 555: static int
556: gint(sp)
557: char **sp;
558: {
559: int n;
560:
561: n = *(*sp)++;
562: n += *(*sp)++ * KRADIX;
563: return (n);
564: }
565:
1.4 millert 566: /*
567: * Process an old (pre-v241) lesskey file.
568: */
1.1 etheisen 569: static int
570: old_lesskey(buf, len)
571: char *buf;
572: int len;
573: {
574: /*
575: * Old-style lesskey file.
576: * The file must end with either
577: * ...,cmd,0,action
578: * or ...,cmd,0,action|A_EXTRA,string,0
579: * So the last byte or the second to last byte must be zero.
580: */
581: if (buf[len-1] != '\0' && buf[len-2] != '\0')
582: return (-1);
583: add_fcmd_table(buf, len);
584: return (0);
585: }
586:
1.4 millert 587: /*
588: * Process a new (post-v241) lesskey file.
589: */
1.1 etheisen 590: static int
1.4 millert 591: new_lesskey(buf, len, sysvar)
1.1 etheisen 592: char *buf;
593: int len;
1.4 millert 594: int sysvar;
1.1 etheisen 595: {
596: char *p;
1.4 millert 597: register int c;
598: register int n;
1.1 etheisen 599:
600: /*
601: * New-style lesskey file.
602: * Extract the pieces.
603: */
604: if (buf[len-3] != C0_END_LESSKEY_MAGIC ||
605: buf[len-2] != C1_END_LESSKEY_MAGIC ||
606: buf[len-1] != C2_END_LESSKEY_MAGIC)
607: return (-1);
608: p = buf + 4;
1.4 millert 609: for (;;)
1.1 etheisen 610: {
611: c = *p++;
612: switch (c)
613: {
614: case CMD_SECTION:
615: n = gint(&p);
616: add_fcmd_table(p, n);
617: p += n;
618: break;
619: case EDIT_SECTION:
620: n = gint(&p);
621: add_ecmd_table(p, n);
622: p += n;
623: break;
1.4 millert 624: case VAR_SECTION:
625: n = gint(&p);
626: add_var_table((sysvar) ?
627: &list_sysvar_tables : &list_var_tables, p, n);
628: p += n;
629: break;
1.1 etheisen 630: case END_SECTION:
1.4 millert 631: return (0);
1.1 etheisen 632: default:
1.4 millert 633: /*
634: * Unrecognized section type.
635: */
1.1 etheisen 636: return (-1);
637: }
638: }
639: }
640:
641: /*
642: * Set up a user command table, based on a "lesskey" file.
643: */
644: public int
1.4 millert 645: lesskey(filename, sysvar)
1.1 etheisen 646: char *filename;
1.4 millert 647: int sysvar;
1.1 etheisen 648: {
1.4 millert 649: register char *buf;
650: register POSITION len;
651: register long n;
652: register int f;
1.1 etheisen 653:
1.4 millert 654: if (secure)
655: return (1);
1.1 etheisen 656: /*
657: * Try to open the lesskey file.
658: */
1.4 millert 659: filename = shell_unquote(filename);
1.1 etheisen 660: f = open(filename, OPEN_READ);
1.4 millert 661: free(filename);
1.1 etheisen 662: if (f < 0)
663: return (1);
664:
665: /*
666: * Read the file into a buffer.
667: * We first figure out the size of the file and allocate space for it.
668: * {{ Minimal error checking is done here.
669: * A garbage .less file will produce strange results.
670: * To avoid a large amount of error checking code here, we
671: * rely on the lesskey program to generate a good .less file. }}
672: */
673: len = filesize(f);
674: if (len == NULL_POSITION || len < 3)
675: {
676: /*
677: * Bad file (valid file must have at least 3 chars).
678: */
679: close(f);
680: return (-1);
681: }
682: if ((buf = (char *) calloc((int)len, sizeof(char))) == NULL)
683: {
684: close(f);
685: return (-1);
686: }
1.5 deraadt 687: if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK)
1.1 etheisen 688: {
689: free(buf);
690: close(f);
691: return (-1);
692: }
693: n = read(f, buf, (unsigned int) len);
694: close(f);
695: if (n != len)
696: {
697: free(buf);
698: return (-1);
699: }
700:
701: /*
702: * Figure out if this is an old-style (before version 241)
703: * or new-style lesskey file format.
704: */
705: if (buf[0] != C0_LESSKEY_MAGIC || buf[1] != C1_LESSKEY_MAGIC ||
706: buf[2] != C2_LESSKEY_MAGIC || buf[3] != C3_LESSKEY_MAGIC)
707: return (old_lesskey(buf, (int)len));
1.4 millert 708: return (new_lesskey(buf, (int)len, sysvar));
1.1 etheisen 709: }
710:
711: /*
712: * Add the standard lesskey file "$HOME/.less"
713: */
714: public void
1.4 millert 715: add_hometable(envname, def_filename, sysvar)
716: char *envname;
717: char *def_filename;
718: int sysvar;
1.1 etheisen 719: {
720: char *filename;
721: PARG parg;
722:
1.4 millert 723: if (envname != NULL && (filename = lgetenv(envname)) != NULL)
724: filename = save(filename);
725: else if (sysvar)
726: filename = save(def_filename);
727: else
728: filename = homefile(def_filename);
1.1 etheisen 729: if (filename == NULL)
730: return;
1.4 millert 731: if (lesskey(filename, sysvar) < 0)
1.1 etheisen 732: {
733: parg.p_string = filename;
734: error("Cannot use lesskey file \"%s\"", &parg);
735: }
736: free(filename);
737: }
738: #endif
739:
740: /*
741: * See if a char is a special line-editing command.
742: */
743: public int
744: editchar(c, flags)
745: int c;
746: int flags;
747: {
748: int action;
749: int nch;
750: char *s;
751: char usercmd[MAX_CMDLEN+1];
752:
753: /*
754: * An editing character could actually be a sequence of characters;
755: * for example, an escape sequence sent by pressing the uparrow key.
756: * To match the editing string, we use the command decoder
757: * but give it the edit-commands command table
758: * This table is constructed to match the user's keyboard.
759: */
1.6 ! shadchin 760: if (c == erase_char || c == erase2_char)
1.1 etheisen 761: return (EC_BACKSPACE);
762: if (c == kill_char)
763: return (EC_LINEKILL);
764:
765: /*
766: * Collect characters in a buffer.
767: * Start with the one we have, and get more if we need them.
768: */
769: nch = 0;
770: do {
771: if (nch > 0)
772: c = getcc();
773: usercmd[nch] = c;
774: usercmd[nch+1] = '\0';
775: nch++;
776: action = ecmd_decode(usercmd, &s);
777: } while (action == A_PREFIX);
778:
1.4 millert 779: if (flags & EC_NORIGHTLEFT)
780: {
781: switch (action)
782: {
783: case EC_RIGHT:
784: case EC_LEFT:
785: action = A_INVALID;
786: break;
787: }
788: }
789: #if CMD_HISTORY
1.1 etheisen 790: if (flags & EC_NOHISTORY)
791: {
792: /*
793: * The caller says there is no history list.
794: * Reject any history-manipulation action.
795: */
796: switch (action)
797: {
798: case EC_UP:
799: case EC_DOWN:
800: action = A_INVALID;
801: break;
802: }
803: }
1.4 millert 804: #endif
805: #if TAB_COMPLETE_FILENAME
1.1 etheisen 806: if (flags & EC_NOCOMPLETE)
807: {
808: /*
809: * The caller says we don't want any filename completion cmds.
810: * Reject them.
811: */
812: switch (action)
813: {
814: case EC_F_COMPLETE:
815: case EC_B_COMPLETE:
816: case EC_EXPAND:
817: action = A_INVALID;
818: break;
819: }
820: }
1.4 millert 821: #endif
1.1 etheisen 822: if ((flags & EC_PEEK) || action == A_INVALID)
823: {
824: /*
825: * We're just peeking, or we didn't understand the command.
826: * Unget all the characters we read in the loop above.
827: * This does NOT include the original character that was
828: * passed in as a parameter.
829: */
1.4 millert 830: while (nch > 1)
831: {
1.1 etheisen 832: ungetcc(usercmd[--nch]);
833: }
834: } else
835: {
836: if (s != NULL)
837: ungetsc(s);
838: }
839: return action;
840: }
841: