Replaced Exit() by exit() because Exit() is like abort().
[AROS-Contrib.git] / scout / source / SmartReadArgs.c
blob9f03e54aa01a1ba6190b1ae6fe818d2c317cada3
1 /*
2 * SmartReadArgs.c -- CLI/Workbench transparent ReadArgs()
4 * $VER: SmartReadArgs.c 1.6 (7.9.98)
6 * Copyright 1998 by Thomas Aglassinger <agi@sbox.tu-graz.ac.at>
8 * Based on ExtReadArgs Copyright 1994,1995 by Stefan Ruppert
9 */
11 /****** SmartReadArgs/--history-- *******************************************
12 * HISTORY
13 * Version 1.6, 7-Sep-1998
15 * - Changed name to SmartReadArgs to avoid confusion with other work based
16 * on the same material
17 * - Changed function parameters for SmartReadArgs() so that no more SAS/c
18 * specific values of argc/argv are required (Of course it still works
19 * with SAS/c, but you have to provide the WBStartup from "outside").
20 * - Changed all #include <clib/...> to #include <proto/..>, except for
21 * <clib/alib_stdio_protos.h> in "test.c". Where the hell is this one?
22 * - Added feature to ignore tooltypes that are not in the template
23 * - Added some missing includes in SmartReadArgs.c so the source codes
24 * compile without warnings
25 * - Changed #include <debug.h> to #include "debug.h" and provided a proper
26 * debug.h
27 * - The WINDOW tooltype is handled properly even if it is not entirely
28 * written in upper case.
29 * - Requires "utility.library" to be open as Stricmp() is used several
30 * times
31 * - Changed from Printf() to printf() using stdio of amiga.lib to make the
32 * code compile easier on non-SAS environments
33 * - Changed autodoc tool to Robodoc
34 * - Fixed enforcer hit if no tooltypes were provided at all
35 * - Remove some "char filename[34]" stuff and replaced the array dimension
36 * by MAXIMUM_FILENAME_LENGTH for future compatibility
37 * - Cleaned-up autodocs
38 * ANCIENT HISTORY
39 * ExtReadArgs() by Stefan Ruppert
41 * See aminet:dev/misc/extrdargs_v1.5.lha for the original version.
43 * $HISTORY
44 * 08.01.95 : 001.005 : changed to ExtReadArgs()
45 * 24.09.94 : 001.004 : now checks after ReadArgs the SIGBREAKF_CTRL_C
46 * flag, thus if anyone canceled during ReadArgs()
47 * help ExtReadArgs() fails
48 * 08.09.94 : 001.003 : between two switches (no equal sign) there was
49 * no space, this is fixed
50 * 08.09.94 : 001.002 : wb files now enclosed in quotes
51 * 04.09.94 : 001.001 : bumped to version 1
52 * 19.05.94 : 000.001 : initial
53 ***************************************************************************/
55 /* ------------------------------ include's ------------------------------- */
57 #define __USE_SYSBASE
58 #undef __USE_BASETYPE__
60 #include <exec/ports.h>
61 #include "SmartReadArgs.h"
63 #include <exec/memory.h>
64 #include <workbench/startup.h>
65 #include <workbench/workbench.h>
66 #include <dos/exall.h>
67 #include <utility/tagitem.h>
69 #include <string.h>
71 #include <proto/dos.h>
72 #include <proto/icon.h>
73 #include <proto/exec.h>
74 #include <proto/utility.h>
76 /* ---------------------------- local defines ----------------------------- */
78 #define TEMPSIZE 512
79 #ifndef MAX
80 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
81 #endif
83 #ifndef EOS
84 #define EOS '\0'
85 #endif
87 #define MODE_MULTI 1
89 #define MAXIMUM_FILENAME_LENGTH 108
91 /* --------------------------- library bases ------------------------------ */
92 extern struct Library *IconBase;
93 #if defined(__AROS__)
94 extern struct UtilityBase *UtilityBase;
95 #else
96 extern struct Library *UtilityBase;
97 #endif
99 #ifdef __GNUC__
100 extern struct WBStartup *_WBenchMsg;
101 #endif
103 /* -------------------------- static prototypes --------------------------- */
105 static struct DiskObject *smart_get_icon(struct SmartArgs *args, struct WBStartup *wbarg);
106 static void fstrcpy(struct SmartArgs *args, CONST_STRPTR string);
107 static void get_arg_name(struct SmartArgs *args, STRPTR buffer, ULONG size, ULONG * modes);
108 static void get_wbarg_name(struct WBArg *wbarg, STRPTR buffer, ULONG size);
109 static BOOL is_in_template(STRPTR name, STRPTR template);
110 extern void kprintf(const char *,...);
112 /****** SmartReadArgs/--background-- ****************************************
113 * COPYRIGHT
114 * SmartReadArgs is Copyright 1998 Thomas Aglassinger
116 * ExtReadArgs, its prequel, is Copyright 1994,1995 Stefan Ruppert
118 * Permission is granted to freely distribute the material (also only
119 * parts of it) as long this ReadMe is included and all the copyright
120 * notes are left unaltered except for a description of your changes.
121 * MOTIVATION
122 * The way of parsing ToolTypes provided by "icon.library" is rather
123 * clumsy. This is particular annoying as many programmers and users got
124 * used to ReadArgs(), which does the argument handling for many CLI
125 * commands and ARexx ports.
127 * Unfortunately, ReadArgs lacks a interface to Workbench tooltypes, thus
128 * its usage preventes your programs from being started from Workbench.
130 * SmartReadArgs() copies all Workbench arguments in a single string and
131 * passes this string to the ReadArgs() function. If started from CLI, it
132 * calls ReadArgs() without this step.
133 * AUTHOR
134 * Stefan Ruppert wrote most parts of the source code, designed the general
135 * interface and implemented loads of nice features. Basically he did the
136 * "hard work".
138 * He got the main idea for the implementation from Stefan Winterstein,
139 * the author of ARoach.
141 * Thomas Aglassinger <agi@sbox.tu-graz.ac.at> did some minor changes,
142 * established a more consistent naming schema, reworked the documentation
143 * and also added support for gcc/libnix.
145 * Contact him in case of problems or if you made some enhancements.
147 * Updates are available from aminet:dev/misc/SmartReadArgs.lha.
148 * DISCLAIMER
149 * There is no warranty for this software package. Although the author
150 * has tried to prevent errors, he can't guarantee that the software
151 * package described in this document is 100% reliable. You are
152 * therefore using this material at your own risk. The author cannot be
153 * made responsible for any damage which is caused by using this
154 * software package.
155 ****************************************************************************/
157 /* The define below is used to rename the example main() used in the autodoc
158 * to dummy_main(). Using two main()s would cause problems for the linker. */
159 #define main dummy_main
161 /****** SmartReadArgs/SmartReadArgs ******************************************
162 * NAME
163 * SmartReadArgs -- Workbench/CLI transparent ReadArgs().
164 * SYNOPSIS
165 * error = SmartReadArgs(wb_startup, smart_args);
167 * LONG SmartReadArgs(struct WBStartup *, struct SmartArgs *);
168 * FUNCTION
169 * This function is a CLI/Workbench transparent interface to ReadArgs().
171 * In case of a Workbench start, it analyzes the WBStartup message and
172 * possible tooltypes. These are converted to a text string that can be
173 * passed to ReadArgs() like before.
175 * Tooltypes that are not part of the template are ignored. This includes
176 * tooltypes being disabled with "(...)", NewIcons image data on systems
177 * without NewIcons installed and all this «« Icon by some idiot »» crap.
179 * If the application was stared from CLI, it simply calls ReadArgs()
180 * without the conversion step.
182 * If all went well you get a return value of zero. This means the passed
183 * arguments fit the template and are ready to use. Otherwise you get a
184 * IoErr()-like return code.
185 * INPUTS
186 * wb_startup - Workbench startup message. Refer to your compiler manual
187 * to learn how to obtain it. If this is NULL, the program was
188 * started from CLI.
189 * smart_args - structure which holds all information used by
190 * SmartReadArgs(). You have to setup the following fields before the
191 * call:
193 * sa_Template - The template passed to ReadArgs()
194 * sa_Parameter - ReadArgs() LONG WORD array to hold the arguments
195 * sa_FileParameter - number of Argument in the template to use
196 * for the files passed via WBStartup->sm_ArgList or -1, that
197 * means you don't want any files
198 * sa_Window - Window description string to open when the program
199 * is started from the workbench. NULL means no window. If the
200 * icon has a WINDOW tooltype, this value is ignored.
201 * sa_RDArgs - RDArgs structure to use for ReadArgs() call. This
202 * can be used to provide extended help.
203 * sa_Buffer - Pointer to a buffer to use for the Workbench startup
204 * or NULL, that means SmartReadArgs() allocates a buffer for you
205 * sa_BufferSize - Size of the optional buffer. If it is smaller than
206 * SA_MINIMUM_BUFFER_SIZE it will be adjusted.
208 * All other fields should be set to NULL.
209 * RESULTS
210 * Zero for success. You can check the sa_Flags field for the
211 * SAF_WORKBENCH flag to learn how the program was started.
213 * Otherwise an IoErr()-like error code is returned. This can be passed
214 * directly to PrintFault() or similar.
215 * NOTES
216 * Always call SmartFreeArgs(), even if SmartReadArgs() failed! See example
217 * below.
219 * This function requires "dos.library", "icon.library" and
220 * "utility.library" to be opened by the application. Normally this
221 * already has been done by the compiler startup code.
223 * There is a not widely known feature of ReadArgs(): with templates like
224 * "FROM/M/A,TO/A", you can select the files from workbench performing the
225 * following steps:
227 * - Select the program
228 * - Select the FROM files
229 * - Select and double click the TO file
231 * This is available because ReadArgs() grabs the last string from a
232 * multi-argument FROM and uses it as the TO parameter, if none is passed
233 * explicitely.
234 * BUGS
235 * There are some known problems when used with GCC, mostly related to the
236 * fact that I never bothered creating a useable developer environment
237 * around it (and I'm not sure if this is even possible >:) ...):
239 * - Debugging output shows up in the console instead of SER:. Does
240 * debug.lib exist for gcc? (Wasn't there this strange hunk2gcc
241 * converter?)
242 * - "Read from 0" Enforcer hit in SmartReadArgs(). Couldn't figure out
243 * the exact location yet because of the asynchronous debugging output
244 * mentioned above.
246 * For someone with a reasonable experience with GCC, it should be easy to
247 * fix this.
249 * The SAS/c implementation does not have these problems.
250 * SEE ALSO
251 * SmartFreeArgs(), dos.library/ReadArgs(), icon.library/GetDiskObjectNew()
252 * EXAMPLE
253 * The main archiev comes with a "test.c" and a couple of icons to start
254 * the corresponding executable "test". Take a look at the source code and
255 * play with it.
257 * See below for a smaller code segment that expects the "dos.library",
258 * "icon.library" and "utility.library" to be open already.
259 * SOURCE
261 /****************************************************************************/
262 LONG SmartReadArgs(struct WBStartup * wb_startup, struct SmartArgs * args)
264 LONG error;
265 #if defined(__amigaos4__)
266 struct ExecIFace *IExec = (struct ExecIFace *)(((struct ExecBase *)SysBase)->MainInterface);
267 #endif
269 args->sa_Flags = 0;
271 if (wb_startup != NULL)
273 struct WBArg *wbarg = wb_startup->sm_ArgList;
274 LONG arg_counter = 0;
276 while (arg_counter < wb_startup->sm_NumArgs)
278 wbarg += 1;
279 arg_counter += 1;
283 if (wb_startup != NULL)
285 if (!(args->sa_RDArgs = AllocDosObject(DOS_RDARGS, NULL)))
287 return (ERROR_NO_FREE_STORE);
289 else
291 args->sa_Flags |= SAF_ALLOCRDARGS;
293 if (!args->sa_Buffer)
295 args->sa_BufferSize = MAX(SA_MINIMUM_BUFFER_SIZE, args->sa_BufferSize);
296 args->sa_Buffer = AllocMem(args->sa_BufferSize, MEMF_ANY);
297 args->sa_Flags |= SAF_ALLOCBUFFER;
300 if (!args->sa_Buffer)
301 return (ERROR_NO_FREE_STORE);
302 else
304 struct DiskObject *dobj;
306 args->sa_ActualPtr = args->sa_Buffer;
307 args->sa_EndPtr = args->sa_Buffer + args->sa_BufferSize - 1;
309 if (!(dobj = smart_get_icon(args, wb_startup)))
311 return (ERROR_OBJECT_NOT_FOUND);
313 else
315 struct WBArg *wbarg = args->sa_WBArg;
316 ULONG num = args->sa_NumArgs;
318 STRPTR *tooltypes = (STRPTR *) dobj->do_ToolTypes;
319 STRPTR name;
320 STRPTR temp;
321 STRPTR ptr;
323 if (num > 1 && args->sa_FileParameter >= 0 && (temp = AllocMem(TEMPSIZE, MEMF_ANY)))
325 ULONG modes = 0;
327 get_arg_name(args, temp, TEMPSIZE, &modes);
328 fstrcpy(args, temp);
329 fstrcpy(args, " ");
331 /* no "/M" specifier in the ReadArgs() template, thus use only the first file */
332 if (modes != MODE_MULTI)
333 num = 2;
335 while (num > 1)
337 get_wbarg_name(wbarg, temp, TEMPSIZE);
338 fstrcpy(args, "\"");
339 fstrcpy(args, temp);
340 fstrcpy(args, "\" ");
341 num--;
342 wbarg++;
345 FreeMem(temp, TEMPSIZE);
348 if (tooltypes)
350 while (*tooltypes)
352 ptr = *tooltypes;
353 name = ptr;
355 /* check if this tooltype enabled and part of the
356 * template */
357 if ((*ptr != '(')
358 && is_in_template(name, args->sa_Template))
360 while (*ptr != '=' && *ptr != EOS)
361 ptr++;
363 if (*ptr == '=')
365 *ptr = EOS;
367 if (!Stricmp(name, "WINDOW"))
369 STRPTR win;
370 if ((win = AllocVec(strlen(ptr + 1) + 1, MEMF_ANY)))
372 strcpy(win, ptr + 1);
373 args->sa_Window = win;
374 args->sa_Flags |= SAF_ALLOCWINDOW;
378 else
380 fstrcpy(args, name);
382 /* enclose the argument in "" */
383 if (*(ptr + 1) == '"')
385 fstrcpy(args, "=");
386 fstrcpy(args, ptr + 1);
388 else
390 fstrcpy(args, "=\"");
391 fstrcpy(args, ptr + 1);
392 fstrcpy(args, "\"");
395 *ptr = '=';
398 else
399 fstrcpy(args, name);
401 fstrcpy(args, " ");
403 tooltypes++;
404 } /* while (*tooltypes) */
405 } /* if (tooltypes) */
406 fstrcpy(args, "\n");
411 args->sa_RDArgs->RDA_Source.CS_Buffer = args->sa_Buffer;
412 args->sa_RDArgs->RDA_Source.CS_Length = strlen(args->sa_Buffer);
414 args->sa_Flags |= SAF_WORKBENCH;
417 // ReadArgs() scheint bei fehlerfreier Arbeit IoErr() nicht neu zu setzen, darum machen wir das hier selbst
418 SetIoErr(0);
419 args->sa_FreeArgs = ReadArgs(args->sa_Template, args->sa_Parameter, args->sa_RDArgs);
421 if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
423 SetIoErr(ERROR_BREAK);
426 if ((error = IoErr()) == 0 && (wb_startup != NULL))
428 if (args->sa_Window)
430 args->sa_WindowFH = Open(args->sa_Window, MODE_NEWFILE);
431 if (args->sa_WindowFH)
433 args->sa_OldOutput = SelectOutput(args->sa_WindowFH);
434 args->sa_OldInput = SelectInput(args->sa_WindowFH);
439 return (error);
442 /****** SmartReadArgs/SmartFreeArgs ******************************************
443 * NAME
444 * SmartFreeArgs -- Free all resources allocated by SmartReadArgs().
445 * SYNOPSIS
446 * SmartFreeArgs(smart_args);
448 * void SmartFreeArgs(struct SmartArgs *);
449 * FUNCTION
450 * Free all resources allocated by a previous call to SmartReadArgs().
451 * INPUTS
452 * smart_args - Same pointer as passed to SmartReadArgs() before
453 * NOTES
454 * Always call SmartFreeArgs(), even if SmartReadArgs() failed! Take a look
455 * at the example for SmartReadArgs().
456 * SEE ALSO
457 * SmartReadArgs()
458 ****************************************************************************/
459 void SmartFreeArgs(struct SmartArgs *args)
461 /* FreeArgs() can handle a NULL pointer */
462 FreeArgs(args->sa_FreeArgs);
464 if (args->sa_Flags & SAF_ALLOCRDARGS)
465 if (args->sa_RDArgs)
466 FreeDosObject(DOS_RDARGS, args->sa_RDArgs);
468 if (args->sa_Flags & SAF_ALLOCBUFFER)
469 FreeMem(args->sa_Buffer, args->sa_BufferSize);
471 if (args->sa_WindowFH)
473 SelectOutput(args->sa_OldOutput);
474 SelectInput(args->sa_OldInput);
475 Close(args->sa_WindowFH);
478 if (args->sa_Flags & SAF_ALLOCWINDOW && args->sa_Window)
479 FreeVec(args->sa_Window);
482 /* This code was grapped from IconImage/wbarg.c/IconFromWBArg()
483 * Commodore-Amiga Example code
485 static struct DiskObject *smart_get_icon(struct SmartArgs *args, struct WBStartup *wb_startup)
487 struct DiskObject *dob = NULL;
488 struct WBArg *wbarg = wb_startup->sm_ArgList;
489 ULONG num = wb_startup->sm_NumArgs;
491 TEXT work_name[MAXIMUM_FILENAME_LENGTH];
492 BPTR old_lock, new_lock;
494 /* Copy the WBArg contents */
495 strncpy(work_name, wbarg->wa_Name, MAXIMUM_FILENAME_LENGTH);
497 new_lock = DupLock(wbarg->wa_Lock);
498 if (new_lock)
500 /* go to the directory where the icon resides */
501 old_lock = CurrentDir(new_lock);
503 dob = GetDiskObjectNew(work_name);
505 /* test, if the first icon is a project icon and if so, get its icon */
506 if (wb_startup->sm_NumArgs > 1)
508 BPTR new_lock2;
510 if ((new_lock2 = DupLock(wbarg[1].wa_Lock)))
512 struct DiskObject *prj;
514 CurrentDir(new_lock2);
516 UnLock(new_lock);
517 new_lock = new_lock2;
519 strncpy(work_name, wbarg[1].wa_Name, MAXIMUM_FILENAME_LENGTH);
521 if ((prj = GetDiskObjectNew(work_name)))
523 if (prj->do_Type == WBPROJECT)
525 BPTR test;
527 /* if this is only an icon skip it */
528 if (!(test = Lock(work_name, SHARED_LOCK)))
530 wbarg++;
531 num--;
533 else
534 UnLock(test);
536 if (dob)
537 FreeDiskObject(dob);
539 dob = prj;
545 /* go back to where we used to be */
546 CurrentDir(old_lock);
548 /* release the duplicated lock */
549 UnLock(new_lock);
551 args->sa_WBArg = wbarg + 1;
552 args->sa_NumArgs = num;
555 return (dob);
558 static void fstrcpy(struct SmartArgs *args, CONST_STRPTR string)
560 STRPTR ptr = args->sa_ActualPtr;
561 STRPTR end = args->sa_EndPtr;
563 while (ptr < end && *string)
564 *ptr++ = *string++;
566 *ptr = EOS; /* Mark end of string */
568 args->sa_ActualPtr = ptr;
571 static void get_arg_name(struct SmartArgs *args, STRPTR buffer, ULONG size, ULONG * modes)
573 ULONG num = args->sa_FileParameter;
574 STRPTR ptr = args->sa_Template;
576 *modes = 0;
578 while (num > 0)
580 while (*ptr != ',' && *ptr != EOS)
581 ptr++;
583 if (*ptr == ',')
584 ptr++;
585 num--;
588 if (*ptr != EOS)
590 while (*ptr != ',' && *ptr != '/' && *ptr != EOS && size > 0)
592 *buffer++ = *ptr++;
593 size--;
596 while (*ptr == '/')
598 ptr++;
600 if (*ptr == 'M' || *ptr == 'm')
601 *modes = MODE_MULTI;
603 ptr++;
607 *buffer = EOS;
610 static void get_wbarg_name(struct WBArg *wbarg, STRPTR buffer, ULONG size)
612 BPTR new;
614 if ((new = DupLock(wbarg->wa_Lock)))
616 if (!NameFromLock(new, buffer, size))
617 *buffer = EOS;
618 else if (!AddPart(buffer, wbarg->wa_Name, size))
619 *buffer = EOS;
621 UnLock(new);
623 else
624 *buffer = EOS;
627 /* Enable extended debugging for is_in_template() */
628 #undef D2
629 #if 0
630 #define D2(x) x
631 #else
632 #define D2(x) /* nufin */
633 #endif
634 static BOOL is_in_template(STRPTR name, STRPTR template)
636 BOOL found = FALSE;
637 STRPTR current_word = template;
638 BOOL skip_switch = FALSE;
639 size_t name_length;
641 /* Evaluate length of name part of whole tooltype */
642 name_length = 0;
643 while ((name[name_length] != EOS)
644 && (name[name_length] != '='))
646 name_length += 1;
649 while ((current_word[0] != '\0') && (!found))
651 STRPTR next_word = strpbrk(current_word, "/=,");
652 size_t current_word_length;
654 if (next_word == NULL)
656 next_word = current_word + strlen(current_word);
658 current_word_length = next_word - current_word;
660 if (skip_switch)
662 skip_switch = FALSE;
664 else
666 if ((name_length == current_word_length)
667 && !Strnicmp(name, current_word, name_length))
669 found = TRUE;
673 current_word = next_word;
674 if (current_word[0] != '\0')
676 if (current_word[0] == '/')
678 skip_switch = TRUE;
680 current_word += 1;
684 return found;