move to /usr/old
[unix-history] / usr / src / usr.bin / more / decode.c
CommitLineData
bfe13c81
KB
1/*
2 * Copyright (c) 1988 Mark Nudleman
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
bfe13c81
KB
6 * Redistribution and use in source and binary forms are permitted
7 * provided that the above copyright notice and this paragraph are
8 * duplicated in all such forms and that any documentation,
9 * advertising materials, and other materials related to such
10 * distribution and use acknowledge that the software was developed
a942b40b
KB
11 * by Mark Nudleman and the University of California, Berkeley. The
12 * name of Mark Nudleman or the
bfe13c81
KB
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20#ifndef lint
dd4dee41 21static char sccsid[] = "@(#)decode.c 5.5 (Berkeley) %G%";
bfe13c81
KB
22#endif /* not lint */
23
24/*
25 * Routines to decode user commands.
26 *
27 * This is all table driven.
28 * A command table is a sequence of command descriptors.
29 * Each command descriptor is a sequence of bytes with the following format:
30 * <c1><c2>...<cN><0><action>
31 * The characters c1,c2,...,cN are the command string; that is,
32 * the characters which the user must type.
33 * It is terminated by a null <0> byte.
34 * The byte after the null byte is the action code associated
35 * with the command string.
36 *
37 * The default commands are described by cmdtable.
38 * User-defined commands are read into usertable.
39 */
40
41#include "less.h"
42#include "cmd.h"
43
44/*
45 * Command table is ordered roughly according to expected
46 * frequency of use, so the common commands are near the beginning.
47 */
48static char cmdtable[] =
49{
50 '\r',0, A_F_LINE,
51 '\n',0, A_F_LINE,
52 'e',0, A_F_LINE,
53 'j',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 CONTROL('K'),0, A_B_LINE,
60 CONTROL('P'),0, A_B_LINE,
61 'd',0, A_F_SCROLL,
62 CONTROL('D'),0, A_F_SCROLL,
63 'u',0, A_B_SCROLL,
64 CONTROL('U'),0, A_B_SCROLL,
65 ' ',0, A_F_SCREEN,
66 'f',0, A_F_SCREEN,
67 CONTROL('F'),0, A_F_SCREEN,
68 CONTROL('V'),0, A_F_SCREEN,
69 'b',0, A_B_SCREEN,
70 CONTROL('B'),0, A_B_SCREEN,
71 CONTROL('['),'v',0, A_B_SCREEN,
72 'R',0, A_FREPAINT,
73 'r',0, A_REPAINT,
74 CONTROL('R'),0, A_REPAINT,
75 CONTROL('L'),0, A_REPAINT,
76 'g',0, A_GOLINE,
77 '<',0, A_GOLINE,
78 CONTROL('['),'<',0, A_GOLINE,
79 'p',0, A_PERCENT,
80 '%',0, A_PERCENT,
81 'G',0, A_GOEND,
82 CONTROL('['),'>',0, A_GOEND,
83 '>',0, A_GOEND,
84
85 '0',0, A_DIGIT,
86 '1',0, A_DIGIT,
87 '2',0, A_DIGIT,
88 '3',0, A_DIGIT,
89 '4',0, A_DIGIT,
90 '5',0, A_DIGIT,
91 '6',0, A_DIGIT,
92 '7',0, A_DIGIT,
93 '8',0, A_DIGIT,
94 '9',0, A_DIGIT,
95
96 '=',0, A_STAT,
97 CONTROL('G'),0, A_STAT,
98 '/',0, A_F_SEARCH,
99 '?',0, A_B_SEARCH,
100 'n',0, A_AGAIN_SEARCH,
101 'm',0, A_SETMARK,
102 '\'',0, A_GOMARK,
103 CONTROL('X'),CONTROL('X'),0, A_GOMARK,
104 'E',0, A_EXAMINE,
105 ':','e',0, A_EXAMINE,
106 CONTROL('X'),CONTROL('V'),0, A_EXAMINE,
107 'N',0, A_NEXT_FILE,
108 'P',0, A_PREV_FILE,
109 ':','n',0, A_NEXT_FILE,
110 ':','p',0, A_PREV_FILE,
111 '-',0, A_TOGGLE_OPTION,
112 '_',0, A_DISP_OPTION,
113 'v',0, A_VISUAL,
114 '!',0, A_SHELL,
115 '+',0, A_FIRSTCMD,
116
117 'H',0, A_HELP,
118 'h',0, A_HELP,
bfe13c81
KB
119 'q',0, A_QUIT,
120 ':','q',0, A_QUIT,
121 'Z','Z',0, A_QUIT
122};
123
124char *cmdendtable = cmdtable + sizeof(cmdtable);
125
126static char usertable[MAX_USERCMD];
127char *userendtable = usertable;
128
129static char kbuf[MAX_CMDLEN+1];
130static char *kp = kbuf;
131
132/*
133 * Decode a command character and return the associated action.
134 */
135 public int
136cmd_decode(c)
137 int c;
138{
139 register int action = A_INVALID;
140
141 /*
142 * Append the new command character to the command string in kbuf.
143 */
144 *kp++ = c;
145 *kp = '\0';
146
bfe13c81
KB
147 /*
148 * Look first for any user-defined commands.
149 */
150 action = cmd_search(usertable, userendtable);
bfe13c81
KB
151 /*
152 * If didn't find user-defined command,
153 * try the normal default commands.
154 */
155 if (action == A_INVALID)
156 action = cmd_search(cmdtable, cmdendtable);
157
158 if (action != A_PREFIX)
159 /*
160 * This is not a prefix character.
161 */
162 noprefix();
163
164 return (action);
165}
166
167/*
168 * Indicate that we're not in a prefix command
169 * by resetting the command buffer pointer.
170 */
171 public void
172noprefix()
173{
174 kp = kbuf;
175}
176
177/*
178 * Search a command table for the current command string (in kbuf).
179 */
180 static int
181cmd_search(table, endtable)
182 char *table;
183 char *endtable;
184{
185 register char *p;
186 register char *q;
187
188 for (p = table, q = kbuf; p < endtable; p++, q++)
189 {
190 if (*p == *q)
191 {
192 /*
193 * Current characters match.
194 * If we're at the end of the string, we've found it.
195 * Return the action code, which is the character
196 * after the null at the end of the string
197 * in the command table.
198 */
199 if (*p == '\0')
200 return (p[1]);
201 } else if (*q == '\0')
202 {
203 /*
204 * Hit the end of the user's command,
205 * but not the end of the string in the command table.
206 * The user's command is incomplete.
207 */
208 return (A_PREFIX);
209 } else
210 {
211 /*
212 * Not a match.
213 * Skip ahead to the next command in the
214 * command table, and reset the pointer
215 * to the user's command.
216 */
217 while (*p++ != '\0') ;
218 q = kbuf-1;
219 }
220 }
221 /*
222 * No match found in the entire command table.
223 */
224 return (A_INVALID);
225}
226
227/*
228 * Initialize the user command table.
229 */
230 public void
231init_cmd()
232{
bfe13c81
KB
233 char *homedir;
234 int f;
235 int n;
e60bf546 236 char filename[MAXPATHLEN];
bfe13c81
KB
237 extern char *getenv();
238
239 /*
240 * Try to open "$HOME/.less"
241 * If we can't, return without doing anything.
242 */
243 homedir = getenv("HOME");
244 if (homedir == NULL)
245 return;
e60bf546
KB
246 (void)sprintf(filename, "%s/%s", homedir, ".less");
247 f = open(filename, O_RDONLY);
bfe13c81
KB
248 if (f < 0)
249 return;
250
251 /*
252 * Read the file into the user table.
253 * {{ Minimal error checking is done here.
254 * A garbage .less file will produce strange results.
255 * To avoid a large amount of error checking code here, we
256 * rely on the lesskey program to generate a good .less file. }}
257 */
258 n = read(f, (char *)usertable, MAX_USERCMD);
259 if (n < 3 || usertable[n-2] != '\0')
260 {
261 /*
262 * Several error cases are lumped together here:
263 * - Cannot read user file (n < 0).
264 * - User file is too short (a valid file must
265 * have at least 3 chars: one char command string,
266 * the terminating null byte, and the action byte).
267 * - The final entry in the user file is bad (it
268 * doesn't have a null byte in the proper place).
269 * Many other error cases are not caught, such as
270 * invalid format in any except the last entry,
271 * invalid action codes, command strings too long, etc.
272 */
273 error("invalid user key file");
274 n = 0;
275 }
276 userendtable = usertable + n;
277 close(f);
bfe13c81 278}