Use poolmem and allocate memory dynamically.
[AROS.git] / workbench / c / R / main.c
blobd95804c02a14cd289a048d05672f56bdfa756bea
1 /*
2 Copyright © 2012, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <proto/exec.h>
7 #include <proto/dos.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <ctype.h>
14 #define DEBUG 1
15 #include <aros/debug.h>
17 #include "r.h"
19 #define ARG_TEMPLATE "FILENAME,PROFILE/K,NOGUI/S,ARGUMENTS/F"
20 #define CMD_TMPLATE_SIZE (2000)
22 APTR poolmem;
24 enum
26 ARG_FILENAME,
27 ARG_PROFILE,
28 ARG_NOGUI,
29 ARG_ARGUMENTS,
30 ARG_COUNT
33 // functions
34 static void clean_exit(struct Req *req, CONST_STRPTR s)
36 LONG retval = RETURN_OK;
38 if (s)
40 retval = RETURN_FAIL;
41 PutStr(s);
43 if (req)
45 if (req->rda) FreeArgs(req->rda);
47 cleanup_gui();
48 DeletePool(poolmem);
49 exit(retval);
52 static struct Req *alloc_req(void)
54 return AllocPooled(poolmem, sizeof (struct Req));
57 static BOOL handle_args(struct Req *req, int argc, char **argv)
59 if (argc)
61 IPTR args[ARG_COUNT] = {0};
63 req->rda = ReadArgs(ARG_TEMPLATE, args, NULL);
64 if (!req->rda)
66 PrintFault(IoErr(), argv[0]);
67 return FALSE;
70 req->filename = (STRPTR)args[ARG_FILENAME];
71 req->profile = (STRPTR)args[ARG_PROFILE];
72 req->nogui = args[ARG_NOGUI] ? TRUE : FALSE;
73 req->arguments = (STRPTR)args[ARG_ARGUMENTS];
75 else
77 return FALSE;
78 // FIXME: it should be possible to use R as default tool
79 // of another command
81 return TRUE;
85 // return TRUE if name exists and is not a directory
86 static BOOL is_file(CONST_STRPTR name)
88 BOOL retval = FALSE;
90 if (name && name[0])
92 struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
93 if (fib)
95 BPTR lock = Lock(name, SHARED_LOCK);
96 if (lock)
98 if (Examine(lock, fib))
100 if (fib->fib_DirEntryType < 0)
102 retval = TRUE;
105 UnLock(lock);
107 FreeDosObject(DOS_FIB, fib);
110 return retval;
114 // search for the command. It must
115 // be an absolute path, exist in the current directory
116 // or exist in "C:".
117 static BOOL check_exist(struct Req *req)
119 BOOL retval = FALSE;
121 if (req->filename == NULL)
122 return FALSE;
124 if (strchr(req->filename, ':')) // absolute path
126 if (is_file(req->filename))
128 D(bug("[R] command found by absolute path\n"));
129 retval = TRUE;
132 else if (strchr(req->filename, '/') == NULL) // not in a sub-dir
134 if (is_file(req->filename)) // in current directory
136 D(bug("[R] command found in current directory\n"));
137 retval = TRUE;
139 else // in C:
141 BPTR lock = Lock("C:", SHARED_LOCK);
142 if (lock)
144 BPTR olddir = CurrentDir(lock);
145 if (is_file(req->filename))
147 D(bug("[R] command found in C:\n"));
148 retval = TRUE;
150 CurrentDir(olddir);
151 UnLock(lock);
157 return retval;
161 // execute the command with "?" option and read the command template
162 static BOOL get_template(struct Req *req)
164 BOOL retval = FALSE;
166 BPTR input_fh = NULL;
167 BPTR output_fh = NULL;
169 TEXT out_file_name[30];
170 TEXT in_file_name[30];
171 TEXT *cmd = NULL;
172 ULONG cmd_len = 0;
174 LONG i;
175 LONG cmd_res = 0;
177 if (req->filename == NULL)
179 goto cleanup;
182 cmd_len = strlen(req->filename) + 20;
183 cmd = AllocPooled(poolmem, cmd_len);
184 if (cmd == NULL)
186 goto cleanup;
189 for (i = 0; i < 20 && output_fh == NULL; i++)
191 sprintf(out_file_name, "t:%08u.request.outfile", i);
192 output_fh = Open(out_file_name, MODE_NEWFILE);
194 if (output_fh == NULL)
196 goto cleanup;
199 for (i = 0; i < 20 && input_fh == NULL; i++)
201 sprintf(in_file_name, "t:%08u.request.infile", i);
202 input_fh = Open(in_file_name, MODE_NEWFILE);
204 if (input_fh == NULL)
206 goto cleanup;
208 Close(input_fh);
209 input_fh = Open(in_file_name, MODE_OLDFILE);
210 if (input_fh == NULL)
212 goto cleanup;
215 // append "*>NIL: ?" to the command
216 strlcpy(cmd, req->filename, cmd_len);
217 strlcat(cmd, " *>NIL: ?", cmd_len);
219 // shut up DOS error message
220 struct Process *me = (struct Process*)FindTask(NULL);
221 APTR oldwin = me->pr_WindowPtr;
222 me->pr_WindowPtr = (APTR)-1;
224 // Execute the command
225 cmd_res = Execute(cmd, input_fh, output_fh);
226 D(bug("[R] Execute() returned: %d\n", cmd_res));
228 // restore window ptr
229 me->pr_WindowPtr = oldwin;
231 req->cmd_template = AllocPooled(poolmem, CMD_TMPLATE_SIZE); // FIXME get mem size from file size
232 if (req->cmd_template == NULL)
234 goto cleanup;
237 // go to the beginning of the output file and read the template
238 Seek(output_fh, 0, OFFSET_BEGINNING);
239 if (FGets(output_fh, req->cmd_template, CMD_TMPLATE_SIZE))
241 D(bug("[R] template read: %s\n", req->cmd_template));
242 retval = TRUE;
245 cleanup:
246 if (input_fh)
248 Close(input_fh);
249 DeleteFile(in_file_name);
251 if (output_fh)
253 Close(output_fh);
254 DeleteFile(out_file_name);
257 FreePooled(poolmem, cmd, cmd_len);
259 return retval;
263 static BOOL parse_template(struct Req *req)
265 TEXT *chr;
266 LONG len;
267 LONG arg;
269 if (req->cmd_template[0] == '\0')
270 return FALSE;
272 // count number of arguments
275 req->arg_cnt = 1, chr = req->cmd_template;
276 *chr != '\0' && req->arg_cnt < 50;
277 chr++
280 if (*chr == ',')
282 req->arg_cnt++;
286 D(bug("[R/parse_template args found %d\n", req->arg_cnt));
288 req->cargs = AllocPooled(poolmem, sizeof (struct CArg) * req->arg_cnt);
289 if (req->cargs == NULL)
291 return FALSE;
296 arg = 0, chr = req->cmd_template;
297 arg < req->arg_cnt;
298 chr++
301 // read name
302 TEXT *name_start = chr;
303 while (1)
305 if (isalnum(*chr))
307 chr++;
308 continue;
310 else if (*chr == '=')
312 // we are only interested in the part after the "=".
313 chr++;
314 name_start = chr;
315 continue;
317 break;
320 len = chr - name_start;
321 if (len == 0)
322 return FALSE;
324 if (len >= 35)
325 len = 35;
327 req->cargs[arg].argname = AllocPooled(poolmem, len + 1);
328 if (req->cargs[arg].argname == NULL)
330 return FALSE;
332 memcpy(req->cargs[arg].argname, name_start, len);
333 req->cargs[arg].argname[len] = '\0';
335 // read modifiers
336 while (*chr == '/')
338 switch (*(chr + 1))
340 case 'A':
341 req->cargs[arg].a_flag = TRUE;
342 chr++;
343 break;
344 case 'F':
345 req->cargs[arg].f_flag = TRUE;
346 chr++;
347 break;
348 case 'K':
349 req->cargs[arg].k_flag = TRUE;
350 chr++;
351 break;
352 case 'M':
353 req->cargs[arg].m_flag = TRUE;
354 chr++;
355 break;
356 case 'N':
357 req->cargs[arg].n_flag = TRUE;
358 chr++;
359 break;
360 case 'S':
361 req->cargs[arg].s_flag = TRUE;
362 chr++;
363 break;
364 case 'T':
365 req->cargs[arg].t_flag = TRUE;
366 chr++;
367 break;
368 default:
369 return FALSE;
370 break;
372 chr++;
374 arg++;
375 if (*chr != ',')
376 break;
378 return TRUE;
382 // create the command line from the selected options
383 static void execute_command(struct Req *req)
385 ULONG i;
386 CONST_STRPTR str;
387 TEXT *cmd;
389 ULONG cmd_size = strlen(req->filename) + 5;
390 for (i = 0; i < req->arg_cnt; i++)
392 cmd_size += strlen(req->cargs[i].argname) + 5;
393 if (!req->cargs[i].s_flag && !req->cargs[i].t_flag)
395 cmd_size += strlen(get_gui_string(&req->cargs[i])) + 5;
399 cmd = AllocPooled(poolmem, cmd_size);
400 if (cmd == NULL)
402 return;
405 strcpy(cmd, req->filename);
407 for (i = 0; i < req->arg_cnt; i++)
409 if (req->cargs[i].s_flag || req->cargs[i].t_flag)
411 if (get_gui_bool(&req->cargs[i]))
413 strcat(cmd, " ");
414 strcat(cmd, req->cargs[i].argname);
417 else if (req->cargs[i].n_flag)
419 str = get_gui_string(&req->cargs[i]);
420 if (str[0] != '\0')
422 strcat(cmd, " ");
423 strcat(cmd, req->cargs[i].argname);
424 strcat(cmd, " ");
425 strcat(cmd, str);
428 else
430 BOOL quote = FALSE;
431 str = get_gui_string(&req->cargs[i]);
432 if (str[0] != '\0')
434 // do we have a space character in the string?
435 // if yes: quote it.
436 // For /M the quotes are already set by the GUI
437 if (!req->cargs[i].m_flag && strchr(str, ' ') && str[0] != '\"')
439 quote = TRUE;
441 strcat(cmd, " ");
442 strcat(cmd, req->cargs[i].argname);
443 strcat(cmd, " ");
444 if (quote)
446 strcat(cmd, "\"");
448 strcat(cmd, str);
449 if (quote)
451 strcat(cmd, "\"");
457 D(bug("[R] executing command %s\n", cmd));
458 LONG result = System
460 cmd,
461 NULL
463 if (result)
465 Printf("\"%s\" failed, return code %ld\n", req->filename, result);
470 int main(int argc, char **argv)
472 poolmem = CreatePool(MEMF_ANY | MEMF_CLEAR, 2000, 2000);
473 if (poolmem == NULL)
474 clean_exit(NULL, "r: Can't create poolmem\n");
476 struct Req *req = alloc_req();
477 if (req == NULL)
478 clean_exit(req, "r: Can't allocate struct Req\n");
480 D(bug("[R/main] req %p\n", req));
482 if (! handle_args(req, argc, argv))
483 clean_exit(req, "r: Failed to parse arguments\n");
485 if (! check_exist(req))
486 clean_exit(req, "r: Command not found\n");
488 if (! get_template(req))
489 clean_exit(req, "r: Failed to get template\n");
491 if (! parse_template(req))
492 clean_exit(req, "r: Failed to parse the template\n");
494 if (! create_gui(req))
495 clean_exit(req, "r: Failed to create application object\n");
497 if (handle_gui(req))
499 execute_command(req);
502 clean_exit(req, NULL);
504 return RETURN_OK;