/*
* INTERNAL.C - command.com internal commands.
*
* Comments:
*
* 17/08/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.
*
* cd()
* started.
*
* dir()
* i have added support for file attributes to the DIR() function. the
* routine adds "d" (directory) and "r" (read only) output. files with the
* system attribute have the filename converted to lowercase. files with
* the hidden attribute are not displayed.
*
* i have added support for directorys. now if the directory attribute is
* detected the file size if replaced with the string "
".
*
* ver()
* started.
*
* md()
* started.
*
* rd()
* started.
*
* del()
* started.
*
* does not support wildcard selection.
*
* todo: add delete directory support.
* add recursive directory delete support.
*
* ren()
* started.
*
* does not support wildcard selection.
*
* todo: add rename directory support.
*
* a general structure has been used for the cd, rd and md commands. this
* will be better in the long run. it is too hard to maintain such diverse
* functions when you are involved in a group project like this.
*
* 12/14/95 (Tim Norman) -----------------------------------------------------
* fixed DIR so that it will stick \*.* if a directory is specified and
* that it will stick on .* if a file with no extension is specified or
* *.* if it ends in a \
*
* 1/6/96 (Tim Norman) -----------------------------------------------------
* added an isatty call to DIR so it won't prompt for keypresses unless
* stdin and stdout are the console.
*
* changed parameters to be mutually consistent to make calling the
* functions easier
*
* rem()
* started.
*
* doskey()
* started.
*
* 1/22/96 (Oliver Mueller) -------------------------------------------------
* error messages are now handled by perror.
*
* 02/05/96 (Tim Norman) ----------------------------------------------------
* converted all functions to accept first/rest parameters
*
* 07/26/96 (Tim Norman) ----------------------------------------------------
*
* changed return values to int instead of void
*
* path()
* started.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#define SHELLINFO "FreeDOS Command Line Interface"
#define SHELLVER "version 0.60"
#define BADCMDLINE "bad or incorrect commandline"
#define USAGE "usage"
#define CD "change to directory cd [d:][path]"
#define MD "make directory md [d:]path"
#define RD "remove directory rd [d:]path"
#define DIR "display directory listing dir [d:][path][filespec]"
#define VER "display shell version info ver"
#define DEL "delete file del [d:][path]filespec"
#define REN "rename file ren [d:][path]filespec1 [d:][path]filespec2"
#define SET "SET"
#define PROMPTEQUAL "PROMPT="
#define PATHEQUAL "PATH="
/*
* function to destructively split a string into an array of strings
*
*
*/
void split (char *s, char **p)
{
int sc = 0, pc = 0; /* string and parameter counters */
while (s[sc])
{
if (sc && isspace (s[sc]) && !isspace (s[sc-1]))
s[sc] = 0;
else if (!isspace (s[sc]) && (sc == 0 || isspace (s[sc-1]) ||
s[sc-1] == 0))
p[pc++] = &s[sc];
sc++;
}
p[pc] = NULL;
}
/*
* set environment variables
*
*
*/
#pragma argsused
int set(char *first, char *rest)
{
unsigned char count; /* counter */
static char env_temp[128]; /* static copy for putenv */
/* if no parameters, show the environment */
if (rest[0] == 0)
{
void show_environment (void);
show_environment ();
return 0;
}
/* make a static local copy for putenv */
strcpy(env_temp, rest);
/* make sure there is an = in the command */
if(strchr(env_temp, '=') == NULL)
{
puts("Syntax error");
return 1;
}
/* capitalize name of env. var. */
for(count = 0; env_temp[count] && env_temp[count] != '='; count++)
{
env_temp[count] = toupper(env_temp[count]);
}
if (putenv(env_temp) < 0)
{
puts("Environment error");
}
return 0;
}
/*
* internal function to get the first argument from the parameter list
* and return a pointer to the beginning of the next argument, or NULL if
* there are no more arguments
*
*/
char *parse_firstarg (char *s)
{
char *place;
/* skip over first argument */
place = s;
while (*place && !isspace (*place))
place++;
if (*place)
{
/* mark the end of the first parameter */
*place = 0;
/* skip over whitespace before next argument */
while (isspace (*place));
place++;
/* if there is something here, return a pointer to it, else NULL */
if (*place)
return place;
else
return NULL;
}
else
return NULL;
}
/*
* generic function to handle cd, md, and rd (and their verbose names)
*
*
*/
int directory_handler(char *first, char *rest,
int (*func)(const char *),
char *func_name, char *usage)
{
char *dir; /* pointer to the directory to change to */
char *place; /* used to search for the \ when no space is used */
/* check if there is no space between the command and the path */
if (rest[0] == 0)
{
/* search for the \ or . so that both short & long names will work */
for (place = first; *place; place++)
if (*place == '.' || *place == '\\')
break;
if (*place)
dir = place;
else
dir = NULL; /* signal that there are no parameters */
}
else
{
/* if there is more than 1 parameter */
if (parse_firstarg (rest) != NULL)
{
printf("%s\n", BADCMDLINE);
printf("%s: %s\n", USAGE, usage);
return 1;
}
else
dir = rest;
}
/* if doing a CD and no parameters given, print out current directory */
if (func == chdir && (!dir || !dir[0]))
{
char direc[128];
char temp[128];
direc[0] = getdisk() + 'A';
direc[1] = ':';
getcurdir(0, temp);
if(temp[0] == '\\')
{
strcpy(&direc[2], temp);
}
else
{
direc[2] = '\\';
strcpy(&direc[3], temp);
}
printf("%s\n", direc);
return 0;
}
/* take off trailing \ if any, but ONLY if dir is not the root dir */
if (strlen (dir) >= 2 && dir[strlen (dir) - 1] == '\\')
dir[strlen (dir) - 1] = 0;
if (func (dir) != 0)
{
perror (func_name);
return 1;
}
return 0;
}
/*
* CD / CHDIR - makes a call to directory_handler to do its work
*
*
*/
int cd (char *first, char *rest)
{
return directory_handler (first, rest, chdir, "cd()", CD);
}
/*
* MD / MKDIR - makes a call to directory_handler to do its work
*
*
*/
int md (char *first, char *rest)
{
return directory_handler (first, rest, mkdir, "md()", MD);
}
/*
* RD / RMDIR - makes a call to directory_handler to do its work
*
*
*/
int rd (char *first, char *rest)
{
return directory_handler (first, rest, rmdir, "rd()", CD);
}
/*
* simple display directory internal command.
*
*
*/
#pragma argsused
int dir(char *first, char *rest)
{
struct ffblk file;
union REGS regs;
long bytes = 0;
int count;
int dirs = 0;
int done;
int files = 0;
int i;
int len;
int wildcards;
char fattrib[4];
char fname[13];
char searchname[128], lastchar;
int console;
char *filespec;
/* if there is more than one argument */
if(parse_firstarg (rest) != NULL)
{
printf("%s\n", BADCMDLINE);
printf("%s: %s\n", USAGE, DIR);
return 1;
}
/* check if we are on the console */
console = isatty (0) && isatty (1);
/* set up search name and see if we have wildcards */
if (!rest[0]) /* no arguments */
{
/* find all files if nothing specified */
strcpy (searchname, "*.*");
wildcards = 1;
len = 3;
}
else /* 1 argument */
{
/* get the filename specified and find the last character */
strcpy (searchname, rest);
len = strlen (searchname);
lastchar = searchname[len - 1];
wildcards = 0;
/* search for wildcards */
for (count = 0; count < len; count++)
if (searchname[count] == '*' || searchname[count] == '?')
{
wildcards = 1;
break;
}
}
/* check if filename ends in : or \ */
if (!wildcards && (lastchar == ':' || lastchar == '\\'))
strcpy (&searchname[len], "*.*");
else
{
/* see if this file is a directory */
if (!wildcards)
done = findfirst (searchname, &file, 0xff);
else
done = 1;
/* if we found a directory */
if (!done && (file.ff_attrib & 0x10))
strcpy (&searchname[len], "\\*.*");
else
{
/* search for a . before a \ */
for (count = len - 1; count >= 0; count--)
if (searchname[count] == '.' || searchname[count] == '\\')
break;
/* if the filename has no extension, add a .* */
if (count < 0 || (count >= 0 && searchname[count] == '\\'))
strcpy (&searchname[len], ".*");
}
}
/* scan through all the files (except hidden/system files) */
done = findfirst(searchname, &file, FA_RDONLY | FA_DIREC | FA_ARCH);
if (done)
{
printf ("File not found.\n");
return 1;
}
do
{
/* check file attributes */
fattrib[0] = file.ff_attrib & FA_DIREC ? 'd' : '-';
fattrib[1] = file.ff_attrib & FA_RDONLY ? 'r' : '-';
fattrib[2] = 0; /* terminate string */
fattrib[3] = file.ff_attrib & FA_HIDDEN ? 'h' : '-';
fattrib[4] = file.ff_attrib & FA_SYSTEM ? 's' : '-';
/* convert filename to lowercase if it has the system attribute */
if(fattrib[4] == 's')
{
for(i = 0; file.ff_name[i]; i++)
{
fname[i] = tolower(file.ff_name[i]);
}
}
else
{
strcpy(fname, file.ff_name);
}
if(fattrib[0] == 'd')
{
/* entry found is a directory */
dirs++;
printf("%s %-12s \n", fattrib, fname);
}
else
{
/* entry found is a file */
files++;
bytes += file.ff_fsize;
printf("%s %-12s %15ld\n", fattrib, fname, file.ff_fsize);
}
/* only prompt for keypress if stdin & stdout are console */
if(console && (files + dirs) % 20 == 0)
{
puts("[press any key to continue]");
getch();
}
done = findnext(&file);
}
while(!done);
printf(" %d file%s\n", files, files == 1 ? "" : "s");
printf(" %d dir%s\n", dirs, dirs == 1 ? "" : "s");
/* get free bytes */
regs.h.ah = 0x36;
regs.h.dl = 0;
int86(0x21, ®s, ®s);
printf(" %15ld byte%s used\n", bytes, bytes == 1 ? "" : "s");
printf(" %15ld bytes free\n", (long) regs.x.ax * regs.x.cx * regs.x.bx);
return 0;
}
/*
* display shell version info internal command.
*
*
*/
#pragma argsused
int ver(char *first, char *rest)
{
if(rest[0])
{
printf("%s\n", BADCMDLINE);
printf("%s: %s\n", USAGE, VER);
}
else
{
printf("License:\n");
printf(" This program is free software; you can redistribute it and/or modify\n");
printf(" it under the terms of the GNU General Public License as published by\n");
printf(" the Free Software Foundation; either version 2 of the License, or\n");
printf(" (at your option) any later version.\n\n");
printf(" This program is distributed in the hope that it will be useful,\n");
printf(" but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
printf(" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
printf(" GNU General Public License for more details.\n\n");
printf(" You should have received a copy of the GNU General Public License\n");
printf(" along with this program; if not, write to the Free Software\n");
printf(" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
printf("%s %s\n\n", SHELLINFO, SHELLVER);
printf("developed by: Tim Norman\n");
printf(" Matt Rains\n");
printf(" Evan Jeffrey\n");
printf(" Steffen Kaiser\n");
printf(" Oliver Mueller\n");
}
return 0;
}
/*
*
* simple file delete internal command.
*
*/
#pragma argsused
int del(char *first, char *rest)
{
/* if there is not exactly 1 parameter */
if(!rest[0] || parse_firstarg (rest) != NULL)
{
printf("%s\n", BADCMDLINE);
printf("%s: %s\n", USAGE, DEL);
return 1;
}
else if (remove (rest) != 0)
{
perror ("del()");
return 1;
}
return 0;
}
/*
*
* simple file rename internal command.
*
*/
#pragma argsused
int ren(char *first, char *rest)
{
char *arg[2];
/* set the first argument */
arg[0] = rest;
/* split off the first argument and get the second argument start */
arg[1] = parse_firstarg (rest);
/* check if there are the wrong number of arguments */
if (!arg[0][0] || !arg[1] || parse_firstarg (arg[1]) != NULL)
{
printf("%s\n", BADCMDLINE);
printf("%s: %s\n", USAGE, REN);
return 1;
}
else if (rename (arg[0], arg[1]) != 0)
{
perror ("ren()");
return 1;
}
return 0;
}
extern char exitflag;
/*
*
* set the exitflag to true
*
*/
#pragma argsused
int internal_exit (char *first, char *rest)
{
exitflag = 1;
return 0;
}
/*
*
* does nothing
*
*/
#pragma argsused
int rem (char *first, char *rest)
{
return 0;
}
/*
*
* prints DOSKEY message... will soon emulate DOSKEY macros
*
*/
#pragma argsused
int doskey (char *first, char *rest)
{
printf ("DOSKEY features are already enabled in the shell.\n");
return 0;
}
/*
*
* changes the PROMPT env. var.
*
*/
#pragma argsused
int prompt (char *first, char *rest)
{
char *from, *to, tempcommand[256];
/* create a fake command to pass to set() */
strcpy (tempcommand, PROMPTEQUAL);
if (*rest == '=')
{
from = &rest[1];
while (isspace (*from))
from++;
strcat (tempcommand, from);
}
else
strcat (tempcommand, rest);
return set(SET, tempcommand);
}
/*
*
* changes the PATH env. var.
*
*/
#pragma argsused
int path (char *first, char *rest)
{
char *from, *to, tempcommand[256];
if (!rest || !*rest)
{
printf ("PATH=%s\n", getenv ("PATH"));
return 0;
}
/* create a fake command to pass to set() */
strcpy (tempcommand, PATHEQUAL);
if (*rest == '=')
{
from = &rest[1];
while (isspace (*from))
from++;
strcat (tempcommand, from);
}
else
strcat (tempcommand, rest);
return set(SET, tempcommand);
}