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