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

    Source: geocities.com/vienna/7079/src

               ( geocities.com/vienna/7079)                   ( geocities.com/vienna)