-
Notifications
You must be signed in to change notification settings - Fork 0
/
lesskey.c
364 lines (334 loc) · 9.35 KB
/
lesskey.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*
* Copyright (C) 1984-2024 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
*
* For more information, see the README file.
*/
/*
* lesskey [-o output] [input]
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Make a .less file.
* If no input file is specified, standard input is used.
* If no output file is specified, $HOME/.less is used.
*
* The .less file is used to specify (to "less") user-defined
* key bindings. Basically any sequence of 1 to MAX_CMDLEN
* keystrokes may be bound to an existing less function.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* The input file is an ascii file consisting of a
* sequence of lines of the form:
* string <whitespace> action [chars] <newline>
*
* "string" is a sequence of command characters which form
* the new user-defined command. The command
* characters may be:
* 1. The actual character itself.
* 2. A character preceded by ^ to specify a
* control character (e.g. ^X means control-X).
* 3. A backslash followed by one to three octal digits
* to specify a character by its octal value.
* 4. A backslash followed by b, e, n, r or t
* to specify \b, ESC, \n, \r or \t, respectively.
* 5. Any character (other than those mentioned above) preceded
* by a \ to specify the character itself (characters which
* must be preceded by \ include ^, \, and whitespace.
* "action" is the name of a "less" action, from the table below.
* "chars" is an optional sequence of characters which is treated
* as keyboard input after the command is executed.
*
* Blank lines and lines which start with # are ignored,
* except for the special control lines:
* #command Signals the beginning of the command
* keys section.
* #line-edit Signals the beginning of the line-editing
* keys section.
* #env Signals the beginning of the environment
* variable section.
* #stop Stops command parsing in less;
* causes all default keys to be disabled.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* The output file is a non-ascii file, consisting of a header,
* one or more sections, and a trailer.
* Each section begins with a section header, a section length word
* and the section data. Normally there are three sections:
* CMD_SECTION Definition of command keys.
* EDIT_SECTION Definition of editing keys.
* END_SECTION A special section header, with no
* length word or section data.
*
* Section data consists of zero or more byte sequences of the form:
* string <0> <action>
* or
* string <0> <action|A_EXTRA> chars <0>
*
* "string" is the command string.
* "<0>" is one null byte.
* "<action>" is one byte containing the action code (the A_xxx value).
* If action is ORed with A_EXTRA, the action byte is followed
* by the null-terminated "chars" string.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
#include "defines.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "lesskey.h"
#include "cmd.h"
constant char fileheader[] = {
C0_LESSKEY_MAGIC,
C1_LESSKEY_MAGIC,
C2_LESSKEY_MAGIC,
C3_LESSKEY_MAGIC
};
constant char filetrailer[] = {
C0_END_LESSKEY_MAGIC,
C1_END_LESSKEY_MAGIC,
C2_END_LESSKEY_MAGIC
};
constant char cmdsection[1] = { CMD_SECTION };
constant char editsection[1] = { EDIT_SECTION };
constant char varsection[1] = { VAR_SECTION };
constant char endsection[1] = { END_SECTION };
constant char *infile = NULL;
constant char *outfile = NULL;
extern char version[];
static void usage(void)
{
fprintf(stderr, "usage: lesskey [-o output] [input]\n");
exit(1);
}
void lesskey_parse_error(constant char *s)
{
fprintf(stderr, "%s\n", s);
}
int lstrtoi(constant char *buf, constant char **ebuf, int radix)
{
return (int) strtol(buf, (char**)ebuf, radix);
}
void out_of_memory(void)
{
fprintf(stderr, "lesskey: cannot allocate memory\n");
exit(1);
}
void * ecalloc(size_t count, size_t size)
{
void *p;
p = calloc(count, size);
if (p == NULL)
out_of_memory();
return (p);
}
static char * mkpathname(constant char *dirname, constant char *filename)
{
char *pathname;
pathname = ecalloc(strlen(dirname) + strlen(filename) + 2, sizeof(char));
strcpy(pathname, dirname);
strcat(pathname, PATHNAME_SEP);
strcat(pathname, filename);
return (pathname);
}
/*
* Figure out the name of a default file (in the user's HOME directory).
*/
char * homefile(constant char *filename)
{
constant char *p;
char *pathname;
if ((p = getenv("HOME")) != NULL && *p != '\0')
pathname = mkpathname(p, filename);
#if OS2
else if ((p = getenv("INIT")) != NULL && *p != '\0')
pathname = mkpathname(p, filename);
#endif
else
{
fprintf(stderr, "cannot find $HOME - using current directory\n");
pathname = mkpathname(".", filename);
}
return (pathname);
}
/*
* Parse command line arguments.
*/
static void parse_args(int argc, constant char **argv)
{
constant char *arg;
outfile = NULL;
while (--argc > 0)
{
arg = *++argv;
if (arg[0] != '-')
/* Arg does not start with "-"; it's not an option. */
break;
if (arg[1] == '\0')
/* "-" means standard input. */
break;
if (arg[1] == '-' && arg[2] == '\0')
{
/* "--" means end of options. */
argc--;
argv++;
break;
}
switch (arg[1])
{
case '-':
if (strncmp(arg, "--output", 8) == 0)
{
if (arg[8] == '\0')
outfile = &arg[8];
else if (arg[8] == '=')
outfile = &arg[9];
else
usage();
goto opt_o;
}
if (strcmp(arg, "--version") == 0)
{
goto opt_V;
}
usage();
break;
case 'o':
outfile = &argv[0][2];
opt_o:
if (*outfile == '\0')
{
if (--argc <= 0)
usage();
outfile = *(++argv);
}
break;
case 'V':
opt_V:
printf("lesskey version %s\n", version);
exit(0);
default:
usage();
}
}
if (argc > 1)
usage();
/*
* Open the input file, or use DEF_LESSKEYINFILE if none specified.
*/
if (argc > 0)
infile = *argv;
}
/*
* Output some bytes.
*/
static void fputbytes(FILE *fd, constant char *buf, size_t len)
{
while (len-- > 0)
{
fwrite(buf, sizeof(char), 1, fd);
buf++;
}
}
/*
* Output an integer, in special KRADIX form.
*/
static void fputint(FILE *fd, size_t val)
{
char c1, c2;
if (val >= KRADIX*KRADIX)
{
fprintf(stderr, "error: cannot write %ld, max %ld\n",
(long) val, (long) (KRADIX*KRADIX));
exit(1);
}
c1 = (char) (val % KRADIX);
val /= KRADIX;
c2 = (char) (val % KRADIX);
val /= KRADIX;
if (val != 0) {
fprintf(stderr, "error: %ld exceeds max integer size (%ld)\n",
(long) val, (long) (KRADIX*KRADIX));
exit(1);
}
fwrite(&c1, sizeof(char), 1, fd);
fwrite(&c2, sizeof(char), 1, fd);
}
int main(int argc, constant char *argv[])
{
struct lesskey_tables tables;
FILE *out;
int errors;
#ifdef WIN32
if (getenv("HOME") == NULL)
{
/*
* If there is no HOME environment variable,
* try the concatenation of HOMEDRIVE + HOMEPATH.
*/
constant char *drive = getenv("HOMEDRIVE");
constant char *path = getenv("HOMEPATH");
if (drive != NULL && path != NULL)
{
char *env = (char *) ecalloc(strlen(drive) +
strlen(path) + 6, sizeof(char));
strcpy(env, "HOME=");
strcat(env, drive);
strcat(env, path);
putenv(env);
}
}
#endif /* WIN32 */
/*
* Process command line arguments.
*/
parse_args(argc, argv);
errors = parse_lesskey(infile, &tables);
if (errors)
{
fprintf(stderr, "%d errors; no output produced\n", errors);
return (1);
}
fprintf(stderr, "NOTE: lesskey is deprecated.\n It is no longer necessary to run lesskey,\n when using less version 582 and later.\n");
/*
* Write the output file.
* If no output file was specified, use "$HOME/.less"
*/
if (outfile == NULL)
outfile = getenv("LESSKEY");
if (outfile == NULL)
outfile = homefile(LESSKEYFILE);
if ((out = fopen(outfile, "wb")) == NULL)
{
#if HAVE_PERROR
perror(outfile);
#else
fprintf(stderr, "Cannot open %s\n", outfile);
#endif
return (1);
}
/* File header */
fputbytes(out, fileheader, sizeof(fileheader));
/* Command key section */
fputbytes(out, cmdsection, sizeof(cmdsection));
fputint(out, tables.cmdtable.buf.end);
fputbytes(out, xbuf_char_data(&tables.cmdtable.buf), tables.cmdtable.buf.end);
/* Edit key section */
fputbytes(out, editsection, sizeof(editsection));
fputint(out, tables.edittable.buf.end);
fputbytes(out, xbuf_char_data(&tables.edittable.buf), tables.edittable.buf.end);
/* Environment variable section */
fputbytes(out, varsection, sizeof(varsection));
fputint(out, tables.vartable.buf.end);
fputbytes(out, xbuf_char_data(&tables.vartable.buf), tables.vartable.buf.end);
/* File trailer */
fputbytes(out, endsection, sizeof(endsection));
fputbytes(out, filetrailer, sizeof(filetrailer));
fclose(out);
return (0);
}