
/* scanarg-ados.c - Ray Burr */

#include "istartup.h"

#define BCPL_ESCAPE '*'
#define ASCII_ESC 0x1b

/* True if character X is whitespace for AmigaDOS purposes.  Beware of
   side effects. */

#define is_white(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')

/* Process a single argument from a command line.  Given a point in a
   command line *LINE and an output buffer *BUF, scan one argument from the
   command line and put it in the output buffer.  AmigaDOS style quoting
   and escape sequence substitution is done.  After returning, *LINE will
   point to the character after the end of argument scanned and *BUF will
   point to the character after the argument in the output buffer.
   LINE_END should point to the character after the end of the command
   line.  BUF_END should point to the last byte after the end of the
   buffer.  If the argument is succesfully converted, SCAN_ARG_GOOD (zero)
   is returned.  If there is no more arguments to read, SCAN_ARG_DONE is
   returned.  If there is not enough space in the buffer, SCAN_ARG_FULL is
   returned.  If the argument for some reason be converted because there
   is an error in the argument itself, SCAN_ARG_BAD is returned.  If it
   can't be converted for some other reason, SCAN_ARG_FAIL is returned.
   SCAN_ARG_BAD and SCAN_ARG_FAIL are currently never returned by this
   function. */

int
__scan_arg_amigados (const char **line, char **buf,
		     const char *line_end, char *buf_end)
{
  const char *p;
  char *s;

  p = *line;
  s = *buf;

  /* Skip whitespace. */
  while (p < line_end && is_white (*p))
    p++;

  /* If we are at the end, there are no more args left to read. */
  if (p >= line_end)
    {
      *line = p;
      return SCAN_ARG_DONE;
    }

  if (*p == '"')
    {
      /* Process a quoted argument. */
      p++;
      while (p < line_end)
	{
	  if (*p == '"')
	    {
	      p++;
	      break;
	    }
	  if (s >= buf_end)
	    return SCAN_ARG_FULL;
	  if (*p != BCPL_ESCAPE)
	    *s++ = *p++;
	  else
	    {
	      p++;
	      if (p >= line_end)
		break;
	      switch (*p)
		{
		case 'N':
		case 'n':
		  *s++ = '\n';
		  break;
		case 'E':
		case 'e':
		  *s++ = ASCII_ESC;
		  break;
		default:
		  *s++ = *p;
		  break;
		}
	      p++;
	    }
	}
    }
  else
    {
      /* Process an unquoted argument. */
      while (p < line_end && !is_white (*p))
 	{
	  if (s >= buf_end)
	    return SCAN_ARG_FULL;
	  *s++ = *p++;
	}
    }

  *line = p;
  *buf = s;

  return SCAN_ARG_GOOD;
}
