clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name extend.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/mg/obj -resource-dir /usr/local/lib/clang/13.0.0 -D REGEX -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/mg/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/mg/extend.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | #include <sys/queue.h> |
9 | #include <sys/types.h> |
10 | #include <regex.h> |
11 | #include <ctype.h> |
12 | #include <limits.h> |
13 | #include <signal.h> |
14 | #include <stdio.h> |
15 | #include <stdlib.h> |
16 | #include <string.h> |
17 | |
18 | #include "chrdef.h" |
19 | #include "def.h" |
20 | #include "funmap.h" |
21 | #include "kbd.h" |
22 | #include "key.h" |
23 | #include "macro.h" |
24 | |
25 | static int remap(KEYMAP *, int, PF, KEYMAP *); |
26 | static KEYMAP *reallocmap(KEYMAP *); |
27 | static void fixmap(KEYMAP *, KEYMAP *, KEYMAP *); |
28 | static int dobind(KEYMAP *, const char *, int); |
29 | static char *parsetoken(char *); |
30 | static int bindkey(KEYMAP **, const char *, KCHAR *, int); |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | int |
37 | insert(int f, int n) |
38 | { |
39 | char buf[BUFSIZE], *bufp, *cp; |
40 | int count, c; |
41 | |
42 | if (inmacro) { |
43 | while (--n >= 0) { |
44 | for (count = 0; count < maclcur->l_used; count++) { |
45 | if ((((c = maclcur->l_text[count]) == |
46 | *curbp->b_nlchr) |
47 | ? lnewline() : linsert(1, c)) != TRUE) |
48 | return (FALSE); |
49 | } |
50 | } |
51 | maclcur = maclcur->l_fp; |
52 | return (TRUE); |
53 | } |
54 | if (n == 1) |
55 | |
56 | thisflag |= CFINS; |
57 | |
58 | if ((bufp = eread("Insert: ", buf, sizeof(buf), EFNEW)) == NULL) |
59 | return (ABORT); |
60 | else if (bufp[0] == '\0') |
61 | return (FALSE); |
62 | while (--n >= 0) { |
63 | cp = buf; |
64 | while (*cp) { |
65 | if (((*cp == *curbp->b_nlchr) ? |
66 | lnewline() : linsert(1, *cp)) |
67 | != TRUE) |
68 | return (FALSE); |
69 | cp++; |
70 | } |
71 | } |
72 | return (TRUE); |
73 | } |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | static int |
93 | remap(KEYMAP *curmap, int c, PF funct, KEYMAP *pref_map) |
94 | { |
95 | int i, n1, n2, nold; |
96 | KEYMAP *mp, *newmap; |
97 | PF *pfp; |
98 | struct map_element *mep; |
99 | |
100 | if (ele >= &curmap->map_element[curmap->map_num] || c < ele->k_base) { |
| 11 | | Assuming the condition is false | |
|
| 12 | | Assuming 'c' is >= field 'k_base' | |
|
| |
101 | if (ele > &curmap->map_element[0] && (funct != NULL || |
102 | (ele - 1)->k_prefmap == NULL)) |
103 | n1 = c - (ele - 1)->k_num; |
104 | else |
105 | n1 = HUGE; |
106 | if (ele < &curmap->map_element[curmap->map_num] && |
107 | (funct != NULL || ele->k_prefmap == NULL)) |
108 | n2 = ele->k_base - c; |
109 | else |
110 | n2 = HUGE; |
111 | if (n1 <= MAPELEDEF && n1 <= n2) { |
112 | ele--; |
113 | if ((pfp = calloc(c - ele->k_base + 1, |
114 | sizeof(PF))) == NULL) |
115 | return (dobeep_msg("Out of memory")); |
116 | |
117 | nold = ele->k_num - ele->k_base + 1; |
118 | for (i = 0; i < nold; i++) |
119 | pfp[i] = ele->k_funcp[i]; |
120 | while (--n1) |
121 | pfp[i++] = curmap->map_default; |
122 | pfp[i] = funct; |
123 | ele->k_num = c; |
124 | ele->k_funcp = pfp; |
125 | } else if (n2 <= MAPELEDEF) { |
126 | if ((pfp = calloc(ele->k_num - c + 1, |
127 | sizeof(PF))) == NULL) |
128 | return (dobeep_msg("Out of memory")); |
129 | |
130 | nold = ele->k_num - ele->k_base + 1; |
131 | for (i = 0; i < nold; i++) |
132 | pfp[i + n2] = ele->k_funcp[i]; |
133 | while (--n2) |
134 | pfp[n2] = curmap->map_default; |
135 | pfp[0] = funct; |
136 | ele->k_base = c; |
137 | ele->k_funcp = pfp; |
138 | } else { |
139 | if (curmap->map_num >= curmap->map_max) { |
140 | if ((newmap = reallocmap(curmap)) == NULL) |
141 | return (FALSE); |
142 | curmap = newmap; |
143 | } |
144 | if ((pfp = malloc(sizeof(PF))) == NULL) |
145 | return (dobeep_msg("Out of memory")); |
146 | |
147 | pfp[0] = funct; |
148 | for (mep = &curmap->map_element[curmap->map_num]; |
149 | mep > ele; mep--) { |
150 | mep->k_base = (mep - 1)->k_base; |
151 | mep->k_num = (mep - 1)->k_num; |
152 | mep->k_funcp = (mep - 1)->k_funcp; |
153 | mep->k_prefmap = (mep - 1)->k_prefmap; |
154 | } |
155 | ele->k_base = c; |
156 | ele->k_num = c; |
157 | ele->k_funcp = pfp; |
158 | ele->k_prefmap = NULL; |
159 | curmap->map_num++; |
160 | } |
161 | if (funct == NULL) { |
162 | if (pref_map != NULL) |
163 | ele->k_prefmap = pref_map; |
164 | else { |
165 | if ((mp = malloc(sizeof(KEYMAP) + |
166 | (MAPINIT - 1) * sizeof(struct map_element))) == NULL) { |
167 | (void)dobeep_msg("Out of memory"); |
168 | ele->k_funcp[c - ele->k_base] = |
169 | curmap->map_default; |
170 | return (FALSE); |
171 | } |
172 | mp->map_num = 0; |
173 | mp->map_max = MAPINIT; |
174 | mp->map_default = rescan; |
175 | ele->k_prefmap = mp; |
176 | } |
177 | } |
178 | } else { |
179 | n1 = c - ele->k_base; |
180 | if (ele->k_funcp[n1] == funct && (funct != NULL || |
| 14 | | Assuming the condition is false | |
|
181 | pref_map == NULL || pref_map == ele->k_prefmap)) |
182 | |
183 | return (TRUE); |
184 | if (funct != NULL || ele->k_prefmap == NULL) { |
| 15 | | Assuming field 'k_prefmap' is not equal to NULL | |
|
| |
185 | if (ele->k_funcp[n1] == NULL) |
186 | ele->k_prefmap = NULL; |
187 | |
188 | ele->k_funcp[n1] = funct; |
189 | if (funct == NULL) { |
190 | if (pref_map != NULL) |
191 | ele->k_prefmap = pref_map; |
192 | else { |
193 | if ((mp = malloc(sizeof(KEYMAP) + |
194 | (MAPINIT - 1) * |
195 | sizeof(struct map_element))) == NULL) { |
196 | (void)dobeep_msg("Out of memory"); |
197 | ele->k_funcp[c - ele->k_base] = |
198 | curmap->map_default; |
199 | return (FALSE); |
200 | } |
201 | mp->map_num = 0; |
202 | mp->map_max = MAPINIT; |
203 | mp->map_default = rescan; |
204 | ele->k_prefmap = mp; |
205 | } |
206 | } |
207 | } else { |
208 | |
209 | |
210 | |
211 | |
212 | |
213 | n2 = 1; |
214 | for (i = 0; n2 && i < n1; i++) |
| 17 | | Assuming 'i' is >= 'n1' | |
|
| 18 | | Loop condition is false. Execution continues on line 216 | |
|
215 | n2 &= ele->k_funcp[i] != NULL; |
216 | if (curmap->map_num >= curmap->map_max) { |
| 19 | | Assuming field 'map_num' is >= field 'map_max' | |
|
| |
217 | if ((newmap = reallocmap(curmap)) == NULL) |
| |
| 30 | | Returning from 'reallocmap' | |
|
| |
218 | return (FALSE); |
219 | curmap = newmap; |
220 | } |
221 | if ((pfp = calloc(ele->k_num - c + !n2, |
| 32 | | Assuming the condition is false | |
|
| |
222 | sizeof(PF))) == NULL) |
223 | return (dobeep_msg("Out of memory")); |
224 | |
225 | ele->k_funcp[n1] = NULL; |
226 | for (i = n1 + n2; i <= ele->k_num - ele->k_base; i++) |
| 34 | | Assuming the condition is false | |
|
| 35 | | Loop condition is false. Execution continues on line 228 | |
|
227 | pfp[i - n1 - n2] = ele->k_funcp[i]; |
228 | for (mep = &curmap->map_element[curmap->map_num]; |
| 36 | | Loop condition is true. Entering loop body | |
|
229 | mep > ele; mep--) { |
230 | mep->k_base = (mep - 1)->k_base; |
| 37 | | Assigned value is garbage or undefined |
|
231 | mep->k_num = (mep - 1)->k_num; |
232 | mep->k_funcp = (mep - 1)->k_funcp; |
233 | mep->k_prefmap = (mep - 1)->k_prefmap; |
234 | } |
235 | ele->k_num = c - !n2; |
236 | (ele + 1)->k_base = c + n2; |
237 | (ele + 1)->k_funcp = pfp; |
238 | ele += !n2; |
239 | ele->k_prefmap = NULL; |
240 | curmap->map_num++; |
241 | if (pref_map == NULL) { |
242 | if ((mp = malloc(sizeof(KEYMAP) + (MAPINIT - 1) |
243 | * sizeof(struct map_element))) == NULL) { |
244 | (void)dobeep_msg("Out of memory"); |
245 | ele->k_funcp[c - ele->k_base] = |
246 | curmap->map_default; |
247 | return (FALSE); |
248 | } |
249 | mp->map_num = 0; |
250 | mp->map_max = MAPINIT; |
251 | mp->map_default = rescan; |
252 | ele->k_prefmap = mp; |
253 | } else |
254 | ele->k_prefmap = pref_map; |
255 | } |
256 | } |
257 | return (TRUE); |
258 | } |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | static KEYMAP * |
265 | reallocmap(KEYMAP *curmap) |
266 | { |
267 | struct maps_s *mps; |
268 | KEYMAP *mp; |
269 | int i; |
270 | |
271 | if (curmap->map_max > SHRT_MAX - MAPGROW) { |
| 22 | | Assuming the condition is false | |
|
| |
272 | (void)dobeep_msg("keymap too large"); |
273 | return (NULL); |
274 | } |
275 | if ((mp = malloc(sizeof(KEYMAP) + (curmap->map_max + (MAPGROW - 1)) * |
| 24 | | Uninitialized value stored to field 'k_base' | |
|
| 25 | | Assuming the condition is false | |
|
| |
276 | sizeof(struct map_element))) == NULL) { |
277 | (void)dobeep_msg("Out of memory"); |
278 | return (NULL); |
279 | } |
280 | mp->map_num = curmap->map_num; |
281 | mp->map_max = curmap->map_max + MAPGROW; |
282 | mp->map_default = curmap->map_default; |
283 | for (i = curmap->map_num; i--;) { |
| 27 | | Loop condition is false. Execution continues on line 289 | |
|
284 | mp->map_element[i].k_base = curmap->map_element[i].k_base; |
285 | mp->map_element[i].k_num = curmap->map_element[i].k_num; |
286 | mp->map_element[i].k_funcp = curmap->map_element[i].k_funcp; |
287 | mp->map_element[i].k_prefmap = curmap->map_element[i].k_prefmap; |
288 | } |
289 | for (mps = maps; mps != NULL; mps = mps->p_next) { |
| 28 | | Assuming 'mps' is equal to NULL | |
|
| 29 | | Loop condition is false. Execution continues on line 295 | |
|
290 | if (mps->p_map == curmap) |
291 | mps->p_map = mp; |
292 | else |
293 | fixmap(curmap, mp, mps->p_map); |
294 | } |
295 | ele = &mp->map_element[ele - &curmap->map_element[0]]; |
296 | return (mp); |
297 | } |
298 | |
299 | |
300 | |
301 | |
302 | static void |
303 | fixmap(KEYMAP *curmap, KEYMAP *mp, KEYMAP *mt) |
304 | { |
305 | int i; |
306 | |
307 | for (i = mt->map_num; i--;) { |
308 | if (mt->map_element[i].k_prefmap != NULL) { |
309 | if (mt->map_element[i].k_prefmap == curmap) |
310 | mt->map_element[i].k_prefmap = mp; |
311 | else |
312 | fixmap(curmap, mp, mt->map_element[i].k_prefmap); |
313 | } |
314 | } |
315 | } |
316 | |
317 | |
318 | |
319 | |
320 | |
321 | static int |
322 | dobind(KEYMAP *curmap, const char *p, int unbind) |
323 | { |
324 | KEYMAP *pref_map = NULL; |
325 | PF funct; |
326 | char bprompt[80], *bufp, *pep; |
327 | int c, s, n; |
328 | |
329 | if (macrodef) { |
| 2 | | Assuming 'macrodef' is 0 | |
|
| |
330 | |
331 | |
332 | |
333 | |
334 | return (dobeep_msg("Can't rebind key in macro")); |
335 | } |
336 | if (inmacro) { |
| 4 | | Assuming 'inmacro' is not equal to 0 | |
|
| |
337 | for (s = 0; s < maclcur->l_used - 1; s++) { |
| 6 | | Assuming the condition is true | |
|
| 7 | | Loop condition is true. Entering loop body | |
|
338 | if (doscan(curmap, c = CHARMASK(maclcur->l_text[s]), &curmap) |
| 8 | | Assuming the condition is true | |
|
| |
339 | != NULL) { |
340 | if (remap(curmap, c, NULL, NULL) |
| |
341 | != TRUE) |
342 | return (FALSE); |
343 | } |
344 | } |
345 | (void)doscan(curmap, c = maclcur->l_text[s], NULL); |
346 | maclcur = maclcur->l_fp; |
347 | } else { |
348 | n = strlcpy(bprompt, p, sizeof(bprompt)); |
349 | if (n >= sizeof(bprompt)) |
350 | n = sizeof(bprompt) - 1; |
351 | pep = bprompt + n; |
352 | for (;;) { |
353 | ewprintf("%s", bprompt); |
354 | pep[-1] = ' '; |
355 | pep = getkeyname(pep, sizeof(bprompt) - |
356 | (pep - bprompt), c = getkey(FALSE)); |
357 | if (doscan(curmap, c, &curmap) != NULL) |
358 | break; |
359 | *pep++ = '-'; |
360 | *pep = '\0'; |
361 | } |
362 | } |
363 | if (unbind) |
364 | funct = rescan; |
365 | else { |
366 | if ((bufp = eread("%s to command: ", bprompt, sizeof(bprompt), |
367 | EFFUNC | EFNEW, bprompt)) == NULL) |
368 | return (ABORT); |
369 | else if (bufp[0] == '\0') |
370 | return (FALSE); |
371 | if (((funct = name_function(bprompt)) == NULL) ? |
372 | (pref_map = name_map(bprompt)) == NULL : funct == NULL) |
373 | return (dobeep_msg("[No match]")); |
374 | |
375 | } |
376 | return (remap(curmap, c, funct, pref_map)); |
377 | } |
378 | |
379 | |
380 | |
381 | |
382 | |
383 | |
384 | |
385 | static int |
386 | bindkey(KEYMAP **mapp, const char *fname, KCHAR *keys, int kcount) |
387 | { |
388 | KEYMAP *curmap = *mapp; |
389 | KEYMAP *pref_map = NULL; |
390 | PF funct; |
391 | int c; |
392 | |
393 | if (fname == NULL) |
394 | funct = rescan; |
395 | else if (((funct = name_function(fname)) == NULL) ? |
396 | (pref_map = name_map(fname)) == NULL : funct == NULL) { |
397 | dobeep(); |
398 | ewprintf("[No match: %s]", fname); |
399 | return (FALSE); |
400 | } |
401 | while (--kcount) { |
402 | if (doscan(curmap, c = *keys++, &curmap) != NULL) { |
403 | if (remap(curmap, c, NULL, NULL) != TRUE) |
404 | return (FALSE); |
405 | |
406 | |
407 | |
408 | |
409 | curmap = ele->k_prefmap; |
410 | } |
411 | } |
412 | (void)doscan(curmap, c = *keys, NULL); |
413 | return (remap(curmap, c, funct, pref_map)); |
414 | } |
415 | |
416 | |
417 | |
418 | |
419 | int |
420 | dobindkey(KEYMAP *map, const char *func, const char *str) |
421 | { |
422 | int i; |
423 | |
424 | for (i = 0; *str && i < MAXKEY; i++) { |
425 | |
426 | if (*str == '^' && *(str + 1) != '\0') { |
427 | key.k_chars[i] = CCHR(toupper((unsigned char)*++str)); |
428 | } else if (*str == '\\' && *(str + 1) != '\0') { |
429 | switch (*++str) { |
430 | case '^': |
431 | key.k_chars[i] = '^'; |
432 | break; |
433 | case 't': |
434 | case 'T': |
435 | key.k_chars[i] = '\t'; |
436 | break; |
437 | case 'n': |
438 | case 'N': |
439 | key.k_chars[i] = *curbp->b_nlchr; |
440 | break; |
441 | case 'r': |
442 | case 'R': |
443 | key.k_chars[i] = '\r'; |
444 | break; |
445 | case 'e': |
446 | case 'E': |
447 | key.k_chars[i] = CCHR('['); |
448 | break; |
449 | case '\\': |
450 | key.k_chars[i] = '\\'; |
451 | break; |
452 | } |
453 | } else |
454 | key.k_chars[i] = *str; |
455 | str++; |
456 | } |
457 | key.k_count = i; |
458 | return (bindkey(&map, func, key.k_chars, key.k_count)); |
459 | } |
460 | |
461 | |
462 | |
463 | |
464 | |
465 | int |
466 | bindtokey(int f, int n) |
467 | { |
468 | return (dobind(fundamental_map, "Global set key: ", FALSE)); |
469 | } |
470 | |
471 | |
472 | |
473 | |
474 | |
475 | int |
476 | localbind(int f, int n) |
477 | { |
478 | return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map, |
479 | "Local set key: ", FALSE)); |
480 | } |
481 | |
482 | |
483 | |
484 | |
485 | |
486 | int |
487 | redefine_key(int f, int n) |
488 | { |
489 | static char buf[48]; |
490 | char tmp[32], *bufp; |
491 | KEYMAP *mp; |
492 | |
493 | (void)strlcpy(buf, "Define key map: ", sizeof(buf)); |
494 | if ((bufp = eread("%s", tmp, sizeof(tmp), EFNEW, buf)) == NULL) |
495 | return (ABORT); |
496 | else if (bufp[0] == '\0') |
497 | return (FALSE); |
498 | (void)strlcat(buf, tmp, sizeof(buf)); |
499 | if ((mp = name_map(tmp)) == NULL) |
500 | return (dobeep_msgs("Unknown map ", tmp)); |
501 | |
502 | if (strlcat(buf, "key: ", sizeof(buf)) >= sizeof(buf)) |
503 | return (FALSE); |
504 | |
505 | return (dobind(mp, buf, FALSE)); |
506 | } |
507 | |
508 | |
509 | int |
510 | unbindtokey(int f, int n) |
511 | { |
512 | return (dobind(fundamental_map, "Global unset key: ", TRUE)); |
513 | } |
514 | |
515 | |
516 | int |
517 | localunbind(int f, int n) |
518 | { |
519 | return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map, |
| |
520 | "Local unset key: ", TRUE)); |
521 | } |
522 | |
523 | |
524 | |
525 | |
526 | |
527 | |
528 | |
529 | int |
530 | extend(int f, int n) |
531 | { |
532 | PF funct; |
533 | char xname[NXNAME], *bufp; |
534 | |
535 | if (!(f & FFARG)) |
536 | bufp = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC); |
537 | else |
538 | bufp = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n); |
539 | if (bufp == NULL) |
540 | return (ABORT); |
541 | else if (bufp[0] == '\0') |
542 | return (FALSE); |
543 | if ((funct = name_function(bufp)) != NULL) { |
544 | if (macrodef) { |
545 | struct line *lp = maclcur; |
546 | macro[macrocount - 1].m_funct = funct; |
547 | maclcur = lp->l_bp; |
548 | maclcur->l_fp = lp->l_fp; |
549 | free(lp); |
550 | } |
551 | return ((*funct)(f, n)); |
552 | } |
553 | return (dobeep_msg("[No match]")); |
554 | } |
555 | |
556 | |
557 | |
558 | |
559 | |
560 | |
561 | |
562 | |
563 | |
564 | |
565 | |
566 | |
567 | |
568 | |
569 | |
570 | |
571 | |
572 | |
573 | |
574 | |
575 | |
576 | |
577 | int |
578 | evalexpr(int f, int n) |
579 | { |
580 | char exbuf[BUFSIZE], *bufp; |
581 | int llen; |
582 | |
583 | if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf), |
584 | EFNEW | EFCR)) == NULL) |
585 | return (ABORT); |
586 | else if (bufp[0] == '\0') |
587 | return (FALSE); |
588 | llen = strlen(bufp); |
589 | |
590 | return (excline(exbuf, llen, 1)); |
591 | } |
592 | |
593 | |
594 | |
595 | |
596 | |
597 | |
598 | int |
599 | evalbuffer(int f, int n) |
600 | { |
601 | struct line *lp; |
602 | struct buffer *bp = curbp; |
603 | int s, llen, lnum = 0; |
604 | static char excbuf[BUFSIZE]; |
605 | |
606 | for (lp = bfirstlp(bp); lp != bp->b_headp; lp = lforw(lp)) { |
607 | lnum++; |
608 | llen = llength(lp); |
609 | if (llen >= BUFSIZE) |
610 | return (FALSE); |
611 | (void)strncpy(excbuf, ltext(lp), llen); |
612 | |
613 | |
614 | excbuf[llen] = '\0'; |
615 | if ((s = excline(excbuf, llen, lnum)) != TRUE) { |
616 | cleanup(); |
617 | return (s); |
618 | } |
619 | } |
620 | cleanup(); |
621 | return (TRUE); |
622 | } |
623 | |
624 | |
625 | |
626 | |
627 | |
628 | |
629 | int |
630 | evalfile(int f, int n) |
631 | { |
632 | char fname[NFILEN], *bufp; |
633 | |
634 | if ((bufp = eread("Load file: ", fname, NFILEN, |
635 | EFNEW | EFCR)) == NULL) |
636 | return (ABORT); |
637 | else if (bufp[0] == '\0') |
638 | return (FALSE); |
639 | return (load(fname)); |
640 | } |
641 | |
642 | |
643 | |
644 | |
645 | int |
646 | load(const char *fname) |
647 | { |
648 | int s = TRUE, line, ret; |
649 | int nbytes = 0; |
650 | char excbuf[BUFSIZE], fncpy[NFILEN]; |
651 | FILE *ffp; |
652 | |
653 | if ((fname = adjustname(fname, TRUE)) == NULL) |
654 | |
655 | return (FALSE); |
656 | |
657 | ret = ffropen(&ffp, fname, NULL); |
658 | if (ret != FIOSUC) { |
659 | if (ret == FIODIR) |
660 | (void)ffclose(ffp, NULL); |
661 | return (FALSE); |
662 | } |
663 | |
664 | |
665 | (void)strlcpy(fncpy, fname, sizeof(fncpy)); |
666 | line = 0; |
667 | while ((s = ffgetline(ffp, excbuf, sizeof(excbuf) - 1, &nbytes)) |
668 | == FIOSUC) { |
669 | line++; |
670 | excbuf[nbytes] = '\0'; |
671 | if (excline(excbuf, nbytes, line) != TRUE) { |
672 | s = FIOERR; |
673 | dobeep(); |
674 | ewprintf("Error loading file %s at line %d", fncpy, line); |
675 | break; |
676 | } |
677 | } |
678 | (void)ffclose(ffp, NULL); |
679 | excbuf[nbytes] = '\0'; |
680 | if (s != FIOEOF || (nbytes && excline(excbuf, nbytes, ++line) != TRUE)) |
681 | return (FALSE); |
682 | return (TRUE); |
683 | } |
684 | |
685 | |
686 | |
687 | |
688 | int |
689 | excline(char *line, int llen, int lnum) |
690 | { |
691 | PF fp; |
692 | struct line *lp, *np; |
693 | int status, c, f, n; |
694 | char *funcp, *tmp; |
695 | char *argp = NULL; |
696 | long nl; |
697 | int bind; |
698 | KEYMAP *curmap; |
699 | #define BINDARG 0 /* this arg is key to bind (local/global set key) */ |
700 | #define BINDNO 1 /* not binding or non-quoted BINDARG */ |
701 | #define BINDNEXT 2 /* next arg " (define-key) */ |
702 | #define BINDDO 3 /* already found key to bind */ |
703 | #define BINDEXT 1 /* space for trailing \0 */ |
704 | |
705 | lp = NULL; |
706 | |
707 | if (macrodef || inmacro) |
708 | return (dobeep_msg("Not now!")); |
709 | |
710 | f = 0; |
711 | n = 1; |
712 | funcp = skipwhite(line); |
713 | if (*funcp == '\0') |
714 | return (TRUE); |
715 | if (*funcp == '(') |
716 | return (foundparen(funcp, llen, lnum)); |
717 | line = parsetoken(funcp); |
718 | if (*line != '\0') { |
719 | *line++ = '\0'; |
720 | line = skipwhite(line); |
721 | if (ISDIGIT(*line) || *line == '-') { |
722 | argp = line; |
723 | line = parsetoken(line); |
724 | } |
725 | } |
726 | if (argp != NULL) { |
727 | f = FFARG; |
728 | nl = strtol(argp, &tmp, 10); |
729 | if (*tmp != '\0') |
730 | return (FALSE); |
731 | if (nl >= INT_MAX || nl <= INT_MIN) |
732 | return (FALSE); |
733 | n = (int)nl; |
734 | } |
735 | if ((fp = name_function(funcp)) == NULL) |
736 | return (dobeep_msgs("Unknown function: ", funcp)); |
737 | |
738 | if (fp == bindtokey || fp == unbindtokey) { |
739 | bind = BINDARG; |
740 | curmap = fundamental_map; |
741 | } else if (fp == localbind || fp == localunbind) { |
742 | bind = BINDARG; |
743 | curmap = curbp->b_modes[curbp->b_nmodes]->p_map; |
744 | } else if (fp == redefine_key) |
745 | bind = BINDNEXT; |
746 | else |
747 | bind = BINDNO; |
748 | |
749 | if ((np = lalloc(0)) == FALSE) |
750 | return (FALSE); |
751 | np->l_fp = np->l_bp = maclcur = np; |
752 | while (*line != '\0') { |
753 | argp = skipwhite(line); |
754 | if (*argp == '\0') |
755 | break; |
756 | line = parsetoken(argp); |
757 | if (*argp != '"') { |
758 | if (*argp == '\'') |
759 | ++argp; |
760 | if ((lp = lalloc((int) (line - argp) + BINDEXT)) == |
761 | NULL) { |
762 | status = FALSE; |
763 | goto cleanup; |
764 | } |
765 | bcopy(argp, ltext(lp), (int)(line - argp)); |
766 | |
767 | lp->l_used--; |
768 | if (bind == BINDARG) |
769 | bind = BINDNO; |
770 | } else { |
771 | |
772 | ++argp; |
773 | if (bind != BINDARG) { |
774 | lp = lalloc((int)(line - argp) + BINDEXT); |
775 | if (lp == NULL) { |
776 | status = FALSE; |
777 | goto cleanup; |
778 | } |
779 | lp->l_used = 0; |
780 | } else |
781 | key.k_count = 0; |
782 | while (*argp != '"' && *argp != '\0') { |
783 | if (*argp != '\\') |
784 | c = *argp++; |
785 | else { |
786 | switch (*++argp) { |
787 | case 't': |
788 | case 'T': |
789 | c = CCHR('I'); |
790 | break; |
791 | case 'n': |
792 | case 'N': |
793 | c = CCHR('J'); |
794 | break; |
795 | case 'r': |
796 | case 'R': |
797 | c = CCHR('M'); |
798 | break; |
799 | case 'e': |
800 | case 'E': |
801 | c = CCHR('['); |
802 | break; |
803 | case '^': |
804 | |
805 | |
806 | |
807 | |
808 | c = CHARMASK(*++argp); |
809 | c = ISLOWER(c) ? |
810 | CCHR(TOUPPER(c)) : CCHR(c); |
811 | break; |
812 | case '0': |
813 | case '1': |
814 | case '2': |
815 | case '3': |
816 | case '4': |
817 | case '5': |
818 | case '6': |
819 | case '7': |
820 | c = *argp - '0'; |
821 | if (argp[1] <= '7' && |
822 | argp[1] >= '0') { |
823 | c <<= 3; |
824 | c += *++argp - '0'; |
825 | if (argp[1] <= '7' && |
826 | argp[1] >= '0') { |
827 | c <<= 3; |
828 | c += *++argp |
829 | - '0'; |
830 | } |
831 | } |
832 | break; |
833 | case 'f': |
834 | case 'F': |
835 | c = *++argp - '0'; |
836 | if (ISDIGIT(argp[1])) { |
837 | c *= 10; |
838 | c += *++argp - '0'; |
839 | } |
840 | c += KFIRST; |
841 | break; |
842 | default: |
843 | c = CHARMASK(*argp); |
844 | break; |
845 | } |
846 | argp++; |
847 | } |
848 | if (bind == BINDARG) |
849 | key.k_chars[key.k_count++] = c; |
850 | else |
851 | lp->l_text[lp->l_used++] = c; |
852 | } |
853 | if (*line) |
854 | line++; |
855 | } |
856 | switch (bind) { |
857 | case BINDARG: |
858 | bind = BINDDO; |
859 | break; |
860 | case BINDNEXT: |
861 | lp->l_text[lp->l_used] = '\0'; |
862 | if ((curmap = name_map(lp->l_text)) == NULL) { |
863 | (void)dobeep_msgs("No such mode: ", lp->l_text); |
864 | status = FALSE; |
865 | free(lp); |
866 | goto cleanup; |
867 | } |
868 | free(lp); |
869 | bind = BINDARG; |
870 | break; |
871 | default: |
872 | lp->l_fp = np->l_fp; |
873 | lp->l_bp = np; |
874 | np->l_fp = lp; |
875 | np = lp; |
876 | } |
877 | } |
878 | switch (bind) { |
879 | default: |
880 | (void)dobeep_msg("Bad args to set key"); |
881 | status = FALSE; |
882 | break; |
883 | case BINDDO: |
884 | if (fp != unbindtokey && fp != localunbind) { |
885 | lp->l_text[lp->l_used] = '\0'; |
886 | status = bindkey(&curmap, lp->l_text, key.k_chars, |
887 | key.k_count); |
888 | } else |
889 | status = bindkey(&curmap, NULL, key.k_chars, |
890 | key.k_count); |
891 | break; |
892 | case BINDNO: |
893 | inmacro = TRUE; |
894 | maclcur = maclcur->l_fp; |
895 | status = (*fp)(f, n); |
896 | inmacro = FALSE; |
897 | } |
898 | cleanup: |
899 | lp = maclcur->l_fp; |
900 | while (lp != maclcur) { |
901 | np = lp->l_fp; |
902 | free(lp); |
903 | lp = np; |
904 | } |
905 | free(lp); |
906 | maclhead = NULL; |
907 | macrodef = FALSE; |
908 | return (status); |
909 | } |
910 | |
911 | |
912 | |
913 | |
914 | char * |
915 | skipwhite(char *s) |
916 | { |
917 | while (*s == ' ' || *s == '\t') |
918 | s++; |
919 | if ((*s == ';') || (*s == '#')) |
920 | *s = '\0'; |
921 | return (s); |
922 | } |
923 | |
924 | static char * |
925 | parsetoken(char *s) |
926 | { |
927 | if (*s != '"') { |
928 | while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(') |
929 | s++; |
930 | if (*s == ';') |
931 | *s = '\0'; |
932 | } else |
933 | do { |
934 | |
935 | |
936 | |
937 | |
938 | if (*s == '\\') |
939 | ++s; |
940 | } while (*++s != '"' && *s != '\0'); |
941 | return (s); |
942 | } |