Bug Summary

File:src/usr.bin/mg/interpreter.c
Warning:line 639, column 2
Value stored to 'spc' is never read

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 interpreter.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/interpreter.c
1/* $OpenBSD: interpreter.c,v 1.32 2021/05/12 11:13:23 lum Exp $ */
2/*
3 * This file is in the public domain.
4 *
5 * Author: Mark Lumsden <mark@showcomplex.com>
6 */
7
8/*
9 * This file attempts to add some 'scripting' functionality into mg.
10 *
11 * The initial goal is to give mg the ability to use it's existing functions
12 * and structures in a linked-up way. Hopefully resulting in user definable
13 * functions. The syntax is 'scheme' like but currently it is not a scheme
14 * interpreter.
15 *
16 * At the moment there is no manual page reference to this file. The code below
17 * is liable to change, so use at your own risk!
18 *
19 * If you do want to do some testing, you can add some lines to your .mg file
20 * like:
21 *
22 * 1. Give multiple arguments to a function that usually would accept only one:
23 * (find-file "a.txt" "b.txt" "c.txt")
24 *
25 * 2. Define a single value variable:
26 * (define myfile "d.txt")
27 *
28 * 3. Define a list:
29 * (define myfiles(list "e.txt" "f.txt"))
30 *
31 * 4. Use the previously defined variable or list:
32 * (find-file myfiles)
33 *
34 * To do:
35 * 1. multiline parsing - currently only single lines supported.
36 * 2. parsing for '(' and ')' throughout whole string and evaluate correctly.
37 * 3. conditional execution.
38 * 4. have memory allocated dynamically for variable values.
39 * 5. do symbol names need more complex regex patterns? [A-Za-z][.0-9_A-Z+a-z-]
40 * at the moment.
41 * 6. display line numbers with parsing errors.
42 * 7. oh so many things....
43 * [...]
44 * n. implement user definable functions.
45 *
46 * Notes:
47 * - Currently calls to excline() from this file have the line length and
48 * line number set to zero.
49 * That's because excline() uses '\0' as the end of line indicator
50 * and only the call to foundparen() within excline() uses excline's 2nd
51 * and 3rd arguments.
52 * Importantly, any lines sent to there from here will not be
53 * coming back here.
54 */
55#include <sys/queue.h>
56
57#include <ctype.h>
58#include <limits.h>
59#include <regex.h>
60#include <signal.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <string.h>
64
65#include "def.h"
66#include "funmap.h"
67
68#ifdef MGLOG
69#include "kbd.h"
70#include "log.h"
71#endif
72
73static int multiarg(char *, char *, int);
74static int isvar(char **, char **, int);
75/*static int dofunc(char **, char **, int);*/
76static int founddef(char *, int, int, int, int);
77static int foundlst(char *, int, int, int);
78static int expandvals(char *, char *, char *);
79static int foundfun(char *, int);
80static int doregex(char *, char *);
81static void clearexp(void);
82static int parse(char *, const char *, const char *, int, int, int, int);
83static int parsdef(char *, const char *, const char *, int, int, int);
84static int parsval(char *, const char *, const char *, int, int, int);
85static int parsexp(char *, const char *, const char *, int, int, int);
86
87static int exitinterpreter(char *, char *, int);
88
89TAILQ_HEAD(exphead, expentry)struct exphead { struct expentry *tqh_first; struct expentry *
*tqh_last; }
ehead;
90struct expentry {
91 TAILQ_ENTRY(expentry)struct { struct expentry *tqe_next; struct expentry **tqe_prev
; }
eentry;
92 char *fun; /* The 1st string found between parens. */
93 char funbuf[BUFSIZE128];
94 const char *par1; /* Parenthesis at start of string */
95 const char *par2; /* Parenthesis at end of string */
96 int expctr; /* An incremental counter:+1 for each exp */
97 int blkid; /* Which block are we in? */
98};
99
100/*
101 * Structure for scheme keywords.
102 */
103#define NUMSCHKEYS4 4
104#define MAXLENSCHKEYS17 17 /* 17 = longest keyword (16) + 1 */
105
106char scharkey[NUMSCHKEYS4][MAXLENSCHKEYS17] =
107 {
108 "define",
109 "list",
110 "if",
111 "lambda"
112 };
113
114static const char lp = '(';
115static const char rp = ')';
116static char *defnam = NULL((void *)0);
117static int lnm;
118
119/*
120 * Line has a '(' as the first non-white char.
121 * Do some very basic parsing of line.
122 * Multi-line not supported at the moment, To do.
123 */
124int
125foundparen(char *funstr, int llen, int lnum)
126{
127 const char *lrp = NULL((void *)0);
128 char *p, *begp = NULL((void *)0), *endp = NULL((void *)0), *prechr;
129 char *lastchr = NULL((void *)0);
130 int i, ret, pctr, expctr, blkid, inquote, esc;
131 int elen, spc, ns;
132
133 pctr = expctr = inquote = esc = elen = spc = ns = 0;
134 blkid = 1;
135 lnm = lnum;
136
137 /*
138 * load expressions into a list called 'expentry', to be processd
139 * when all are obtained.
140 * Not really live code at the moment. Just part of the process of
141 * working out what needs to be done.
142 */
143 TAILQ_INIT(&ehead)do { (&ehead)->tqh_first = ((void *)0); (&ehead)->
tqh_last = &(&ehead)->tqh_first; } while (0)
;
144
145 /*
146 * Check for blocks of code with opening and closing ().
147 * One block = (cmd p a r a m)
148 * Two blocks = (cmd p a r a m s)(hola)
149 * Two blocks = (cmd p a r (list a m s))(hola)
150 * Only single line at moment, but more for multiline.
151 */
152 p = funstr;
153
154 for (i = 0; i < llen; ++i, p++) {
155 if (pctr == 0 && *p != ' ' && *p != '\t' && *p != '(') {
156 if (*p == ')')
157 return(dobeep_num("Extra ')' found on line:",
158 lnm));
159 return(dobeep_num("Error line:", lnm));
160 }
161 if (begp != NULL((void *)0))
162 elen++;
163
164 if (*p == '\\') {
165 esc = 1;
166 } else if (*p == '(') {
167 if (lastchr != NULL((void *)0) && *lastchr == '(')
168 return(dobeep_num("Multiple consecutive "\
169 "left parantheses line", lnm));
170 if (inquote == 0) {
171 if (begp != NULL((void *)0)) {
172 if (*prechr == ' ')
173 ns--;
174 if (endp == NULL((void *)0))
175 *p = '\0';
176 else
177 *endp = '\0';
178
179 ret = parse(begp, lrp, &lp, blkid,
180 ++expctr, elen - spc, ns);
181 if (!ret) {
182 cleanup();
183 return(ret);
184 }
185 elen = 0;
186 }
187 lrp = &lp;
188 begp = endp = NULL((void *)0);
189 pctr++;
190 } else if (inquote != 1) {
191 cleanup();
192 return(dobeep_num("Opening and closing quote "\
193 "char error line:", lnm));
194 }
195 esc = spc = 0;
196 } else if (*p == ')') {
197 if (lastchr != NULL((void *)0) && *lastchr == '(')
198 return(dobeep_num("Empty parenthesis "\
199 "not supported line", lnm));
200 if (inquote == 0) {
201 if (begp != NULL((void *)0)) {
202 if (*prechr == ' ')
203 ns--;
204 if (endp == NULL((void *)0))
205 *p = '\0';
206 else
207 *endp = '\0';
208
209 ret = parse(begp, lrp, &rp, blkid,
210 ++expctr, elen - spc, ns);
211 if (!ret) {
212 cleanup();
213 return(ret);
214 }
215 elen = 0;
216 }
217 lrp = &rp;
218 begp = endp = NULL((void *)0);
219 pctr--;
220 } else if (inquote != 1) {
221 cleanup();
222 return(dobeep_num("Opening and closing quote "\
223 "char error line:", lnm));
224 }
225 esc = spc = 0;
226 } else if (*p != ' ' && *p != '\t') {
227 if (begp == NULL((void *)0)) {
228 begp = p;
229 if (*begp == '"' || isdigit(*begp))
230 return(dobeep_num("First char of "\
231 "expression error line:", lnm));
232 }
233 if (*p == '"') {
234 if (inquote == 0 && esc == 0) {
235 if (*prechr != ' ' && *prechr != '\t')
236 return(dobeep_num("Parse error"\
237 " line:", lnm));
238 inquote++;
239 } else if (inquote > 0 && esc == 1)
240 esc = 0;
241 else
242 inquote--;
243 } else if (*prechr == '"' && inquote == 0) {
244 return(dobeep_num("Parse error line:", lnm));
245 }
246 endp = NULL((void *)0);
247 spc = 0;
248 } else if (endp == NULL((void *)0) && (*p == ' ' || *p == '\t')) {
249 if (inquote == 0) {
250 *p = ' ';
251 endp = p;
252 spc++;
253 if (begp != NULL((void *)0))
254 ns++;
255 }
256 esc = 0;
257 } else if (*p == '\t' || *p == ' ') {
258 if (inquote == 0) {
259 *p = ' ';
260 spc++;
261 }
262 esc = 0;
263 }
264 if (*p != '\t' && *p != ' ' && inquote == 0)
265 lastchr = p;
266
267 if (pctr == 0) {
268 blkid++;
269 expctr = 0;
270 defnam = NULL((void *)0);
271 }
272 prechr = p;
273 }
274
275 if (pctr != 0) {
276 cleanup();
277 return(dobeep_num("Opening and closing parentheses error line:",
278 lnm));
279 }
280 if (ret == FALSE0)
281 cleanup();
282 else
283 clearexp(); /* leave lists but remove expressions */
284
285 return (ret);
286}
287
288
289static int
290parse(char *begp, const char *par1, const char *par2, int blkid, int expctr,
291 int elen, int ns)
292{
293 char *regs;
294 int ret = FALSE0;
295
296 if (strncmp(begp, "define", 6) == 0) {
297 ret = parsdef(begp, par1, par2, blkid, expctr, elen);
298 if (ret == TRUE1 || ret == FALSE0)
299 return (ret);
300 } else if (strncmp(begp, "list", 4) == 0)
301 return(parsval(begp, par1, par2, blkid, expctr, elen));
302
303 regs = "^exit$";
304 if (doregex(regs, begp))
305 return(exitinterpreter(NULL((void *)0), NULL((void *)0), FALSE0));
306
307 /* mg function name regex */
308 regs = "^[A-Za-z-]+$";
309 if (doregex(regs, begp))
310 return(excline(begp, 0, 0));
311
312 /* Corner case 1 */
313 if (strncmp(begp, "global-set-key ", 15) == 0)
314 /* function name as 2nd param screws up multiarg. */
315 return(excline(begp, 0, 0));
316
317 /* Corner case 2 */
318 if (strncmp(begp, "define-key ", 11) == 0)
319 /* function name as 3rd param screws up multiarg. */
320 return(excline(begp, 0, 0));
321
322 return (parsexp(begp, par1, par2, blkid, expctr, elen));
323}
324
325static int
326parsdef(char *begp, const char *par1, const char *par2, int blkid, int expctr,
327 int elen)
328{
329 char *regs;
330
331 if ((defnam == NULL((void *)0)) && (expctr != 1))
332 return(dobeep_num("'define' incorrectly used line:", lnm));
333
334 /* Does the line have a incorrect variable 'define' like: */
335 /* (define i y z) */
336 regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.+[ ]+.+$";
337 if (doregex(regs, begp))
338 return(dobeep_num("Invalid use of define line:", lnm));
339
340 /* Does the line have a single variable 'define' like: */
341 /* (define i 0) */
342 regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.*$";
343 if (doregex(regs, begp)) {
344 if (par1 == &lp && par2 == &rp && expctr == 1)
345 return(founddef(begp, blkid, expctr, 1, elen));
346 return(dobeep_num("Invalid use of define line:", lnm));
347 }
348 /* Does the line have '(define i(' */
349 regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]*$";
350 if (doregex(regs, begp)) {
351 if (par1 == &lp && par2 == &lp && expctr == 1)
352 return(founddef(begp, blkid, expctr, 0, elen));
353 return(dobeep_num("Invalid use of 'define' line:", lnm));
354 }
355 /* Does the line have '(define (' */
356 regs = "^define$";
357 if (doregex(regs, begp)) {
358 if (par1 == &lp && par2 == &lp && expctr == 1)
359 return(foundfun(begp, expctr));
360 return(dobeep_num("Invalid use of 'define' line:", lnm));
361 }
362
363 return (ABORT2);
364}
365
366static int
367parsval(char *begp, const char *par1, const char *par2, int blkid, int expctr,
368 int elen)
369{
370 char *regs;
371
372 /* Does the line have 'list' */
373 regs = "^list$";
374 if (doregex(regs, begp))
375 return(dobeep_num("Invalid use of list line:", lnm));
376
377 /* Does the line have a 'list' like: */
378 /* (list "a" "b") */
379 regs = "^list[ ]+.*$";
380 if (doregex(regs, begp)) {
381 if (expctr == 1)
382 return(dobeep_num("list with no-where to go.", lnm));
383
384 if (par1 == &lp && expctr > 1)
385 return(foundlst(begp, blkid, expctr, elen));
386
387 return(dobeep_num("Invalid use of list line:", lnm));
388 }
389 return (FALSE0);
390}
391
392static int
393parsexp(char *begp, const char *par1, const char *par2, int blkid, int expctr,
394 int elen)
395{
396 struct expentry *e1 = NULL((void *)0);
397 PF funcp;
398 char *cmdp, *fendp, *valp, *fname, *funb = NULL((void *)0);;
399 int numparams, ret;
400
401 cmdp = begp;
402 fendp = strchr(cmdp, ' ');
403 *fendp = '\0';
404
405 /*
406 * If no extant mg command found, just return.
407 */
408 if ((funcp = name_function(cmdp)) == NULL((void *)0))
409 return (dobeep_msgs("Unknown command: ", cmdp));
410
411 numparams = numparams_function(funcp);
412 if (numparams == 0)
413 return (dobeep_msgs("Command takes no arguments:", cmdp));
414
415 if (numparams == -1)
416 return (dobeep_msgs("Interactive command found:", cmdp));
417
418 if ((e1 = malloc(sizeof(struct expentry))) == NULL((void *)0)) {
419 cleanup();
420 return (dobeep_msg("malloc Error"));
421 }
422 TAILQ_INSERT_HEAD(&ehead, e1, eentry)do { if (((e1)->eentry.tqe_next = (&ehead)->tqh_first
) != ((void *)0)) (&ehead)->tqh_first->eentry.tqe_prev
= &(e1)->eentry.tqe_next; else (&ehead)->tqh_last
= &(e1)->eentry.tqe_next; (&ehead)->tqh_first =
(e1); (e1)->eentry.tqe_prev = &(&ehead)->tqh_first
; } while (0)
;
423 if ((e1->fun = strndup(cmdp, BUFSIZE128)) == NULL((void *)0)) {
424 cleanup();
425 return(dobeep_msg("strndup error"));
426 }
427 cmdp = e1->fun;
428 fname = e1->fun;
429 e1->funbuf[0] = '\0';
430 funb = e1->funbuf;
431 e1->expctr = expctr;
432 e1->blkid = blkid;
433 /* need to think about these two */
434 e1->par1 = par1;
435 e1->par2 = par2;
436
437 *fendp = ' ';
438 valp = fendp + 1;
439
440 ret = expandvals(cmdp, valp, funb);
441 if (!ret)
442 return (ret);
443
444 return (multiarg(fname, funb, numparams));
445}
446
447/*
448 * Pass a list of arguments to a function.
449 */
450static int
451multiarg(char *cmdp, char *argbuf, int numparams)
452{
453 char excbuf[BUFSIZE128];
454 char *argp, *p, *s = " ";
455 char *regs;
456 int spc, numspc;
457 int fin, inquote;
458
459 argp = argbuf;
460 spc = 1; /* initially fake a space so we find first argument */
461 numspc = fin = inquote = 0;
462
463 for (p = argbuf; *p != '\0'; p++) {
464 if (*(p + 1) == '\0')
465 fin = 1;
466
467 if (*p != ' ') {
468 if (*p == '"') {
469 if (inquote == 1)
470 inquote = 0;
471 else
472 inquote = 1;
473 }
474 if (spc == 1)
475 if ((numspc % numparams) == 0) {
476 argp = p;
477 }
478 spc = 0;
479 }
480 if ((*p == ' ' && inquote == 0) || fin) {
481 if (spc == 1)/* || (numspc % numparams == 0))*/
482 continue;
483 if ((numspc % numparams) != (numparams - 1)) {
484 numspc++;
485 continue;
486 }
487 if (*p == ' ') {
488 *p = '\0'; /* terminate arg string */
489 }
490 excbuf[0] = '\0';
491 regs = "[\"]+.*[\"]+";
492
493 if (!doregex(regs, argp)) {
494 const char *errstr;
495 int iters;
496
497 iters = strtonum(argp, 0, INT_MAX2147483647, &errstr);
498 if (errstr != NULL((void *)0))
499 return (dobeep_msgs("Var not found:",
500 argp));
501 }
502
503 if (strlcpy(excbuf, cmdp, sizeof(excbuf))
504 >= sizeof(excbuf))
505 return (dobeep_msg("strlcpy error"));
506 if (strlcat(excbuf, s, sizeof(excbuf))
507 >= sizeof(excbuf))
508 return (dobeep_msg("strlcat error"));
509 if (strlcat(excbuf, argp, sizeof(excbuf))
510 >= sizeof(excbuf))
511 return (dobeep_msg("strlcat error"));
512
513 excline(excbuf, 0, 0);
514
515 if (fin)
516 break;
517
518 *p = ' '; /* unterminate arg string */
519 numspc++;
520 spc = 1;
521 }
522 }
523 return (TRUE1);
524}
525
526/*
527 * Is an item a value or a variable?
528 */
529static int
530isvar(char **argp, char **varbuf, int sizof)
531{
532 struct varentry *v1 = NULL((void *)0);
533
534 if (SLIST_EMPTY(&varhead)(((&varhead)->slh_first) == ((void *)0)))
535 return (FALSE0);
536#ifdef MGLOG
537 mglog_isvar(*varbuf, *argp, sizof);
538#endif
539 SLIST_FOREACH(v1, &varhead, entry)for((v1) = ((&varhead)->slh_first); (v1) != ((void *)0
); (v1) = ((v1)->entry.sle_next))
{
540 if (strcmp(*argp, v1->v_name) == 0) {
541 (void)(strlcpy(*varbuf, v1->v_buf, sizof) >= sizof);
542 return (TRUE1);
543 }
544 }
545 return (FALSE0);
546}
547
548
549static int
550foundfun(char *defstr, int expctr)
551{
552 return (TRUE1);
553}
554
555static int
556foundlst(char *defstr, int blkid, int expctr, int elen)
557{
558 char *p;
559
560 p = strstr(defstr, " ");
561 p = skipwhite(p);
562 expandvals(NULL((void *)0), p, defnam);
563
564 return (TRUE1);
565}
566
567/*
568 * 'define' strings follow the regex in parsdef().
569 */
570static int
571founddef(char *defstr, int blkid, int expctr, int hasval, int elen)
572{
573 struct varentry *vt, *v1 = NULL((void *)0);
574 char *p, *vnamep, *vendp = NULL((void *)0), *valp;
575
576 p = strstr(defstr, " "); /* move to first ' ' char. */
577 vnamep = skipwhite(p); /* find first char of var name. */
578 vendp = vnamep;
579
580 /* now find the end of the define/list name */
581 while (1) {
582 ++vendp;
583 if (*vendp == ' ')
584 break;
585 }
586 *vendp = '\0';
587
588 /*
589 * Check list name is not an existing mg function.
590 */
591 if (name_function(vnamep) != NULL((void *)0))
592 return(dobeep_msgs("Variable/function name clash:", vnamep));
593
594 if (!SLIST_EMPTY(&varhead)(((&varhead)->slh_first) == ((void *)0))) {
595 SLIST_FOREACH_SAFE(v1, &varhead, entry, vt)for ((v1) = ((&varhead)->slh_first); (v1) && (
(vt) = ((v1)->entry.sle_next), 1); (v1) = (vt))
{
596 if (strcmp(vnamep, v1->v_name) == 0)
597 SLIST_REMOVE(&varhead, v1, varentry, entry)do { if ((&varhead)->slh_first == (v1)) { do { ((&
varhead))->slh_first = ((&varhead))->slh_first->
entry.sle_next; } while (0); } else { struct varentry *curelm
= (&varhead)->slh_first; while (curelm->entry.sle_next
!= (v1)) curelm = curelm->entry.sle_next; curelm->entry
.sle_next = curelm->entry.sle_next->entry.sle_next; } ;
} while (0)
;
598 }
599 }
600 if ((v1 = malloc(sizeof(struct varentry))) == NULL((void *)0))
601 return (ABORT2);
602 SLIST_INSERT_HEAD(&varhead, v1, entry)do { (v1)->entry.sle_next = (&varhead)->slh_first; (
&varhead)->slh_first = (v1); } while (0)
;
603 if ((v1->v_name = strndup(vnamep, BUFSIZE128)) == NULL((void *)0))
604 return(dobeep_msg("strndup error"));
605 vnamep = v1->v_name;
606 v1->v_count = 0;
607 v1->v_vals = NULL((void *)0);
608 v1->v_buf[0] = '\0';
609
610 defnam = v1->v_buf;
611
612 if (hasval) {
613 valp = skipwhite(vendp + 1);
614
615 expandvals(NULL((void *)0), valp, defnam);
616 defnam = NULL((void *)0);
617 }
618 *vendp = ' ';
619 return (TRUE1);
620}
621
622
623static int
624expandvals(char *cmdp, char *valp, char *bp)
625{
626 char excbuf[BUFSIZE128], argbuf[BUFSIZE128];
627 char contbuf[BUFSIZE128], varbuf[BUFSIZE128];
628 char *argp, *endp, *p, *v, *s = " ";
629 char *regs;
630 int spc, cnt;
631 int inlist, sizof, fin, inquote;
632
633 /* now find the first argument */
634 p = skipwhite(valp);
635
636 if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))
637 return (dobeep_msg("strlcpy error"));
638 argp = argbuf;
639 spc = 1; /* initially fake a space so we find first argument */
Value stored to 'spc' is never read
640 inlist = fin = inquote = cnt = spc = 0;
641
642 for (p = argbuf; *p != '\0'; p++) {
643 if (*(p + 1) == '\0')
644 fin = 1;
645
646 if (*p != ' ') {
647 if (*p == '"') {
648 if (inquote == 1)
649 inquote = 0;
650 else
651 inquote = 1;
652 }
653 if (spc == 1)
654 argp = p;
655 spc = 0;
656 }
657 if ((*p == ' ' && inquote == 0) || fin) {
658 if (spc == 1)
659 continue;
660 /* terminate arg string */
661 if (*p == ' ') {
662 *p = '\0';
663 }
664 endp = p + 1;
665 excbuf[0] = '\0';
666 varbuf[0] = '\0';
667 contbuf[0] = '\0';
668 sizof = sizeof(varbuf);
669 v = varbuf;
670 regs = "[\"]+.*[\"]+";
671 if (doregex(regs, argp))
672 ; /* found quotes */
673 else if (isvar(&argp, &v, sizof)) {
674
675 (void)(strlcat(varbuf, " ",
676 sizof) >= sizof);
677
678 *p = ' ';
679 (void)(strlcpy(contbuf, endp,
680 sizeof(contbuf)) >= sizeof(contbuf));
681
682 (void)(strlcat(varbuf, contbuf,
683 sizof) >= sizof);
684
685 argbuf[0] = ' ';
686 argbuf[1] = '\0';
687 (void)(strlcat(argbuf, varbuf,
688 sizof) >= sizof);
689
690 p = argp = argbuf;
691 spc = 1;
692 fin = 0;
693 continue;
694 } else {
695 const char *errstr;
696 int iters;
697
698 iters = strtonum(argp, 0, INT_MAX2147483647, &errstr);
699 if (errstr != NULL((void *)0))
700 return (dobeep_msgs("Var not found:",
701 argp));
702 }
703#ifdef MGLOG
704 mglog_misc("x|%s|%p|%d|\n", bp, defnam, BUFSIZE128);
705#endif
706 if (*bp != '\0') {
707 if (strlcat(bp, s, BUFSIZE128) >= BUFSIZE128)
708 return (dobeep_msg("strlcat error"));
709 }
710 if (strlcat(bp, argp, BUFSIZE128) >= BUFSIZE128) {
711 return (dobeep_msg("strlcat error"));
712 }
713/* v1->v_count++;*/
714
715 if (fin)
716 break;
717
718 *p = ' '; /* unterminate arg string */
719 spc = 1;
720 }
721 }
722 return (TRUE1);
723}
724
725/*
726 * Finished with buffer evaluation, so clean up any vars.
727 * Perhaps keeps them in mg even after use,...
728 */
729/*static int
730clearvars(void)
731{
732 struct varentry *v1 = NULL;
733
734 while (!SLIST_EMPTY(&varhead)) {
735 v1 = SLIST_FIRST(&varhead);
736 SLIST_REMOVE_HEAD(&varhead, entry);
737 free(v1->v_name);
738 free(v1);
739 }
740 return (FALSE);
741}
742*/
743/*
744 * Finished with block evaluation, so clean up any expressions.
745 */
746static void
747clearexp(void)
748{
749 struct expentry *e1 = NULL((void *)0);
750
751 while (!TAILQ_EMPTY(&ehead)(((&ehead)->tqh_first) == ((void *)0))) {
752 e1 = TAILQ_FIRST(&ehead)((&ehead)->tqh_first);
753 TAILQ_REMOVE(&ehead, e1, eentry)do { if (((e1)->eentry.tqe_next) != ((void *)0)) (e1)->
eentry.tqe_next->eentry.tqe_prev = (e1)->eentry.tqe_prev
; else (&ehead)->tqh_last = (e1)->eentry.tqe_prev; *
(e1)->eentry.tqe_prev = (e1)->eentry.tqe_next; ; ; } while
(0)
;
754 free(e1->fun);
755 free(e1);
756 }
757 return;
758}
759
760/*
761 * Cleanup before leaving.
762 */
763void
764cleanup(void)
765{
766 defnam = NULL((void *)0);
767
768 clearexp();
769/* clearvars();*/
770}
771
772/*
773 * Test a string against a regular expression.
774 */
775static int
776doregex(char *r, char *e)
777{
778 regex_t regex_buff;
779
780 if (regcomp(&regex_buff, r, REG_EXTENDED0001)) {
781 regfree(&regex_buff);
782 return(dobeep_num("Regex compilation error line:", lnm));
783 }
784 if (!regexec(&regex_buff, e, 0, NULL((void *)0), 0)) {
785 regfree(&regex_buff);
786 return(TRUE1);
787 }
788 regfree(&regex_buff);
789 return(FALSE0);
790}
791
792/*
793 * Display a message so it is apparent that this is the method which stopped
794 * execution.
795 */
796static int
797exitinterpreter(char *ptr, char *dobuf, int dosiz)
798{
799 cleanup();
800 if (batch == 0)
801 return(dobeep_msg("Interpreter exited via exit command."));
802 return(FALSE0);
803}
804
805/*
806 * All code below commented out (until end of file).
807 *
808 * Need to think about how interpreter functions are done.
809 * Probably don't have a choice with string-append().
810
811static int getenvironmentvariable(char *, char *, int);
812static int stringappend(char *, char *, int);
813
814typedef int (*PFI)(char *, char *, int);
815
816
817struct ifunmap {
818 PFI fn_funct;
819 const char *fn_name;
820 struct ifunmap *fn_next;
821};
822static struct ifunmap *ifuns;
823
824static struct ifunmap ifunctnames[] = {
825 {exitinterpreter, "exit"},
826 {getenvironmentvariable, "get-environment-variable"},
827 {stringappend, "string-append"},
828 {NULL, NULL}
829};
830
831void
832ifunmap_init(void)
833{
834 struct ifunmap *fn;
835
836 for (fn = ifunctnames; fn->fn_name != NULL; fn++) {
837 fn->fn_next = ifuns;
838 ifuns = fn;
839 }
840}
841
842PFI
843name_ifun(const char *ifname)
844{
845 struct ifunmap *fn;
846
847 for (fn = ifuns; fn != NULL; fn = fn->fn_next) {
848 if (strcmp(fn->fn_name, ifname) == 0)
849 return (fn->fn_funct);
850 }
851
852 return (NULL);
853}
854
855
856int
857dofunc(char **ifname, char **tmpbuf, int sizof)
858{
859 PFI fnc;
860 char *p, *tmp;
861
862 p = strstr(*ifname, " ");
863 *p = '\0';
864
865 fnc = name_ifun(*ifname);
866 if (fnc == NULL)
867 return (FALSE);
868
869 *p = ' ';
870
871 tmp = *tmpbuf;
872
873 fnc(p, tmp, sizof);
874
875 return (TRUE);
876}
877
878static int
879getenvironmentvariable(char *ptr, char *dobuf, int dosiz)
880{
881 char *t;
882 char *tmp;
883 const char *q = "\"";
884
885 t = skipwhite(ptr);
886
887 if (t[0] == *q || t[strlen(t) - 1] == *q)
888 return (dobeep_msgs("Please remove '\"' around:", t));
889 if ((tmp = getenv(t)) == NULL || *tmp == '\0')
890 return(dobeep_msgs("Envar not found:", t));
891
892 dobuf[0] = '\0';
893 if (strlcat(dobuf, q, dosiz) >= dosiz)
894 return (dobeep_msg("strlcat error"));
895 if (strlcat(dobuf, tmp, dosiz) >= dosiz)
896 return (dobeep_msg("strlcat error"));
897 if (strlcat(dobuf, q, dosiz) >= dosiz)
898 return (dobeep_msg("strlcat error"));
899
900 return (TRUE);
901}
902
903static int
904stringappend(char *ptr, char *dobuf, int dosiz)
905{
906 char varbuf[BUFSIZE], funbuf[BUFSIZE];
907 char *p, *f, *v, *vendp;
908 int sizof, fin = 0;
909
910 varbuf[0] = funbuf[0] = '\0';
911 f = funbuf;
912 v = varbuf;
913 sizof = sizeof(varbuf);
914 *dobuf = '\0';
915
916 p = skipwhite(ptr);
917
918 while (*p != '\0') {
919 vendp = p;
920 while (1) {
921 if (*vendp == ' ') {
922 break;
923 } else if (*vendp == '\0') {
924 fin = 1;
925 break;
926 }
927 ++vendp;
928 }
929 *vendp = '\0';
930
931 if (isvar(&p, &v, sizof)) {
932 if (v[0] == '"' && v[strlen(v) - 1] == '"' ) {
933 v[strlen(v) - 1] = '\0';
934 v = v + 1;
935 }
936 if (strlcat(f, v, sizof) >= sizof)
937 return (dobeep_msg("strlcat error"));
938 } else {
939 if (p[0] == '"' && p[strlen(p) - 1] == '"' ) {
940 p[strlen(p) - 1] = '\0';
941 p = p + 1;
942 }
943 if (strlcat(f, p, sizof) >= sizof)
944 return (dobeep_msg("strlcat error"));
945 }
946 if (fin)
947 break;
948 vendp++;
949 if (*vendp == '\0')
950 break;
951 p = skipwhite(vendp);
952 }
953
954 (void)snprintf(dobuf, dosiz, "\"%s\"", f);
955
956 return (TRUE);
957}
958
959Index: main.c
960===================================================================
961RCS file: /cvs/src/usr.bin/mg/main.c,v
962retrieving revision 1.89
963diff -u -p -u -p -r1.89 main.c
964--- main.c 20 Mar 2021 09:00:49 -0000 1.89
965+++ main.c 12 Apr 2021 17:58:52 -0000
966@@ -133,10 +133,12 @@ main(int argc, char **argv)
967 extern void grep_init(void);
968 extern void cmode_init(void);
969 extern void dired_init(void);
970+ extern void ifunmap_init(void);
971
972 dired_init();
973 grep_init();
974 cmode_init();
975+ ifunmap_init();
976 }
977
978
979*/