Bug Summary

File:src/usr.bin/mg/interpreter.c
Warning:line 640, column 27
Although the value stored to 'cnt' is used in the enclosing expression, the value is never actually read from 'cnt'

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 */
640 inlist = fin = inquote = cnt = spc = 0;
Although the value stored to 'cnt' is used in the enclosing expression, the value is never actually read from 'cnt'
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*/