Various Changes
[tpg/acess2.git] / Usermode / Applications / CLIShell_src / main.c
index d605baa..d6c40d6 100644 (file)
@@ -1,9 +1,10 @@
 /*\r
- AcessOS Shell Version 2\r
-- Based on IOOS CLI Shell\r
-*/\r
+ * AcessOS Shell Version 3\r
+ */\r
 #include <acess/sys.h>\r
 #include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
 #include "header.h"\r
 \r
 #define _stdin 0\r
 // ==== PROTOTYPES ====\r
 char   *ReadCommandLine(int *Length);\r
 void   Parse_Args(char *str, char **dest);\r
-void   Command_Colour(int argc, char **argv);\r
+void   CallCommand(char **Args);\r
+void   Command_Logout(int argc, char **argv);\r
 void   Command_Clear(int argc, char **argv);\r
-//void Command_Ls(int argc, char **argv);\r
+void   Command_Help(int argc, char **argv);\r
 void   Command_Cd(int argc, char **argv);\r
-//void Command_Cat(int argc, char **argv);\r
+void   Command_Dir(int argc, char **argv);\r
 \r
 // ==== CONSTANT GLOBALS ====\r
-char   *cCOLOUR_NAMES[8] = {"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"};\r
 struct {\r
        char    *name;\r
        void    (*fcn)(int argc, char **argv);\r
 }      cBUILTINS[] = {\r
-       {"colour", Command_Colour}, {"clear", Command_Clear}, {"cd", Command_Cd}\r
+       {"exit", Command_Logout},       {"logout", Command_Logout},\r
+       {"help", Command_Help}, {"clear", Command_Clear},\r
+       {"cd", Command_Cd}, {"dir", Command_Dir}\r
 };\r
+static char    *cDEFAULT_PATH[] = {"/Acess/Bin"};\r
 #define        BUILTIN_COUNT   (sizeof(cBUILTINS)/sizeof(cBUILTINS[0]))\r
 \r
 // ==== LOCAL VARIABLES ====\r
+ int   giNumPathDirs = 1;\r
+char   **gasPathDirs = cDEFAULT_PATH;\r
+char   **gasEnvironment;\r
 char   gsCommandBuffer[1024];\r
-char   *gsCurrentDirectory = "/";\r
-char   gsTmpBuffer[1024];\r
+char   *gsCurrentDirectory = NULL;\r
 char   **gasCommandHistory;\r
  int   giLastCommand = 0;\r
  int   giCommandSpace = 0;\r
