View Issue Details

IDProjectCategoryView StatusLast Update
0000531tcshGeneralpublic2024-05-31 04:46
ReporterMProG10 Assigned To 
PrioritynormalSeverityminorReproducibilityN/A
Status newResolutionopen 
Summary0000531: Variable assignment from pipes and redirections
DescriptionIn recognition of Bourne-compatible Shells and Mashey Shell, I came up with an implementation for assigning variables from pipes and redirections. Normal assignment reads until EOF or a newline is found. Indexed assignment reads until EOF. This is implemented for environment variable assignment as well. In order to avoid confusion with manual assignment, assignment from pipes and redirections is only possible if the variable name doesn't precede the assignment operator [equal sign]. This means subsequent names in a single command (e.g: set a b c) will be assigned from a pipe or redirection. If the name precedes the assignment operator, subsequent names, even if preceded or not by the assignment operator, won't read from a pipe or redirection.

This work also provides a fix for pipes and piped built-ins, at the cost of having piped built-ins forked. I don't think this cost should be taken badly, since most (if not all) Bourne-compatible Shells fork piped built-ins. The fix remedies the issue regarded here [https://mailman.astron.com/pipermail/tcsh/2023-November/000337.html], on blank output from pipes.
Additional Informationhttps://github.com/tcsh-org/tcsh/pull/105
https://mailman.astron.com/pipermail/tcsh/2023-November/000337.html
TagsNo tags attached.

Activities

MProG10

2024-05-31 04:46

reporter  

sh.func.c.diff (590 bytes)   
--- a/sh.func.c
+++ b/sh.func.c
@@ -1353,8 +1353,21 @@ dosetenv(Char **v, struct command *c)
     if (*lp != '\0')
 	stderror(ERR_NAME | ERR_VARALNUM);
 
-    if ((lp = *v++) == 0)
-	lp = STRNULL;
+    if ((lp = *v++) == 0) {
+	if (c->t_dlef || !isatty(OLDSTD)) {
+	    Char c;
+	    struct Strbuf s = Strbuf_INIT;
+
+	    while (wide_read(0, &c, (size_t) 1, 0) > 0) {
+		if (c == '\n')
+		    break;
+		Strbuf_append1(&s, c | LITERAL);
+	    }
+	    Strbuf_terminate(&s);
+	    lp = s.s;
+	} else
+	    lp = STRNULL;
+    }
 
     lp = globone(lp, G_APPEND);
     cleanup_push(lp, xfree);
sh.func.c.diff (590 bytes)   
sh.sem.c.diff (2,517 bytes)   
--- a/sh.sem.c
+++ b/sh.sem.c
@@ -367,23 +367,13 @@ execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
 	if (bifunc && (t->t_dflg & F_PIPEIN))
 	    t->t_dflg &= ~(F_NOFORK);
 #endif /* BACKPIPE */
-	/*
-	 * Prevent forking cd, pushd, popd, chdir cause this will cause the
-	 * shell not to change dir! (XXX: but only for nice?)
-	 */
-	if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd ||
-		       bifunc->bfunct == (bfunc_t)dopushd ||
-		       bifunc->bfunct == (bfunc_t)dopopd))
-	    t->t_dflg &= ~(F_NICE);
-
 	if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
 	     (!bifunc || t->t_dflg &
 	      (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) ||
 	/*
-	 * We have to fork for eval too.
+	 * We have to fork for piped built-ins too.
 	 */
-	    (bifunc && (t->t_dflg & F_PIPEIN) != 0 &&
-	     bifunc->bfunct == (bfunc_t)doeval)) {
+	    (bifunc && (t->t_dflg & F_PIPEIN) != 0)) {
 #ifdef VFORK
 	    if (t->t_dtyp == NODE_PAREN ||
 		t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc)
@@ -631,17 +621,6 @@ execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
 	}
 
 	doio(t, pipein, pipeout);
-#ifdef BACKPIPE
-	if (t->t_dflg & F_PIPEIN) {
-	    xclose(pipein[0]);
-	    xclose(pipein[1]);
-	}
-#else /* !BACKPIPE */
-	if (t->t_dflg & F_PIPEOUT) {
-	    xclose(pipeout[0]);
-	    xclose(pipeout[1]);
-	}
-#endif /* BACKPIPE */
 	/*
 	 * Perform a builtin function. If we are not forked, arrange for
 	 * possible stopping
@@ -717,7 +696,6 @@ execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
 	execute(t->t_dcdr, wanttty, pv, pipeout, do_glob);
 #endif /* BACKPIPE */
 	break;
