Bringing v7.10 in main trunk.
[AROS.git] / workbench / libs / openurl / cmd / SmartReadArgs.c
blob6cb3030fd3004824b1ab4f4977261aa8650b7b68
1 /*
2 * SmartReadArgs.c -- CLI/Workbench transparent ReadArgs()
4 * $VER: SmartReadArgs.c 1.7 (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
10 * Ported to OS4 by Alexandre Balaban <alexandre@balaban.name>
13 /****** SmartReadArgs/--history-- *******************************************
14 * HISTORY
15 * Version 1.7
16 * - TODO: use dos/FindArg() instead of is_in_template()
17 * - Fixed two minor "size_t vs. LONG" warnings in
19 * Version 1.6, 7-Sep-1998
21 * - Changed name to SmartReadArgs to avoid confusion with other work based
22 * on the same material
23 * - Changed function parameters for SmartReadArgs() so that no more SAS/c
24 * specific values of argc/argv are required (Of course it still works
25 * with SAS/c, but you have to provide the WBStartup from "outside").
26 * - Changed all #include <clib/...> to #include <proto/..>, except for
27 * <clib/alib_stdio_protos.h> in "test.c". Where the hell is this one?
28 * - Added feature to ignore tooltypes that are not in the template
29 * - Added some missing includes in SmartReadArgs.c so the source codes
30 * compile without warnings
31 * - Changed #include <debug.h> to #include "debug.h" and provided a proper
32 * debug.h
33 * - The WINDOW tooltype is handled properly even if it is not entirely
34 * written in upper case.
35 * - Requires "utility.library" to be open as Stricmp() is used several
36 * times
37 * - Changed from Printf() to printf() using stdio of amiga.lib to make the
38 * code compile easier on non-SAS environments
39 * - Changed autodoc tool to Robodoc
40 * - Fixed enforcer hit if no tooltypes were provided at all
41 * - Remove some "char filename[34]" stuff and replaced the array dimension
42 * by MAXIMUM_FILENAME_LENGTH for future compatibility
43 * - Cleaned-up autodocs
44 * ANCIENT HISTORY
45 * ExtReadArgs() by Stefan Ruppert
47 * See aminet:dev/misc/extrdargs_v1.5.lha for the original version.
49 * $HISTORY
50 * 08.01.95 : 001.005 : changed to ExtReadArgs()
51 * 24.09.94 : 001.004 : now checks after ReadArgs the SIGBREAKF_CTRL_C
52 * flag, thus if anyone canceled during ReadArgs()
53 * help ExtReadArgs() fails
54 * 08.09.94 : 001.003 : between two switches (no equal sign) there was
55 * no space, this is fixed
56 * 08.09.94 : 001.002 : wb files now enclosed in quotes
57 * 04.09.94 : 001.001 : bumped to version 1
58 * 19.05.94 : 000.001 : initial
59 ***************************************************************************/
61 /* ------------------------------ include's ------------------------------- */
63 #include "debug.h"
64 #include "SmartReadArgs.h"
65 #include "SDI_compiler.h"
67 #include <exec/memory.h>
68 #include <workbench/startup.h>
69 #include <workbench/workbench.h>
70 #include <dos/exall.h>
71 #include <utility/tagitem.h>
73 #include <string.h>
75 #include <proto/dos.h>
76 #include <proto/icon.h>
77 #include <proto/exec.h>
78 #include <proto/utility.h>
80 /* ---------------------------- local defines ----------------------------- */
82 #define TEMPSIZE 512
83 #ifndef MAX
84 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
85 #endif
87 #ifndef EOS
88 #define EOS '\0'
89 #endif
91 #ifndef ZERO
92 #define ZERO ((BPTR)0)
93 #endif
95 #define MODE_MULTI 1
97 #define MAXIMUM_FILENAME_LENGTH 108
99 /* --------------------------- library bases ------------------------------ */
100 extern struct Library *IconBase;
101 #if defined(__AROS__)
102 extern struct UtilityBase *UtilityBase;
103 #else
104 extern struct Library *UtilityBase;
105 #endif
107 #if defined(__GNUC__) && !defined(__amigaos4__)
108 extern struct WBStartup *_WBenchMsg;
109 #endif
111 /* -------------------------- static prototypes --------------------------- */
113 static struct DiskObject *smart_get_icon(struct SmartArgs *args, struct WBStartup *wbarg);
114 static void fstrcpy(struct SmartArgs *args, CONST_STRPTR string);
115 static void get_arg_name(struct SmartArgs *args, STRPTR buffer, ULONG size, ULONG * modes);
116 static void get_wbarg_name(struct WBArg *wbarg, STRPTR buffer, ULONG size);
117 static BOOL is_in_template(STRPTR name, CONST_STRPTR template);
119 /****** SmartReadArgs/--background-- ****************************************
120 * COPYRIGHT
121 * SmartReadArgs is Copyright 1998 Thomas Aglassinger
123 * ExtReadArgs, its prequel, is Copyright 1994,1995 Stefan Ruppert
125 * Permission is granted to freely distribute the material (also only
126 * parts of it) as long this ReadMe is included and all the copyright
127 * notes are left unaltered except for a description of your changes.
128 * MOTIVATION
129 * The way of parsing ToolTypes provided by "icon.library" is rather
130 * clumsy. This is particular annoying as many programmers and users got
131 * used to ReadArgs(), which does the argument handling for many CLI
132 * commands and ARexx ports.
134 * Unfortunately, ReadArgs lacks a interface to Workbench tooltypes, thus
135 * its usage preventes your programs from being started from Workbench.
137 * SmartReadArgs() copies all Workbench arguments in a single string and
138 * passes this string to the ReadArgs() function. If started from CLI, it
139 * calls ReadArgs() without this step.
140 * AUTHOR
141 * Stefan Ruppert wrote most parts of the source code, designed the general
142 * interface and implemented loads of nice features. Basically he did the
143 * "hard work".
145 * He got the main idea for the implementation from Stefan Winterstein,
146 * the author of ARoach.
148 * Thomas Aglassinger <agi@sbox.tu-graz.ac.at> did some minor changes,
149 * established a more consistent naming schema, reworked the documentation
150 * and also added support for gcc/libnix.
152 * Contact him in case of problems or if you made some enhancements.
154 * Updates are available from aminet:dev/misc/SmartReadArgs.lha.
155 * DISCLAIMER
156 * There is no warranty for this software package. Although the author
157 * has tried to prevent errors, he can't guarantee that the software
158 * package described in this document is 100% reliable. You are
159 * therefore using this material at your own risk. The author cannot be
160 * made responsible for any damage which is caused by using this
161 * software package.
162 ****************************************************************************/
164 /* The define below is used to rename the example main() used in the autodoc
165 * to dummy_main(). Using two main()s would cause problems for the linker. */
166 #define main dummy_main
168 /****** SmartReadArgs/SmartReadArgs ******************************************
169 * NAME
170 * SmartReadArgs -- Workbench/CLI transparent ReadArgs().
171 * SYNOPSIS
172 * error = SmartReadArgs(wb_startup, smart_args);
174 * LONG SmartReadArgs(struct WBStartup *, struct SmartArgs *);
175 * FUNCTION
176 * This function is a CLI/Workbench transparent interface to ReadArgs().
178 * In case of a Workbench start, it analyzes the WBStartup message and
179 * possible tooltypes. These are converted to a text string that can be
180 * passed to ReadArgs() like before.
182 * Tooltypes that are not part of the template are ignored. This includes
183 * tooltypes being disabled with "(...)", NewIcons image data on systems
184 * without NewIcons installed and all this «« Icon by some idiot »» crap.
186 * If the application was stared from CLI, it simply calls ReadArgs()
187 * without the conversion step.
189 * If all went well you get a return value of zero. This means the passed
190 * arguments fit the template and are ready to use. Otherwise you get a
191 * IoErr()-like return code.
192 * INPUTS
193 * wb_startup - Workbench startup message. Refer to your compiler manual
194 * to learn how to obtain it. If this is NULL, the program was
195 * started from CLI.
196 * smart_args - structure which holds all information used by
197 * SmartReadArgs(). You have to setup the following fields before the
198 * call:
200 * sa_Template - The template passed to ReadArgs()
201 * sa_Parameter - ReadArgs() LONG WORD array to hold the arguments
202 * sa_FileParameter - number of Argument in the template to use
203 * for the files passed via WBStartup->sm_ArgList or -1, that
204 * means you don't want any files
205 * sa_Window - Window description string to open when the program
206 * is started from the workbench. NULL means no window. If the
207 * icon has a WINDOW tooltype, this value is ignored.
208 * sa_RDArgs - RDArgs structure to use for ReadArgs() call. This
209 * can be used to provide extended help.
210 * sa_Buffer - Pointer to a buffer to use for the Workbench startup
211 * or NULL, that means SmartReadArgs() allocates a buffer for you
212 * sa_BufferSize - Size of the optional buffer. If it is smaller than
213 * SA_MINIMUM_BUFFER_SIZE it will be adjusted.
215 * All other fields should be set to NULL.
216 * RESULTS
217 * Zero for success. You can check the sa_Flags field for the
218 * SAF_WORKBENCH flag to learn how the program was started.
220 * Otherwise an IoErr()-like error code is returned. This can be passed
221 * directly to PrintFault() or similar.
222 * NOTES
223 * Always call SmartFreeArgs(), even if SmartReadArgs() failed! See example
224 * below.
226 * This function requires "dos.library", "icon.library" and
227 * "utility.library" to be opened by the application. Normally this
228 * already has been done by the compiler startup code.
230 * There is a not widely known feature of ReadArgs(): with templates like
231 * "FROM/M/A,TO/A", you can select the files from workbench performing the
232 * following steps:
234 * - Select the program
235 * - Select the FROM files
236 * - Select and double click the TO file
238 * This is available because ReadArgs() grabs the last string from a
239 * multi-argument FROM and uses it as the TO parameter, if none is passed
240 * explicitely.
241 * BUGS
242 * There are some known problems when used with GCC, mostly related to the
243 * fact that I never bothered creating a useable developer environment
244 * around it (and I'm not sure if this is even possible >:) ...):
246 * - Debugging output shows up in the console instead of SER:. Does
247 * debug.lib exist for gcc? (Wasn't there this strange hunk2gcc
248 * converter?)
249 * - "Read from 0" Enforcer hit in SmartReadArgs(). Couldn't figure out
250 * the exact location yet because of the asynchronous debugging output
251 * mentioned above.
253 * For someone with a reasonable experience with GCC, it should be easy to
254 * fix this.
256 * The SAS/c implementation does not have these problems.
257 * SEE ALSO
258 * SmartFreeArgs(), dos.library/ReadArgs(), icon.library/GetDiskObjectNew()
259 * EXAMPLE
260 * The main archiev comes with a "test.c" and a couple of icons to start
261 * the corresponding executable "test". Take a look at the source code and
262 * play with it.
264 * See below for a smaller code segment that expects the "dos.library",
265 * "icon.library" and "utility.library" to be open already.
266 * SOURCE
268 /****************************************************************************/
269 LONG SmartReadArgs(struct WBStartup * wb_startup, struct SmartArgs * args)
271 LONG error;
273 #if defined(__amigaos4__)
274 struct ExecIFace *IExec = (struct ExecIFace *)(((struct ExecBase *)SysBase)->MainInterface);
275 #endif
277 args->sa_Flags = 0;
279 D(DBF_STARTUP, "UtilityBase = 0x%08lx", (ULONG)UtilityBase);
280 D(DBF_STARTUP, "IconBase = 0x%08lx", (ULONG)IconBase);
281 D(DBF_STARTUP, "WBStartup = 0x%08lx", (ULONG)wb_startup);
283 if (wb_startup != NULL)
285 struct WBArg *wbarg = wb_startup->sm_ArgList;
286 LONG arg_counter = 0;
288 D(DBF_STARTUP, " numArgs = %ld", wb_startup->sm_NumArgs);
289 while (arg_counter < wb_startup->sm_NumArgs)
291 D(DBF_STARTUP, " name[%ld] = '%s'", arg_counter, wbarg->wa_Name);
292 wbarg += 1;
293 arg_counter += 1;
297 if (wb_startup != NULL)
299 if (!(args->sa_RDArgs = AllocDosObject(DOS_RDARGS, NULL)))
301 return (ERROR_NO_FREE_STORE);
303 else
305 args->sa_Flags |= SAF_ALLOCRDARGS;
307 if (!args->sa_Buffer)
309 args->sa_BufferSize = MAX(SA_MINIMUM_BUFFER_SIZE, args->sa_BufferSize);
310 args->sa_Buffer = AllocMem(args->sa_BufferSize, MEMF_ANY);
311 args->sa_Flags |= SAF_ALLOCBUFFER;
314 if (!args->sa_Buffer)
315 return (ERROR_NO_FREE_STORE);
316 else
318 struct DiskObject *dobj;
320 args->sa_ActualPtr = args->sa_Buffer;
321 args->sa_EndPtr = args->sa_Buffer + args->sa_BufferSize - 1;
323 if (!(dobj = smart_get_icon(args, wb_startup)))
325 return (ERROR_OBJECT_NOT_FOUND);
327 else
329 struct WBArg *wbarg = args->sa_WBArg;
330 ULONG num = args->sa_NumArgs;
332 STRPTR *tooltypes = (STRPTR *) dobj->do_ToolTypes;
333 STRPTR name;
334 STRPTR temp;
335 STRPTR ptr;
337 if (num > 1 && args->sa_FileParameter >= 0 && (temp = AllocMem(TEMPSIZE, MEMF_ANY)))
339 ULONG modes = 0;
341 get_arg_name(args, temp, TEMPSIZE, &modes);
342 fstrcpy(args, temp);
343 fstrcpy(args, " ");
345 /* no "/M" specifier in the ReadArgs() template, thus use only the first file */
346 if (modes != MODE_MULTI)
347 num = 2;
349 while (num > 1)
351 get_wbarg_name(wbarg, temp, TEMPSIZE);
352 fstrcpy(args, "\"");
353 fstrcpy(args, temp);
354 fstrcpy(args, "\" ");
355 num--;
356 wbarg++;
359 FreeMem(temp, TEMPSIZE);
362 D(DBF_STARTUP, "tooltypes=%08lx", (ULONG)tooltypes);
363 if (tooltypes)
365 while (*tooltypes)
367 ptr = *tooltypes;
368 name = ptr;
370 /* check if this tooltype enabled and part of the
371 * template */
372 if ((*ptr != '(')
373 && is_in_template(name, args->sa_Template))
375 while (*ptr != '=' && *ptr != EOS)
376 ptr++;
378 if (*ptr == '=')
380 *ptr = EOS;
382 if (!Stricmp(name, "WINDOW"))
384 STRPTR win;
385 if ((win = AllocVec((ULONG) strlen(ptr + 1) + 1, MEMF_ANY)))
387 strcpy(win, ptr + 1);
388 args->sa_Window = win;
389 args->sa_Flags |= SAF_ALLOCWINDOW;
393 else
395 fstrcpy(args, name);
397 /* enclose the argument in "" */
398 if (*(ptr + 1) == '"')
400 fstrcpy(args, "=");
401 fstrcpy(args, ptr + 1);
403 else
405 fstrcpy(args, "=\"");
406 fstrcpy(args, ptr + 1);
407 fstrcpy(args, "\"");
410 *ptr = '=';
413 else
414 fstrcpy(args, name);
416 fstrcpy(args, " ");
418 tooltypes++;
419 } /* while (*tooltypes) */
420 } /* if (tooltypes) */
421 fstrcpy(args, "\n");
423 D(DBF_STARTUP, "final wb command line : '%s'", args->sa_Buffer);
428 args->sa_RDArgs->RDA_Source.CS_Buffer = args->sa_Buffer;
429 args->sa_RDArgs->RDA_Source.CS_Length = strlen(args->sa_Buffer);
431 args->sa_Flags |= SAF_WORKBENCH;
434 SetIoErr(0);
436 args->sa_FreeArgs = ReadArgs(args->sa_Template, (APTR)args->sa_Parameter, args->sa_RDArgs);
438 if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
440 SetIoErr(ERROR_BREAK);
443 if ((error = IoErr()) == 0 && (wb_startup != NULL))
445 if (args->sa_Window)
447 args->sa_WindowFH = Open(args->sa_Window, MODE_NEWFILE);
448 if (args->sa_WindowFH)
450 args->sa_OldOutput = SelectOutput(args->sa_WindowFH);
451 args->sa_OldInput = SelectInput(args->sa_WindowFH);
456 return (error);
459 /****** SmartReadArgs/SmartFreeArgs ******************************************
460 * NAME
461 * SmartFreeArgs -- Free all resources allocated by SmartReadArgs().
462 * SYNOPSIS
463 * SmartFreeArgs(smart_args);
465 * void SmartFreeArgs(struct SmartArgs *);
466 * FUNCTION
467 * Free all resources allocated by a previous call to SmartReadArgs().
468 * INPUTS
469 * smart_args - Same pointer as passed to SmartReadArgs() before
470 * NOTES
471 * Always call SmartFreeArgs(), even if SmartReadArgs() failed! Take a look
472 * at the example for SmartReadArgs().
473 * SEE ALSO
474 * SmartReadArgs()
475 ****************************************************************************/
476 void SmartFreeArgs(struct SmartArgs *args)
478 /* FreeArgs() can handle a NULL pointer */
479 FreeArgs(args->sa_FreeArgs);
481 if (args->sa_Flags & SAF_ALLOCRDARGS)
482 if (args->sa_RDArgs)
483 FreeDosObject(DOS_RDARGS, args->sa_RDArgs);
485 if (args->sa_Flags & SAF_ALLOCBUFFER)
486 FreeMem(args->sa_Buffer, args->sa_BufferSize);
488 if (args->sa_WindowFH)
490 SelectOutput(args->sa_OldOutput);
491 SelectInput(args->sa_OldInput);
492 Close(args->sa_WindowFH);
495 if (args->sa_Flags & SAF_ALLOCWINDOW && args->sa_Window)
496 FreeVec(args->sa_Window);
500 /* This code was grapped from IconImage/wbarg.c/IconFromWBArg()
501 * Commodore-Amiga Example code
503 static struct DiskObject *smart_get_icon(struct SmartArgs *args, struct WBStartup *wb_startup)
505 struct DiskObject *dob = NULL;
506 struct WBArg *wbarg = wb_startup->sm_ArgList;
507 ULONG num = wb_startup->sm_NumArgs;
509 TEXT work_name[MAXIMUM_FILENAME_LENGTH];
510 BPTR old_lock, new_lock;
512 /* Copy the WBArg contents */
513 strncpy(work_name, wbarg->wa_Name, MAXIMUM_FILENAME_LENGTH);
515 new_lock = DupLock(wbarg->wa_Lock);
516 if (new_lock != ZERO)
518 D(DBF_STARTUP, "work_name : '%s'", work_name);
520 /* go to the directory where the icon resides */
521 old_lock = CurrentDir(new_lock);
523 dob = GetDiskObjectNew(work_name);
525 /* test, if the first icon is a project icon and if so, get its icon */
526 if (wb_startup->sm_NumArgs > 1)
528 BPTR new_lock2;
530 if ((new_lock2 = DupLock(wbarg[1].wa_Lock)))
532 struct DiskObject *prj;
534 CurrentDir(new_lock2);
536 UnLock(new_lock);
537 new_lock = new_lock2;
539 strncpy(work_name, wbarg[1].wa_Name, MAXIMUM_FILENAME_LENGTH);
540 D(DBF_STARTUP, "work_name2 : '%s'", work_name);
542 if ((prj = GetDiskObjectNew(work_name)))
544 if (prj->do_Type == WBPROJECT)
546 BPTR test;
548 /* if this is only an icon skip it */
549 if (!(test = Lock(work_name, SHARED_LOCK)))
551 wbarg++;
552 num--;
554 else
555 UnLock(test);
557 if (dob)
558 FreeDiskObject(dob);
560 dob = prj;
566 if (dob)
568 D(DBF_STARTUP, "dobj window : '%s'", dob->do_ToolWindow);
571 /* go back to where we used to be */
572 CurrentDir(old_lock);
574 /* release the duplicated lock */
575 UnLock(new_lock);
577 args->sa_WBArg = wbarg + 1;
578 args->sa_NumArgs = num;
581 D(DBF_STARTUP, "return (dob)");
583 return (dob);
586 static void fstrcpy(struct SmartArgs *args, CONST_STRPTR string)
588 STRPTR ptr = args->sa_ActualPtr;
589 STRPTR end = args->sa_EndPtr;
591 while (ptr < end && *string)
592 *ptr++ = *string++;
594 *ptr = EOS; /* Mark end of string */
596 args->sa_ActualPtr = ptr;
599 static void get_arg_name(struct SmartArgs *args, STRPTR buffer, ULONG size, ULONG * modes)
601 ULONG num = args->sa_FileParameter;
602 CONST_STRPTR ptr = args->sa_Template;
604 *modes = 0;
606 while (num > 0)
608 while (*ptr != ',' && *ptr != EOS)
609 ptr++;
611 if (*ptr == ',')
612 ptr++;
613 num--;
616 if (*ptr != EOS)
618 while (*ptr != ',' && *ptr != '/' && *ptr != EOS && size > 0)
620 *buffer++ = *ptr++;
621 size--;
624 while (*ptr == '/')
626 ptr++;
628 if (*ptr == 'M' || *ptr == 'm')
629 *modes = MODE_MULTI;
631 ptr++;
635 *buffer = EOS;
638 static void get_wbarg_name(struct WBArg *wbarg, STRPTR buffer, ULONG size)
640 BPTR new;
642 if ((new = DupLock(wbarg->wa_Lock)))
644 if (!NameFromLock(new, buffer, size))
645 *buffer = EOS;
646 else if (!AddPart(buffer, wbarg->wa_Name, size))
647 *buffer = EOS;
649 UnLock(new);
651 else
652 *buffer = EOS;
655 static BOOL is_in_template(STRPTR name, CONST_STRPTR template)
657 BOOL found = FALSE;
658 CONST_STRPTR current_word = template;
659 BOOL skip_switch = FALSE;
660 size_t name_length;
662 /* Evaluate length of name part of whole tooltype */
663 name_length = 0;
664 while ((name[name_length] != EOS)
665 && (name[name_length] != '='))
667 name_length += 1;
670 D(DBF_TEMPLATE, "find '%s' in template '%s'\n", name, template);
671 while ((current_word[0] != '\0') && (!found))
673 STRPTR next_word = strpbrk(current_word, "/=,");
674 size_t current_word_length;
676 if (next_word == NULL)
678 next_word = (STRPTR)current_word + strlen(current_word);
680 current_word_length = next_word - current_word;
682 if (skip_switch)
684 D(DBF_TEMPLATE, " skip ('%s', %lu)", current_word, current_word_length);
685 skip_switch = FALSE;
687 else
689 D(DBF_TEMPLATE, " check ('%s', %lu)", current_word, current_word_length);
690 if ((name_length == current_word_length)
691 && !Strnicmp(name, current_word, (LONG) name_length))
693 D(DBF_TEMPLATE, " found!");
694 found = TRUE;
698 current_word = next_word;
699 if (current_word[0] != '\0')
701 if (current_word[0] == '/')
703 skip_switch = TRUE;
705 current_word += 1;
709 return found;