Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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/* $OpenBSD: extend.c,v 1.80 2023/04/17 10:11:30 op 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 */
35int
36insert(int f, int n)
37{
38 char buf[BUFSIZE128], *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)) != TRUE1)
47 return (FALSE0);
48 }
49 }
50 maclcur = maclcur->l_fp;
51 return (TRUE1);
52 }
53 if (n == 1)
54 /* CFINS means selfinsert can tack on the end */
55 thisflag |= CFINS0x0004;
56
57 if ((bufp = eread("Insert: ", buf, sizeof(buf), EFNEW0x0008)) == NULL((void *)0))
58 return (ABORT2);
59 else if (bufp[0] == '\0')
60 return (FALSE0);
61 while (--n >= 0) {
62 cp = buf;
63 while (*cp) {
64 if (((*cp == *curbp->b_nlchr) ?
65 lnewline() : linsert(1, *cp))
66 != TRUE1)
67 return (FALSE0);
68 cp++;
69 }
70 }
71 return (TRUE1);
72}
73
74/*
75 * Bind a key to a function. Cases range from the trivial (replacing an
76 * existing binding) to the extremely complex (creating a new prefix in a
77 * map_element that already has one, so the map_element must be split,
78 * but the keymap doesn't have enough room for another map_element, so
79 * the keymap is reallocated). No attempt is made to reclaim space no
80 * longer used, if this is a problem flags must be added to indicate
81 * malloced versus static storage in both keymaps and map_elements.
82 * Structure assignments would come in real handy, but K&R based compilers
83 * don't have them. Care is taken so running out of memory will leave
84 * the keymap in a usable state.
85 * Parameters are:
86 * curmap: pointer to the map being changed
87 * c: character being changed
88 * funct: function being changed to
89 * pref_map: if funct==NULL, map to bind to or NULL for new
90 */
91static int
92remap(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((void *)0) ||
13
Assuming the condition is false
101 (ele - 1)->k_prefmap == NULL((void *)0)))
102 n1 = c - (ele - 1)->k_num;
103 else
104 n1 = HUGE1000;
105 if (ele < &curmap->map_element[curmap->map_num] &&
14
Assuming the condition is false
106 (funct != NULL((void *)0) || ele->k_prefmap == NULL((void *)0)))
107 n2 = ele->k_base - c;
108 else
109 n2 = HUGE1000;
110 if (n1
14.1
'n1' is > MAPELEDEF
<= MAPELEDEF4 && n1 <= n2) {
111 ele--;
112 if ((pfp = calloc(c - ele->k_base + 1,
113 sizeof(PF))) == NULL((void *)0))
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
14.2
'n2' is > MAPELEDEF
<= MAPELEDEF4) {
15
Taking false branch
125 if ((pfp = calloc(ele->k_num - c + 1,
126 sizeof(PF))) == NULL((void *)0))
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'
17
Taking true branch
139 if ((newmap = reallocmap(curmap)) == NULL((void *)0))
18
Calling 'reallocmap'
27
Returning from 'reallocmap'
28
Taking false branch
140 return (FALSE0);
141 curmap = newmap;
142 }
143 if ((pfp = malloc(sizeof(PF))) == NULL((void *)0))
29
Assuming the condition is false
30
Taking false branch
144 return (dobeep_msg("Out of memory"));
145
146 pfp[0] = funct;
147 for (mep = &curmap->map_element[curmap->map_num];
31
Loop condition is true. Entering loop body
148 mep > ele; mep--) {
149 mep->k_base = (mep - 1)->k_base;
32
Assigned value is garbage or undefined
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((void *)0);
158 curmap->map_num++;
159 }
160 if (funct == NULL((void *)0)) {
161 if (pref_map != NULL((void *)0))
162 ele->k_prefmap = pref_map;
163 else {
164 if ((mp = malloc(sizeof(KEYMAP) +
165 (MAPINIT(3 +1) - 1) * sizeof(struct map_element))) == NULL((void *)0)) {
166 (void)dobeep_msg("Out of memory");
167 ele->k_funcp[c - ele->k_base] =
168 curmap->map_default;
169 return (FALSE0);
170 }
171 mp->map_num = 0;
172 mp->map_max = MAPINIT(3 +1);
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((void *)0) ||
180 pref_map == NULL((void *)0) || pref_map == ele->k_prefmap))
181 /* no change */
182 return (TRUE1);
183 if (funct != NULL((void *)0) || ele->k_prefmap == NULL((void *)0)) {
184 if (ele->k_funcp[n1] == NULL((void *)0))
185 ele->k_prefmap = NULL((void *)0);
186 /* easy case */
187 ele->k_funcp[n1] = funct;
188 if (funct == NULL((void *)0)) {
189 if (pref_map != NULL((void *)0))
190 ele->k_prefmap = pref_map;
191 else {
192 if ((mp = malloc(sizeof(KEYMAP) +
193 (MAPINIT(3 +1) - 1) *
194 sizeof(struct map_element))) == NULL((void *)0)) {
195 (void)dobeep_msg("Out of memory");
196 ele->k_funcp[c - ele->k_base] =
197 curmap->map_default;
198 return (FALSE0);
199 }
200 mp->map_num = 0;
201 mp->map_max = MAPINIT(3 +1);
202 mp->map_default = rescan;
203 ele->k_prefmap = mp;
204 }
205 }
206 } else {
207 /*
208 * This case is the splits.
209 * Determine which side of the break c goes on
210 * 0 = after break; 1 = before break
211 */
212 n2 = 1;
213 for (i = 0; n2 && i < n1; i++)
214 n2 &= ele->k_funcp[i] != NULL((void *)0);
215 if (curmap->map_num >= curmap->map_max) {
216 if ((newmap = reallocmap(curmap)) == NULL((void *)0))
217 return (FALSE0);
218 curmap = newmap;
219 }
220 if ((pfp = calloc(ele->k_num - c + !n2,
221 sizeof(PF))) == NULL((void *)0))
222 return (dobeep_msg("Out of memory"));
223
224 ele->k_funcp[n1] = NULL((void *)0);
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((void *)0);
239 curmap->map_num++;
240 if (pref_map == NULL((void *)0)) {
241 if ((mp = malloc(sizeof(KEYMAP) + (MAPINIT(3 +1) - 1)
242 * sizeof(struct map_element))) == NULL((void *)0)) {
243 (void)dobeep_msg("Out of memory");
244 ele->k_funcp[c - ele->k_base] =
245 curmap->map_default;
246 return (FALSE0);
247 }
248 mp->map_num = 0;
249 mp->map_max = MAPINIT(3 +1);
250 mp->map_default = rescan;
251 ele->k_prefmap = mp;
252 } else
253 ele->k_prefmap = pref_map;
254 }
255 }
256 return (TRUE1);
257}
258
259/*
260 * Reallocate a keymap. Returns NULL (without trashing the current map)
261 * on failure.
262 */
263static KEYMAP *
264reallocmap(KEYMAP *curmap)
265{
266 struct maps_s *mps;
267 KEYMAP *mp;
268 int i;
269
270 if (curmap->map_max > SHRT_MAX0x7fff - MAPGROW3) {
19
Assuming the condition is false
20
Taking false branch
271 (void)dobeep_msg("keymap too large");
272 return (NULL((void *)0));
273 }
274 if ((mp = malloc(sizeof(KEYMAP) + (curmap->map_max + (MAPGROW3 - 1)) *
21
Uninitialized value stored to field 'k_base'
22
Assuming the condition is false
23
Taking false branch
275 sizeof(struct map_element))) == NULL((void *)0)) {
276 (void)dobeep_msg("Out of memory");
277 return (NULL((void *)0));
278 }
279 mp->map_num = curmap->map_num;
280 mp->map_max = curmap->map_max + MAPGROW3;
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((void *)0); 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 * Fix references to a reallocated keymap (recursive).
300 */
301static void
302fixmap(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((void *)0)) {
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 * Do the input for local-set-key, global-set-key and define-key
318 * then call remap to do the work.
319 */
320static int
321dobind(KEYMAP *curmap, const char *p, int unbind)
322{
323 KEYMAP *pref_map = NULL((void *)0);
324 PF funct;
325 char bprompt[80], *bufp, *pep;
326 int c, s, n;
327
328 if (macrodef) {
2
Assuming 'macrodef' is 0
3
Taking false branch
329 /*
330 * Keystrokes aren't collected. Not hard, but pretty useless.
331 * Would not work for function keys in any case.
332 */
333 return (dobeep_msg("Can't rebind key in macro"));
334 }
335 if (inmacro) {
4
Assuming 'inmacro' is not equal to 0
5
Taking true branch
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])((unsigned char) (maclcur->l_text[s])), &curmap)
8
Assuming the condition is true
9
Taking true branch
338 != NULL((void *)0)) {
339 if (remap(curmap, c, NULL((void *)0), NULL((void *)0))
10
Calling 'remap'
340 != TRUE1)
341 return (FALSE0);
342 }
343 }
344 (void)doscan(curmap, c = maclcur->l_text[s], NULL((void *)0));
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(FALSE0));
356 if (doscan(curmap, c, &curmap) != NULL((void *)0))
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 EFFUNC0x0001 | EFNEW0x0008, bprompt)) == NULL((void *)0))
367 return (ABORT2);
368 else if (bufp[0] == '\0')
369 return (FALSE0);
370 if (((funct = name_function(bprompt)) == NULL((void *)0)) ?
371 (pref_map = name_map(bprompt)) == NULL((void *)0) : funct == NULL((void *)0))
372 return (dobeep_msg("[No match]"));
373
374 }
375 return (remap(curmap, c, funct, pref_map));
376}
377
378/*
379 * bindkey: bind key sequence to a function in the specified map. Used by
380 * excline so it can bind function keys. To close to release to change
381 * calling sequence, should just pass KEYMAP *curmap rather than
382 * KEYMAP **mapp.
383 */
384static int
385bindkey(KEYMAP **mapp, const char *fname, KCHAR *keys, int kcount)
386{
387 KEYMAP *curmap = *mapp;
388 KEYMAP *pref_map = NULL((void *)0);
389 PF funct;
390 int c;
391
392 if (fname == NULL((void *)0))
393 funct = rescan;
394 else if (((funct = name_function(fname)) == NULL((void *)0)) ?
395 (pref_map = name_map(fname)) == NULL((void *)0) : funct == NULL((void *)0)) {
396 dobeep();
397 ewprintf("[No match: %s]", fname);
398 return (FALSE0);
399 }
400 while (--kcount) {
401 if (doscan(curmap, c = *keys++, &curmap) != NULL((void *)0)) {
402 if (remap(curmap, c, NULL((void *)0), NULL((void *)0)) != TRUE1)
403 return (FALSE0);
404 /*
405 * XXX - Bizzarreness. remap creates an empty KEYMAP
406 * that the last key is supposed to point to.
407 */
408 curmap = ele->k_prefmap;
409 }
410 }
411 (void)doscan(curmap, c = *keys, NULL((void *)0));
412 return (remap(curmap, c, funct, pref_map));
413}
414
415/*
416 * Wrapper for bindkey() that converts escapes.
417 */
418int
419dobindkey(KEYMAP *map, const char *func, const char *str)
420{
421 int i;
422
423 for (i = 0; *str && i < MAXKEY8; i++) {
424 /* XXX - convert numbers w/ strol()? */
425 if (*str == '^' && *(str + 1) != '\0') {
426 key.k_chars[i] = CCHR(toupper((unsigned char)*++str))((toupper((unsigned char)*++str)) ^ 0x40);
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('[')(('[') ^ 0x40);
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 * This function modifies the fundamental keyboard map.
462 */
463int
464bindtokey(int f, int n)
465{
466 return (dobind(fundamental_map(fundamental_mode.p_map), "Global set key: ", FALSE0));
467}
468
469/*
470 * This function modifies the current mode's keyboard map.
471 */
472int
473localbind(int f, int n)
474{
475 return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
476 "Local set key: ", FALSE0));
477}
478
479/*
480 * This function redefines a key in any keymap.
481 */
482int
483redefine_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), EFNEW0x0008, buf)) == NULL((void *)0))
491 return (ABORT2);
492 else if (bufp[0] == '\0')
493 return (FALSE0);
494 (void)strlcat(buf, tmp, sizeof(buf));
495 if ((mp = name_map(tmp)) == NULL((void *)0))
496 return (dobeep_msgs("Unknown map", tmp));
497
498 if (strlcat(buf, "key: ", sizeof(buf)) >= sizeof(buf))
499 return (FALSE0);
500
501 return (dobind(mp, buf, FALSE0));
502}
503
504int
505unbindtokey(int f, int n)
506{
507 return (dobind(fundamental_map(fundamental_mode.p_map), "Global unset key: ", TRUE1));
508}
509
510int
511localunbind(int f, int n)
512{
513 return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
1
Calling 'dobind'
514 "Local unset key: ", TRUE1));
515}
516
517/*
518 * Extended command. Call the message line routine to read in the command
519 * name and apply autocompletion to it. When it comes back, look the name
520 * up in the symbol table and run the command if it is found. Print an
521 * error if there is anything wrong.
522 */
523int
524extend(int f, int n)
525{
526 PF funct;
527 char xname[NXNAME64], *bufp;
528
529 if (!(f & FFARG7))
530 bufp = eread("M-x ", xname, NXNAME64, EFNEW0x0008 | EFFUNC0x0001);
531 else
532 bufp = eread("%d M-x ", xname, NXNAME64, EFNEW0x0008 | EFFUNC0x0001, n);
533 if (bufp == NULL((void *)0))
534 return (ABORT2);
535 else if (bufp[0] == '\0')
536 return (FALSE0);
537 if ((funct = name_function(bufp)) != NULL((void *)0)) {
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 * Define the commands needed to do startup-file processing.
552 * This code is mostly a kludge just so we can get startup-file processing.
553 *
554 * If you're serious about having this code, you should rewrite it.
555 * To wit:
556 * It has lots of funny things in it to make the startup-file look
557 * like a GNU startup file; mostly dealing with parens and semicolons.
558 * This should all vanish.
559 *
560 * We define eval-expression because it's easy. It can make
561 * *-set-key or define-key set an arbitrary key sequence, so it isn't
562 * useless.
563 */
564
565/*
566 * evalexpr - get one line from the user, and run it.
567 * Use strlen for length of line, assume user is not typing in a '\0' in the
568 * modeline. llen only used for foundparen() so old-school will be ok.
569 */
570int
571evalexpr(int f, int n)
572{
573 char exbuf[BUFSIZE128], *bufp;
574 int llen;
575
576 if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf),
577 EFNEW0x0008 | EFCR0x0010)) == NULL((void *)0))
578 return (ABORT2);
579 else if (bufp[0] == '\0')
580 return (FALSE0);
581 llen = strlen(bufp);
582
583 return (excline(exbuf, llen, 1));
584}
585
586/*
587 * evalbuffer - evaluate the current buffer as line commands. Useful for
588 * testing startup files.
589 */
590int
591evalbuffer(int f, int n)
592{
593 struct line *lp;
594 struct buffer *bp = curbp;
595 int s, llen, lnum = 0;
596 static char excbuf[BUFSIZE128];
597
598 for (lp = bfirstlp(bp)((((bp)->b_headp)->l_fp)); lp != bp->b_headp; lp = lforw(lp)((lp)->l_fp)) {
599 lnum++;
600 llen = llength(lp)((lp)->l_used);
601 if (llen >= BUFSIZE128)
602 return (FALSE0);
603 (void)strncpy(excbuf, ltext(lp)((lp)->l_text), llen);
604
605 /* make sure the line is terminated */
606 excbuf[llen] = '\0';
607 if ((s = excline(excbuf, llen, lnum)) != TRUE1) {
608 cleanup();
609 return (s);
610 }
611 }
612 cleanup();
613 return (TRUE1);
614}
615
616/*
617 * evalfile - go get a file and evaluate it as line commands. You can
618 * go get your own startup file if need be.
619 */
620int
621evalfile(int f, int n)
622{
623 FILE *ffp;
624 char fname[NFILEN1024], *bufp;
625 int ret;
626
627 if ((bufp = eread("Load file: ", fname, NFILEN1024,
628 EFNEW0x0008 | EFCR0x0010)) == NULL((void *)0))
629 return (ABORT2);
630 if (bufp[0] == '\0')
631 return (FALSE0);
632 if ((bufp = adjustname(fname, TRUE1)) == NULL((void *)0))
633 return (FALSE0);
634 ret = ffropen(&ffp, bufp, NULL((void *)0));
635 if (ret == FIODIR5)
636 (void)ffclose(ffp, NULL((void *)0));
637 if (ret != FIOSUC0)
638 return (FALSE0);
639 ret = load(ffp, bufp);
640 (void)ffclose(ffp, NULL((void *)0));
641 return (ret);
642}
643
644/*
645 * load - go load the file name we got passed.
646 */
647int
648load(FILE *ffp, const char *fname)
649{
650 int s = TRUE1, line;
651 int nbytes = 0;
652 char excbuf[BUFSIZE128];
653
654 line = 0;
655 while ((s = ffgetline(ffp, excbuf, sizeof(excbuf) - 1, &nbytes))
656 == FIOSUC0) {
657 line++;
658 excbuf[nbytes] = '\0';
659 if (excline(excbuf, nbytes, line) != TRUE1) {
660 s = FIOERR3;
661 dobeep();
662 ewprintf("Error loading file %s at line %d", fname, line);
663 break;
664 }
665 }
666 excbuf[nbytes] = '\0';
667 if (s != FIOEOF2 || (nbytes && excline(excbuf, nbytes, ++line) != TRUE1))
668 return (FALSE0);
669 return (TRUE1);
670}
671
672/*
673 * excline - run a line from a load file or eval-expression.
674 */
675int
676excline(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((void *)0);
683 long nl;
684 int bind;
685 KEYMAP *curmap;
686#define BINDARG0 0 /* this arg is key to bind (local/global set key) */
687#define BINDNO1 1 /* not binding or non-quoted BINDARG */
688#define BINDNEXT2 2 /* next arg " (define-key) */
689#define BINDDO3 3 /* already found key to bind */
690#define BINDEXT1 1 /* space for trailing \0 */
691
692 lp = NULL((void *)0);
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 (TRUE1); /* No error on blank lines */
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)((cinfo[((unsigned char) (*line))]&0x20)!=0) || *line == '-') {
709 argp = line;
710 line = parsetoken(line);
711 }
712 }
713 if (argp != NULL((void *)0)) {
714 f = FFARG7;
715 nl = strtol(argp, &tmp, 10);
716 if (*tmp != '\0')
717 return (FALSE0);
718 if (nl >= INT_MAX0x7fffffff || nl <= INT_MIN(-0x7fffffff-1))
719 return (FALSE0);
720 n = (int)nl;
721 }
722 if ((fp = name_function(funcp)) == NULL((void *)0))
723 return (dobeep_msgs("Unknown function:", funcp));
724
725 if (fp == bindtokey || fp == unbindtokey) {
726 bind = BINDARG0;
727 curmap = fundamental_map(fundamental_mode.p_map);
728 } else if (fp == localbind || fp == localunbind) {
729 bind = BINDARG0;
730 curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
731 } else if (fp == redefine_key)
732 bind = BINDNEXT2;
733 else
734 bind = BINDNO1;
735 /* Pack away all the args now... */
736 if ((np = lalloc(0)) == FALSE0)
737 return (FALSE0);
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) + BINDEXT1)) ==
748 NULL((void *)0)) {
749 status = FALSE0;
750 goto cleanup;
751 }
752 bcopy(argp, ltext(lp)((lp)->l_text), (int)(line - argp));
753 /* don't count BINDEXT */
754 lp->l_used--;
755 if (bind == BINDARG0)
756 bind = BINDNO1;
757 } else {
758 /* quoted strings are special */
759 ++argp;
760 if (bind != BINDARG0) {
761 lp = lalloc((int)(line - argp) + BINDEXT1);
762 if (lp == NULL((void *)0)) {
763 status = FALSE0;
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')(('I') ^ 0x40);
777 break;
778 case 'n':
779 case 'N':
780 c = CCHR('J')(('J') ^ 0x40);
781 break;
782 case 'r':
783 case 'R':
784 c = CCHR('M')(('M') ^ 0x40);
785 break;
786 case 'e':
787 case 'E':
788 c = CCHR('[')(('[') ^ 0x40);
789 break;
790 case '^':
791 /*
792 * split into two statements
793 * due to bug in OSK cpp
794 */
795 c = CHARMASK(*++argp)((unsigned char) (*++argp));
796 c = ISLOWER(c)((cinfo[((unsigned char) (c))]&0x04)!=0) ?
797 CCHR(TOUPPER(c))((((c)-0x20)) ^ 0x40) : CCHR(c)((c) ^ 0x40);
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])((cinfo[((unsigned char) (argp[1]))]&0x20)!=0)) {
824 c *= 10;
825 c += *++argp - '0';
826 }
827 c += KFIRST256;
828 break;
829 default:
830 c = CHARMASK(*argp)((unsigned char) (*argp));
831 break;
832 }
833 argp++;
834 }
835 if (bind == BINDARG0)
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 BINDARG0:
845 bind = BINDDO3;
846 break;
847 case BINDNEXT2:
848 lp->l_text[lp->l_used] = '\0';
849 if ((curmap = name_map(lp->l_text)) == NULL((void *)0)) {
850 (void)dobeep_msgs("No such mode:", lp->l_text);
851 status = FALSE0;
852 free(lp);
853 goto cleanup;
854 }
855 free(lp);
856 bind = BINDARG0;
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 = FALSE0;
869 break;
870 case BINDDO3:
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((void *)0), key.k_chars,
877 key.k_count);
878 break;
879 case BINDNO1:
880 inmacro = TRUE1;
881 maclcur = maclcur->l_fp;
882 status = (*fp)(f, n);
883 inmacro = FALSE0;
884 }
885cleanup:
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((void *)0);
894 macrodef = FALSE0;
895 return (status);
896}
897
898/*
899 * a pair of utility functions for the above
900 */
901char *
902skipwhite(char *s)
903{
904 while (*s == ' ' || *s == '\t')
905 s++;
906 if ((*s == ';') || (*s == '#'))
907 *s = '\0';
908 return (s);
909}
910
911static char *
912parsetoken(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 * Strings get special treatment.
923 * Beware: You can \ out the end of the string!
924 */
925 if (*s == '\\')
926 ++s;
927 } while (*++s != '"' && *s != '\0');
928 return (s);
929}