[comp.bugs.4bsd] The else clause of an if within a for does not get executed. +Fix

gww@marduk.UUCP (Gary Winiger) (09/05/87)

Subject: The else clause of an if within a for does not get executed. +Fix
Index:	bin/make 4.3BSD +Fix
Index:	bin/sh 4.3BSD +Fix

Description:
	The following Makefile rule succeed will succeed and the rule
fail will fail.  The bugs section in make(1) suggests using the ``-i''
flag to avoid such problems.

Makefile:
	#
	#	files /a, /b, /c, /d, /e exist.
	#	files /f, /g, /h, /i, /j do not exist
	#
	succeed:	
		-for i in a b c d e f g h i j; do \
			echo "/$$i for"; \
			if [ -f /$$i ]; then \
				echo "/$$i exists"; \
			else \
				echo "/$$i does not exist"; \
			fi; \
		done
	
	fail:
		for i in a b c d e f g h i j; do \
			echo "/$$i for"; \
			if [ -f /$$i ]; then \
				echo "/$$i exists"; \
			else \
				echo "/$$i does not exist"; \
			fi; \
		done
Repeat-By:
	Creating files /a, /b, /c, /d, /e and running
make succeed:
	for i in a b c d e f g h i j; do  echo "/$i for";  if [ -f /$i ];
	then  echo "/$i exists";  else  echo "/$i does not exist";  fi;  done
	/a for
	/a exists
	/b for
	/b exists
	/c for
	/c exists
	/d for
	/d exists
	/e for
	/e exists
	/f for
	/f does not exist
	/g for
	/g does not exist
	/h for
	/h does not exist
	/i for
	/i does not exist
	/j for
	/j does not exist
make fail:
	for i in a b c d e f g h i j; do  echo "/$i for";  if [ -f /$i ];
	then  echo "/$i exists";  else  echo "/$i does not exist";  fi;  done
	/a for
	/a exists
	/b for
	/b exists
	/c for
	/c exists
	/d for
	/d exists
	/e for
	/e exists
	/f for
	*** Exit 1
	
	Stop.
and make -i fail:
	for i in a b c d e f g h i j; do  echo "/$i for";  if [ -f /$i ];
	then  echo "/$i exists";  else  echo "/$i does not exist";  fi;  done
	/a for
	/a exists
	/b for
	/b exists
	/c for
	/c exists
	/d for
	/d exists
	/e for
	/e exists
	/f for
	/f does not exist
	/g for
	/g does not exist
	/h for
	/h does not exist
	/i for
	/i does not exist
	/j for
	/j does not exist
Fix:
	I believe the problem does not exist in make(1), but in sh(1).
It is true that make(1) may still require ``-i'' in some cases, but sh(1) is 
inappropriately reporting errors.  The enclosed fixes to sh(1) eliminate
this problem at Elxsi.  The files effected are:
	bin/sh/{args.c defs.h error.c macro.c main.c service.c xec.c}

Gary..
{ucbvax!sun,lll-lcc!lll-tis,amdahl!altos86,bridge2}!elxsi!gww
--------- cut --------- snip --------- :.,$w diff -------------
RCS file: /RCS/usr/src/bin/sh/args.c,v
retrieving revision 1.1
diff -c -r1.1 args.c
*** /tmp/,RCSt1001416	Mon Dec 15 12:05:57 1986
--- args.c	Mon Dec 15 11:54:29 1986
***************
*** 1,9 ****
  #ifndef lint
