Moving more stuff to new makefiles
[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    length = 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                 \r
80                 // Read Command line\r
81                 sCommandStr = Readline( readline_state );\r
82                 printf("\n");\r
83                 length = strlen(sCommandStr);\r
84                 \r
85                 // Parse Command Line into arguments\r
86                 iArgCount = Parse_Args(sCommandStr, saArgs);\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                 for( i = 0; i < BUILTIN_COUNT; i++ )\r
93                 {\r
94                         if( strcmp(saArgs[1], cBUILTINS[i].name) == 0 )\r
95                         {\r
96                                 cBUILTINS[i].fcn(iArgCount-1, &saArgs[1]);\r
97                                 break;\r
98                         }\r
99                 }\r
100                 if(i != BUILTIN_COUNT)  continue;\r
101                 \r
102                 // Shall we?\r
103                 CallCommand( &saArgs[1] );\r
104                 \r
105                 free( sCommandStr );\r
106         }\r
107 }\r
108 \r
109 /**\r
110  * \fn int Parse_Args(const char *str, char **dest)\r
111  * \brief Parse a string into an argument array\r
112  */\r
113 int Parse_Args(const char *str, char **dest)\r
114 {\r
115          int    i = 1;\r
116         char    *buf = malloc( strlen(str) + 1 );\r
117         \r
118         if(buf == NULL) {\r
119                 dest[0] = NULL;\r
120                 printf("Parse_Args: Out of heap space!\n");\r
121                 return 0;\r
122         }\r
123         \r
124         strcpy(buf, str);\r
125         dest[0] = buf;\r
126         \r
127         // Trim leading whitespace\r
128         while(*buf == ' ' && *buf)      buf++;\r
129         \r
130         for(;;)\r
131         {\r
132                 dest[i] = buf;  // Save start of string\r
133                 i++;\r
134                 while(*buf && *buf != ' ')\r
135                 {\r
136                         if(*buf++ == '"')\r
137                         {\r
138                                 while(*buf && !(*buf == '"' && buf[-1] != '\\'))\r
139                                         buf++;\r
140                         }\r
141                 }\r
142                 if(*buf == '\0')        break;\r
143                 *buf = '\0';\r
144                 while(*++buf == ' ' && *buf);\r
145                 if(*buf == '\0')        break;\r
146         }\r
147         dest[i] = NULL;\r
148         \r
149         return i;\r
150 }\r
151 \r
152 /**\r
153  * \fn void CallCommand(char **Args)\r
154  */\r
155 void CallCommand(char **Args)\r
156 {\r
157         t_sysFInfo      info;\r
158          int    pid = -1;\r
159          int    fd = 0;\r
160         char    sTmpBuffer[1024];\r
161         char    *exefile = Args[0];\r
162         \r
163         if(exefile[0] == '/'\r
164         || (exefile[0] == '.' && exefile[1] == '/')\r
165         || (exefile[0] == '.' && exefile[1] == '.' && exefile[2] == '/')\r
166                 )\r
167         {\r
168                 GeneratePath(exefile, gsCurrentDirectory, sTmpBuffer);\r
169                 // Check file existence\r
170                 fd = open(sTmpBuffer, OPENFLAG_EXEC);\r
171                 if(fd == -1) {\r
172                         printf("Unknown Command: `%s'\n", Args[0]);     // Error Message\r
173                         return ;\r
174                 }\r
175                 \r
176                 // Get File info and close file\r
177                 finfo( fd, &info, 0 );\r
178                 close( fd );\r
179                 \r
180                 // Check if the file is a directory\r
181                 if(info.flags & FILEFLAG_DIRECTORY) {\r
182                         printf("`%s' is a directory.\n", sTmpBuffer);\r
183                         return ;\r
184                 }\r
185         }\r
186         else\r
187         {\r
188                  int    i;\r
189                 \r
190                 // Check all components of $PATH\r
191                 for( i = 0; i < giNumPathDirs; i++ )\r
192                 {\r
193                         GeneratePath(exefile, gasPathDirs[i], sTmpBuffer);\r
194                         fd = open(sTmpBuffer, OPENFLAG_EXEC);\r
195                         if(fd == -1)    continue;\r
196                         finfo( fd, &info, 0 );\r
197                         close( fd );\r
198                         if(info.flags & FILEFLAG_DIRECTORY)     continue;\r
199                         // Woohoo! We found a valid command\r
200                         break;\r
201                 }\r
202                 \r
203                 // Exhausted path directories\r
204                 if( i == giNumPathDirs ) {\r
205                         printf("Unknown Command: `%s'\n", exefile);\r
206                         return ;\r
207                 }\r
208         }\r
209         \r
210         // Create new process\r
211         pid = clone(CLONE_VM, 0);\r
212         // Start Task\r
213         if(pid == 0) {\r
214                 execve(sTmpBuffer, Args, gasEnvironment);\r
215                 printf("Execve returned, ... oops\n");\r
216                 exit(-1);\r
217         }\r
218         if(pid <= 0) {\r
219                 printf("Unable to create process: `%s'\n", sTmpBuffer); // Error Message\r
220         }\r
221         else {\r
222                  int    status;\r
223                 waittid(pid, &status);\r
224         }\r
225 }\r
226 \r
227 /**\r
228  * \fn void Command_Logout(int argc, char **argv)\r
229  * \brief Exit the shell, logging the user out\r
230  */\r
231 void Command_Logout(int argc, char **argv)\r
232 {\r
233         exit(0);\r
234 }\r
235 \r
236 /**\r
237  * \fn void Command_Colour(int argc, char **argv)\r
238  * \brief Displays the help screen\r
239  */\r
240 void Command_Help(int argc, char **argv)\r
241 {\r
242         printf( "Acess 2 Command Line Interface\n"\r
243                 " By John Hodge (thePowersGang / [TPG])\n"\r
244                 "\n"\r
245                 "Builtin Commands:\n"\r
246                 " logout: Return to the login prompt\n"\r
247                 " exit:   Same\n"\r
248                 " help:   Display this message\n"\r
249                 " clear:  Clear the screen\n"\r
250                 " cd:     Change the current directory\n"\r
251                 " dir:    Print the contents of the current directory\n");\r
252         return;\r
253 }\r
254 \r
255 /**\r
256  * \fn void Command_Clear(int argc, char **argv)\r
257  * \brief Clear the screen\r
258  */\r
259 void Command_Clear(int argc, char **argv)\r
260 {\r
261         write(_stdout, "\x1B[2J", 4);   //Clear Screen\r
262 }\r
263 \r
264 /**\r
265  * \fn void Command_Cd(int argc, char **argv)\r
266  * \brief Change directory\r
267  */\r
268 void Command_Cd(int argc, char **argv)\r
269 {\r
270         char    tmpPath[1024];\r
271         int             fp;\r
272         t_sysFInfo      stats;\r
273         \r
274         if(argc < 2)\r
275         {\r
276                 printf("%s\n", gsCurrentDirectory);\r
277                 return;\r
278         }\r
279         \r
280         GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
281         \r
282         fp = open(tmpPath, 0);\r
283         if(fp == -1) {\r
284                 printf("Directory does not exist\n");\r
285                 return;\r
286         }\r
287         finfo(fp, &stats, 0);\r
288         close(fp);\r
289         \r
290         if( !(stats.flags & FILEFLAG_DIRECTORY) ) {\r
291                 printf("Not a Directory\n");\r
292                 return;\r
293         }\r
294         \r
295         free(gsCurrentDirectory);\r
296         gsCurrentDirectory = malloc(strlen(tmpPath)+1);\r
297         strcpy(gsCurrentDirectory, tmpPath);\r
298         \r
299         // Register change with kernel\r
300         chdir( gsCurrentDirectory );\r
301 }\r
302 \r
303 /**\r
304  * \fn void Command_Dir(int argc, char **argv)\r
305  * \brief Print the contents of a directory\r
306  */\r
307 void Command_Dir(int argc, char **argv)\r
308 {\r
309          int    dp, fp, dirLen;\r
310         char    modeStr[11] = "RWXrwxRWX ";\r
311         char    tmpPath[1024];\r
312         char    *fileName;\r
313         t_sysFInfo      info;\r
314         t_sysACL        acl;\r
315         \r
316         // Generate Directory Path\r
317         if(argc > 1)\r
318                 dirLen = GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
319         else\r
320         {\r
321                 strcpy(tmpPath, gsCurrentDirectory);\r
322         }\r
323         dirLen = strlen(tmpPath);\r
324         \r
325         // Open Directory\r
326         dp = open(tmpPath, OPENFLAG_READ);\r
327         // Check if file opened\r
328         if(dp == -1)\r
329         {\r
330                 printf("Unable to open directory `%s', File cannot be found\n", tmpPath);\r
331                 return;\r
332         }\r
333         // Get File Stats\r
334         if( finfo(dp, &info, 0) == -1 )\r
335         {\r
336                 close(dp);\r
337                 printf("stat Failed, Bad File Descriptor\n");\r
338                 return;\r
339         }\r
340         // Check if it's a directory\r
341         if(!(info.flags & FILEFLAG_DIRECTORY))\r
342         {\r
343                 close(dp);\r
344                 printf("Unable to open directory `%s', Not a directory\n", tmpPath);\r
345                 return;\r
346         }\r
347         \r
348         // Append Shash for file paths\r
349         if(tmpPath[dirLen-1] != '/')\r
350         {\r
351                 tmpPath[dirLen++] = '/';\r
352                 tmpPath[dirLen] = '\0';\r
353         }\r
354         \r
355         fileName = (char*)(tmpPath+dirLen);\r
356         // Read Directory Content\r
357         while( (fp = readdir(dp, fileName)) )\r
358         {\r
359                 if(fp < 0)\r
360                 {\r
361                         if(fp == -3)\r
362                                 printf("Invalid Permissions to traverse directory\n");\r
363                         break;\r
364                 }\r
365                 // Open File\r
366                 fp = open(tmpPath, 0);\r
367                 if(fp == -1)    continue;\r
368                 // Get File Stats\r
369                 finfo(fp, &info, 0);\r
370                 \r
371                 if(info.flags & FILEFLAG_DIRECTORY)\r
372                         printf("d");\r
373                 else\r
374                         printf("-");\r
375                 \r
376                 // Print Mode\r
377                 // - Owner\r
378                 acl.object = info.uid;\r
379                 _SysGetACL(fp, &acl);\r
380                 if(acl.perms & 1)       modeStr[0] = 'r';       else    modeStr[0] = '-';\r
381                 if(acl.perms & 2)       modeStr[1] = 'w';       else    modeStr[1] = '-';\r
382                 if(acl.perms & 8)       modeStr[2] = 'x';       else    modeStr[2] = '-';\r
383                 // - Group\r
384                 acl.object = info.gid | 0x80000000;\r
385                 _SysGetACL(fp, &acl);\r
386                 if(acl.perms & 1)       modeStr[3] = 'r';       else    modeStr[3] = '-';\r
387                 if(acl.perms & 2)       modeStr[4] = 'w';       else    modeStr[4] = '-';\r
388                 if(acl.perms & 8)       modeStr[5] = 'x';       else    modeStr[5] = '-';\r
389                 // - World\r
390                 acl.object = 0xFFFFFFFF;\r
391                 _SysGetACL(fp, &acl);\r
392                 if(acl.perms & 1)       modeStr[6] = 'r';       else    modeStr[6] = '-';\r
393                 if(acl.perms & 2)       modeStr[7] = 'w';       else    modeStr[7] = '-';\r
394                 if(acl.perms & 8)       modeStr[8] = 'x';       else    modeStr[8] = '-';\r
395                 printf(modeStr);\r
396                 close(fp);\r
397                 \r
398                 // Colour Code\r
399                 if(info.flags & FILEFLAG_DIRECTORY)     // Directory: Green\r
400                         printf("\x1B[32m");\r
401                 // Default: White\r
402                 \r
403                 // Print Name\r
404                 printf("%s", fileName);\r
405                 \r
406                 // Print slash if applicable\r
407                 if(info.flags & FILEFLAG_DIRECTORY)\r
408                         printf("/");\r
409                 \r
410                 // Revert Colour\r
411                 printf("\x1B[37m");\r
412                 \r
413                 // Newline!\r
414                 printf("\n");\r
415         }\r
416         // Close Directory\r
417         close(dp);\r
418 }\r

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