~ubuntu-branches/ubuntu/quantal/less/quantal

« back to all changes in this revision

Viewing changes to decode.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Schoepf
  • Date: 2002-04-04 16:43:52 UTC
  • Revision ID: james.westby@ubuntu.com-20020404164352-qldq048yoc7x5sd5
Tags: upstream-374
ImportĀ upstreamĀ versionĀ 374

Show diffs side-by-side

added added

removed removed

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