! static char *ERcsId = "$Header: args.c,v 1.1 86/12/10 17:37:50 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)args.c	4.4 7/31/85";
  #endif
  /*
   * $Log:	args.c,v $
   * Revision 1.1  86/12/10  17:37:50  gww
   * Initial revision
   * 
--- 1,17 ----
  #ifndef lint
! static char *ERcsId = "$Header: args.c,v 1.2 86/12/15 11:49:52 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)args.c	4.4 7/31/85";
  #endif
  /*
   * $Log:	args.c,v $
+  * Revision 1.2  86/12/15  11:49:52  gww
+  * Add an error flag to support correct processing of such constructs as 
+  * an if within a for.  If there is an else, it should be executed and the
+  * if should not report failure to the for.  The is especially noticable
+  * in Makefiles.  Make has a comment to use ``-i'' in this case.  This
+  * mod may infact fix the need to use ``-i'' when the shell should have
+  * handled the error response.
+  * 
   * Revision 1.1  86/12/10  17:37:50  gww
   * Initial revision
   * 
***************
*** 53,58 ****
--- 61,69 ----
  			WHILE *flagc ANDF *flagc != *cp DO flagc++ OD
  			IF *cp == *flagc
  			THEN	flags |= flagval[flagc-flagchar];
+ 				IF flags & errflg
+ 				THEN eflag = errflg
+ 				FI
  			ELIF *cp=='c' ANDF argc>2 ANDF comdiv==0
  			THEN	comdiv=argp[2];
  				argp[1]=argp[0]; argp++; argc--;
===================================================================
RCS file: /RCS/usr/src/bin/sh/defs.h,v
retrieving revision 1.1
diff -c -r1.1 defs.h
*** /tmp/,RCSt1001444	Mon Dec 15 12:09:03 1986
--- defs.h	Mon Dec 15 11:55:07 1986
***************
*** 1,6 ****
! /*	$Header: defs.h,v 1.1 86/12/10 17:38:02 gww Exp $ ENIX BSD
   *
   * $Log:	defs.h,v $
   * Revision 1.1  86/12/10  17:38:02  gww
   * Initial revision
   * 
--- 1,18 ----
! /*	$Header: defs.h,v 1.3 86/12/15 11:54:31 gww Exp $ ENIX BSD
   *
   * $Log:	defs.h,v $
+  * Revision 1.3  86/12/15  11:54:31  gww
+  * Add an error flag to support correct processing of such constructs as 
+  * an if within a for.  If there is an else, it should be executed and the
+  * if should not report failure to the for.  The is especially noticable
+  * in Makefiles.  Make has a comment to use ``-i'' in this case.  This
+  * mod may infact fix the need to use ``-i'' when the shell should have
+  * handled the error response.
+  * 
+  * Revision 1.2  86/12/10  18:25:23  gww
+  * Declare environ external so it gets linked correctly.
+  * Probably a typo in 4.3 code.
+  * 
   * Revision 1.1  86/12/10  17:38:02  gww
   * Initial revision
   * 
***************
*** 225,230 ****
--- 237,243 ----
  #define		keyflg	020000
  #define		batchflg	040000
  INT		flags;
+ INT		eflag;
  
  /* error exits from various parts of shell */
  #include	<setjmp.h>
***************
*** 255,261 ****
  BOOL		trapjmp[];
  
  /* name tree and words */
! STRING		*environ;
  CHAR		numbuf[];
  MSG		export;
  MSG		readonly;
--- 268,274 ----
  BOOL		trapjmp[];
  
  /* name tree and words */
! extern STRING	*environ;
  CHAR		numbuf[];
  MSG		export;
  MSG		readonly;
===================================================================
RCS file: /RCS/usr/src/bin/sh/error.c,v
retrieving revision 1.1
diff -c -r1.1 error.c
*** /tmp/,RCSt1001416	Mon Dec 15 12:05:59 1986
--- error.c	Mon Dec 15 11:55:37 1986
***************
*** 1,9 ****
  #ifndef lint
! static char *ERcsId = "$Header: error.c,v 1.1 86/12/10 17:38:04 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)error.c	4.2 8/11/83";
  #endif
  /*
   * $Log:	error.c,v $
   * Revision 1.1  86/12/10  17:38:04  gww
   * Initial revision
   * 
--- 1,17 ----
  #ifndef lint
! static char *ERcsId = "$Header: error.c,v 1.2 86/12/15 11:55:08 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)error.c	4.2 8/11/83";
  #endif
  /*
   * $Log:	error.c,v $
+  * Revision 1.2  86/12/15  11:55:08  gww
+  * Add an error flag to support correct processing of such constructs as 
+  * an if within a for.  If there is an else, it should be executed and the
+  * if should not report failure to the for.  The is especially noticable
+  * in Makefiles.  Make has a comment to use ``-i'' in this case.  This
+  * mod may infact fix the need to use ``-i'' when the shell should have
+  * handled the error response.
+  * 
   * Revision 1.1  86/12/10  17:38:04  gww
   * Initial revision
   * 
***************
*** 66,71 ****
--- 74,80 ----
  	 * Action is to return to command level or exit.
  	 */
  	exitval=xno;
+ 	flags |= eflag;
  	IF (flags & (forked|errflg|ttyflg)) != ttyflg
  	THEN	done();
  	ELSE	clearup();
===================================================================
RCS file: /RCS/usr/src/bin/sh/macro.c,v
retrieving revision 1.1
diff -c -r1.1 macro.c
*** /tmp/,RCSt1001416	Mon Dec 15 12:06:01 1986
--- macro.c	Mon Dec 15 11:55:41 1986
***************
*** 1,9 ****
  #ifndef lint
