I was finding it a bit tedious with long evaluation buffers so I wrote a
function that would translate these three (or more) lines:
find-file a.txt
find-file b.txt
find-file c.txt
into this one line:
(find-file a.txt b.txt c.txt)
There are a few commands that can be used like this: insert,
self-insert-char, kill-buffer, make-directory and some others.
Interestingly 'insert-buffer' makes mg segv when used in this way, though
it does behave the same without the below diff applied. I'll have to
have a look and see why.
I'm thinking I might write some kind of loop in the buffer evaulation
code.
However, does anyone object to this code? There is the side effect that
the '(' and ')' characters are no longer seen as white space during buffer
evaluation.
Mark
Index: extend.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/extend.c,v
retrieving revision 1.66
diff -u -p -u -p -r1.66 extend.c
--- extend.c 5 Jul 2019 14:50:59 -0000 1.66
+++ extend.c 5 Jul 2019 14:58:23 -0000
@@ -8,6 +8,7 @@
#include <sys/queue.h>
#include <sys/types.h>
+#include <regex.h>
#include <ctype.h>
#include <limits.h>
#include <signal.h>
@@ -693,6 +694,93 @@ load(const char *fname)
}
/*
+ * Line has a '(' as the first non-white char.
+ */
+int
+multiarg(char *funstr)
+{
+ regex_t regex_buff;
+ PF funcp;
+ char excbuf[128];
+ char *cmdp, *argp, *fendp, *endp, *p, *s = " ";
+ int singlecmd = 0, spc;
+
+ endp = strrchr(funstr, ')');
+ if (endp == NULL) {
+ ewprintf("No closing parenthesis found");
+ return(FALSE);
+ }
+ p = endp + 1;
+ /* we now know that string starts with '(' and ends with ')' */
+ *p = '\0';
+
+ if (regcomp(®ex_buff, "^\([\t ]*)$", 0)) {
+ dobeep();
+ ewprintf("Could not compile regex");
+ return(FALSE);
+ }
+ if (!regexec(®ex_buff, funstr, 0, NULL, 0)) {
+ dobeep();
+ ewprintf("No command found");
+ return(FALSE);
+ }
+
+ /* currently there are no mg commands that don't have a letter */
+ if (regcomp(®ex_buff, "^\([\t ]*[A-Za-z]*[\t ]*)$", 0)) {
+ dobeep();
+ ewprintf("Could not compile regex");
+ return(FALSE);
+ }
+ if (!regexec(®ex_buff, funstr, 0, NULL, 0))
+ singlecmd = 1;
+
+ p = funstr + 1; /* move past first '(' char. */
+ cmdp = skipwhite(p); /* find first char of command. */
+
+ if (singlecmd) {
+ cmdp[strlen(cmdp) - 1] = '\0'; /* remove ')' */
+ return(excline(cmdp));
+ }
+ if (((fendp = strchr(cmdp, ' ')) == NULL) &&
+ ((fendp = strchr(cmdp, '\t')) == NULL)) {
+ dobeep();
+ ewprintf("Regular expression misuse");
+ return (FALSE);
+ }
+ *fendp = '\0';
+
+ if ((funcp = name_function(cmdp)) == NULL) {
+ dobeep();
+ ewprintf("Unknown command: %s", cmdp);
+ return (FALSE);
+ }
+ /* now find the first argument */
+ p = fendp + 1;
+ argp = skipwhite(p);
+ spc = 1; /* initally fake a space so we find first argument */
+
+ for (p = argp; *p != '\0'; p++) {
+ if (*p == ' ' || *p == '\t' || *p == ')') {
+ if (spc == 0) {
+ *p = '\0'; /* terminate arg string */
+ excbuf[0] = '\0';
+ strlcpy(excbuf, cmdp, sizeof(excbuf));
+ strlcat(excbuf, s, sizeof(excbuf));
+ strlcat(excbuf, argp, sizeof(excbuf));
+ excline(excbuf);
+ *p = ' '; /* so 'for' loop can continue */
+ }
+ spc = 1;
+ } else {
+ if (spc == 1)
+ argp = p;
+ spc = 0;
+ }
+ }
+ return (TRUE);
+}
+
+/*
* excline - run a line from a load file or eval-expression.
*/
int
@@ -724,6 +812,8 @@ excline(char *line)
funcp = skipwhite(line);
if (*funcp == '\0')
return (TRUE); /* No error on blank lines */
+ if (*funcp == '(')
+ return (multiarg(funcp));
line = parsetoken(funcp);
if (*line != '\0') {
*line++ = '\0';
@@ -928,7 +1018,7 @@ cleanup:
static char *
skipwhite(char *s)
{
- while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
+ while (*s == ' ' || *s == '\t')
s++;
if ((*s == ';') || (*s == '#'))
*s = '\0';