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