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

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