! static char *ERcsId = "$Header: macro.c,v 1.1 86/12/10 17:38:11 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)macro.c	4.3 8/11/83";
  #endif
  /*
   * $Log:	macro.c,v $
   * Revision 1.1  86/12/10  17:38:11  gww
   * Initial revision
   * 
--- 1,17 ----
  #ifndef lint
! static char *ERcsId = "$Header: macro.c,v 1.2 86/12/15 11:55:38 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)macro.c	4.3 8/11/83";
  #endif
  /*
   * $Log:	macro.c,v $
+  * Revision 1.2  86/12/15  11:55:38  gww
+  * Add an error flag to support correct processing of such constructs as 
+  * an if within a for.  If there is an else, it should be executed and the
+  * if should not report failure to the for.  The is especially noticable
+  * in Makefiles.  Make has a comment to use ``-i'' in this case.  This
+  * mod may infact fix the need to use ``-i'' when the shell should have
+  * handled the error response.
+  * 
   * Revision 1.1  86/12/10  17:38:11  gww
   * Initial revision
   * 
***************
*** 201,207 ****
  	    */
  	   chkpipe(pv);
  	   initf(pv[INPIPE]);
! 	   execute(t, 0, 0, pv);
  	   close(pv[OTPIPE]);
  	END
  	tdystak(savptr); staktop=movstr(savptr,stakbot);
--- 209,215 ----
  	    */
  	   chkpipe(pv);
  	   initf(pv[INPIPE]);
! 	   execute(t, 0, (int)(flags & errflg), 0, pv);
  	   close(pv[OTPIPE]);
  	END
  	tdystak(savptr); staktop=movstr(savptr,stakbot);
===================================================================
RCS file: /RCS/usr/src/bin/sh/main.c,v
retrieving revision 1.1
diff -c -r1.1 main.c
*** /tmp/,RCSt1001416	Mon Dec 15 12:06:03 1986
--- main.c	Mon Dec 15 11:55:45 1986
***************
*** 1,9 ****
  #ifndef lint
! static char *ERcsId = "$Header: main.c,v 1.1 86/12/10 17:38:12 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)main.c	4.3 3/19/85";
  #endif
  /*
   * $Log:	main.c,v $
   * Revision 1.1  86/12/10  17:38:12  gww
   * Initial revision
   * 
--- 1,17 ----
  #ifndef lint
! static char *ERcsId = "$Header: main.c,v 1.2 86/12/15 11:55:42 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)main.c	4.3 3/19/85";
  #endif
  /*
   * $Log:	main.c,v $
+  * Revision 1.2  86/12/15  11:55:42  gww
+  * Add an error flag to support correct processing of such constructs as 
+  * an if within a for.  If there is an else, it should be executed and the
+  * if should not report failure to the for.  The is especially noticable
+  * in Makefiles.  Make has a comment to use ``-i'' in this case.  This
+  * mod may infact fix the need to use ``-i'' when the shell should have
+  * handled the error response.
+  * 
   * Revision 1.1  86/12/10  17:38:12  gww
   * Initial revision
   * 
***************
*** 168,174 ****
  		IF eof
  		THEN	return;
  		FI
! 		execute(cmd(NL,MTFLG),0);
  		eof |= (flags&oneflg);
  	POOL
  }
--- 176,182 ----
  		IF eof
  		THEN	return;
  		FI
! 		execute(cmd(NL, MTFLG), 0, eflag);
  		eof |= (flags&oneflg);
  	POOL
  }
===================================================================
RCS file: /RCS/usr/src/bin/sh/service.c,v
retrieving revision 1.1
diff -c -r1.1 service.c
*** /tmp/,RCSt1001416	Mon Dec 15 12:06:07 1986
--- service.c	Mon Dec 15 11:55:49 1986
***************
*** 1,9 ****
  #ifndef lint
! static char *ERcsId = "$Header: service.c,v 1.1 86/12/10 17:38:21 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)service.c	4.4 3/19/85";
  #endif
  /*
   * $Log:	service.c,v $
   * Revision 1.1  86/12/10  17:38:21  gww
   * Initial revision
   * 
--- 1,17 ----
  #ifndef lint
! static char *ERcsId = "$Header: service.c,v 1.2 86/12/15 11:55:46 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)service.c	4.4 3/19/85";
  #endif
  /*
   * $Log:	service.c,v $
+  * Revision 1.2  86/12/15  11:55:46  gww
+  * Add an error flag to support correct processing of such constructs as 
+  * an if within a for.  If there is an else, it should be executed and the
+  * if should not report failure to the for.  The is especially noticable
+  * in Makefiles.  Make has a comment to use ``-i'' in this case.  This
+  * mod may infact fix the need to use ``-i'' when the shell should have
+  * handled the error response.
+  * 
   * Revision 1.1  86/12/10  17:38:21  gww
   * Initial revision
   * 
***************
*** 288,293 ****
--- 296,302 ----
  	IF wx ANDF flags&errflg
  	THEN	exitsh(rc);
  	FI
+ 	flags |= eflag;
  	exitval=rc; exitset();
  }
  
===================================================================
RCS file: /RCS/usr/src/bin/sh/xec.c,v
retrieving revision 1.1
diff -c -r1.1 xec.c
*** /tmp/,RCSt1001416	Mon Dec 15 12:06:12 1986
--- xec.c	Mon Dec 15 11:55:54 1986
***************
*** 1,9 ****
  #ifndef lint
! static char *ERcsId = "$Header: xec.c,v 1.1 86/12/10 17:38:31 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)xec.c	4.3 8/11/83";
  #endif
  /*
   * $Log:	xec.c,v $
   * Revision 1.1  86/12/10  17:38:31  gww
   * Initial revision
   * 
--- 1,20 ----
  #ifndef lint
! static char *ERcsId = "$Header: xec.c,v 1.3 86/12/15 11:55:49 gww Exp $ ENIX BSD";
  static char sccsid[] = "@(#)xec.c	4.3 8/11/83";
  #endif
  /*
   * $Log:	xec.c,v $
+  * Revision 1.3  86/12/15  11:55:49  gww
+  * Add an error flag to support correct processing of such constructs as 
+  * an if within a for.  If there is an else, it should be executed and the
+  * if should not report failure to the for.  The is especially noticable
+  * in Makefiles.  Make has a comment to use ``-i'' in this case.  This
+  * mod may infact fix the need to use ``-i'' when the shell should have
+  * handled the error response.
+  * 
+  * Revision 1.2  86/12/10  18:24:36  gww
+  * Fix typo-s in 4.3 code.
+  * 
   * Revision 1.1  86/12/10  17:38:31  gww
   * Initial revision
   * 
***************
*** 30,36 ****
  /* ========	command execution	========*/
  
  
