Bug Summary

File:src/usr.bin/mg/interpreter.c
Warning:line 639, column 18
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.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;
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
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;
Although the value stored to 'cnt' is used in the enclosing expression, the value is never actually read from 'cnt'
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*/