Bug Summary

File:src/usr.bin/mg/interpreter.c
Warning:line 280, column 10
The left operand of '==' is a garbage value

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 interpreter.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/interpreter.c
1/* $OpenBSD: interpreter.c,v 1.35 2023/04/17 10:11:30 op 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 its 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;
1
'ret' declared without an initial value
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)
;
2
Loop condition is false. Exiting loop
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++) {
3
Assuming 'i' is >= 'llen'
4
Loop condition is false. Execution continues on line 275
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
4.1
'pctr' is equal to 0
!= 0) {
5
Taking false branch
276 cleanup();
277 return(dobeep_num("Opening and closing parentheses error line:",
278 lnm));
279 }
280 if (ret == FALSE0)
6
The left operand of '==' is a garbage value
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
496 strtonum(argp, 0, INT_MAX0x7fffffff, &errstr);
497 if (errstr != NULL((void *)0))
498 return (dobeep_msgs("Var not found:",
499 argp));
500 }
501
502 if (strlcpy(excbuf, cmdp, sizeof(excbuf))
503 >= sizeof(excbuf))
504 return (dobeep_msg("strlcpy error"));
505 if (strlcat(excbuf, s, sizeof(excbuf))
506 >= sizeof(excbuf))
507 return (dobeep_msg("strlcat error"));
508 if (strlcat(excbuf, argp, sizeof(excbuf))
509 >= sizeof(excbuf))
510 return (dobeep_msg("strlcat error"));
511
512 excline(excbuf, 0, 0);
513
514 if (fin)
515 break;
516
517 *p = ' '; /* unterminate arg string */
518 numspc++;
519 spc = 1;
520 }
521 }
522 return (TRUE1);
523}
524
525/*
526 * Is an item a value or a variable?
527 */
528static int
529isvar(char **argp, char **varbuf, int sizof)
530{
531 struct varentry *v1 = NULL((void *)0);
532
533 if (SLIST_EMPTY(&varhead)(((&varhead)->slh_first) == ((void *)0)))
534 return (FALSE0);
535#ifdef MGLOG
536 mglog_isvar(*varbuf, *argp, sizof);
537#endif
538 SLIST_FOREACH(v1, &varhead, entry)for((v1) = ((&varhead)->slh_first); (v1) != ((void *)0
); (v1) = ((v1)->entry.sle_next))
{
539 if (strcmp(*argp, v1->v_name) == 0) {
540 (void)(strlcpy(*varbuf, v1->v_buf, sizof) >= sizof);
541 return (TRUE1);
542 }
543 }
544 return (FALSE0);
545}
546
547
548static int
549foundfun(char *defstr, int expctr)
550{
551 return (TRUE1);
552}
553
554static int
555foundlst(char *defstr, int blkid, int expctr, int elen)
556{
557 char *p;
558
559 p = strstr(defstr, " ");
560 p = skipwhite(p);
561 expandvals(NULL((void *)0), p, defnam);
562
563 return (TRUE1);
564}
565
566/*
567 * 'define' strings follow the regex in parsdef().
568 */
569static int
570founddef(char *defstr, int blkid, int expctr, int hasval, int elen)
571{
572 struct varentry *vt, *v1 = NULL((void *)0);
573 char *p, *vnamep, *vendp = NULL((void *)0), *valp;
574
575 p = strstr(defstr, " "); /* move to first ' ' char. */
576 vnamep = skipwhite(p); /* find first char of var name. */
577 vendp = vnamep;
578
579 /* now find the end of the define/list name */
580 while (1) {
581 ++vendp;
582 if (*vendp == ' ')
583 break;
584 }
585 *vendp = '\0';
586
587 /*
588 * Check list name is not an existing mg function.
589 */
590 if (name_function(vnamep) != NULL((void *)0))
591 return(dobeep_msgs("Variable/function name clash:", vnamep));
592
593 if (!SLIST_EMPTY(&varhead)(((&varhead)->slh_first) == ((void *)0))) {
594 SLIST_FOREACH_SAFE(v1, &varhead, entry, vt)for ((v1) = ((&varhead)->slh_first); (v1) && (
(vt) = ((v1)->entry.sle_next), 1); (v1) = (vt))
{
595 if (strcmp(vnamep, v1->v_name) == 0)
596 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)
;
597 }
598 }
599 if ((v1 = malloc(sizeof(struct varentry))) == NULL((void *)0))
600 return (ABORT2);
601 SLIST_INSERT_HEAD(&varhead, v1, entry)do { (v1)->entry.sle_next = (&varhead)->slh_first; (
&varhead)->slh_first = (v1); } while (0)
;
602 if ((v1->v_name = strndup(vnamep, BUFSIZE128)) == NULL((void *)0))
603 return(dobeep_msg("strndup error"));
604 vnamep = v1->v_name;
605 v1->v_count = 0;
606 v1->v_vals = NULL((void *)0);
607 v1->v_buf[0] = '\0';
608
609 defnam = v1->v_buf;
610
611 if (hasval) {
612 valp = skipwhite(vendp + 1);
613
614 expandvals(NULL((void *)0), valp, defnam);
615 defnam = NULL((void *)0);
616 }
617 *vendp = ' ';
618 return (TRUE1);
619}
620
621
622static int
623expandvals(char *cmdp, char *valp, char *bp)
624{
625 char excbuf[BUFSIZE128], argbuf[BUFSIZE128];
626 char contbuf[BUFSIZE128], varbuf[BUFSIZE128];
627 char *argp, *endp, *p, *v, *s = " ";
628 char *regs;
629 int spc, cnt;
630 int sizof, fin, inquote;
631
632 /* now find the first argument */
633 p = skipwhite(valp);
634
635 if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))
636 return (dobeep_msg("strlcpy error"));
637 argp = argbuf;
638 spc = 1; /* initially fake a space so we find first argument */
639 fin = inquote = cnt = spc = 0;
640
641 for (p = argbuf; *p != '\0'; p++) {
642 if (*(p + 1) == '\0')
643 fin = 1;
644
645 if (*p != ' ') {
646 if (*p == '"') {
647 if (inquote == 1)
648 inquote = 0;
649 else
650 inquote = 1;
651 }
652 if (spc == 1)
653 argp = p;
654 spc = 0;
655 }
656 if ((*p == ' ' && inquote == 0) || fin) {
657 if (spc == 1)
658 continue;
659 /* terminate arg string */
660 if (*p == ' ') {
661 *p = '\0';
662 }
663 endp = p + 1;
664 excbuf[0] = '\0';
665 varbuf[0] = '\0';
666 contbuf[0] = '\0';
667 sizof = sizeof(varbuf);
668 v = varbuf;
669 regs = "[\"]+.*[\"]+";
670 if (doregex(regs, argp))
671 ; /* found quotes */
672 else if (isvar(&argp, &v, sizof)) {
673
674 (void)(strlcat(varbuf, " ",
675 sizof) >= sizof);
676
677 *p = ' ';
678 (void)(strlcpy(contbuf, endp,
679 sizeof(contbuf)) >= sizeof(contbuf));
680
681 (void)(strlcat(varbuf, contbuf,
682 sizof) >= sizof);
683
684 argbuf[0] = ' ';
685 argbuf[1] = '\0';
686 (void)(strlcat(argbuf, varbuf,
687 sizof) >= sizof);
688
689 p = argp = argbuf;
690 spc = 1;
691 fin = 0;
692 continue;
693 } else {
694 const char *errstr;
695
696 strtonum(argp, 0, INT_MAX0x7fffffff, &errstr);
697 if (errstr != NULL((void *)0))
698 return (dobeep_msgs("Var not found:",
699 argp));
700 }
701#ifdef MGLOG
702 mglog_misc("x|%s|%p|%d|\n", bp, defnam, BUFSIZE128);
703#endif
704 if (*bp != '\0') {
705 if (strlcat(bp, s, BUFSIZE128) >= BUFSIZE128)
706 return (dobeep_msg("strlcat error"));
707 }
708 if (strlcat(bp, argp, BUFSIZE128) >= BUFSIZE128) {
709 return (dobeep_msg("strlcat error"));
710 }
711/* v1->v_count++;*/
712
713 if (fin)
714 break;
715
716 *p = ' '; /* unterminate arg string */
717 spc = 1;
718 }
719 }
720 return (TRUE1);
721}
722
723/*
724 * Finished with buffer evaluation, so clean up any vars.
725 * Perhaps keeps them in mg even after use,...
726 */
727/*static int
728clearvars(void)
729{
730 struct varentry *v1 = NULL;
731
732 while (!SLIST_EMPTY(&varhead)) {
733 v1 = SLIST_FIRST(&varhead);
734 SLIST_REMOVE_HEAD(&varhead, entry);
735 free(v1->v_name);
736 free(v1);
737 }
738 return (FALSE);
739}
740*/
741/*
742 * Finished with block evaluation, so clean up any expressions.
743 */
744static void
745clearexp(void)
746{
747 struct expentry *e1 = NULL((void *)0);
748
749 while (!TAILQ_EMPTY(&ehead)(((&ehead)->tqh_first) == ((void *)0))) {
750 e1 = TAILQ_FIRST(&ehead)((&ehead)->tqh_first);
751 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)
;
752 free(e1->fun);
753 free(e1);
754 }
755 return;
756}
757
758/*
759 * Cleanup before leaving.
760 */
761void
762cleanup(void)
763{
764 defnam = NULL((void *)0);
765
766 clearexp();
767/* clearvars();*/
768}
769
770/*
771 * Test a string against a regular expression.
772 */
773static int
774doregex(char *r, char *e)
775{
776 regex_t regex_buff;
777
778 if (regcomp(&regex_buff, r, REG_EXTENDED0001)) {
779 regfree(&regex_buff);
780 return(dobeep_num("Regex compilation error line:", lnm));
781 }
782 if (!regexec(&regex_buff, e, 0, NULL((void *)0), 0)) {
783 regfree(&regex_buff);
784 return(TRUE1);
785 }
786 regfree(&regex_buff);
787 return(FALSE0);
788}
789
790/*
791 * Display a message so it is apparent that this is the method which stopped
792 * execution.
793 */
794static int
795exitinterpreter(char *ptr, char *dobuf, int dosiz)
796{
797 cleanup();
798 if (batch == 0)
799 return(dobeep_msg("Interpreter exited via exit command."));
800 return(FALSE0);
801}
802
803/*
804 * All code below commented out (until end of file).
805 *
806 * Need to think about how interpreter functions are done.
807 * Probably don't have a choice with string-append().
808
809static int getenvironmentvariable(char *, char *, int);
810static int stringappend(char *, char *, int);
811
812typedef int (*PFI)(char *, char *, int);
813
814
815struct ifunmap {
816 PFI fn_funct;
817 const char *fn_name;
818 struct ifunmap *fn_next;
819};
820static struct ifunmap *ifuns;
821
822static struct ifunmap ifunctnames[] = {
823 {exitinterpreter, "exit"},
824 {getenvironmentvariable, "get-environment-variable"},
825 {stringappend, "string-append"},
826 {NULL, NULL}
827};
828
829void
830ifunmap_init(void)
831{
832 struct ifunmap *fn;
833
834 for (fn = ifunctnames; fn->fn_name != NULL; fn++) {
835 fn->fn_next = ifuns;
836 ifuns = fn;
837 }
838}
839
840PFI
841name_ifun(const char *ifname)
842{
843 struct ifunmap *fn;
844
845 for (fn = ifuns; fn != NULL; fn = fn->fn_next) {
846 if (strcmp(fn->fn_name, ifname) == 0)
847 return (fn->fn_funct);
848 }
849
850 return (NULL);
851}
852
853
854int
855dofunc(char **ifname, char **tmpbuf, int sizof)
856{
857 PFI fnc;
858 char *p, *tmp;
859
860 p = strstr(*ifname, " ");
861 *p = '\0';
862
863 fnc = name_ifun(*ifname);
864 if (fnc == NULL)
865 return (FALSE);
866
867 *p = ' ';
868
869 tmp = *tmpbuf;
870
871 fnc(p, tmp, sizof);
872
873 return (TRUE);
874}
875
876static int
877getenvironmentvariable(char *ptr, char *dobuf, int dosiz)
878{
879 char *t;
880 char *tmp;
881 const char *q = "\"";
882
883 t = skipwhite(ptr);
884
885 if (t[0] == *q || t[strlen(t) - 1] == *q)
886 return (dobeep_msgs("Please remove '\"' around:", t));
887 if ((tmp = getenv(t)) == NULL || *tmp == '\0')
888 return(dobeep_msgs("Envar not found:", t));
889
890 dobuf[0] = '\0';
891 if (strlcat(dobuf, q, dosiz) >= dosiz)
892 return (dobeep_msg("strlcat error"));
893 if (strlcat(dobuf, tmp, dosiz) >= dosiz)
894 return (dobeep_msg("strlcat error"));
895 if (strlcat(dobuf, q, dosiz) >= dosiz)
896 return (dobeep_msg("strlcat error"));
897
898 return (TRUE);
899}
900
901static int
902stringappend(char *ptr, char *dobuf, int dosiz)
903{
904 char varbuf[BUFSIZE], funbuf[BUFSIZE];
905 char *p, *f, *v, *vendp;
906 int sizof, fin = 0;
907
908 varbuf[0] = funbuf[0] = '\0';
909 f = funbuf;
910 v = varbuf;
911 sizof = sizeof(varbuf);
912 *dobuf = '\0';
913
914 p = skipwhite(ptr);
915
916 while (*p != '\0') {
917 vendp = p;
918 while (1) {
919 if (*vendp == ' ') {
920 break;
921 } else if (*vendp == '\0') {
922 fin = 1;
923 break;
924 }
925 ++vendp;
926 }
927 *vendp = '\0';
928
929 if (isvar(&p, &v, sizof)) {
930 if (v[0] == '"' && v[strlen(v) - 1] == '"' ) {
931 v[strlen(v) - 1] = '\0';
932 v = v + 1;
933 }
934 if (strlcat(f, v, sizof) >= sizof)
935 return (dobeep_msg("strlcat error"));
936 } else {
937 if (p[0] == '"' && p[strlen(p) - 1] == '"' ) {
938 p[strlen(p) - 1] = '\0';
939 p = p + 1;
940 }
941 if (strlcat(f, p, sizof) >= sizof)
942 return (dobeep_msg("strlcat error"));
943 }
944 if (fin)
945 break;
946 vendp++;
947 if (*vendp == '\0')
948 break;
949 p = skipwhite(vendp);
950 }
951
952 (void)snprintf(dobuf, dosiz, "\"%s\"", f);
953
954 return (TRUE);
955}
956
957Index: main.c
958===================================================================
959RCS file: /cvs/src/usr.bin/mg/main.c,v
960retrieving revision 1.89
961diff -u -p -u -p -r1.89 main.c
962--- main.c 20 Mar 2021 09:00:49 -0000 1.89
963+++ main.c 12 Apr 2021 17:58:52 -0000
964@@ -133,10 +133,12 @@ main(int argc, char **argv)
965 extern void grep_init(void);
966 extern void cmode_init(void);
967 extern void dired_init(void);
968+ extern void ifunmap_init(void);
969
970 dired_init();
971 grep_init();
972 cmode_init();
973+ ifunmap_init();
974 }
975
976
977*/