! execute(argt, execflg, pf1, pf2)
  	TREPTR		argt;
  	INT		*pf1, *pf2;
  {
--- 41,47 ----
  /* ========	command execution	========*/
  
  
! execute(argt, execflg, errorflg, pf1, pf2)
  	TREPTR		argt;
  	INT		*pf1, *pf2;
  {
***************
*** 38,43 ****
--- 49,57 ----
  	REG TREPTR	t;
  	STKPTR		sav=savstak();
  
+ 	IF !errorflg
+ 	THEN	flags &= ~errflg;
+ 	FI
  	sigchk();
  
  	IF (t=argt) ANDF execbrk==0
***************
*** 213,219 ****
  
                                  case SYSUMASK:
                                          if (a1) {
!                                                 int c, i
                                                  i = 0;
                                                  while ((c = *a1++) >= '0' &&
                                                          c <= '7')
--- 227,233 ----
  
                                  case SYSUMASK:
                                          if (a1) {
!                                                 int c, i;
                                                  i = 0;
                                                  while ((c = *a1++) >= '0' &&
                                                          c <= '7')
***************
*** 300,308 ****
  				/* io redirection */
  				initio(t->treio);
  				IF type!=TCOM
! 				THEN	execute(t->forktre,1);
  				ELIF com[0]!=ENDARGS
! 				THEN	setlist(t->comset,N_EXPORT);
  					execa(com);
  				FI
  				done();
--- 314,323 ----
  				/* io redirection */
  				initio(t->treio);
  				IF type!=TCOM
! 				THEN	execute(t->forktre,1,errorflg);
  				ELIF com[0]!=ENDARGS
! 				THEN	eflag = 0;
! 					setlist(t->comset,N_EXPORT);
  					execa(com);
  				FI
  				done();
***************
*** 310,323 ****
  
  		case TPAR:
  			rename(dup(2),output);
! 			execute(t->partre,execflg);
  			done();
  
  		case TFIL:
  			BEGIN
  			   INT pv[2]; chkpipe(pv);
! 			   IF execute(t->lstlef, 0, pf1, pv)==0
! 			   THEN	execute(t->lstrit, execflg, pv, pf2);
  			   ELSE	closepipe(pv);
  			   FI
  			END
--- 325,338 ----
  
  		case TPAR:
  			rename(dup(2),output);
! 			execute(t->partre,execflg,errorflg);
  			done();
  
  		case TFIL:
  			BEGIN
  			   INT pv[2]; chkpipe(pv);
! 			   IF execute(t->lstlef, 0, errorflg, pf1, pv)==0
! 			   THEN	execute(t->lstrit, execflg, errorflg, pv, pf2);
  			   ELSE	closepipe(pv);
  			   FI
  			END
***************
*** 324,342 ****
  			break;
  
  		case TLST:
! 			execute(t->lstlef,0);
! 			execute(t->lstrit,execflg);
  			break;
  
  		case TAND:
! 			IF execute(t->lstlef,0)==0
! 			THEN	execute(t->lstrit,execflg);
  			FI
  			break;
  
  		case TORF:
! 			IF execute(t->lstlef,0)!=0
! 			THEN	execute(t->lstrit,execflg);
  			FI
  			break;
  
--- 339,357 ----
  			break;
  
  		case TLST:
! 			execute(t->lstlef,0,errorflg);
! 			execute(t->lstrit,execflg,errorflg);
  			break;
  
  		case TAND:
! 			IF execute(t->lstlef,0,0)==0
! 			THEN	execute(t->lstrit,execflg,errorflg);
  			FI
  			break;
  
  		case TORF:
! 			IF execute(t->lstlef,0,0)!=0
! 			THEN	execute(t->lstrit,execflg,errorflg);
  			FI
  			break;
  
***************
*** 357,363 ****
  			   loopcnt++;
  			   WHILE *args!=ENDARGS ANDF execbrk==0
  			   DO	assign(n,*args++);
! 				execute(t->fortre,0);
  				IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
--- 372,378 ----
  			   loopcnt++;
  			   WHILE *args!=ENDARGS ANDF execbrk==0
  			   DO	assign(n,*args++);
! 				execute(t->fortre,0,errorflg);
  				IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
***************
*** 372,379 ****
  			   INT		i=0;
  
  			   loopcnt++;
! 			   WHILE execbrk==0 ANDF (execute(t->whtre,0)==0)==(type==TWH)
! 			   DO i=execute(t->dotre,0);
  			      IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
--- 387,395 ----
  			   INT		i=0;
  
  			   loopcnt++;
! 			   WHILE execbrk==0 
! 				 ANDF (execute(t->whtre,0,0)==0)==(type==TWH)
! 			   DO i=execute(t->dotre,0,errorflg);
  			      IF execbrk<0 THEN execbrk=0 FI
  			   OD
  			   IF breakcnt THEN breakcnt-- FI
***************
*** 382,390 ****
  			break;
  
  		case TIF:
! 			IF execute(t->iftre,0)==0
! 			THEN	execute(t->thtre,execflg);
! 			ELSE	execute(t->eltre,execflg);
  			FI
  			break;
  
--- 398,408 ----
  			break;
  
  		case TIF:
! 			IF execute(t->iftre,0,0)==0
! 			THEN	execute(t->thtre,execflg,errorflg);
! 			ELIF t->eltre
! 			   THEN	execute(t->eltre,execflg,errorflg);
! 			   ELSE	exitval = 0;  /* force zero exit for if-then-fi */
  			FI
  			break;
  
***************
*** 397,403 ****
  				WHILE rex
  				DO	REG STRING	s;
  					IF gmatch(r,s=macro(rex->argval)) ORF (trim(s), eq(r,s))
! 					THEN	execute(t->regcom,0);
  						t=0; break;
  					ELSE	rex=rex->argnxt;
  					FI
--- 415,421 ----
  				WHILE rex
  				DO	REG STRING	s;
  					IF gmatch(r,s=macro(rex->argval)) ORF (trim(s), eq(r,s))
! 					THEN	execute(t->regcom,0,errorflg);
  						t=0; break;
  					ELSE	rex=rex->argnxt;
  					FI
***************
*** 412,417 ****
--- 430,436 ----
  
  	sigchk();
  	tdystak(sav);
+ 	flags |= eflag;
  	return(exitval);
  }
  
***************
*** 427,432 ****
  	ELIF f>=0
  	THEN	initf(f);
  	FI
! 	execute(cmd(NL, NLFLG|MTFLG),0);
  	pop();
  }
--- 446,451 ----
  	ELIF f>=0
  	THEN	initf(f);
  	FI
! 	execute(cmd(NL, NLFLG|MTFLG),0,(int)(flags & errflg));
  	pop();
  }