This is lesskey.c in view mode; [Download] [Up]
/* * 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 <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 preceeded by ^ to specify a * control character (e.g. ^X means control-X). * 3. Any character (other than an octal digit) preceeded by * a \ to specify the character itself (characters which * must be preceeded by \ include ^, \, and whitespace. * 4. A backslash followed by one to three octal digits * to specify a character by its octal value. * "action" is the name of a "less" action, from the table below. * * Blank lines and lines which start with # are ignored. * * * The output file is a non-ascii file, consisting of * zero or more byte sequences of the form: * string <0> <action> * * "string" is the command string. * "<0>" is one null byte. * "<action>" is one byte containing the action code (the A_xxx value). * * * Revision history * * v1: Initial version. 10/13/87 mark */ #include <stdio.h> #include "less.h" #include "cmd.h" char usertable[MAX_USERCMD]; struct cmdname { char *cn_name; int cn_action; } cmdnames[] = { "back-line", A_B_LINE, "back-screen", A_B_SCREEN, "back-scroll", A_B_SCROLL, "back-search", A_B_SEARCH, "debug", A_DEBUG, "display-flag", A_DISP_OPTION, "display-option", A_DISP_OPTION, "end", A_GOEND, "examine", A_EXAMINE, "first-cmd", A_FIRSTCMD, "firstcmd", A_FIRSTCMD, "flush-repaint", A_FREPAINT, "forw-line", A_F_LINE, "forw-screen", A_F_SCREEN, "forw-scroll", A_F_SCROLL, "forw-search", A_F_SEARCH, "goto-end", A_GOEND, "goto-line", A_GOLINE, "goto-mark", A_GOMARK, "help", A_HELP, "invalid", A_NOACTION, "next-file", A_NEXT_FILE, "noaction", A_NOACTION, "percent", A_PERCENT, "prev-file", A_PREV_FILE, "quit", A_QUIT, "repaint", A_REPAINT, "repaint-flush", A_FREPAINT, "repeat-search", A_AGAIN_SEARCH, "set-mark", A_SETMARK, "shell", A_SHELL, "status", A_STAT, "toggle-flag", A_TOGGLE_OPTION, "toggle-option", A_TOGGLE_OPTION, "version", A_VERSION, "visual", A_VISUAL, NULL, 0 }; main(argc, argv) int argc; char *argv[]; { char *p; /* {{ Can't be register since we use &p }} */ register char *up; /* Pointer into usertable */ FILE *desc; /* Description file (input) */ FILE *out; /* Output file */ int linenum; /* Line number in input file */ char *currcmd; /* Start of current command string */ int errors; int i; char line[100]; char *outfile; extern char *getenv(); /* * Process command line arguments. */ outfile = NULL; while (--argc > 0 && **(++argv) == '-') { switch (argv[0][1]) { case 'o': outfile = &argv[0][2]; if (*outfile == '\0') { if (--argc <= 0) usage(); outfile = *(++argv); } break; default: usage(); } } if (argc > 1) usage(); /* * Open the input file, or use standard input if none specified. */ if (argc > 0) { if ((desc = fopen(*argv, "r")) == NULL) { perror(*argv); exit(1); } } else desc = stdin; /* * Read the input file, one line at a time. * Each line consists of a command string, * followed by white space, followed by an action name. */ linenum = 0; errors = 0; up = usertable; while (fgets(line, sizeof(line), desc) != NULL) { ++linenum; /* * Skip leading white space. * Replace the final newline with a null byte. * Ignore blank lines and comment lines. */ p = line; while (*p == ' ' || *p == '\t') ++p; for (i = 0; p[i] != '\n' && p[i] != '\0'; i++) ; p[i] = '\0'; if (*p == '#' || *p == '\0') continue; /* * Parse the command string and store it in the usertable. */ currcmd = up; do { if (up >= usertable + MAX_USERCMD) { fprintf(stderr, "too many commands, line %d\n", linenum); exit(1); } if (up >= currcmd + MAX_CMDLEN) { fprintf(stderr, "command too long on line %d\n", linenum); errors++; break; } *up++ = tchar(&p); } while (*p != ' ' && *p != '\t' && *p != '\0'); /* * Terminate the command string with a null byte. */ *up++ = '\0'; /* * Skip white space between the command string * and the action name. * Terminate the action name if it is followed * by whitespace or a # comment. */ if (*p == '\0') { fprintf(stderr, "missing whitespace on line %d\n", linenum); errors++; continue; } while (*p == ' ' || *p == '\t') ++p; for (i = 0; p[i] != ' ' && p[i] != '\t' && p[i] != '#' && p[i] != '\0'; i++) ; p[i] = '\0'; /* * Parse the action name and store it in the usertable. */ for (i = 0; cmdnames[i].cn_name != NULL; i++) if (strcmp(cmdnames[i].cn_name, p) == 0) break; if (cmdnames[i].cn_name == NULL) { fprintf(stderr, "unknown action <%s> on line %d\n", p, linenum); errors++; continue; } *up++ = cmdnames[i].cn_action; } if (errors > 0) { fprintf(stderr, "%d errors; no output produced\n", errors); exit(1); } /* * Write the output file. * If no output file was specified, use "$HOME/.less" */ if (outfile == NULL) { p = getenv("HOME"); if (p == NULL) { fprintf(stderr, "cannot find $HOME\n"); exit(1); } strcpy(line, p); strcat(line, "/.less"); outfile = line; } if ((out = fopen(outfile, "w")) == NULL) perror(outfile); else fwrite((char *)usertable, 1, up-usertable, out); } /* * Parse one character of the command string. */ tchar(pp) char **pp; { register char *p; register char ch; register int i; p = *pp; switch (*p) { case '\\': if (*++p >= '0' && *p <= '7') { /* * Parse an octal number. */ ch = 0; i = 0; do ch = 8*ch + (*p - '0'); while (*++p >= '0' && *p <= '7' && ++i < 3); *pp = p; return (ch); } /* * Backslash followed by a char just means that char. */ *pp = p+1; return (*p); case '^': /* * Carat means CONTROL. */ *pp = p+2; return (CONTROL(p[1])); } *pp = p+1; return (*p); } usage() { fprintf(stderr, "usage: lesskey [-o output] [input]\n"); exit(1); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.