Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
[tpg/acess2.git] / Usermode / Applications / CLIShell_src / main.c
1 /*\r
2  * AcessOS Shell Version 3\r
3  */\r
4 #define USE_READLINE    1\r
5 #include <acess/sys.h>\r
6 #include <stdlib.h>\r
7 #include <stdio.h>\r
8 #include <string.h>\r
9 #include "header.h"\r
10 #include <readline.h>\r
11 \r
12 #define _stdin  0\r
13 #define _stdout 1\r
14 #define _stderr 2\r
15 \r
16 // ==== PROTOTYPES ====\r
17  int    Parse_Args(const char *str, char **dest);\r
18 void    CallCommand(char **Args);\r
19 void    Command_Logout(int argc, char **argv);\r
20 void    Command_Clear(int argc, char **argv);\r
21 void    Command_Help(int argc, char **argv);\r
22 void    Command_Cd(int argc, char **argv);\r
23 void    Command_Dir(int argc, char **argv);\r
24 \r
25 // ==== CONSTANT GLOBALS ====\r
26 struct  {\r
27         char    *name;\r
28         void    (*fcn)(int argc, char **argv);\r
29 }       cBUILTINS[] = {\r
30         {"exit", Command_Logout},       {"logout", Command_Logout},\r
31         {"help", Command_Help}, {"clear", Command_Clear},\r
32         {"cd", Command_Cd}, {"dir", Command_Dir}\r
33 };\r
34 static char     *cDEFAULT_PATH[] = {"/Acess/Bin"};\r
35 #define BUILTIN_COUNT   (sizeof(cBUILTINS)/sizeof(cBUILTINS[0]))\r
36 \r
37 // ==== LOCAL VARIABLES ====\r
38  int    giNumPathDirs = 1;\r
39 char    **gasPathDirs = cDEFAULT_PATH;\r
40 char    **gasEnvironment;\r
41 char    gsCommandBuffer[1024];\r
42 char    *gsCurrentDirectory = NULL;\r
43 char    **gasCommandHistory;\r
44  int    giLastCommand = 0;\r
45  int    giCommandSpace = 0;\r
46 \r
47 // ==== CODE ====\r
48 int main(int argc, char *argv[], char **envp)\r
49 {\r
50         char    *sCommandStr;\r
51         char    *saArgs[32] = {0};\r
52          int    i;\r
53          int    iArgCount = 0;\r
54         tReadline       *readline_state = Readline_Init(1);\r
55         \r
56         gasEnvironment = envp;\r
57         \r
58         Command_Clear(0, NULL);\r
59         \r
60         {\r
61                 char    *tmp = getenv("CWD");\r
62                 if(tmp) {\r
63                         gsCurrentDirectory = malloc(strlen(tmp)+1);\r
64                         strcpy(gsCurrentDirectory, tmp);\r
65                 } else {\r
66                         gsCurrentDirectory = malloc(2);\r
67                         strcpy(gsCurrentDirectory, "/");\r
68                 }\r
69         }       \r
70         \r
71         printf("Acess Shell Version 3\n\n");\r
72         for(;;)\r
73         {\r
74                 // Free last command & arguments\r
75                 if(saArgs[0])   free(saArgs[0]);\r
76                 \r
77                 printf("%s$ ", gsCurrentDirectory);\r
78                 \r
79                 // Read Command line\r
80                 sCommandStr = Readline( readline_state );\r
81                 printf("\n");\r
82                 \r
83                 // Parse Command Line into arguments\r
84                 iArgCount = Parse_Args(sCommandStr, saArgs);\r
85                 \r
86                 // Silently Ignore all empty commands\r
87                 if(saArgs[1][0] == '\0')        continue;\r
88                 \r
89                 // Check Built-In Commands\r
90                 for( i = 0; i < BUILTIN_COUNT; i++ )\r
91                 {\r
92                         if( strcmp(saArgs[1], cBUILTINS[i].name) == 0 )\r
93                         {\r
94                                 cBUILTINS[i].fcn(iArgCount-1, &saArgs[1]);\r
95                                 break;\r
96                         }\r
97                 }\r
98                 if(i != BUILTIN_COUNT)  continue;\r
99                 \r
100                 // Shall we?\r
101                 CallCommand( &saArgs[1] );\r
102                 \r
103                 free( sCommandStr );\r
104         }\r
105 }\r
106 \r
107 /**\r
108  * \fn int Parse_Args(const char *str, char **dest)\r
109  * \brief Parse a string into an argument array\r
110  */\r
111 int Parse_Args(const char *str, char **dest)\r
112 {\r
113          int    i = 1;\r
114         char    *buf = malloc( strlen(str) + 1 );\r
115         \r
116         if(buf == NULL) {\r
117                 dest[0] = NULL;\r
118                 printf("Parse_Args: Out of heap space!\n");\r
119                 return 0;\r
120         }\r
121         \r
122         strcpy(buf, str);\r
123         dest[0] = buf;\r
124         \r
125         // Trim leading whitespace\r
126         while(*buf == ' ' && *buf)      buf++;\r
127         \r
128         for(;;)\r
129         {\r
130                 dest[i] = buf;  // Save start of string\r
131                 i++;\r
132                 while(*buf && *buf != ' ')\r
133                 {\r
134                         if(*buf++ == '"')\r
135                         {\r
136                                 while(*buf && !(*buf == '"' && buf[-1] != '\\'))\r
137                                         buf++;\r
138                         }\r
139                 }\r
140                 if(*buf == '\0')        break;\r
141                 *buf = '\0';\r
142                 while(*++buf == ' ' && *buf);\r
143                 if(*buf == '\0')        break;\r
144         }\r
145         dest[i] = NULL;\r
146         \r
147         return i;\r
148 }\r
149 \r
150 /**\r
151  * \fn void CallCommand(char **Args)\r
152  */\r
153 void CallCommand(char **Args)\r
154 {\r
155         t_sysFInfo      info;\r
156          int    pid = -1;\r
157          int    fd = 0;\r
158         char    sTmpBuffer[1024];\r
159         char    *exefile = Args[0];\r
160         \r
161         if(exefile[0] == '/'\r
162         || (exefile[0] == '.' && exefile[1] == '/')\r
163         || (exefile[0] == '.' && exefile[1] == '.' && exefile[2] == '/')\r
164                 )\r
165         {\r
166                 GeneratePath(exefile, gsCurrentDirectory, sTmpBuffer);\r
167                 // Check file existence\r
168                 fd = _SysOpen(sTmpBuffer, OPENFLAG_EXEC);\r
169                 if(fd == -1) {\r
170                         printf("Unknown Command: `%s'\n", Args[0]);     // Error Message\r
171                         return ;\r
172                 }\r
173                 \r
174                 // Get File info and close file\r
175                 _SysFInfo( fd, &info, 0 );\r
176                 _SysClose( fd );\r
177                 \r
178                 // Check if the file is a directory\r
179                 if(info.flags & FILEFLAG_DIRECTORY) {\r
180                         printf("`%s' is a directory.\n", sTmpBuffer);\r
181                         return ;\r
182                 }\r
183         }\r
184         else\r
185         {\r
186                  int    i;\r
187                 \r
188                 // Check all components of $PATH\r
189                 for( i = 0; i < giNumPathDirs; i++ )\r
190                 {\r
191                         GeneratePath(exefile, gasPathDirs[i], sTmpBuffer);\r
192                         fd = _SysOpen(sTmpBuffer, OPENFLAG_EXEC);\r
193                         if(fd == -1)    continue;\r
194                         _SysFInfo( fd, &info, 0 );\r
195                         _SysClose( fd );\r
196                         if(info.flags & FILEFLAG_DIRECTORY)     continue;\r
197                         // Woohoo! We found a valid command\r
198                         break;\r
199                 }\r
200                 \r
201                 // Exhausted path directories\r
202                 if( i == giNumPathDirs ) {\r
203                         printf("Unknown Command: `%s'\n", exefile);\r
204                         return ;\r
205                 }\r
206         }\r
207         \r
208         // Create new process\r
209         int fds[] = {0, 1, 2};\r
210         pid = _SysSpawn(sTmpBuffer, (const char **)Args, (const char **)gasEnvironment, 3, fds, NULL);\r
211         if(pid <= 0) {\r
212                 printf("Unable to create process: `%s'\n", sTmpBuffer); // Error Message\r
213         }\r
214         else {\r
215                  int    status;\r
216                 _SysWaitTID(pid, &status);\r
217         }\r
218 }\r
219 \r
220 /**\r
221  * \fn void Command_Logout(int argc, char **argv)\r
222  * \brief Exit the shell, logging the user out\r
223  */\r
224 void Command_Logout(int argc, char **argv)\r
225 {\r
226         exit(0);\r
227 }\r
228 \r
229 /**\r
230  * \fn void Command_Colour(int argc, char **argv)\r
231  * \brief Displays the help screen\r
232  */\r
233 void Command_Help(int argc, char **argv)\r
234 {\r
235         printf( "Acess 2 Command Line Interface\n"\r
236                 " By John Hodge (thePowersGang / [TPG])\n"\r
237                 "\n"\r
238                 "Builtin Commands:\n"\r
239                 " logout: Return to the login prompt\n"\r
240                 " exit:   Same\n"\r
241                 " help:   Display this message\n"\r
242                 " clear:  Clear the screen\n"\r
243                 " cd:     Change the current directory\n"\r
244                 " dir:    Print the contents of the current directory\n");\r
245         return;\r
246 }\r
247 \r
248 /**\r
249  * \fn void Command_Clear(int argc, char **argv)\r
250  * \brief Clear the screen\r
251  */\r
252 void Command_Clear(int argc, char **argv)\r
253 {\r
254         _SysWrite(_stdout, "\x1B[2J", 4);       //Clear Screen\r
255 }\r
256 \r
257 /**\r
258  * \fn void Command_Cd(int argc, char **argv)\r
259  * \brief Change directory\r
260  */\r
261 void Command_Cd(int argc, char **argv)\r
262 {\r
263         char    tmpPath[1024];\r
264         int             fp;\r
265         t_sysFInfo      stats;\r
266         \r
267         if(argc < 2)\r
268         {\r
269                 printf("%s\n", gsCurrentDirectory);\r
270                 return;\r
271         }\r
272         \r
273         GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
274         \r
275         fp = _SysOpen(tmpPath, 0);\r
276         if(fp == -1) {\r
277                 printf("Directory does not exist\n");\r
278                 return;\r
279         }\r
280         _SysFInfo(fp, &stats, 0);\r
281         _SysClose(fp);\r
282         \r
283         if( !(stats.flags & FILEFLAG_DIRECTORY) ) {\r
284                 printf("Not a Directory\n");\r
285                 return;\r
286         }\r
287         \r
288         free(gsCurrentDirectory);\r
289         gsCurrentDirectory = malloc(strlen(tmpPath)+1);\r
290         strcpy(gsCurrentDirectory, tmpPath);\r
291         \r
292         // Register change with kernel\r
293         _SysChdir( gsCurrentDirectory );\r
294 }\r
295 \r
296 /**\r
297  * \fn void Command_Dir(int argc, char **argv)\r
298  * \brief Print the contents of a directory\r
299  */\r
300 void Command_Dir(int argc, char **argv)\r
301 {\r
302          int    dp, fp, dirLen;\r
303         char    modeStr[11] = "RWXrwxRWX ";\r
304         char    tmpPath[1024];\r
305         char    *fileName;\r
306         t_sysFInfo      info;\r
307         t_sysACL        acl;\r
308         \r
309         // Generate Directory Path\r
310         if(argc > 1)\r
311                 dirLen = GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
312         else\r
313         {\r
314                 strcpy(tmpPath, gsCurrentDirectory);\r
315         }\r
316         dirLen = strlen(tmpPath);\r
317         \r
318         // Open Directory\r
319         dp = _SysOpen(tmpPath, OPENFLAG_READ);\r
320         // Check if file opened\r
321         if(dp == -1)\r
322         {\r
323                 printf("Unable to open directory `%s', File cannot be found\n", tmpPath);\r
324                 return;\r
325         }\r
326         // Get File Stats\r
327         if( _SysFInfo(dp, &info, 0) == -1 )\r
328         {\r
329                 _SysClose(dp);\r
330                 printf("stat Failed, Bad File Descriptor\n");\r
331                 return;\r
332         }\r
333         // Check if it's a directory\r
334         if(!(info.flags & FILEFLAG_DIRECTORY))\r
335         {\r
336                 _SysClose(dp);\r
337                 printf("Unable to open directory `%s', Not a directory\n", tmpPath);\r
338                 return;\r
339         }\r
340         \r
341         // Append Shash for file paths\r
342         if(tmpPath[dirLen-1] != '/')\r
343         {\r
344                 tmpPath[dirLen++] = '/';\r
345                 tmpPath[dirLen] = '\0';\r
346         }\r
347         \r
348         fileName = (char*)(tmpPath+dirLen);\r
349         // Read Directory Content\r
350         while( (fp = _SysReadDir(dp, fileName)) )\r
351         {\r
352                 if(fp < 0)\r
353                 {\r
354                         if(fp == -3)\r
355                                 printf("Invalid Permissions to traverse directory\n");\r
356                         break;\r
357                 }\r
358                 // Open File\r
359                 fp = _SysOpen(tmpPath, 0);\r
360                 if(fp == -1)    continue;\r
361                 // Get File Stats\r
362                 _SysFInfo(fp, &info, 0);\r
363                 \r
364                 if(info.flags & FILEFLAG_DIRECTORY)\r
365                         printf("d");\r
366                 else\r
367                         printf("-");\r
368                 \r
369                 // Print Mode\r
370                 // - Owner\r
371                 acl.object = info.uid;\r
372                 _SysGetACL(fp, &acl);\r
373                 if(acl.perms & 1)       modeStr[0] = 'r';       else    modeStr[0] = '-';\r
374                 if(acl.perms & 2)       modeStr[1] = 'w';       else    modeStr[1] = '-';\r
375                 if(acl.perms & 8)       modeStr[2] = 'x';       else    modeStr[2] = '-';\r
376                 // - Group\r
377                 acl.object = info.gid | 0x80000000;\r
378                 _SysGetACL(fp, &acl);\r
379                 if(acl.perms & 1)       modeStr[3] = 'r';       else    modeStr[3] = '-';\r
380                 if(acl.perms & 2)       modeStr[4] = 'w';       else    modeStr[4] = '-';\r
381                 if(acl.perms & 8)       modeStr[5] = 'x';       else    modeStr[5] = '-';\r
382                 // - World\r
383                 acl.object = 0xFFFFFFFF;\r
384                 _SysGetACL(fp, &acl);\r
385                 if(acl.perms & 1)       modeStr[6] = 'r';       else    modeStr[6] = '-';\r
386                 if(acl.perms & 2)       modeStr[7] = 'w';       else    modeStr[7] = '-';\r
387                 if(acl.perms & 8)       modeStr[8] = 'x';       else    modeStr[8] = '-';\r
388                 printf(modeStr);\r
389                 _SysClose(fp);\r
390                 \r
391                 // Colour Code\r
392                 if(info.flags & FILEFLAG_DIRECTORY)     // Directory: Green\r
393                         printf("\x1B[32m");\r
394                 // Default: White\r
395                 \r
396                 // Print Name\r
397                 printf("%s", fileName);\r
398                 \r
399                 // Print slash if applicable\r
400                 if(info.flags & FILEFLAG_DIRECTORY)\r
401                         printf("/");\r
402                 \r
403                 // Revert Colour\r
404                 printf("\x1B[37m");\r
405                 \r
406                 // Newline!\r
407                 printf("\n");\r
408         }\r
409         // Close Directory\r
410         _SysClose(dp);\r
411 }\r

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