-
     case NODE_LIST:
 	if (t->t_dcar) {
 	    t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ);
@@ -871,8 +849,7 @@ doio(struct command *t, int *pipein, int *pipeout)
 	}
 	else if (flags & F_PIPEIN) {
 	    xclose(0);
-	    TCSH_IGNORE(dup(pipein[0]));
-	    xclose(pipein[0]);
+	    OLDSTD = dmove(pipein[0], 0);
 	    xclose(pipein[1]);
 	}
 	else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
@@ -934,7 +911,7 @@ doio(struct command *t, int *pipein, int *pipeout)
     }
     else if (flags & F_PIPEOUT) {
 	xclose(1);
-	TCSH_IGNORE(dup(pipeout[1]));
+	SHOUT = dcopy(pipeout[1], 1);
 	is1atty = 0;
     }
     else {
@@ -948,7 +925,7 @@ doio(struct command *t, int *pipein, int *pipeout)
 
     xclose(2);
     if (flags & F_STDERR) {
-	TCSH_IGNORE(dup(1));
+	SHDIAG = dcopy(1, 2);
 	is2atty = is1atty;
     }
     else {
sh.sem.c.diff (2,517 bytes)   
sh.set.c.diff (1,746 bytes)   
--- a/sh.set.c
+++ b/sh.set.c
@@ -248,7 +248,8 @@ doset(Char **v, struct command *c)
     int	    flags = VAR_READWRITE;
     int    first_match = 0;
     int    last_match = 0;
-    int    changed = 0;
+    int    changed;
+    int    pipe;
 
     USE(c);
     v++;
@@ -278,6 +279,9 @@ doset(Char **v, struct command *c)
 	plist(&shvhed, flags);
 	return;
     }
+    pipe = 0;
+    if (c->t_dlef || !isatty(OLDSTD))
+	pipe = 1;
     do {
 	hadsub = 0;
 	vp = p;
@@ -300,6 +304,7 @@ doset(Char **v, struct command *c)
 	else if (*v && eq(*v, STRequal)) {
 	    if (*++v != NULL)
 		p = *v++;
+	    pipe = 0;
 	}
 	if (eq(p, STRLparen)) {
 	    Char **e = v;
@@ -328,14 +333,48 @@ doset(Char **v, struct command *c)
 	else if (hadsub) {
 	    Char *copy;
 
-	    copy = Strsave(p);
+	    if (pipe) {
+		Char c;
+		struct Strbuf s = Strbuf_INIT;
+
+		while (wide_read(0, &c, (size_t) 1, 0) > 0)
+		    Strbuf_append1(&s, c | LITERAL);
+		Strbuf_terminate(&s);
+		copy = s.s;
+	    } else
+		copy = Strsave(p);
 	    cleanup_push(copy, xfree);
 	    asx(vp, subscr, copy);
 	    cleanup_ignore(copy);
 	    cleanup_until(copy);
 	}
-	else
-	    setv(vp, Strsave(p), flags);
+	else {
+	    if (pipe) {
+		Char c;
+		struct Strbuf s = Strbuf_INIT;
+		int empty = 1;
+
+		while (wide_read(0, &c, (size_t) 1, 0) > 0) {
+		    if (c == '\n') {
+			empty = 0;
+
+			break;
+		    }
+		    Strbuf_append1(&s, c | LITERAL);
+		}
+		if (empty && s.s == NULL) {
+		    Char **empty;
+
+		    *(empty = xmalloc(sizeof *empty)) = NULL;
+		    set1(vp, empty, &shvhed, flags);
+		}
+		else {
+		    Strbuf_terminate(&s);
+		    setv(vp, s.s, flags);
+		}
+	    } else
+		setv(vp, Strsave(p), flags);
+	}
 	update_vars(vp);
     } while ((p = *v++) != NULL);
 }
sh.set.c.diff (1,746 bytes)   

Issue History

Date Modified Username Field Change
2024-05-31 04:46 MProG10 New Issue
2024-05-31 04:46 MProG10 File Added: sh.func.c.diff
2024-05-31 04:46 MProG10 File Added: sh.sem.c.diff
2024-05-31 04:46 MProG10 File Added: sh.set.c.diff