f753788de35c4218682dfedf31d8965ef48fcea4
[tpg/acess2.git] / Usermode / Applications / CLIShell_src / main.c
1 /*\r
2  AcessOS Shell Version 2\r
3 - Based on IOOS CLI Shell\r
4 */\r
5 #include <acess/sys.h>\r
6 #include <stdlib.h>\r
7 #include "header.h"\r
8 \r
9 #define _stdin  0\r
10 #define _stdout 1\r
11 #define _stderr 2\r
12 \r
13 // ==== PROTOTYPES ====\r
14 char    *ReadCommandLine(int *Length);\r
15 void    Parse_Args(char *str, char **dest);\r
16 void    Command_Colour(int argc, char **argv);\r
17 void    Command_Clear(int argc, char **argv);\r
18 //void  Command_Ls(int argc, char **argv);\r
19 void    Command_Cd(int argc, char **argv);\r
20 //void  Command_Cat(int argc, char **argv);\r
21 \r
22 // ==== CONSTANT GLOBALS ====\r
23 char    *cCOLOUR_NAMES[8] = {"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"};\r
24 struct  {\r
25         char    *name;\r
26         void    (*fcn)(int argc, char **argv);\r
27 }       cBUILTINS[] = {\r
28         {"colour", Command_Colour}, {"clear", Command_Clear}, {"cd", Command_Cd}\r
29 };\r
30 #define BUILTIN_COUNT   (sizeof(cBUILTINS)/sizeof(cBUILTINS[0]))\r
31 \r
32 // ==== LOCAL VARIABLES ====\r
33 char    gsCommandBuffer[1024];\r
34 char    *gsCurrentDirectory = "/";\r
35 char    gsTmpBuffer[1024];\r
36 char    **gasCommandHistory;\r
37  int    giLastCommand = 0;\r
38  int    giCommandSpace = 0;\r
39 \r
40 // ==== CODE ====\r
41 int main(int argc, char *argv[], char *envp[])\r
42 {\r
43         char    *sCommandStr;\r
44         char    *saArgs[32];\r
45          int    length = 0;\r
46          int    pid = -1;\r
47          int    iArgCount = 0;\r
48          int    bCached = 1;\r
49         t_sysFInfo      info;\r
50         \r
51         //Command_Clear(0, NULL);\r
52         \r
53         write(_stdout, 1, "\n");\r
54         write(_stdout, 36, "Acess Shell Version 3\n");\r
55         write(_stdout, 30, " Based on CLI Shell for IOOS\n");\r
56         write(_stdout,  2, "\n");\r
57         for(;;)\r
58         {\r
59                 // Free last command & arguments\r
60                 if(saArgs[0])   free(saArgs);\r
61                 if(!bCached)    free(sCommandStr);\r
62                 bCached = 0;\r
63                 write(_stdout, strlen(gsCurrentDirectory), gsCurrentDirectory);\r
64                 write(_stdout, 3, "$ ");\r
65                 \r
66                 // Read Command line\r
67                 sCommandStr = ReadCommandLine( &length );\r
68                 \r
69                 // Check if the command should be cached\r
70                 if(gasCommandHistory == NULL || strcmp(sCommandStr, gasCommandHistory[giLastCommand]) != 0)\r
71                 {\r
72                         if(giLastCommand >= giCommandSpace) {\r
73                                 giCommandSpace += 12;\r
74                                 gasCommandHistory = realloc(gasCommandHistory, giCommandSpace*sizeof(char*));\r
75                         }\r
76                         giLastCommand ++;\r
77                         gasCommandHistory[ giLastCommand ] = sCommandStr;\r
78                         bCached = 1;\r
79                 }\r
80                 \r
81                 // Parse Command Line into arguments\r
82                 Parse_Args(sCommandStr, saArgs);\r
83                 \r
84                 // Count Arguments\r
85                 iArgCount = 0;\r
86                 while(saArgs[iArgCount])        iArgCount++;\r
87                 \r
88                 // Silently Ignore all empty commands\r
89                 if(saArgs[1][0] == '\0')        continue;\r
90                 \r
91                 // Check Built-In Commands\r
92                 //  [HACK] Mem Usage - Use Length in place of `i'\r
93                 for(length=0;length<BUILTIN_COUNT;length++)\r
94                 {\r
95                         if(strcmp(saArgs[1], cBUILTINS[length].name) == 0)\r
96                         {\r
97                                 cBUILTINS[length].fcn(iArgCount-1, &saArgs[1]);\r
98                                 break;\r
99                         }\r
100                 }
101                 // Calling a file\r
102                 if(length == BUILTIN_COUNT)\r
103                 {\r
104                         GeneratePath(saArgs[1], gsCurrentDirectory, gsTmpBuffer);\r
105                         // Use length in place of fp\r
106                         length = open(gsTmpBuffer, 0);\r
107                         // Check file existence\r
108                         if(length == -1) {\r
109                                 Print("Unknown Command: `");Print(saArgs[1]);Print("'\n");      // Error Message\r
110                                 continue;\r
111                         }\r
112                         // Check if the file is a directory\r
113                         finfo( length, &info );
114                         close( length );\r
115                         if(info.flags & FILEFLAG_DIRECTORY) {\r
116                                 Print("`");Print(saArgs[1]);    // Error Message\r
117                                 Print("' is a directory.\n");\r
118                                 continue;\r
119                         }\r
120                         pid = clone(CLONE_VM, 0);\r
121                         if(pid == 0)    execve(gsTmpBuffer, &saArgs[1], NULL);\r
122                         if(pid <= 0) {\r
123                                 Print("Unablt to create process: `");Print(gsTmpBuffer);Print("'\n");   // Error Message
124                                 //SysDebug("pid = %i\n", pid);\r
125                         }\r
126                         else {\r
127                                 //waitpid(pid, K_WAITPID_DIE);\r
128                         }\r
129                 }\r
130         }\r
131 }\r
132 \r
133 /**\r
134  * \fn char *ReadCommandLine(int *Length)\r
135  * \brief Read from the command line\r
136  */\r
137 char *ReadCommandLine(int *Length)\r
138 {\r
139         char    *ret;\r
140          int    len, pos, space = 1023;\r
141         char    ch;\r
142          \r
143         // Preset Variables\r
144         ret = malloc( space+1 );\r
145         len = 0;\r
146         pos = 0;\r
147                 \r
148         // Read In Command Line\r
149         do {\r
150                 read(_stdin, 1, &ch);   // Read Character from stdin (read is a blocking call)\r
151                 // Ignore control characters\r
152                 if(ch < 0)      continue;\r
153                 // Backspace\r
154                 if(ch == '\b') {\r
155                         if(len <= 0)            continue;       // Protect against underflows\r
156                         if(pos == len) {        // Simple case of end of string\r
157                                 len --; pos--;\r
158                         } else {\r
159                                 memmove(&ret[pos-1], &ret[pos], len-pos);\r
160                                 pos --;\r
161                                 len --;\r
162                         }\r
163                         write(_stdout, 1, &ch);\r
164                         continue;\r
165                 }\r
166                 // Expand Buffer\r
167                 if(len > space) {\r
168                         space += 256;\r
169                         ret = realloc(ret, space+1);\r
170                         if(!ret)        return NULL;\r
171                 }\r
172                 \r
173                 write(_stdout, 1, &ch);\r
174                 ret[pos++] = ch;\r
175                 len ++;\r
176         } while(ch != '\n');\r
177         \r
178         // Remove newline\r
179         pos --;\r
180         ret[pos] = '\0';\r
181         \r
182         // Return length\r
183         if(Length)      *Length = len;\r
184         \r
185         return ret;\r
186 }\r
187 \r
188 /**\r
189  * \fn void Parse_Args(char *str, char **dest)\r
190  * \brief Parse a string into an argument array\r
191  */\r
192 void Parse_Args(char *str, char **dest)\r
193 {\r
194          int    i = 1;\r
195         char    *buf = malloc( strlen(str) + 1 );\r
196         \r
197         strcpy(buf, str);\r
198         dest[0] = buf;\r
199         \r
200         // Trim leading whitespace\r
201         while(*buf == ' ' && *buf)      buf++;\r
202         \r
203         for(;;)\r
204         {\r
205                 dest[i] = buf;  // Save start of string\r
206                 i++;\r
207                 while(*buf && *buf != ' ')\r
208                 {\r
209                         if(*buf++ == '"')\r
210                         {\r
211                                 while(*buf && !(*buf == '"' && buf[-1] != '\\'))\r
212                                         buf++;\r
213                         }\r
214                 }\r
215                 if(*buf == '\0')        break;\r
216                 *buf = '\0';\r
217                 while(*++buf == ' ' && *buf);\r
218                 if(*buf == '\0')        break;\r
219         }\r
220         dest[i] = NULL;\r
221         if(i == 1) {\r
222                 free(buf);\r
223                 dest[0] = NULL;\r
224         }\r
225 }\r
226 \r
227 /**\r
228  * \fn void Command_Colour(int argc, char **argv)\r
229  * \brief \r
230  */\r
231 void Command_Colour(int argc, char **argv)\r
232 {\r
233         int fg, bg;\r
234         char    clrStr[6] = "\x1B[37m";\r
235         \r
236         // Verify Arg Count\r
237         if(argc < 2)\r
238         {\r
239                 Print("Please specify a colour\n");\r
240                 goto usage;\r
241         }\r
242         \r
243         // Check Colour\r
244         for(fg=0;fg<8;fg++)\r
245                 if(strcmp(cCOLOUR_NAMES[fg], argv[1]) == 0)\r
246                         break;\r
247 \r
248         // Foreground a valid colour\r
249         if(fg == 8) {\r
250                 Print("Unknown Colour '");Print(argv[1]);Print("'\n");\r
251                 goto usage;\r
252         }\r
253         // Set Foreground\r
254         clrStr[3] = '0' + fg;\r
255         write(_stdout, 6, clrStr);\r
256         \r
257         // Need to Set Background?\r
258         if(argc > 2)\r
259         {\r
260                 for(bg=0;bg<8;bg++)\r
261                         if(strcmp(cCOLOUR_NAMES[bg], argv[2]) == 0)\r
262                                 break;\r
263         \r
264                 // Valid colour\r
265                 if(bg == 8)\r
266                 {\r
267                         Print("Unknown Colour '");Print(argv[2]);Print("'\n");\r
268                         goto usage;\r
269                 }\r
270         \r
271                 clrStr[2] = '4';\r
272                 clrStr[3] = '0' + bg;\r
273                 write(_stdout, 6, clrStr);\r
274         }\r
275         // Return\r
276         return;\r
277 \r
278         // Function Usage (Requested via a Goto (I know it's ugly))\r
279 usage:\r
280         Print("Valid Colours are ");\r
281         for(fg=0;fg<8;fg++)\r
282         {\r
283                 Print(cCOLOUR_NAMES[fg]);\r
284                 write(_stdout, 3, ", ");\r
285         }\r
286         write(_stdout, 4, "\b\b\n");\r
287         return;\r
288 }\r
289 \r
290 void Command_Clear(int argc, char **argv)\r
291 {\r
292         write(_stdout, 4, "\x1B[2J");   //Clear Screen\r
293 }\r
294 \r
295 /**\r
296  * \fn void Command_Cd(int argc, char **argv)\r
297  * \brief Change directory\r
298  */\r
299 void Command_Cd(int argc, char **argv)\r
300 {\r
301         char    tmpPath[1024];\r
302         int             fp;\r
303         t_sysFInfo      stats;\r
304         \r
305         if(argc < 2)\r
306         {\r
307                 Print(gsCurrentDirectory);Print("\n");\r
308                 return;\r
309         }\r
310         \r
311         GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
312         \r
313         fp = open(tmpPath, 0);\r
314         if(fp == -1) {\r
315                 write(_stdout, 26, "Directory does not exist\n");\r
316                 return;\r
317         }\r
318         finfo(fp, &stats);\r
319         close(fp);\r
320         \r
321         if( !(stats.flags & FILEFLAG_DIRECTORY) ) {\r
322                 write(_stdout, 17, "Not a Directory\n");\r
323                 return;\r
324         }\r
325         \r
326         strcpy(gsCurrentDirectory, tmpPath);\r
327 }\r
328 \r

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