Hint added.
[AROS.git] / workbench / c / R / main.c
blob59008fa129baeb2d6773223dc8512fccff80b6f4
1 /*
2 Copyright © 2012, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
9 #include <proto/exec.h>
10 #include <proto/dos.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
17 #include "r.h"
18 #include "locale.h"
20 #define ARG_TEMPLATE "FILENAME,PROFILE/K,NOGUI/S,ARGUMENTS/F"
21 #define CMD_TMPLATE_SIZE (2000)
23 APTR poolmem;
25 enum
27 ARG_FILENAME,
28 ARG_PROFILE,
29 ARG_NOGUI,
30 ARG_ARGUMENTS,
31 ARG_COUNT
34 // functions
35 static void clean_exit(struct Req *req, CONST_STRPTR s)
37 LONG retval = RETURN_OK;
39 if (s)
41 retval = RETURN_FAIL;
42 PutStr(s);
44 if (req)
46 if (req->rda) FreeArgs(req->rda);
48 cleanup_gui();
49 DeletePool(poolmem);
50 exit(retval);
53 static struct Req *alloc_req(void)
55 return AllocPooled(poolmem, sizeof (struct Req));
58 static BOOL handle_args(struct Req *req, int argc, char **argv)
60 if (argc)
62 IPTR args[ARG_COUNT] = {(IPTR)"R", 0, 0, 0};
64 req->rda = ReadArgs(ARG_TEMPLATE, args, NULL);
65 if (!req->rda)
67 PrintFault(IoErr(), argv[0]);
68 return FALSE;
71 req->filename = (STRPTR)args[ARG_FILENAME];
72 req->profile = (STRPTR)args[ARG_PROFILE];
73 req->nogui = args[ARG_NOGUI] ? TRUE : FALSE;
74 req->arguments = (STRPTR)args[ARG_ARGUMENTS];
76 else
78 return FALSE;
79 // FIXME: it should be possible to use R as default tool
80 // of another command
82 return TRUE;
86 // return TRUE if name exists and is not a directory
87 static BOOL is_file(CONST_STRPTR name)
89 BOOL retval = FALSE;
91 if (name && name[0])
93 struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
94 if (fib)
96 BPTR lock = Lock(name, SHARED_LOCK);
97 if (lock)
99 if (Examine(lock, fib))
101 if (fib->fib_DirEntryType < 0)
103 retval = TRUE;
106 UnLock(lock);
108 FreeDosObject(DOS_FIB, fib);
111 return retval;
115 // search for the command. It must
116 // be an absolute path, exist in the current directory
117 // or exist in "C:".
118 static BOOL check_exist(struct Req *req)
120 BOOL retval = FALSE;
122 if (req->filename == NULL)
123 return FALSE;
125 if (strchr(req->filename, ':')) // absolute path
127 if (is_file(req->filename))
129 D(bug("[R] command found by absolute path\n"));
130 retval = TRUE;
133 else if (strchr(req->filename, '/') == NULL) // not in a sub-dir
135 if (is_file(req->filename)) // in current directory
137 D(bug("[R] command found in current directory\n"));
138 retval = TRUE;
140 else // in C:
142 BPTR lock = Lock("C:", SHARED_LOCK);
143 if (lock)
145 BPTR olddir = CurrentDir(lock);
146 if (is_file(req->filename))
148 D(bug("[R] command found in C:\n"));
149 retval = TRUE;
151 CurrentDir(olddir);
152 UnLock(lock);
158 return retval;
162 // execute the command with "?" option and read the command template
163 static BOOL get_template(struct Req *req)
165 BOOL retval = FALSE;
167 BPTR input_fh = BNULL;
168 BPTR output_fh = BNULL;
170 TEXT out_file_name[30];
171 TEXT in_file_name[30];
172 TEXT *cmd = NULL;
173 ULONG cmd_len = 0;
175 LONG i;
176 __unused LONG cmd_res = 0;
178 if (req->filename == NULL)
180 goto cleanup;
183 cmd_len = strlen(req->filename) + 20;
184 cmd = AllocPooled(poolmem, cmd_len);
185 if (cmd == NULL)
187 goto cleanup;
190 for (i = 0; i < 20 && output_fh == BNULL; i++)
192 sprintf(out_file_name, "t:%08u.request.outfile", (unsigned int)i);
193 output_fh = Open(out_file_name, MODE_NEWFILE);
195 if (output_fh == BNULL)
197 goto cleanup;
200 for (i = 0; i < 20 && input_fh == BNULL; i++)
202 sprintf(in_file_name, "t:%08u.request.infile", (unsigned int)i);
203 input_fh = Open(in_file_name, MODE_NEWFILE);
205 if (input_fh == BNULL)
207 goto cleanup;
209 Close(input_fh);
210 input_fh = Open(in_file_name, MODE_OLDFILE);
211 if (input_fh == BNULL)
213 goto cleanup;
216 // append "= ?" to the command to make ReadArgs fail so
217 // that the command prints the template and stops
218 strlcpy(cmd, req->filename, cmd_len);
219 strlcat(cmd, " = ?", cmd_len);
221 // shut up DOS error message
222 struct Process *me = (struct Process*)FindTask(NULL);
223 APTR oldwin = me->pr_WindowPtr;
224 me->pr_WindowPtr = (APTR)-1;
226 // Execute the command
227 cmd_res = Execute(cmd, input_fh, output_fh);
228 D(bug("[R] Execute() returned: %d\n", cmd_res));
230 // restore window ptr
231 me->pr_WindowPtr = oldwin;
233 req->cmd_template = AllocPooled(poolmem, CMD_TMPLATE_SIZE); // FIXME get mem size from file size
234 if (req->cmd_template == NULL)
236 goto cleanup;
239 // go to the beginning of the output file and read the template
240 Seek(output_fh, 0, OFFSET_BEGINNING);
241 if (FGets(output_fh, req->cmd_template, CMD_TMPLATE_SIZE))
243 D(bug("[R] template read: %s\n", req->cmd_template));
244 retval = TRUE;
247 cleanup:
248 if (input_fh)
250 Close(input_fh);
251 DeleteFile(in_file_name);
253 if (output_fh)
255 Close(output_fh);
256 DeleteFile(out_file_name);
259 FreePooled(poolmem, cmd, cmd_len);
261 return retval;
265 static BOOL parse_template(struct Req *req)
267 TEXT *chr;
268 LONG len;
269 LONG arg;
271 if (req->cmd_template[0] == '\0')
272 return FALSE;
274 // count number of arguments
277 req->arg_cnt = 1, chr = req->cmd_template;
278 *chr != '\0' && req->arg_cnt < 50;
279 chr++
282 if (*chr == ',')
284 req->arg_cnt++;
288 D(bug("[R/parse_template] args found %d\n", req->arg_cnt));
290 req->cargs = AllocPooled(poolmem, sizeof (struct CArg) * req->arg_cnt);
291 if (req->cargs == NULL)
293 return FALSE;
298 arg = 0, chr = req->cmd_template;
299 arg < req->arg_cnt;
300 chr++
303 // read name
304 TEXT *name_start = chr;
305 while (1)
307 if (isalnum(*chr))
309 chr++;
310 continue;
312 else if (*chr == '=')
314 // we are only interested in the part after the "=".
315 chr++;
316 name_start = chr;
317 continue;
319 break;
322 len = chr - name_start;
323 if (len == 0)
324 return FALSE;
326 if (len >= 35)
327 len = 35;
329 req->cargs[arg].argname = AllocPooled(poolmem, len + 1);
330 if (req->cargs[arg].argname == NULL)
332 return FALSE;
334 memcpy(req->cargs[arg].argname, name_start, len);
335 req->cargs[arg].argname[len] = '\0';
337 // read modifiers
338 while (*chr == '/')
340 switch (*(chr + 1))
342 case 'A':
343 req->cargs[arg].a_flag = TRUE;
344 chr++;
345 break;
346 case 'F':
347 req->cargs[arg].f_flag = TRUE;
348 chr++;
349 break;
350 case 'K':
351 req->cargs[arg].k_flag = TRUE;
352 chr++;
353 break;
354 case 'M':
355 req->cargs[arg].m_flag = TRUE;
356 chr++;
357 break;
358 case 'N':
359 req->cargs[arg].n_flag = TRUE;
360 chr++;
361 break;
362 case 'S':
363 req->cargs[arg].s_flag = TRUE;
364 chr++;
365 break;
366 case 'T':
367 req->cargs[arg].t_flag = TRUE;
368 chr++;
369 break;
370 default:
371 return FALSE;
372 break;
374 chr++;
376 arg++;
377 if (*chr != ',')
378 break;
380 return TRUE;
384 // create the command line from the selected options
385 static void execute_command(struct Req *req)
387 ULONG i;
388 CONST_STRPTR str;
389 TEXT *cmd;
391 ULONG cmd_size = strlen(req->filename) + 5;
392 for (i = 0; i < req->arg_cnt; i++)
394 cmd_size += strlen(req->cargs[i].argname) + 5;
395 if (!req->cargs[i].s_flag && !req->cargs[i].t_flag)
397 cmd_size += strlen(get_gui_string(&req->cargs[i])) + 5;
401 cmd = AllocPooled(poolmem, cmd_size);
402 if (cmd == NULL)
404 return;
407 strcpy(cmd, req->filename);
409 for (i = 0; i < req->arg_cnt; i++)
411 if (req->cargs[i].s_flag || req->cargs[i].t_flag)
413 if (get_gui_bool(&req->cargs[i]))
415 strcat(cmd, " ");
416 strcat(cmd, req->cargs[i].argname);
419 else if (req->cargs[i].n_flag)
421 str = get_gui_string(&req->cargs[i]);
422 if (str[0] != '\0')
424 strcat(cmd, " ");
425 strcat(cmd, req->cargs[i].argname);
426 strcat(cmd, " ");
427 strcat(cmd, str);
430 else
432 BOOL quote = FALSE;
433 str = get_gui_string(&req->cargs[i]);
434 if (str[0] != '\0')
436 // do we have a space character in the string?
437 // if yes: quote it.
438 // For /M the quotes are already set by the GUI
439 if (!req->cargs[i].m_flag && strchr(str, ' ') && str[0] != '\"')
441 quote = TRUE;
443 strcat(cmd, " ");
444 strcat(cmd, req->cargs[i].argname);
445 strcat(cmd, " ");
446 if (quote)
448 strcat(cmd, "\"");
450 strcat(cmd, str);
451 if (quote)
453 strcat(cmd, "\"");
459 D(bug("[R] executing command %s\n", cmd));
460 LONG result = System
462 cmd,
463 NULL
465 if (result)
467 Printf(_(MSG_ERROR_RETURN), req->filename, result);
472 int main(int argc, char **argv)
474 poolmem = CreatePool(MEMF_ANY | MEMF_CLEAR, 2000, 2000);
475 if (poolmem == NULL)
476 clean_exit(NULL, _(MSG_ERROR_POOL));
478 struct Req *req = alloc_req();
479 if (req == NULL)
480 clean_exit(req, _(MSG_ERROR_STRUCT));
482 D(bug("[R/main] req %p\n", req));
484 if (! handle_args(req, argc, argv))
485 clean_exit(req, _(MSG_ERROR_ARGS));
487 if (! check_exist(req))
488 clean_exit(req, _(MSG_ERROR_NOTFOUND));
490 if (! get_template(req))
491 clean_exit(req, _(MSG_ERROR_TMPLT_GET));
493 if (! parse_template(req))
494 clean_exit(req, _(MSG_ERROR_TMPLT_PARSE));
496 if (! create_gui(req))
497 clean_exit(req, _(MSG_ERROR_GUI));
499 if (! set_defaults(req))
500 clean_exit(req, _(MSG_ERROR_DEFAULTS));
502 if (handle_gui(req))
504 execute_command(req);
507 clean_exit(req, NULL);
509 return RETURN_OK;