@@ -41,18 +47,28 @@ char        **gasCommandHistory;
 int main(int argc, char *argv[], char *envp[])\r
 {\r
        char    *sCommandStr;\r
-       char    *saArgs[32];\r
+       char    *saArgs[32] = {0};\r
         int    length = 0;\r
-        int    pid = -1;\r
+        int    i;\r
         int    iArgCount = 0;\r
         int    bCached = 1;\r
-       t_sysFInfo      info;\r
        \r
-       //Command_Clear(0, NULL);\r
+       gasEnvironment = envp;\r
+       \r
+       Command_Clear(0, NULL);\r
+       \r
+       {\r
+               char    *tmp = getenv("CWD");\r
+               if(tmp) {\r
+                       gsCurrentDirectory = malloc(strlen(tmp)+1);\r
+                       strcpy(gsCurrentDirectory, tmp);\r
+               } else {\r
+                       gsCurrentDirectory = malloc(2);\r
+                       strcpy(gsCurrentDirectory, "/");\r
+               }\r
+       }       \r
        \r
-       write(_stdout, 1, "\n");\r
-       write(_stdout, 36, "Acess Shell Version 3\n");\r
-       write(_stdout, 30, " Based on CLI Shell for IOOS\n");\r
+       write(_stdout, 22, "Acess Shell Version 3\n");\r
        write(_stdout,  2, "\n");\r
        for(;;)\r
        {\r
@@ -60,12 +76,18 @@ int main(int argc, char *argv[], char *envp[])
                if(saArgs[0])   free(saArgs);\r
                if(!bCached)    free(sCommandStr);\r
                bCached = 0;\r
+               \r
                write(_stdout, strlen(gsCurrentDirectory), gsCurrentDirectory);\r
-               write(_stdout, 3, "$ ");\r
+               write(_stdout, 2, "$ ");\r
                \r
                // Read Command line\r
                sCommandStr = ReadCommandLine( &length );\r
                \r
+               if(!sCommandStr) {\r
+                       write(_stdout, 25, "PANIC: Out of heap space\n");\r
+                       return -1;\r
+               }\r
+               \r
                // Check if the command should be cached\r
                if(gasCommandHistory == NULL || strcmp(sCommandStr, gasCommandHistory[giLastCommand]) != 0)\r
                {\r
@@ -89,44 +111,18 @@ int main(int argc, char *argv[], char *envp[])
                if(saArgs[1][0] == '\0')        continue;\r
                \r
                // Check Built-In Commands\r
-               //  [HACK] Mem Usage - Use Length in place of `i'\r
-               for(length=0;length<BUILTIN_COUNT;length++)\r
+               for( i = 0; i < BUILTIN_COUNT; i++ )\r
                {\r
-                       if(strcmp(saArgs[1], cBUILTINS[length].name) == 0)\r
+                       if( strcmp(saArgs[1], cBUILTINS[i].name) == 0 )\r
                        {\r
-                               cBUILTINS[length].fcn(iArgCount-1, &saArgs[1]);\r
+                               cBUILTINS[i].fcn(iArgCount-1, &saArgs[1]);\r
                                break;\r
                        }\r
                }\r
+               if(i != BUILTIN_COUNT)  continue;\r
                \r
-               if(length != BUILTIN_COUNT)     continue;\r
-               
-               // - Calling a file\r
-               GeneratePath(saArgs[1], gsCurrentDirectory, gsTmpBuffer);\r
-               // Use length in place of fp\r
-               length = open(gsTmpBuffer, 0);\r
-               // Check file existence\r
-               if(length == -1) {\r
-                       Print("Unknown Command: `");Print(saArgs[1]);Print("'\n");      // Error Message\r
-                       continue;\r
-               }\r
-               // Check if the file is a directory\r
-               finfo( length, &info );
-               close( length );\r
-               if(info.flags & FILEFLAG_DIRECTORY) {\r
-                       Print("`");Print(saArgs[1]);    // Error Message\r
-                       Print("' is a directory.\n");\r
-                       continue;\r
-               }\r
-               pid = clone(CLONE_VM, 0);\r
-               if(pid == 0)    execve(gsTmpBuffer, &saArgs[1], NULL);\r
-               if(pid <= 0) {\r
-                       Print("Unablt to create process: `");Print(gsTmpBuffer);Print("'\n");   // Error Message
-                       //SysDebug("pid = %i\n", pid);\r
-               }\r
-               else {\r
-                       //waitpid(pid, K_WAITPID_DIE);\r
-               }\r
+               // Shall we?\r
+               CallCommand( &saArgs[1] );\r
        }\r
 }\r
 \r
@@ -139,17 +135,62 @@ char *ReadCommandLine(int *Length)
        char    *ret;\r
         int    len, pos, space = 1023;\r
        char    ch;\r
+       // int  scrollbackPos = giLastCommand;\r
         \r
        // Preset Variables\r
        ret = malloc( space+1 );\r
-       len = 0;\r
-       pos = 0;\r
+       if(!ret)        return NULL;\r
+       len = 0;        pos = 0;\r
                \r
        // Read In Command Line\r
        do {\r
                read(_stdin, 1, &ch);   // Read Character from stdin (read is a blocking call)\r
-               // Ignore control characters\r
-               if(ch < 0)      continue;\r
+               // Control characters\r
+               if(ch == '\x1B') {\r
+                       read(_stdin, 1, &ch);   // Read control character\r
+                       switch(ch)\r
+                       {\r
+                       //case 'D':     if(pos) pos--;  break;\r
+                       //case 'C':     if(pos<len)     pos++;  break;\r
+                       case '[':\r
+                               read(_stdin, 1, &ch);   // Read control character\r
+                               switch(ch)\r
+                               {\r
+                               #if 0\r
+                               case 'A':       // Up\r
+                                       if( scrollbackPos > 0 ) break;\r
+                                       \r
+                                       free(ret);\r
+                                       ret = strdup( gasCommandHistory[--scrollbackPos] );\r
+                                       \r
+                                       len = strlen(ret);\r
+                                       while(pos--)    write(_stdout, 3, "\x1B[D");\r
+                                       while(pos++ < len)      write(_stdout, 3, "\x1B[C");\r
+                                       break;\r
+                               case 'B':       // Down\r
+                                       if( scrollbackPos < giLastCommand-1 )   break;\r
+                                       free(ret);\r
+                                       ret = strdup( gasCommandHistory[++scrollbackPos] );\r
+                                       \r
+                                       len = strlen(ret);\r
+                                       while(pos--)    write(_stdout, 3, "\x1B[D");\r
+                                       while(pos++ < len)      write(_stdout, 3, "\x1B[C");\r
+                                       break;\r
+                               #endif\r
+                               case 'D':       // Left\r
+                                       if(pos == 0)    break;\r
+                                       pos --;\r
+                                       write(_stdout, 3, "\x1B[D");\r
+                                       break;\r
+                               case 'C':       // Right\r
+                                       if(pos == len-1)        break;\r
+                                       pos++;\r
+                                       write(_stdout, 3, "\x1B[C");\r
+                                       break;\r
+                               }\r
+                       }\r
+                       continue;\r
+               }\r
                // Backspace\r
                if(ch == '\b') {\r
                        if(len <= 0)            continue;       // Protect against underflows\r
@@ -163,6 +204,13 @@ char *ReadCommandLine(int *Length)
                        write(_stdout, 1, &ch);\r
                        continue;\r
                }\r
+               // Tab\r
+               if(ch == '\t') {\r
+                       //TODO: Implement Tab-Completion\r
+                       //Currently just ignore tabs\r
+                       continue;\r
+               }\r
+               \r
                // Expand Buffer\r
                if(len > space) {\r
                        space += 256;\r
@@ -194,6 +242,12 @@ void Parse_Args(char *str, char **dest)
         int    i = 1;\r
        char    *buf = malloc( strlen(str) + 1 );\r
        \r
+       if(buf == NULL) {\r
+               dest[0] = NULL;\r
+               Print("Parse_Args: Out of heap space!\n");\r
+               return ;\r
+       }\r
+       \r
        strcpy(buf, str);\r
        dest[0] = buf;\r
        \r
@@ -225,68 +279,111 @@ void Parse_Args(char *str, char **dest)
 }\r
 \r
 /**\r
- * \fn void Command_Colour(int argc, char **argv)\r
- * \brief \r
+ * \fn void CallCommand(char **Args)\r
  */\r
-void Command_Colour(int argc, char **argv)\r
+void CallCommand(char **Args)\r
 {\r
-       int fg, bg;\r
-       char    clrStr[6] = "\x1B[37m";\r
+       t_sysFInfo      info;\r
+        int    pid = -1;\r
+        int    fd = 0;\r
+       char    sTmpBuffer[1024];\r
+       char    *exefile = Args[0];\r
        \r
-       // Verify Arg Count\r
-       if(argc < 2)\r
+       if(exefile[0] == '/'\r
+       || (exefile[0] == '.' && exefile[1] == '/')\r
+       || (exefile[0] == '.' && exefile[1] == '.' && exefile[2] == '/')\r
+               )\r
        {\r
-               Print("Please specify a colour\n");\r
-               goto usage;\r
-       }\r
-       \r
-       // Check Colour\r
-       for(fg=0;fg<8;fg++)\r
-               if(strcmp(cCOLOUR_NAMES[fg], argv[1]) == 0)\r
-                       break;\r
-\r
-       // Foreground a valid colour\r
-       if(fg == 8) {\r
-               Print("Unknown Colour '");Print(argv[1]);Print("'\n");\r
-               goto usage;\r
+               GeneratePath(exefile, gsCurrentDirectory, sTmpBuffer);\r
+               // Check file existence\r
+               fd = open(sTmpBuffer, OPENFLAG_EXEC);\r
+               if(fd == -1) {\r
+                       Print("Unknown Command: `");Print(Args[0]);Print("'\n");        // Error Message\r
+                       return ;\r
+               }\r
+               \r
+               // Get File info and close file\r
+               finfo( fd, &info, 0 );\r
+               close( fd );\r
+               \r
+               // Check if the file is a directory\r
+               if(info.flags & FILEFLAG_DIRECTORY) {\r
+                       Print("`");Print(sTmpBuffer);   // Error Message\r
+                       Print("' is a directory.\n");\r
+                       return ;\r
+               }\r
        }\r
-       // Set Foreground\r
-       clrStr[3] = '0' + fg;\r
-       write(_stdout, 6, clrStr);\r
-       \r
-       // Need to Set Background?\r
-       if(argc > 2)\r
+       else\r
        {\r
-               for(bg=0;bg<8;bg++)\r
-                       if(strcmp(cCOLOUR_NAMES[bg], argv[2]) == 0)\r
-                               break;\r
-       \r
-               // Valid colour\r
-               if(bg == 8)\r
+                int    i;\r
+               \r
+               // Check all components of $PATH\r
+               for( i = 0; i < giNumPathDirs; i++ )\r
                {\r
-                       Print("Unknown Colour '");Print(argv[2]);Print("'\n");\r
-                       goto usage;\r
+                       GeneratePath(exefile, gasPathDirs[i], sTmpBuffer);\r
+                       fd = open(sTmpBuffer, OPENFLAG_EXEC);\r
+                       if(fd == -1)    continue;\r
+                       finfo( fd, &info, 0 );\r
+                       close( fd );\r
+                       if(info.flags & FILEFLAG_DIRECTORY)     continue;\r
+                       // Woohoo! We found a valid command\r
+                       break;\r
+               }\r
+               \r
+               // Exhausted path directories\r
+               if( i == giNumPathDirs ) {\r
+                       Print("Unknown Command: `");Print(exefile);Print("'\n");\r
+                       return ;\r
                }\r
+       }\r
        \r
-               clrStr[2] = '4';\r
-               clrStr[3] = '0' + bg;\r
-               write(_stdout, 6, clrStr);\r
+       // Create new process\r
+       pid = clone(CLONE_VM, 0);\r
+       // Start Task\r
+       if(pid == 0)\r
+               execve(sTmpBuffer, Args, gasEnvironment);\r
+       if(pid <= 0) {\r
+               Print("Unablt to create process: `");Print(sTmpBuffer);Print("'\n");    // Error Message\r
        }\r
-       // Return\r
-       return;\r
-\r
-       // Function Usage (Requested via a Goto (I know it's ugly))\r
-usage:\r
-       Print("Valid Colours are ");\r
-       for(fg=0;fg<8;fg++)\r
-       {\r
-               Print(cCOLOUR_NAMES[fg]);\r
-               write(_stdout, 3, ", ");\r
+       else {\r
+                int    status;\r
+               waittid(pid, &status);\r
        }\r
-       write(_stdout, 4, "\b\b\n");\r
+}\r
+\r
+/**\r
+ * \fn void Command_Logout(int argc, char **argv)\r
+ * \brief Exit the shell, logging the user out\r
+ */\r
+void Command_Logout(int argc, char **argv)\r
+{\r
+       exit(0);\r
+}\r
+\r
+/**\r
+ * \fn void Command_Colour(int argc, char **argv)\r
+ * \brief Displays the help screen\r
+ */\r
+void Command_Help(int argc, char **argv)\r
+{\r
+       Print("Acess 2 Command Line Interface\n");\r
+       Print(" By John Hodge (thePowersGang / [TPG])\n");\r
+       Print("\n");\r
+       Print("Builtin Commands:\n");\r
+       Print(" logout: Return to the login prompt\n");\r
+       Print(" exit:   Same\n");\r
+       Print(" help:   Display this message\n");\r
+       Print(" clear:  Clear the screen\n");\r
+       Print(" cd:     Change the current directory\n");\r
+       Print(" dir:    Print the contents of the current directory\n");\r
+       //Print("\n");\r
        return;\r
 }\r
 \r
+/**\r
+ * \fn void Command_Clear(int argc, char **argv)\r
+ * \brief Clear the screen\r
+ */\r
 void Command_Clear(int argc, char **argv)\r
 {\r
        write(_stdout, 4, "\x1B[2J");   //Clear Screen\r
@@ -315,7 +412,7 @@ void Command_Cd(int argc, char **argv)
                write(_stdout, 26, "Directory does not exist\n");\r
                return;\r
        }\r
-       finfo(fp, &stats);\r
+       finfo(fp, &stats, 0);\r
        close(fp);\r
        \r
        if( !(stats.flags & FILEFLAG_DIRECTORY) ) {\r
@@ -323,6 +420,129 @@ void Command_Cd(int argc, char **argv)
                return;\r
        }\r
        \r
+       free(gsCurrentDirectory);\r
+       gsCurrentDirectory = malloc(strlen(tmpPath)+1);\r
        strcpy(gsCurrentDirectory, tmpPath);\r
+       \r
+       // Register change with kernel\r
+       chdir( gsCurrentDirectory );\r
 }\r
 \r
+/**\r
+ * \fn void Command_Dir(int argc, char **argv)\r
+ * \brief Print the contents of a directory\r
+ */\r
+void Command_Dir(int argc, char **argv)\r
+{\r
+        int    dp, fp, dirLen;\r
+       char    modeStr[11] = "RWXrwxRWX ";\r
+       char    tmpPath[1024];\r
+       char    *fileName;\r
+       t_sysFInfo      info;\r
+       t_sysACL        acl;\r
+       \r
+       // Generate Directory Path\r
+       if(argc > 1)\r
+               dirLen = GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
+       else\r
+       {\r
+               strcpy(tmpPath, gsCurrentDirectory);\r
+       }\r
+       dirLen = strlen(tmpPath);\r
+       \r
+       // Open Directory\r
+       dp = open(tmpPath, OPENFLAG_READ);\r
+       // Check if file opened\r
+       if(dp == -1)\r
+       {\r
+               printf("Unable to open directory `%s', File cannot be found\n", tmpPath);\r
+               return;\r
+       }\r
+       // Get File Stats\r
+       if( finfo(dp, &info, 0) == -1 )\r
+       {\r
+               close(dp);\r
+               write(_stdout, 34, "stat Failed, Bad File Descriptor\n");\r
+               return;\r
+       }\r
+       // Check if it's a directory\r
+       if(!(info.flags & FILEFLAG_DIRECTORY))\r
+       {\r
+               close(dp);\r
+               write(_stdout, 27, "Unable to open directory `");\r
+               write(_stdout, strlen(tmpPath)+1, tmpPath);\r
+               write(_stdout, 20, "', Not a directory\n");\r
+               return;\r
+       }\r
+       \r
+       // Append Shash for file paths\r
+       if(tmpPath[dirLen-1] != '/')\r
+       {\r
+               tmpPath[dirLen++] = '/';\r
+               tmpPath[dirLen] = '\0';\r
+       }\r
+       \r
+       fileName = (char*)(tmpPath+dirLen);\r
+       // Read Directory Content\r
+       while( (fp = readdir(dp, fileName)) )\r
+       {\r
+               if(fp < 0)\r
+               {\r
+                       if(fp == -3)\r
+                               write(_stdout, 42, "Invalid Permissions to traverse directory\n");\r
+                       break;\r
+               }\r
+               // Open File\r
+               fp = open(tmpPath, 0);\r
+               if(fp == -1)    continue;\r
+               // Get File Stats\r
+               finfo(fp, &info, 0);\r
+               \r
+               if(info.flags & FILEFLAG_DIRECTORY)\r
+                       write(_stdout, 1, "d");\r
+               else\r
+                       write(_stdout, 1, "-");\r
+               \r
+               // Print Mode\r
+               // - Owner\r
+               acl.group = 0;  acl.id = info.uid;\r
+               _SysGetACL(fp, &acl);\r
+               if(acl.perms & 1)       modeStr[0] = 'r';       else    modeStr[0] = '-';\r
+               if(acl.perms & 2)       modeStr[1] = 'w';       else    modeStr[1] = '-';\r
+               if(acl.perms & 8)       modeStr[2] = 'x';       else    modeStr[2] = '-';\r
+               // - Group\r
+               acl.group = 1;  acl.id = info.gid;\r
+               _SysGetACL(fp, &acl);\r
+               if(acl.perms & 1)       modeStr[3] = 'r';       else    modeStr[3] = '-';\r
+               if(acl.perms & 2)       modeStr[4] = 'w';       else    modeStr[4] = '-';\r
+               if(acl.perms & 8)       modeStr[5] = 'x';       else    modeStr[5] = '-';\r
+               // - World\r
+               acl.group = 1;  acl.id = -1;\r
+               _SysGetACL(fp, &acl);\r
+               if(acl.perms & 1)       modeStr[6] = 'r';       else    modeStr[6] = '-';\r
+               if(acl.perms & 2)       modeStr[7] = 'w';       else    modeStr[7] = '-';\r
+               if(acl.perms & 8)       modeStr[8] = 'x';       else    modeStr[8] = '-';\r
+               write(_stdout, 10, modeStr);\r
+               close(fp);\r
+               \r
+               // Colour Code\r
+               if(info.flags & FILEFLAG_DIRECTORY)     // Directory: Green\r
+                       write(_stdout, 6, "\x1B[32m");\r
+               // Default: White\r
+               \r
+               // Print Name\r
+               write(_stdout, strlen(fileName), fileName);\r
+               \r
+               // Print slash if applicable\r
+               if(info.flags & FILEFLAG_DIRECTORY)\r
+                       write(_stdout, 1, "/");\r
+               \r
+               // Revert Colour\r
+               write(_stdout, 6, "\x1B[37m");\r
+               \r
+               // Newline!\r
+               write(_stdout, 1, "\n");\r
+       }\r
+       // Close Directory\r
+       close(dp);\r
+}\r

UCC git Repository :: git.ucc.asn.au