
#ifdef __amigados__
#include <exec/types.h>
#include <exec/memory.h>
#include <functions.h>
#endif /* __amigados__ */

#include <stdlib.h>
#include <string.h>

#include "istartup.h"

#ifdef __amigados__

/* Small memory allocation routines for AmigaDOS so that the using this
   routine in the C startup code doesn't pull in the library's malloc()
   code.  exit() will not free memory allocated this way. */

#undef malloc
#define malloc small_malloc

#undef free
#define free small_free

#ifdef __GNUC__
__inline__
#endif
static void *
small_malloc (size_t size)
{
  ULONG *block;
  size += sizeof (ULONG);
  block = AllocMem (size, MEMF_PUBLIC);
  if (block)
    *block++ = size;
  return (void *) block;
}

#ifdef __GNUC__
__inline__
#endif
static void
small_free (void *p)
{
  ULONG *block = p;
  ULONG size = *--block;
  FreeMem (block, size);
}

#endif /* __amigados__ */


/* This function will build an `argv' array in the form expected by the
   main().  The variable *ARGV will be set to an array of zero terminated
   argument strings.  This array may be modified.  When it is no longer
   needed it can be freed by calling the associated free function.
   CMD_STRING is the name of the command that invoked the program and
   CMD_LENGTH is its length.  ARG_STRING is the rest of the command line and
   ARG_LENGTH is its length.  CMD_STRING and ARG_STRING need not be zero
   terminated.  The returned value is the number of elements in the array.
   If this function fails, a negative value is returned.

   This version parses the command using AmigaDOS style quoting and escape
   characters.  No filename or variable expansions of any kind are done.  The
   function __free_argv() will free the array. */

int
__build_argv_amigados (char ***argv,
		       const char *cmd_string, size_t cmd_length,
		       const char *arg_string, size_t arg_length)
{
  char **argv_block;
  char *string_block, *string_end, *s;
  const char *arg, *arg_end;
  int argc, i, rc;
  size_t string_block_length;

  /* Allocate space for the argument strings.  Copy the command name as the
     first string. */

  string_block_length = cmd_length + arg_length + 4;
  string_block = malloc (string_block_length);
  if (!string_block)
    return -1;
  memcpy (string_block, cmd_string, cmd_length);
  string_block[cmd_length] = '\0';

  /* Process the argument string and count the number of arguments
     while inserting zero terminators. */

  s = string_block + cmd_length + 1;
  arg = arg_string;
  arg_end = arg_string + arg_length;
  string_end = string_block_length + string_block;
  argc = 1;
  for (;;)
    {
      rc = __scan_arg_amigados (&arg, &s, arg_end, string_end);
      if (rc)
	break;
      *s++ = '\0';
      argc++;
    }

  /* Now we know the number of args but not where their strings are.  Fill in
     ARGV_BLOCK[] by scanning through STRING_BLOCK and finding the zero
     terminators.  An extra element at the end of ARGV_BLOCK[] is set to
     NULL, this is because I have seen programs that expect it and it only
     takes four more bytes. */

  argv_block = malloc ((argc + 2) * sizeof (char *));
  *argv_block++ = string_block;
  if (!argv_block)
    return -1;
  argv_block[0] = string_block;
  s = string_block;
  for (i = 0; i < argc; i++)
    {
      argv_block[i] = s;
      while (*s++ != '\0')
	;
    }
  argv_block[argc] = NULL;

  /* Set *ARGV and return ARGC. */

  *argv = argv_block;
  return argc;
}

void
__free_argv_amigados (char **argv)
{
  free (*--argv);
  free (argv);
}
