/**************** It is a mistake to use (raw) curse terminal, consider using GNU readline instead *************/
/*An "MS-DOS" Command-line Interpreter (shell) for Unix
You are to implement a simple shell for Unix that accepts MS-DOS
commands. Users are familiar with MS-DOS
commands, and like the output displayed similar to MS-DOS systems.
Typically, they would like to type their
favorite commands (dir, ch, del, ren) along with appropriate switches
and wildcards (*), and have the interpreter
perform the system calls and library functions. The result will be
formatted and displayed in a manner similar to
how MS-DOS displays the results.
Your interpreter should prompt with "currentdir>", and accept the
following commands (case insensitive):
Key
It keeps track of command lines typed at the prompt.
Syntax: Key [-N | -E]
-N number of commands to keep in the history list. Default is 20.
-E quit keeping track of previous commands.
Arrow Up/Down
Using the Up or Down arrow keys should recall previous commands by
scrolling through the history list.
Selecting a command and hitting return should invoke the command.
Dir
It displays a list of files and subdirectories in a directory. The "*"
wildcard can be used to select multiple files.
Syntax: DIR [path] [filename] [-P] [-W]
-P pauses after each screenful of information.
-W uses wide list format.
Example:
/home/y>dir
Directory of /home/y
. 04-16-97 1:20p
.. 04-16-97 1:20p
UA0249 EXE 19,423 08-14-98 2:42p
UA0249 TXT 2,399 06-23-98 1:01p
UA0249 RPT 9,789 06-23-98 1:01p
BROWSE COM 1,010 10-03-96 2:46p
4 file(s) 32621 bytes
2 dir(s)
DEL
It deletes one or more files. The "*" wildcard can be used to select
multiple files.
Syntax: DEL [path]filename [-P]
/P prompts for confirmation before deleting each file.
Example:
/home/y>del dir.txt -p
dir.txt, Delete (Y/N)?
REN
It renames a file/directory.
Syntax: REN [path][directoryname1 | filename1] [directoryname2 |
filename2]
Example:
/home/y>ren dir.txt dir.bak
CD
It displays the name of or changes the current directory.
Syntax: CD [path], or CD [..]
Example:
/home/y>cd ..
/home>
EXIT
Exit the MS-DOS shell.
*/
/* Anan Tongprasith */
#include
#include
#include
#include
#include
#include
#include
#include
/*Global variable*/
const char *del1="del",*exit1="exit",*cd1="cd",*ren1="ren",*key1="key",*dir1="dir";
char *myprompt="dos-",paramlist[10][50];
int maxline=21;maxhis=0,key=0,starthis=0,currentindex=0;
/* This is for error number returned from system call.*/
extern int errno;
/* Max history is 20 data + 1 space +1 position mark = total 22 record*/
int main()
{ int i,myx,myy,myinput,myindex=0,starty,hisindex=0;
int x,maxparam;/*systemmax=22*/
char myhistory[22][100];
char mymesg[50],mycommand[50],*mymark="|:>";
/*Initialize curse terminal*/
initscr();
cbreak();echo();
nonl();
intrflush(stdscr,FALSE);keypad(stdscr,TRUE);
setscrreg(0,25);
scrollok(stdscr,TRUE);
strcat(myprompt,getcwd(mymesg,50));
strcat(myprompt,&'>');
/*Set up the first mark in history array. This mark help prevent down
arrow key going beyond current index.*/
strcpy(myhistory[currentindex],mymark);
/* Say something */
addstr("Basic DOS-emulator");myy=mynewline(myy);
addstr("This program is a part of CSE3320 Operating Systems.");
myy=mynewline(myy);
addstr("Written by Anan Tongprasith.");myy=mynewline(myy);
/*Begin accepting command*/
addstr(myprompt); /*First prompt*/
getyx(stdscr,starty,myx); /*Get starting point*/
for(i=1;i<2210;i++)
{
myinput=getch(); /*Accepting input*/
switch (myinput) /*Determining input*/
{ case 13: /*Enter key*/
getyx(stdscr,myy,myx);
/* Using terminator to wrap up command*/
mycommand[myindex]='\0';
myy=mynewline(myy);
/* Check if mycommand is null*/
if(strcmp(mycommand,&'\0')!=0)
{
/* Record history if key command is active */
if(key!=0)
{ /* Copy command into history index */
strcpy(myhistory[currentindex],mycommand);
currentindex++;
/* Goto record 0 if over 20+1+1 records*/
if(currentindex==22)
{ currentindex=0;
}
/* Calculate how to shift the whole set if full */
/* The recorded history cross over 22 and 0 */
if(currentindex<=starthis)
{ currentindex+=22; /*imaginary index*/
}
/* If full, move the starting point*/
if(currentindex==starthis+maxhis)
if(++starthis==22) starthis=0;
currentindex=currentindex%22; /*real index*/
/* Put current position mark in place */
strcpy(myhistory[currentindex],mymark);
hisindex=currentindex;
}
/* Separate parameters and execute the command*/
maxparam=separate(mycommand);
if(execute(maxparam)==1)
return 0; /*exit program*/
}
myindex=0;
/* New prompt on newcom line */
addstr(myprompt);
refresh();
break;
case 8: /*Backspace key*/
case 127: /*Delete key*/
case KEY_LEFT: /*Left arrow key*/
myindex-=1;
if(myindex<0)
{ addstr(&'>');myindex=0; }
break;
case KEY_UP: /*Up arrow key pressed*/
/* Check if key command is active or not */
if(key!=0)
{
/* Clear current line */
getyx(stdscr,myy,myx);
move(myy,0);
clrtobot();
/* Put a newcom prompt in*/
addstr(myprompt);
--hisindex;
/* Circular history-index check */
/*Never go under starting index*/
if(hisindex-starthis==-1)
hisindex=starthis;
/* If go beyond 0 then circle back to 22 */
if(hisindex<0)
hisindex=21; /*(1to22)=(0to21)*/
/*Put an old command in*/
if(strcmp(mymark,myhistory[hisindex])!=0)
{ strcpy(mycommand,myhistory[hisindex]);
addstr(mycommand);
myindex=strlen(mycommand);
}
refresh();
}
break;
case KEY_DOWN: /*Down arrow key pressed*/
/* Check if key command is active or not */
if(key!=0)
{
/* Clear current line */
getyx(stdscr,myy,myx);
move(myy,0);
clrtobot();
/* Put a newcom prompt in */
addstr(myprompt);
/*Looking for current position*/
if(strcmp(myhistory[hisindex],mymark)!=0)
{ hisindex++;
hisindex=hisindex%22;
if(strcmp(myhistory[hisindex],mymark)!=0)
{ strcpy(mycommand,myhistory[hisindex]);
addstr(mycommand);
myindex=strlen(mycommand);
}
else
{ strcpy(mycommand,&'\0');
myindex=0;
}
}
refresh();
}
break;
default:
if (myinput<128)
mycommand[myindex]=myinput;
myindex++;
}
}
}
/* This function is for inserting a new line in. */
int mynewline(int myyy)
{ int mvy,mvx;
getyx(stdscr,mvy,mvx);
/* Scroll the terminal if maxline is met */
if(++mvy>maxline)
{ scroll(stdscr);mvy--;
move(mvy,0);refresh();
return(mvy);
}
/* Just increase line number if maxline is not met */
move(mvy,0);refresh();
return mvy;
}
/* This function is for separating command and parameters */
int separate(char newcom[50])
{ int i=0,j=0,k=0,linelength=strlen(newcom);char piece[50];
/* Big loop for the whole command line */
do
{
j=0;
/* Check for spaces (or tabs) */
while(newcom[i]==' '||newcom[i]==' ') i++;
/* Separation loop */
while (newcom[i]!=' '&&newcom[i]!='\0'&&newcom[i]!=' ')
{
piece[j]=newcom[i]; /*buffer=data*/
j++;i++;
}
/* Terminate the buffer before copying */
piece[j]='\0';
/* Copying the buffer into parameter list */
strcpy(paramlist[k],piece);
*piece='\0'; /*reset buffer*/
k=k+1;i++;
} while(i1) { mydel(max); }
else { addstr("Usage: del filenames [-p]");
myy=mynewline(myy);
}
return 0;
}
/* Check if it is a cd command */
if(strcmp(paramlist[0],cd1)==0)
{
if(max==2) { mycd(); }
else { addstr("Usage: cd pathname");
myy=mynewline(myy);
}
return 0;
}
/* Check if it is a ren command */
if(strcmp(paramlist[0],ren1)==0)
{
if(max==3) { myren(); }
else { addstr("Usage: ren filename1 filename2");
myy=mynewline(myy);
}
return 0;
}
/* Check if it is a key command */
if(strcmp(paramlist[0],key1)==0)
{
/* If no parameter specified set it to -20 */
if(max==1)
{ max=2;
strcpy(paramlist[1],buf);
}
if(max==2&¶mlist[1][0]=='-')
{ mykey(); }
else { addstr("Usage: key [-n] [-e]");
myy=mynewline(myy);
}
return 0;
}
/* Check if it is an exit command*/
if(strcmp(paramlist[0],exit1)==0)
{
return 1;
}
addstr("Invalid command");
myy=mynewline(myy);
return 0;
}
/* This function do the delete file job */
int mydel(int mycount)
{ int i=1;char myoption[3]="-p",myanswer[3]="y";
int ask=0,myyy,myxx;
getyx(stdscr,myyy,myxx);
/* Check for option -p */
if(strcmp(paramlist[mycount-1],myoption)==0)
{ ask=1;mycount--;
/* Option -p but no filename */
if (mycount==1)
{ addstr("Usage: del filenames [-p]");
myyy=mynewline(myyy);
return 0;
}
}
for(i=1;i');
}
}
/*This function do the rename job*/
int myren()
{ int myy;
if (link(paramlist[1],paramlist[2])==0)
{
/* Check if able to unlink the first file */
if(unlink(paramlist[1])!=0)
{ unlink(paramlist[2]);
addstr("Error! cannot rename the file.");
}
}
else
switch(errno)
{ case EACCES:
addstr("Error! permission denied.");
break;
case EDQUOT:
addstr("Error! out of disk space.");
break;
case EEXIST:
addstr(paramlist[2]);
addstr(" already exists.");
break;
case ENOENT:
addstr("Error! cannot find ");
addstr(paramlist[1]);
break;
case EPERM:
addstr("Error! cannot rename a directory");
break;
default:
addstr("Error!");
}
myy=mynewline(myy);
}
/*This function process the key command */
int mykey()
{ char cancl[5]="-e";int newmax,oldkey,myy;
/* Check for the flag -e */
if(strcmp(paramlist[1],cancl)==0)
{ key=0;
return 0;
}
/* No -e flag */
else
{ strcpy(cancl,paramlist[1]);
newmax=abs(atoi(cancl));
/* Check if new max is greater than the old one */
if(key0&&key<21)
{ /* if restart from -e clear the history */
if(oldkey==0)
starthis=currentindex;
sprintf(cancl,"%i",key);
addstr("New maximum is ");addstr(cancl);
sprintf(cancl,"%i",key);
maxhis=key+1; /* n data + 1 mark */
myy=mynewline(myy);
}
else
{
addstr("Key number must be between 0 and 20.");
myy=mynewline(myy);
key=oldkey;
}
}
else
/* New max is less than the old one; stick with the old one */
{ addstr("Maximum ");
sprintf(cancl,"%i",key);
addstr(cancl);addstr(" remains.");
myy=mynewline(myy);
}
}
}
/* This function do the directory command */
int mydir(int mmax)
{ int dircount=0,filecount=0,i,w=0,p=0,myy,myx,myline=0;
char buff[50],myday[3],mymon[3],myyear[3],myhour[3],mymin[3];
struct dirent *dp;struct stat fp;struct tm *mytime;
DIR *dfd;long bytecount=0;
/* Check for -p and -w flag */
if(mmax>1)
{ if(strcmp(paramlist[mmax-1],"-p")==0||strcmp(paramlist[mmax-2],"-p")==0)
{ p=1;mmax--; }
if(strcmp(paramlist[mmax-1],"-w")==0||strcmp(paramlist[mmax-2],"-w")==0)
{ w=1;mmax--; }
}
/* If no name is specified, use "." */
if(mmax==1) strcpy(paramlist[1],&'.');
if(mmax>2) {addstr("One at a time please.");mynewline(myy);return 0;}
/* Check if it is a file or a directory */
if((dfd=opendir(paramlist[1]))==NULL)
{
/* Happen to be a file */
if(lstat(paramlist[1],&fp)==0)
{ getcwd(buff,50);
addstr("Directory of ");addstr(buff);
myy=mynewline(myy);
addstr(paramlist[1]);
sprintf(buff,"%i",fp.st_size);
bytecount+=fp.st_size;
move(myy,20);
addstr(buff);
mytime=gmtime(&(fp.st_mtime));
if(mytime->tm_year<10) sprintf(myyear,"0%i",mytime->tm_year);
else sprintf(myyear,"%i",mytime->tm_year);
if(mytime->tm_mon<9) sprintf(mymon,"0%i",mytime->tm_mon+1);
else sprintf(mymon,"%i",mytime->tm_mon+1);
if(mytime->tm_mday<10) sprintf(myday,"0%i",mytime->tm_mday);
else sprintf(myday,"%i",mytime->tm_mday);
if(mytime->tm_hour<10) sprintf(myhour,"0%i",mytime->tm_hour);
else sprintf(myhour,"%i",mytime->tm_hour);
if(mytime->tm_min<10) sprintf(mymin,"0%i",mytime->tm_min);
else sprintf(mymin,"%i",mytime->tm_min);
sprintf(buff,"%s-%s-%s %s:%s",mymon,myday,myyear,myhour,mymin);
move(myy,30);
addstr(buff);
myy=mynewline(myy);
}
else
{
addstr("Error! cannot open the directory.");
myy=mynewline(myy);
}
}
/* Happen to be a directory */
else
{ getcwd(buff,50);strcat(buff,&'/');
addstr("Directory of ");addstr(buff);addstr(paramlist[1]);
myy=mynewline(myy);
if(p==1) myline=check(myline);
/* Read the directory entries */
while((dp=readdir(dfd))!=NULL)
{
lstat(dp->d_name,&fp);
/* Found a directory */
if(S_ISDIR(fp.st_mode))
{ dircount++;
addstr(dp->d_name);
/* No -w flag, full information return */
if(w==0)
{ move(myy,20);
addstr("");
mytime=gmtime(&(fp.st_mtime));
if(mytime->tm_year<10) sprintf(myyear,"0%i",mytime->tm_year);
else sprintf(myyear,"%i",mytime->tm_year);
if(mytime->tm_mon<9) sprintf(mymon,"0%i",mytime->tm_mon+1);
else sprintf(mymon,"%i",mytime->tm_mon+1);
if(mytime->tm_mday<10) sprintf(myday,"0%i",mytime->tm_mday);
else sprintf(myday,"%i",mytime->tm_mday);
if(mytime->tm_hour<10) sprintf(myhour,"0%i",mytime->tm_hour);
else sprintf(myhour,"%i",mytime->tm_hour);
if(mytime->tm_min<10) sprintf(mymin,"0%i",mytime->tm_min);
else sprintf(mymin,"%i",mytime->tm_min);
sprintf(buff,"%s-%s-%s %s:%s",mymon,myday,myyear,myhour,mymin);
move(myy,30);
addstr(buff);
myy=mynewline(myy);
if(p==1) myline=check(myline);
}
else
/* -w flag, spread into 4 columns */
{ move(myy,20*w);
if(w++>3)
{ myy=mynewline(myy);
w=1;
if(p==1) myline=check(myline);
}
}
}
/* A regular file is found */
if(S_ISREG(fp.st_mode))
{ filecount++;
addstr(dp->d_name);
sprintf(buff,"%i",fp.st_size);
bytecount+=fp.st_size;
/* No -w flag, full information return */
if(w==0)
{ move(myy,20);
addstr(buff);
mytime=gmtime(&(fp.st_mtime));
if(mytime->tm_year<10) sprintf(myyear,"0%i",mytime->tm_year);
else sprintf(myyear,"%i",mytime->tm_year);
if(mytime->tm_mon<9) sprintf(mymon,"0%i",mytime->tm_mon+1);
else sprintf(mymon,"%i",mytime->tm_mon+1);
if(mytime->tm_mday<10) sprintf(myday,"0%i",mytime->tm_mday);
else sprintf(myday,"%i",mytime->tm_mday);
if(mytime->tm_hour<10) sprintf(myhour,"0%i",mytime->tm_hour);
else sprintf(myhour,"%i",mytime->tm_hour);
if(mytime->tm_min<10) sprintf(mymin,"0%i",mytime->tm_min);
else sprintf(mymin,"%i",mytime->tm_min);
sprintf(buff,"%s-%s-%s %s:%s",mymon,myday,myyear,myhour,mymin);
move(myy,30);
addstr(buff);
myy=mynewline(myy);
if(p==1) myline=check(myline);
}
else
/* -w flag, spread into 4 colums */
{ move(myy,w*20);
if(w++>3)
{ w=1;
myy=mynewline(myy);
if(p==1) myline=check(myline);
}
}
}
}
myy=mynewline(myy);
if(p==1) myline=check(myline);
/* Display the summary information */
sprintf(buff,"%i",filecount);
addstr(buff);addstr(" file(s)");
sprintf(buff,"%i",bytecount);
move(myy,20);addstr(buff);addstr(" bytes");
myy=mynewline(myy);
if(p==1) myline=check(myline);
sprintf(buff,"%i",dircount);
addstr(buff);addstr(" dir(s)");
myy=mynewline(myy);
if(p==1) myline=check(myline);
closedir(dfd);
}
}
/* This function helps stop the display when a whole page filled */
int check(int mline)
{
mline++;
if(mline+1>maxline)
{ move(mline,0);addstr("Press any key to continue");
getch();
move(mline,0);clrtobot();refresh();
return 0;
}
return mline;
}
               (
geocities.com/vienna/7079)                   (
geocities.com/vienna)