/*
 * Copyright (c) 2003-2011
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 */

/*****************************************************************************
 * COPYRIGHT AND PERMISSION NOTICE
 * 
 * Copyright (c) 2001-2003 The Queen in Right of Canada
 * 
 * All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, and/or sell
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, provided that the above copyright notice(s) and this
 * permission notice appear in all copies of the Software and that both the
 * above copyright notice(s) and this permission notice appear in supporting
 * documentation.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE 
 * BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
 * SOFTWARE.
 * 
 * Except as contained in this notice, the name of a copyright holder shall not
 * be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization of the
 * copyright holder.
 ***************************************************************************/

/*
 * mkargv - scan a string and create an argv vector
 *
 * Given STR, find its individual elements and assign each to its relative
 * position in the argv vector.  Each element is copied using malloc(3).
 * The argv vector is managed using the ds library.
 * The input string is terminated (eos) by a newline or null character.
 *
 * If the ARGVP argument is NULL, then only a count of the number of
 * elements is returned.
 *
 * Examples:
 * The call: mkargv("hello world!", NULL, &argv);
 * would return 2, with argv[0] set to "hello" (no quotes), argv[1] set to
 * "world!" (no quotes), and argv[2] set to NULL.
 *
 * The call: mkargv("{Auggie's string}", NULL, &argv);
 * would return 1, with argv[0] set to "Auggie's string" (no quotes)
 * and argv[1] set to NULL.
 *
 * Each element is demarcated as follows:
 * o initial whitespace (blanks or tabs) is skipped
 * o Optionally, a starting quote character signals the start of the element
 * o The element continues until eos or whitespace is found (the no quote case)
 *   or the matching ending quote character is found followed by eos or
 *   whitespace
 * o Any character other than eos can be quoted by being preceded with
 *   a backslash character
 *
 * Different quote characters may be used to demarcate different elements.
 *
 * If KEEPQ is non-zero, any starting and ending quote characters are
 * kept in the copied elements.
 *
 * The pointer to the last element is followed by a NULL pointer.
 *
 * Errors are indicated by the following values:
 *   -1: malloc failed
 *   -2: a matching closing quote is missing
 *   -3: STR ends with a backslash character
 * 
 * The number of elements in STR is returned, or a negative value (as above)
 * on error.
 */

#ifndef lint
static const char copyright[] =
"Copyright (c) 2003-2011\n\
Distributed Systems Software.  All rights reserved.";
static const char revid[] =
  "$Id: mkargv.c 2528 2011-09-23 21:54:05Z brachman $";
#endif

#include "mkargv.h"

void
mkargv_free(char **a)
{
  int i;

  for (i = 0; a[i] != NULL; i++)
	free(a[i]);
  i++;

#ifdef NOTDEF
  /*
   * XXX
   * This is borken - the problem is that we need to get a pointer to
   * the Dsvec given only the pointer vector itself, but where to put
   * that pointer?  It must be invisible to users of the structure.  The
   * problem is difficult because the "pointer vector" may contain arbitrary
   * sized objects rather than actual pointers.  Appending a hidden pointer to
   * the start or end of the vector seems the only possibility but requires
   * a kludge to get around alignment problems...
   */
  argv = (Dsvec *) a[i];

  dsvec_free(argv);
  free(argv);
#endif
}

int
mkargv(char *str, Mkargv *conf, char ***argvp)
{
  Dsvec *dsv;

  if ((dsv = ds_mkargv(NULL, str, conf)) == NULL)
	return(-1);

  if (argvp != NULL)
	*argvp = (char **) dsvec_base(dsv);
  else {
	/* mkargv_free((char **) dsvec_base(dsv)); */
  }

  return(dsvec_len(dsv) - 1);
}

#ifdef PROG
int
main(int argc, char **argv)
{
  int i, n;
  char **a, *ifs, buf[1024];
  Mkargv conf;
  
  ifs = NULL;
  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-ifs") == 0) {
      if (argv[++i] != NULL)
        ifs = argv[i];
      else {
        fprintf(stderr, "?\n");
        exit(1);
      }
    }
    else {
      fprintf(stderr, "?\n");
      exit(1);
    }
  }

  conf.keepq = 0;
  conf.keepws = 0;
  conf.ifs = ifs;
  conf.startq = NULL;
  conf.endq = NULL;

  while (1) {
	fprintf(stderr, "type a line: ");
	if (fgets(buf, sizeof(buf), stdin) == NULL) {
	  fprintf(stderr, "\n");
	  break;
	}
	if ((n = mkargv(buf, &conf, &a)) == -1)
	  fprintf(stderr, "Error\n");
	else {
	  for (i = 0; i < n; i++)
		fprintf(stderr, "%d. \"%s\"\n", i, a[i]);
	}
  }

  exit(0);
}
#endif
