/* progargs - a simple, extensible package for handling command line
 * arguments and tooltypes.
 *
 * Copyright © 1993 by Peter Schachte
 *
 * I hereby grant everyone the right to use this code for any purpose
 * whatsoever, so long as this copyright notice remains intact.
 */

#include "progargs.h"
#include <stdlib.h>
#include <string.h>
#include <exec/memory.h>
#include <workbench/startup.h>
#include <workbench/icon.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/icon.h>

struct Library *IconBase;

static struct DiskObject *diskobj;
static char *string_chain = NULL;


/* public */
void handle_args(int argc, char **argv, struct arg_descriptor *args);
void handle_args_finish(void);
long my_atoi(char *string);

/* private */
static void handle_arg(struct arg_descriptor *arg, char *value);
static void handle_cmd_line(char **argv, struct arg_descriptor *args);


void handle_args(int argc, char **argv, struct arg_descriptor *args)
    {
	if (argc == 0) {
	    /* started from workbench:  get options from icon */
	    struct WBStartup *startup = (struct WBStartup *)argv;
	    LONG olddir;
	    struct arg_descriptor *ptr;
	    char *value;
	    char **toolarray;

	    if (NULL == (IconBase=OpenLibrary(ICONNAME,1)))
	      return;

	    olddir = CurrentDir(startup->sm_ArgList->wa_Lock);
	    diskobj = GetDiskObject(startup->sm_ArgList->wa_Name);
	    CurrentDir(olddir);
	    toolarray = diskobj->do_ToolTypes;
	    if (diskobj != NULL) {
		for (ptr=args; ptr->name!=NULL; ++ptr) {
		    if (NULL != (value=FindToolType(toolarray,ptr->name))) {
			handle_arg(ptr, value);
		    }
		}
	    }
	    FreeDiskObject(diskobj);
	    CloseLibrary(IconBase);
	} else {
	    handle_cmd_line(argv, args);
	}
    }


void handle_args_finish(void)
    {
	char *ptr;

	for (; string_chain!=NULL; string_chain=ptr) {
	    ptr = (char*)*string_chain;
	    FreeMem(string_chain,
		    sizeof(char*) + strlen(string_chain+sizeof(char*)) + 1);
	}
    }


static void handle_cmd_line(char **argv, struct arg_descriptor *args)
    {
	struct arg_descriptor *ptr;

	for (++argv; *argv; ++argv) {
	    for (ptr=args; ptr->name!=NULL&&stricmp(*argv, ptr->name); ++ptr);
	    if (ptr->name != NULL) {
		if (ptr->value_allowed) {
		    handle_arg(ptr, *++argv);
		} else {
		    handle_arg(ptr, NULL);
		}
	    } /* note no error message about invalid option */
	}
    }


static void handle_arg(struct arg_descriptor *arg, char *value)
    {
	(arg->parser)(value, arg->extra_parse_arg, arg->variable);
    }


int parse_int_arg(char *string, void *extra, void **value)
    {
	*value = (void *)my_atoi(string);
	return 1;
    }


/* returns in *value a pointer to the string string.  We must copy string
 * because it may be in an icon's tooltypes, and we are going to free the
 * icon soon.  We collect the buffers we allocate in a chain pointed to by
 * string_chain, so we can free them all when we're exiting
 */
int parse_string_arg(char *string, void *extra, void **value)
    {
	char *record = AllocMem((sizeof(char *)+strlen(string)+1), MEMF_ANY);
	char *buff = record+sizeof(char *);
	char **link = (char **)record;
	
	if (record==NULL) return 0;
	*link = string_chain;
	string_chain = record;
	strcpy(buff, string);
	*value = (void *)buff;
	return 1;
    }


/* a quick and dirty atoi routine that doesn't use ctypes to keep size down */
long my_atoi(char *string)
    {
	int negative = 0;
	long value = 0;

	/* skip leading blanks */
	while (*string == ' ') ++string;
	if (*string == '-') {
	    negative = 1;
	    ++string;
	}

	while (*string >= '0' && *string <= '9') {
	    value = (value*10 + *string - '0');
	    ++string;
	}
	if (negative) value = -value;
	return value;
    }


int parse_bool_arg(char *string, void *extra, void **value)
    {
	*value = extra;
	return 1;
    }

