void sprintfs
[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 *
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 23static 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 */
50static 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
127char *cmdendtable = cmdtable + sizeof(cmdtable);
128
129static char usertable[MAX_USERCMD];
130char *userendtable = usertable;
131
132static char kbuf[MAX_CMDLEN+1];
133static char *kp = kbuf;
134
135/*
136 * Decode a command character and return the associated action.
137 */
138 public int
139cmd_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
175noprefix()
176{
177 kp = kbuf;
178}
179
180/*
181 * Search a command table for the current command string (in kbuf).
182 */
183 static int
184cmd_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
234init_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}