home *** CD-ROM | disk | FTP | other *** search
- /*
- * COMMAND.C - command-line interface.
- *
- * Version: 0.50
- *
- * Comments:
- *
- * 06/17/94 (Tim Norman) ---------------------------------------------------
- * started.
- *
- * 08/08/95 (Matt Rains) ---------------------------------------------------
- * i have cleaned up the source code. changes now bring this source into
- * guidelines for recommended programming practice.
- *
- * i have added the the standard FreeDOS GNU licence test to the
- * initialize() function.
- *
- * i have started to replease puts() with printf(). this will help
- * standardize output. please follow my lead.
- *
- * i have added some constants to help making changes easier.
- *
- * 12/15/95 (Tim Norman) ---------------------------------------------------
- * major rewrite of the code to make it more efficient and add
- * redirection support (finally!)
- *
- * 1/6/96 (Tim Norman) -----------------------------------------------------
- * finished adding redirection support!!! Changed to use our own exec
- * code (MUCH thanks to Svante Frey!!
- *
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <string.h>
- #include <dos.h>
- #include <process.h>
- #include <time.h>
- #include <errno.h>
- #include <dir.h>
- #include <fcntl.h>
- #include <io.h>
- #include <sys\stat.h>
-
- #include "command.h"
-
- #define DEBUG
-
- #define SYNTAXERR "ERROR: syntax error"
- #define NOENVERR "ERROR: no environment"
-
- #define INVALIDDRIVE "ERROR: invalid drive"
- #define INVALIDFUNCTION "ERROR: invalid function"
- #define FILENOTFOUND "ERROR: file not found"
- #define ACCESSDENIED "ERROR: access denied"
- #define NOTENOUGHMEMORY "ERROR: not enough memory"
- #define BADENVIROMENT "ERROR: bad enviroment"
- #define BADFORMAT "ERROR: bad format"
- #define ERROR_E2BIG "ERROR: Argument list too long"
- #define ERROR_EINVAL "ERROR: Invalid argument"
-
- #define PROMPT "prompt"
-
- #define EXIT "exit"
- #define CD "cd"
- #define DOSKEY "doskey"
- #define DIR "dir"
- #define REM "rem"
- #define SET "set"
- #define VER "ver"
- #define MD "md"
- #define RD "rd"
- #define DEL "del"
- #define REN "ren"
-
- char exitflag = 0; /* indicates EXIT was typed */
- char canexit = 1; /* indicates if this shell is exitable */
-
- /*
- * fatal error handler.
- *
- *
- */
- void fatal_error(char *s)
- {
- printf("fatal_error() : %s\n", s);
- exit(100);
- }
-
- /*
- * is character a delimeter when used on first word?
- *
- *
- */
- char is_delim(char c)
- {
- return(c == '/' || c == '=' || c == 0 || isspace (c));
- }
-
- /*
- * strip the extra spaces between parameters on command-line. quotation
- * mark aware.
- *
- */
- int strip(char *command)
- {
- unsigned char place = 0;
- unsigned char tempplace = 0;
- unsigned char firstword = 1;
- unsigned char inquote = 0;
- char temp[128] = "";
- char foundspace = 0;
-
- while(isspace(command[place]))
- {
- place++;
- }
-
- while(command[place])
- {
- if(foundspace && !isspace(command[place]))
- {
- temp[tempplace++] = ' ';
- foundspace = 0;
- }
-
- if (isspace (command[place]) && !inquote)
- {
- foundspace = 1;
- firstword = 0;
- }
- else if(is_delim(command[place]) && firstword)
- {
- temp[tempplace++] = ' ';
- temp[tempplace++] = command[place];
- }
- else if (command[place] == '"')
- {
- if(!inquote && place > 0 && !isspace(command[place - 1]))
- {
- temp[tempplace++] = ' ';
- }
-
- temp[tempplace++] = '"';
- inquote = !inquote;
-
- if(!inquote && !isspace(command[place + 1]))
- {
- temp[tempplace++] = ' ';
- }
- }
- else
- {
- temp[tempplace++] = command[place];
- }
-
- place++;
- }
-
- temp[tempplace] = 0;
- strcpy(command, temp);
-
- if(inquote)
- {
- return(0);
- }
- else
- {
- return(1); /* true on success */
- }
- }
-
- /*
- * split the command-line into parameters. works with quotation marks.
- *
- *
- */
- unsigned char split(char *command, char *p[128])
- {
- unsigned char count;
- unsigned char place = 1;
- unsigned char len;
- unsigned char inquote = 0;
-
- p[0] = command;
- len = strlen (command);
-
- for(count = 0; count < len; count++)
- {
- if(command[count] == '"')
- {
- inquote = !inquote;
- }
- else if(isspace (command[count]) && !inquote)
- {
- command[count] = 0;
- p[place++] = &command[count + 1];
- }
- }
-
- p[place] = NULL;
- return(place);
- }
-
- /* returns TRUE if the char is a delimiter char (i.e. can't be in a filename) */
- char is_special(char ch)
- {
- return(ch == '<' || ch == '>' || ch == '=' || ch == ',' || ch == ';' ||
- ch == ':' || ch == '*' || ch == '?' || ch == '[' || ch == ']' ||
- ch == '/' || ch == '\\'|| ch == '+' || ch == '"' || ch <= ' ' ||
- ch == '|');
- }
-
- /*
- * execute this as an external program
- *
- *
- */
- void execute (char *s)
- {
- char cmd[128], *p[128], *paths[129], fullname[128];
- int args, r;
-
- /* vars needed for the new EXEC stuff */
- char *start;
-
- strcpy (cmd, s);
-
- if (!strip (cmd))
- {
- fprintf (stderr, "%s\n", SYNTAXERR); /* unmatched quotes */
- return;
- }
-
- args = split (cmd, p);
-
- /* check this for shortcut commands and the like */
- if(p[0][0] && p[0][1] == ':' && p[0][2] == 0) /* change drives */
- {
- if(isalpha(p[0][0]))
- {
- setdisk(toupper(p[0][0]) - 'A');
- }
-
- if(getdisk () != toupper(p[0][0]) - 'A')
- {
- printf("%s\n", INVALIDDRIVE);
- }
- return;
- }
- else if (memicmp (p[0], CD, 2) == 0 && (p[0][2] == '\\' || p[0][2] == '.'))
- {
- cd(args, p, s);
- return;
- }
- else if (memicmp (p[0], MD, 2) == 0 && (p[0][2] == '\\' || p[0][2] == '.'))
- {
- md(args, p, s);
- return;
- }
- else if (memicmp (p[0], RD, 2) == 0 && (p[0][2] == '\\' || p[0][2] == '.'))
- {
- rd(args, p, s);
- return;
- }
-
- /* we need to search OUR path for the binary... use my searching algo */
- get_paths(paths);
-
- if(!find_which(paths, p[0], fullname))
- {
- fprintf(stderr, "%s\n", FILENOTFOUND);
- return;
- }
-
- start = s; /* point to command-line params */
-
- while(isspace(*start))
- {
- start++;
- }
-
- while(*start != 0 && !is_delim (*start))
- {
- start++;
- }
-
- while(isspace(*start))
- {
- start++;
- }
-
- if(!stricmp(strrchr(fullname,'.') + 1, "bat"))
- {
- batch(fullname, args, p);
- }
- else if((r = exec(fullname, start, EnvSeg)) != 0)
- {
- switch(r)
- {
- case 1 :
- {
- printf("%s\n", INVALIDFUNCTION);
- break;
- }
- case 2 :
- {
- printf("%s\n", FILENOTFOUND);
- break;
- }
- case 5 :
- {
- printf("%s\n", ACCESSDENIED);
- break;
- }
- case 8 :
- {
- printf("%s\n", NOTENOUGHMEMORY);
- break;
- }
- case 10 :
- {
- printf("%s\n", BADENVIROMENT);
- break;
- }
- case 11 :
- {
- printf("%s\n", BADFORMAT);
- break;
- }
- default :
- {
- printf("ERROR: unknown error %d.\n", errno);
- break;
- }
- }
- }
- }
-
- /* move this somewhere else later */
- static struct CMD
- {
- char *name;
- void (*func)(int, char *[128], char *);
- } cmds[] = { { "DIR", dir },
- { "CD", cd },
- { "RD", rd },
- { "MD", md },
- { "DEL", del },
- { "REN", ren },
- { "REM", rem },
- { "DOSKEY", doskey },
- { "EXIT", internal_exit },
- { "VER", ver },
- { "SET", set },
- { "PROMPT", prompt },
- { "LH", loadhigh },
- { "LOADHIGH", loadhigh },
- { "LOADFIX", loadfix },
- { NULL, NULL } };
-
- /*
- * run this command
- *
- *
- */
- void command (char *s)
- {
- char line[256]; /* just a little extra space :) */
- char com[128]; /* the first word in the command */
- int count, start;
- int executed = 0; /* whether the command was executed */
-
- strcpy (line, s);
-
- /* find the first word */
- /* skip over whitespace */
- start = 0;
- while (isspace (line[start]))
- start++;
- for (count = start; !is_delim (line[count]); count++)
- ;
-
- memcpy (com, &line[start], count - start);
- com[count - start] = 0;
-
- if (!com[0]) /* empty command line */
- return;
-
- for (count = 0; cmds[count].name; count++)
- if (strcmpi (com, cmds[count].name) == 0)
- {
- char *p[128];
- int num;
-
- if(!strip(line))
- {
- fprintf(stderr, "%s\n", SYNTAXERR); /* unmatched quote */
- return;
- }
-
- /* replace spaces with null's and place in p */
- num = split(line, p);
-
- cmds[count].func (num, p, s);
-
- executed = 1;
- break;
- }
-
- /* if none of those work, try calling it as an external program */
- if (!executed)
- execute (s);
- }
-
- /*
- * process the command line and execute the appropriate functions
- * full input/output redirection and piping are supported
- *
- */
- void parsecommandline (char *s)
- {
- char in[128] = "", out[128] = "", *pipes[128];
- int num, count;
- int oldinfd, oldoutfd, prevfd = -1, infd, outfd;
- char tempdir[128], fname[2][128] = {"", ""}, *t;
- int curfname = 0;
-
- /* find the temp directory to store temporary files */
- t = getenv ("TEMP");
- if (t)
- strcpy (tempdir, t);
- else
- strcpy (tempdir, ".");
-
- if (tempdir[strlen (tempdir) - 1] != '\\')
- strcat (tempdir, "\\");
-
- /* get the redirections from the command line */
- get_redirection (s, in, out, pipes, &num);
-
- /* inefficient, but oh well for now */
- while (isspace (in[0]))
- memmove (in, &in[1], strlen (in));
- while (isspace (out[0]))
- memmove (out, &out[1], strlen (out));
-
- if (in[0])
- {
- infd = open (in, O_TEXT | O_RDONLY, S_IREAD);
- if (infd == EOF)
- {
- printf ("Can't redirect from file %s\n", in);
- return;
- }
- }
- else
- infd = -1;
-
- if (out[0])
- {
- outfd = open (out, O_CREAT | O_TEXT, S_IWRITE);
- if (outfd == EOF)
- {
- printf ("Can't redirect to file %s\n", out);
- close (infd);
- return;
- }
- }
- else
- outfd = -1;
-
- for (count = 0; count < num; count++)
- {
- if (count == 0) /* make backups of stdin and stdout */
- {
- oldinfd = dup (0);
- oldoutfd = dup (1);
- }
-
- if (count == 0) /* first pipe gets input redirection */
- {
- if (infd != -1)
- {
- close (0);
- dup2 (infd, 0);
- close (infd);
- }
- }
- else /* input from last pipe's output */
- {
- close (prevfd);
- prevfd = open (fname[1 - curfname], O_TEXT | O_RDONLY, S_IREAD);
- if (prevfd == EOF)
- {
- close (0);
- dup2 (oldinfd, 0);
- close (oldinfd);
-
- close (1);
- dup2 (oldoutfd, 1);
- close (oldoutfd);
-
- /* this might leave some temporary files around... oh well */
- fprintf (stderr, "Error! Cannot pipe! Cannot open temporary file!\n");
- close (outfd);
- return;
- }
-
- close (0);
- dup2 (prevfd, 0);
- close (prevfd);
-
- if (fname[curfname][0])
- {
- unlink (fname[curfname]);
- }
- }
-
- if (count == num - 1) /* last pipe gets output redirection */
- {
- if (outfd != -1)
- {
- close (1);
- dup2 (outfd, 1);
- close (outfd);
- }
- else
- {
- close (1);
- dup2 (oldoutfd, 1);
- close (oldoutfd);
- }
- }
- else
- {
- strcpy (fname[curfname], tempdir);
- prevfd = creattemp (fname[curfname], 0);
- if (prevfd == EOF)
- {
- close (0);
- dup2 (oldinfd, 0);
- close (oldinfd);
-
- close (1);
- dup2 (oldoutfd, 1);
- close (oldoutfd);
-
- /* might leave some temp files around */
- fprintf (stderr, "Error! Cannot pipe! Cannot create temporary file!\n");
- close (infd);
- close (outfd);
- return;
- }
-
- close (1);
- dup2 (prevfd, 1);
- /* closing prevfd here causes things to not work for some reason */
-
- curfname = 1 - curfname; /* switch to other fname for next time */
- }
-
- /* process this command */
- command (pipes[count]);
- }
-
- if (prevfd != -1)
- close (prevfd);
-
- if (fname[1 - curfname][0])
- {
- unlink (fname[1 - curfname]);
- }
-
- if (in[0] || num > 1)
- {
- close (0);
- dup2 (oldinfd, 0);
- close (oldinfd);
- }
- else
- close (oldinfd);
-
- if (out[0])
- {
- close (1);
- dup2 (oldoutfd, 1);
- close (oldoutfd);
- }
- else
- close (oldoutfd);
- }
-
- /*
- *
- *
- *
- */
- int process_input(void)
- {
- char commandline[1024];
-
- do
- {
- printprompt();
- readcommand(commandline, 128);
- parsecommandline(commandline);
- }
- while(!canexit || !exitflag);
-
- return(0);
- }
-
- /*
- * control-break handler.
- *
- *
- */
- int c_brk(void)
- {
- return(1); /* continue execution */
- }
-
- /*
- *
- *
- *
- */
- void initialize(int argc, char *argv[])
- {
- unsigned char args; /* number of words on command line */
- char *p[128]; /* array of char pointers for splitting up command */
-
- args = 1;
-
- ctrlbrk(c_brk);
- ver(args, p, "ver");
-
- /* set up environment space and such */
- if(!EnvSeg) /* fix this to later make its own environment */
- {
- printf("%s\n", NOENVERR);
- exit(1);
- }
-
- /* figure out if we're a permanent shell... and make it do this */
- /* OwnerPSP = _psp; */
-
- return;
- }
-
- /*
- *
- *
- *
- */
- int main(int argc, char *argv[])
- {
- /* check switches on command-line */
- initialize(argc, argv);
-
- return(process_input()); /* call prompt routine */
- }
-