[net.general] Those annoying shell_commands type-o errors

malik@rdin.UUCP (05/02/84)

Subject:  UNIX shell editor
From:	  Jeffrey Malik
	  Resource Dynamics Inc.
Reply-to: philabs!rdin!/v/malik



	The following is a shell editor program.  It will allow users to redis-
play a shell command and correct it if it had been entered in error.

	The following are the commands that my program accept:

	1. Control A -to redisplay a shell command
	2. Control Y -to backspace over the redisplayed command
	3. Control C -to forward space over the redisplayed command
	4. Control E -to insert characters into the command
	5. Question Mark (?) -to verify user is in this program
	6. Control D -to exit shell editor program

All commands are self explanatory except for the Control E, which I will
comment on.

	To insert into the command, simply back or forward space to the point
of insertion.  Hit Control E.  Insertion will take place at the point just
before where the cursor is at.  Enter your additional command characters and
terminate insertion with another Control E.

	I do not forsee any problems with this program; I have thoroughly
tested it.  The only modification I believe it needs in order to work
on other terminals is changing the escape sequences for the back and
forward spacing.

	Please feel free to use it, and modify it if you like.  I would
greatly appreciate any comments, such as modifications made, functions
I left out, or bugs.  Thanks.





/* This shell editor program will enable a user to modify a	*/
/* shell command if it had been entered in error.		*/
/* Created April 27, 1984 by Jeffrey Malik			*/

#include <termio.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <stdio.h>

#define ESC 27		/* escape character			*/
#define CTRLE 5		/* control E -add to command		*/
#define CTRLD 4		/* control D -exit program		*/
#define CTRLA 1		/* control A -display previous command	*/
#define CTRLY 25	/* control Y -backspace over command	*/
#define CTRLC 3		/* control C -ahead space over command	*/

#define CR '\n'		/* carriage return 			*/
#define SPACE 32	/* decimal 32 is a space		*/
#define KYBRD 0		/* keyboard is standard input device	*/

int errno;		/* system error code			*/

main() {
char	command[80],    /* buffer for shell command		*/
	cmdchar;	/* shell command character		*/
int	cmdindex,	/* index to enter shell command		*/
	cmdlen;		/* lenght of shell command		*/

			/* save areas:				*/
int	lflagsav;	/* flags for control terminal functions	*/
char	eofsav,		/* end of file character		*/
	eolsav;		/* end of line character		*/
struct  termio term;	/* structure of terminal parameters	*/

  /* enable immediate input from keyboard without need for the	*/
  /* carriage return						*/

  /* get initial keyboard parameters and save those that will	*/
  /* be changed							*/
  ioctl(KYBRD, TCGETA, &term);
  lflagsav = term.c_lflag;
  eofsav = term.c_cc[4];
  eolsav = term.c_cc[5];

  /* change required keyboard parameters and store in structure */
  term.c_lflag = 57; /* -icanon */
  term.c_cc[4] = 01; /* eof = 1	*/
  term.c_cc[5] = 01; /* eol = 1	*/
  ioctl(KYBRD, TCSETA, &term);
  do {
	printf("$ ");
	fflush(stdout); /* needed to print prompt because of	*/
			/* 2.1 compiler bug			*/

	/* enter command */
	cmdchar = getchar();
	switch (cmdchar) {
		case CTRLA:
			modify(command, cmdlen);
			execute(command);
			break;
		case '?':
			printf("IN SHELL PROGRAM.\n");
			break;
		case CTRLD:
			printf("EXITING SHELL PROGRAM.\n");
			break;
		default:
			for (cmdindex=0; cmdindex < 80; cmdindex++)
				command[cmdindex] = NULL;
			cmdindex = 0;

		        /* enter shell command, terminate    	*/
			/* command input and execute it when	*/
			/* a carriage return is encountered	*/
			while (cmdchar != CR) {
				command[cmdindex] = cmdchar;
				cmdchar = getchar();
				++cmdindex;
			}
			cmdlen = cmdindex-1;
			execute(command);
			break;
	} /* end case statement */

  /* continue until user enters a Control D */
  } while (cmdchar != CTRLD);

  /* disable immediate input from keyboard */
  term.c_lflag = lflagsav;
  term.c_cc[4] = eofsav;
  term.c_cc[5] = eolsav;
  ioctl(KYBRD, TCSETA, &term);
}; /* end program */




modify(command, cmdlen)
char command[];		/* buffer for shell command to be modified	     */
int  cmdlen;		/* lenght of this shell command			     */
{
int	index,		/* index for the shell command			     */
	x;		/* index to save and restore parts of shell command  */
char	choice,		/* users control character input		     */
	cmdchar;	/* user entered shell command character		     */
char	tmpbuf[80];	/* save area for characters of command after insert  */
int	tmplen;		/* input index and size of tmpbuf		     */

/* display shell command */
for (index=0; index <= cmdlen; index++)
	printf("%c", command[index]);
choice = getchar();

/* modify the shell command until a carriage return is encountered at which  */
/* point the return is made from "modify" and the shell command is resub-    */
/* mitted to UNIX							     */
while (choice != CR) {
	switch (choice) {
		case CTRLY: /* backspace */
			--index;
			putchar(ESC);
			putchar('[');
			putchar('D');
			break;
		case CTRLC: /* forward */
			++index;
			putchar(ESC);
			putchar('[');
			putchar('C');
			break;
		case CTRLE: /* insert */
			/* save all characters of shell command after the   */
			/* the point of insertion			    */
			tmplen=(-1);
			for (x=index; x<=cmdlen; x++) {
				tmplen+=1;
				tmpbuf[tmplen] = command[x];
			}

			/* insert command characters until user enters      */
			/* another control E				    */
			cmdchar = getchar();
			while (cmdchar != CTRLE) {
				command[index] = cmdchar;
				cmdchar = getchar();
				++index;
			}

			/* restore saved characters and display		    */
			/* modified command 				    */
			for (x=0; x<=tmplen; x++) {
				command[index] = tmpbuf[x];
				printf("%c", command[index]);
				index+=1;
			}
			break;
		default:
			/* character change mode -increment index to shell  */
			/* command in case user needs to change more than   */
			/* one character the index will point to the next   */
			/* character to change				    */
			command[index]=choice;
			index += 1;
			break;
	} /* end case ststement */
	choice = getchar();
} /* end while-loop	   */
} /* end subroutine modify */





execute(command)
char command[]; /* buffer for shell command to execute		*/
{
char *strchr(), /* will return pointer to 'd' in 'cd' command	*/
     *getenv(), /* will return user's home directory		*/
     *dirnam;	/* pointer to directory name in cd command	*/
int  err;	/* error number return from the chdir command	*/

strskip(&command, SPACE);
if (!strncmp(command, "cd", 2)) {

	/* user entered a 'cd' command    */
	dirnam = (strchr(command, 'd') + 1);
	strskip(&dirnam, SPACE);
	if (*dirnam != NULL) {

		/* 'cd' command with directory argument */
		err = chdir(dirnam);
		if (err)
			printf("ERROR ON CHDIR: %d\n", errno);
	}
	else {  /* 'cd' without directory argument */
		dirnam = getenv("HOME");
		err = chdir(dirnam);
		if (err)
			printf("ERROR ON CHDIR: %d\n", errno);
	}
}
else /* any other shell command */
	system(command);

}





/* This routine will search past the character "byte" in the	*/
/* string "string".						*/
strskip(string, byte)
char **string,	/* pointer to the pointer to string to search	*/
     byte;	/* character to search past in string		*/
{
while (**string == byte)
	++(*string);
}