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