Bug Summary

File:src/usr.bin/mg/extend.c
Warning:line 230, column 17
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

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/* $OpenBSD: extend.c,v 1.75 2021/05/06 14:16:12 lum Exp $ */
2/* This file is in the public domain. */
3
4/*
5 * Extended (M-x) commands, rebinding, and startup file processing.
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
25static int remap(KEYMAP *, int, PF, KEYMAP *);
26static KEYMAP *reallocmap(KEYMAP *);
27static void fixmap(KEYMAP *, KEYMAP *, KEYMAP *);
28static int dobind(KEYMAP *, const char *, int);
29static char *parsetoken(char *);
30static int bindkey(KEYMAP **, const char *, KCHAR *, int);
31
32/*
33 * Insert a string, mainly for use from macros (created by selfinsert).
34 */
35/* ARGSUSED */
36int
37insert(int f, int n)
38{
39 char buf[BUFSIZE128], *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)) != TRUE1)
48 return (FALSE0);
49 }
50 }
51 maclcur = maclcur->l_fp;
52 return (TRUE1);
53 }
54 if (n == 1)
55 /* CFINS means selfinsert can tack on the end */
56 thisflag |= CFINS0x0004;
57
58 if ((bufp = eread("Insert: ", buf, sizeof(buf), EFNEW0x0008)) == NULL((void *)0))
59 return (ABORT2);
60 else if (bufp[0] == '\0')
61 return (FALSE0);
62 while (--n >= 0) {
63 cp = buf;
64 while (*cp) {
65 if (((*cp == *curbp->b_nlchr) ?
66 lnewline() : linsert(1, *cp))
67 != TRUE1)
68 return (FALSE0);
69 cp++;
70 }
71 }
72 return (TRUE1);
73}
74
75/*
76 * Bind a key to a function. Cases range from the trivial (replacing an
77 * existing binding) to the extremely complex (creating a new prefix in a
78 * map_element that already has one, so the map_element must be split,
79 * but the keymap doesn't have enough room for another map_element, so
80 * the keymap is reallocated). No attempt is made to reclaim space no
81 * longer used, if this is a problem flags must be added to indicate
82 * malloced versus static storage in both keymaps and map_elements.
83 * Structure assignments would come in real handy, but K&R based compilers
84 * don't have them. Care is taken so running out of memory will leave
85 * the keymap in a usable state.
86 * Parameters are:
87 * curmap: pointer to the map being changed
88 * c: character being changed
89 * funct: function being changed to
90 * pref_map: if funct==NULL, map to bind to or NULL for new
91 */
92static int
93remap(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'
13
Taking false branch
101 if (ele > &curmap->map_element[0] && (funct != NULL((void *)0) ||
102 (ele - 1)->k_prefmap == NULL((void *)0)))
103 n1 = c - (ele - 1)->k_num;
104 else
105 n1 = HUGE1000;
106 if (ele < &curmap->map_element[curmap->map_num] &&
107 (funct != NULL((void *)0) || ele->k_prefmap == NULL((void *)0)))
108 n2 = ele->k_base - c;
109 else
110 n2 = HUGE1000;
111 if (n1 <= MAPELEDEF4 && n1 <= n2) {
112 ele--;
113 if ((pfp = calloc(c - ele->k_base + 1,
114 sizeof(PF))) == NULL((void *)0))
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 <= MAPELEDEF4) {
126 if ((pfp = calloc(ele->k_num - c + 1,
127 sizeof(PF))) == NULL((void *)0))
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((void *)0))
141 return (FALSE0);
142 curmap = newmap;
143 }
144 if ((pfp = malloc(sizeof(PF))) == NULL((void *)0))
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((void *)0);
159 curmap->map_num++;
160 }
161 if (funct == NULL((void *)0)) {
162 if (pref_map != NULL((void *)0))
163 ele->k_prefmap = pref_map;
164 else {
165 if ((mp = malloc(sizeof(KEYMAP) +
166 (MAPINIT(3 +1) - 1) * sizeof(struct map_element))) == NULL((void *)0)) {
167 (void)dobeep_msg("Out of memory");
168 ele->k_funcp[c - ele->k_base] =
169 curmap->map_default;
170 return (FALSE0);
171 }
172 mp->map_num = 0;
173 mp->map_max = MAPINIT(3 +1);
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((void *)0) ||
14
Assuming the condition is false
181 pref_map == NULL((void *)0) || pref_map == ele->k_prefmap))
182 /* no change */
183 return (TRUE1);
184 if (funct
14.1
'funct' is equal to NULL
!= NULL((void *)0) || ele->k_prefmap == NULL((void *)0)) {
15
Assuming field 'k_prefmap' is not equal to NULL
16
Taking false branch
185 if (ele->k_funcp[n1] == NULL((void *)0))
186 ele->k_prefmap = NULL((void *)0);
187 /* easy case */
188 ele->k_funcp[n1] = funct;
189 if (funct == NULL((void *)0)) {
190 if (pref_map != NULL((void *)0))
191 ele->k_prefmap = pref_map;
192 else {
193 if ((mp = malloc(sizeof(KEYMAP) +
194 (MAPINIT(3 +1) - 1) *
195 sizeof(struct map_element))) == NULL((void *)0)) {
196 (void)dobeep_msg("Out of memory");
197 ele->k_funcp[c - ele->k_base] =
198 curmap->map_default;
199 return (FALSE0);
200 }
201 mp->map_num = 0;
202 mp->map_max = MAPINIT(3 +1);
203 mp->map_default = rescan;
204 ele->k_prefmap = mp;
205 }
206 }
207 } else {
208 /*
209 * This case is the splits.
210 * Determine which side of the break c goes on
211 * 0 = after break; 1 = before break
212 */
213 n2 = 1;
214 for (i = 0; n2
16.1
'n2' is 1
&& 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((void *)0);
216 if (curmap->map_num >= curmap->map_max) {
19
Assuming field 'map_num' is >= field 'map_max'
20
Taking true branch
217 if ((newmap = reallocmap(curmap)) == NULL((void *)0))
21
Calling 'reallocmap'
30
Returning from 'reallocmap'
31
Taking false branch
218 return (FALSE0);
219 curmap = newmap;
220 }
221 if ((pfp = calloc(ele->k_num - c + !n2,
32
Assuming the condition is false
33
Taking false branch
222 sizeof(PF))) == NULL((void *)0))
223 return (dobeep_msg("Out of memory"));
224
225 ele->k_funcp[n1] = NULL((void *)0);
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((void *)0);
240 curmap->map_num++;
241 if (pref_map == NULL((void *)0)) {
242 if ((mp = malloc(sizeof(KEYMAP) + (MAPINIT(3 +1) - 1)
243 * sizeof(struct map_element))) == NULL((void *)0)) {
244 (void)dobeep_msg("Out of memory");
245 ele->k_funcp[c - ele->k_base] =
246 curmap->map_default;
247 return (FALSE0);
248 }
249 mp->map_num = 0;
250 mp->map_max = MAPINIT(3 +1);
251 mp->map_default = rescan;
252 ele->k_prefmap = mp;
253 } else
254 ele->k_prefmap = pref_map;
255 }
256 }
257 return (TRUE1);
258}
259
260/*
261 * Reallocate a keymap. Returns NULL (without trashing the current map)
262 * on failure.
263 */
264static KEYMAP *
265reallocmap(KEYMAP *curmap)
266{
267 struct maps_s *mps;
268 KEYMAP *mp;
269 int i;
270
271 if (curmap->map_max > SHRT_MAX32767 - MAPGROW3) {
22
Assuming the condition is false
23
Taking false branch
272 (void)dobeep_msg("keymap too large");
273 return (NULL((void *)0));
274 }
275 if ((mp = malloc(sizeof(KEYMAP) + (curmap->map_max + (MAPGROW3 - 1)) *
24
Uninitialized value stored to field 'k_base'
25
Assuming the condition is false
26
Taking false branch
276 sizeof(struct map_element))) == NULL((void *)0)) {
277 (void)dobeep_msg("Out of memory");
278 return (NULL((void *)0));
279 }
280 mp->map_num = curmap->map_num;
281 mp->map_max = curmap->map_max + MAPGROW3;
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((void *)0); 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 * Fix references to a reallocated keymap (recursive).
301 */
302static void
303fixmap(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((void *)0)) {
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 * Do the input for local-set-key, global-set-key and define-key
319 * then call remap to do the work.
320 */
321static int
322dobind(KEYMAP *curmap, const char *p, int unbind)
323{
324 KEYMAP *pref_map = NULL((void *)0);
325 PF funct;
326 char bprompt[80], *bufp, *pep;
327 int c, s, n;
328
329 if (macrodef) {
2
Assuming 'macrodef' is 0
3
Taking false branch
330 /*
331 * Keystrokes aren't collected. Not hard, but pretty useless.
332 * Would not work for function keys in any case.
333 */
334 return (dobeep_msg("Can't rebind key in macro"));
335 }
336 if (inmacro) {
4
Assuming 'inmacro' is not equal to 0
5
Taking true branch
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])((unsigned char) (maclcur->l_text[s])), &curmap)
8
Assuming the condition is true
9
Taking true branch
339 != NULL((void *)0)) {
340 if (remap(curmap, c, NULL((void *)0), NULL((void *)0))
10
Calling 'remap'
341 != TRUE1)
342 return (FALSE0);
343 }
344 }
345 (void)doscan(curmap, c = maclcur->l_text[s], NULL((void *)0));
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(FALSE0));
357 if (doscan(curmap, c, &curmap) != NULL((void *)0))
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 EFFUNC0x0001 | EFNEW0x0008, bprompt)) == NULL((void *)0))
368 return (ABORT2);
369 else if (bufp[0] == '\0')
370 return (FALSE0);
371 if (((funct = name_function(bprompt)) == NULL((void *)0)) ?
372 (pref_map = name_map(bprompt)) == NULL((void *)0) : funct == NULL((void *)0))
373 return (dobeep_msg("[No match]"));
374
375 }
376 return (remap(curmap, c, funct, pref_map));
377}
378
379/*
380 * bindkey: bind key sequence to a function in the specified map. Used by
381 * excline so it can bind function keys. To close to release to change
382 * calling sequence, should just pass KEYMAP *curmap rather than
383 * KEYMAP **mapp.
384 */
385static int
386bindkey(KEYMAP **mapp, const char *fname, KCHAR *keys, int kcount)
387{
388 KEYMAP *curmap = *mapp;
389 KEYMAP *pref_map = NULL((void *)0);
390 PF funct;
391 int c;
392
393 if (fname == NULL((void *)0))
394 funct = rescan;
395 else if (((funct = name_function(fname)) == NULL((void *)0)) ?
396 (pref_map = name_map(fname)) == NULL((void *)0) : funct == NULL((void *)0)) {
397 dobeep();
398 ewprintf("[No match: %s]", fname);
399 return (FALSE0);
400 }
401 while (--kcount) {
402 if (doscan(curmap, c = *keys++, &curmap) != NULL((void *)0)) {
403 if (remap(curmap, c, NULL((void *)0), NULL((void *)0)) != TRUE1)
404 return (FALSE0);
405 /*
406 * XXX - Bizzarreness. remap creates an empty KEYMAP
407 * that the last key is supposed to point to.
408 */
409 curmap = ele->k_prefmap;
410 }
411 }
412 (void)doscan(curmap, c = *keys, NULL((void *)0));
413 return (remap(curmap, c, funct, pref_map));
414}
415
416/*
417 * Wrapper for bindkey() that converts escapes.
418 */
419int
420dobindkey(KEYMAP *map, const char *func, const char *str)
421{
422 int i;
423
424 for (i = 0; *str && i < MAXKEY8; i++) {
425 /* XXX - convert numbers w/ strol()? */
426 if (*str == '^' && *(str + 1) != '\0') {
427 key.k_chars[i] = CCHR(toupper((unsigned char)*++str))((toupper((unsigned char)*++str)) ^ 0x40);
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('[')(('[') ^ 0x40);
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 * This function modifies the fundamental keyboard map.
463 */
464/* ARGSUSED */
465int
466bindtokey(int f, int n)
467{
468 return (dobind(fundamental_map(fundamental_mode.p_map), "Global set key: ", FALSE0));
469}
470
471/*
472 * This function modifies the current mode's keyboard map.
473 */
474/* ARGSUSED */
475int
476localbind(int f, int n)
477{
478 return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
479 "Local set key: ", FALSE0));
480}
481
482/*
483 * This function redefines a key in any keymap.
484 */
485/* ARGSUSED */
486int
487redefine_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), EFNEW0x0008, buf)) == NULL((void *)0))
495 return (ABORT2);
496 else if (bufp[0] == '\0')
497 return (FALSE0);
498 (void)strlcat(buf, tmp, sizeof(buf));
499 if ((mp = name_map(tmp)) == NULL((void *)0))
500 return (dobeep_msgs("Unknown map ", tmp));
501
502 if (strlcat(buf, "key: ", sizeof(buf)) >= sizeof(buf))
503 return (FALSE0);
504
505 return (dobind(mp, buf, FALSE0));
506}
507
508/* ARGSUSED */
509int
510unbindtokey(int f, int n)
511{
512 return (dobind(fundamental_map(fundamental_mode.p_map), "Global unset key: ", TRUE1));
513}
514
515/* ARGSUSED */
516int
517localunbind(int f, int n)
518{
519 return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
1
Calling 'dobind'
520 "Local unset key: ", TRUE1));
521}
522
523/*
524 * Extended command. Call the message line routine to read in the command
525 * name and apply autocompletion to it. When it comes back, look the name
526 * up in the symbol table and run the command if it is found. Print an
527 * error if there is anything wrong.
528 */
529int
530extend(int f, int n)
531{
532 PF funct;
533 char xname[NXNAME64], *bufp;
534
535 if (!(f & FFARG7))
536 bufp = eread("M-x ", xname, NXNAME64, EFNEW0x0008 | EFFUNC0x0001);
537 else
538 bufp = eread("%d M-x ", xname, NXNAME64, EFNEW0x0008 | EFFUNC0x0001, n);
539 if (bufp == NULL((void *)0))
540 return (ABORT2);
541 else if (bufp[0] == '\0')
542 return (FALSE0);
543 if ((funct = name_function(bufp)) != NULL((void *)0)) {
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 * Define the commands needed to do startup-file processing.
558 * This code is mostly a kludge just so we can get startup-file processing.
559 *
560 * If you're serious about having this code, you should rewrite it.
561 * To wit:
562 * It has lots of funny things in it to make the startup-file look
563 * like a GNU startup file; mostly dealing with parens and semicolons.
564 * This should all vanish.
565 *
566 * We define eval-expression because it's easy. It can make
567 * *-set-key or define-key set an arbitrary key sequence, so it isn't
568 * useless.
569 */
570
571/*
572 * evalexpr - get one line from the user, and run it.
573 * Use strlen for length of line, assume user is not typing in a '\0' in the
574 * modeline. llen only used for foundparen() so old-school will be ok.
575 */
576/* ARGSUSED */
577int
578evalexpr(int f, int n)
579{
580 char exbuf[BUFSIZE128], *bufp;
581 int llen;
582
583 if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf),
584 EFNEW0x0008 | EFCR0x0010)) == NULL((void *)0))
585 return (ABORT2);
586 else if (bufp[0] == '\0')
587 return (FALSE0);
588 llen = strlen(bufp);
589
590 return (excline(exbuf, llen, 1));
591}
592
593/*
594 * evalbuffer - evaluate the current buffer as line commands. Useful for
595 * testing startup files.
596 */
597/* ARGSUSED */
598int
599evalbuffer(int f, int n)
600{
601 struct line *lp;
602 struct buffer *bp = curbp;
603 int s, llen, lnum = 0;
604 static char excbuf[BUFSIZE128];
605
606 for (lp = bfirstlp(bp)((((bp)->b_headp)->l_fp)); lp != bp->b_headp; lp = lforw(lp)((lp)->l_fp)) {
607 lnum++;
608 llen = llength(lp)((lp)->l_used);
609 if (llen >= BUFSIZE128)
610 return (FALSE0);
611 (void)strncpy(excbuf, ltext(lp)((lp)->l_text), llen);
612
613 /* make sure the line is terminated */
614 excbuf[llen] = '\0';
615 if ((s = excline(excbuf, llen, lnum)) != TRUE1) {
616 cleanup();
617 return (s);
618 }
619 }
620 cleanup();
621 return (TRUE1);
622}
623
624/*
625 * evalfile - go get a file and evaluate it as line commands. You can
626 * go get your own startup file if need be.
627 */
628/* ARGSUSED */
629int
630evalfile(int f, int n)
631{
632 char fname[NFILEN1024], *bufp;
633
634 if ((bufp = eread("Load file: ", fname, NFILEN1024,
635 EFNEW0x0008 | EFCR0x0010)) == NULL((void *)0))
636 return (ABORT2);
637 else if (bufp[0] == '\0')
638 return (FALSE0);
639 return (load(fname));
640}
641
642/*
643 * load - go load the file name we got passed.
644 */
645int
646load(const char *fname)
647{
648 int s = TRUE1, line, ret;
649 int nbytes = 0;
650 char excbuf[BUFSIZE128], fncpy[NFILEN1024];
651 FILE *ffp;
652
653 if ((fname = adjustname(fname, TRUE1)) == NULL((void *)0))
654 /* just to be careful */
655 return (FALSE0);
656
657 ret = ffropen(&ffp, fname, NULL((void *)0));
658 if (ret != FIOSUC0) {
659 if (ret == FIODIR5)
660 (void)ffclose(ffp, NULL((void *)0));
661 return (FALSE0);
662 }
663
664 /* keep a note of fname incase of errors in loaded file. */
665 (void)strlcpy(fncpy, fname, sizeof(fncpy));
666 line = 0;
667 while ((s = ffgetline(ffp, excbuf, sizeof(excbuf) - 1, &nbytes))
668 == FIOSUC0) {
669 line++;
670 excbuf[nbytes] = '\0';
671 if (excline(excbuf, nbytes, line) != TRUE1) {
672 s = FIOERR3;
673 dobeep();
674 ewprintf("Error loading file %s at line %d", fncpy, line);
675 break;
676 }
677 }
678 (void)ffclose(ffp, NULL((void *)0));
679 excbuf[nbytes] = '\0';
680 if (s != FIOEOF2 || (nbytes && excline(excbuf, nbytes, ++line) != TRUE1))
681 return (FALSE0);
682 return (TRUE1);
683}
684
685/*
686 * excline - run a line from a load file or eval-expression.
687 */
688int
689excline(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((void *)0);
696 long nl;
697 int bind;
698 KEYMAP *curmap;
699#define BINDARG0 0 /* this arg is key to bind (local/global set key) */
700#define BINDNO1 1 /* not binding or non-quoted BINDARG */
701#define BINDNEXT2 2 /* next arg " (define-key) */
702#define BINDDO3 3 /* already found key to bind */
703#define BINDEXT1 1 /* space for trailing \0 */
704
705 lp = NULL((void *)0);
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 (TRUE1); /* No error on blank lines */
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)((cinfo[((unsigned char) (*line))]&0x20)!=0) || *line == '-') {
722 argp = line;
723 line = parsetoken(line);
724 }
725 }
726 if (argp != NULL((void *)0)) {
727 f = FFARG7;
728 nl = strtol(argp, &tmp, 10);
729 if (*tmp != '\0')
730 return (FALSE0);
731 if (nl >= INT_MAX2147483647 || nl <= INT_MIN(-2147483647 -1))
732 return (FALSE0);
733 n = (int)nl;
734 }
735 if ((fp = name_function(funcp)) == NULL((void *)0))
736 return (dobeep_msgs("Unknown function: ", funcp));
737
738 if (fp == bindtokey || fp == unbindtokey) {
739 bind = BINDARG0;
740 curmap = fundamental_map(fundamental_mode.p_map);
741 } else if (fp == localbind || fp == localunbind) {
742 bind = BINDARG0;
743 curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
744 } else if (fp == redefine_key)
745 bind = BINDNEXT2;
746 else
747 bind = BINDNO1;
748 /* Pack away all the args now... */
749 if ((np = lalloc(0)) == FALSE0)
750 return (FALSE0);
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) + BINDEXT1)) ==
761 NULL((void *)0)) {
762 status = FALSE0;
763 goto cleanup;
764 }
765 bcopy(argp, ltext(lp)((lp)->l_text), (int)(line - argp));
766 /* don't count BINDEXT */
767 lp->l_used--;
768 if (bind == BINDARG0)
769 bind = BINDNO1;
770 } else {
771 /* quoted strings are special */
772 ++argp;
773 if (bind != BINDARG0) {
774 lp = lalloc((int)(line - argp) + BINDEXT1);
775 if (lp == NULL((void *)0)) {
776 status = FALSE0;
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')(('I') ^ 0x40);
790 break;
791 case 'n':
792 case 'N':
793 c = CCHR('J')(('J') ^ 0x40);
794 break;
795 case 'r':
796 case 'R':
797 c = CCHR('M')(('M') ^ 0x40);
798 break;
799 case 'e':
800 case 'E':
801 c = CCHR('[')(('[') ^ 0x40);
802 break;
803 case '^':
804 /*
805 * split into two statements
806 * due to bug in OSK cpp
807 */
808 c = CHARMASK(*++argp)((unsigned char) (*++argp));
809 c = ISLOWER(c)((cinfo[((unsigned char) (c))]&0x04)!=0) ?
810 CCHR(TOUPPER(c))((((c)-0x20)) ^ 0x40) : CCHR(c)((c) ^ 0x40);
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])((cinfo[((unsigned char) (argp[1]))]&0x20)!=0)) {
837 c *= 10;
838 c += *++argp - '0';
839 }
840 c += KFIRST256;
841 break;
842 default:
843 c = CHARMASK(*argp)((unsigned char) (*argp));
844 break;
845 }
846 argp++;
847 }
848 if (bind == BINDARG0)
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 BINDARG0:
858 bind = BINDDO3;
859 break;
860 case BINDNEXT2:
861 lp->l_text[lp->l_used] = '\0';
862 if ((curmap = name_map(lp->l_text)) == NULL((void *)0)) {
863 (void)dobeep_msgs("No such mode: ", lp->l_text);
864 status = FALSE0;
865 free(lp);
866 goto cleanup;
867 }
868 free(lp);
869 bind = BINDARG0;
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 = FALSE0;
882 break;
883 case BINDDO3:
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((void *)0), key.k_chars,
890 key.k_count);
891 break;
892 case BINDNO1:
893 inmacro = TRUE1;
894 maclcur = maclcur->l_fp;
895 status = (*fp)(f, n);
896 inmacro = FALSE0;
897 }
898cleanup:
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((void *)0);
907 macrodef = FALSE0;
908 return (status);
909}
910
911/*
912 * a pair of utility functions for the above
913 */
914char *
915skipwhite(char *s)
916{
917 while (*s == ' ' || *s == '\t')
918 s++;
919 if ((*s == ';') || (*s == '#'))
920 *s = '\0';
921 return (s);
922}
923
924static char *
925parsetoken(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 * Strings get special treatment.
936 * Beware: You can \ out the end of the string!
937 */
938 if (*s == '\\')
939 ++s;
940 } while (*++s != '"' && *s != '\0');
941 return (s);
942}