/* * 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); }