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);
}
|