/* ----------------------------------------------------------------
 *	argv.c
 *
 *	$Header: /usr/local/dev/postgres/mastertree/newconf/RCS/argv.c,v 1.4 1991/03/04 13:56:10 mao Exp $
 * ----------------------------------------------------------------
 */

#include <ctype.h>
#include <stdio.h>

/***********************************************************************
**
** These routines build argv's.  An "argv" is a null-terminated array
** of pointers to strings.  Argv's are often declared as char** or
** char* foo [];
** 
** char***
** argv_new() 
**
**    returns a structure which is a "scaffold" for building up
**    an argv. At any point, the structure will contain an argv in its
**    first field.  If it overflows, a new, larger one is substituted,
**    and the old one discarded.  So don't keep direct references to the argv
**    unless you are not going to put any more stuff into it.
**
**    Say 
**         char*** scaffold = (char***)argv_new();
**    
**    Then, when the argv is completed, dereference it...
** 
**         char** complete_argv = *scaffold;
**
**    Then free the scaffold if you wish...
**
**         cfree(scaffold);
**
**    The argv itself is also allocated by calloc, and may be cfree()'d when
**    it is no longer needed.
**
**    argv_new() returns 0 if it runs out of memory.
**
** 
** int
** argv_put(scaffold, arg) 
**    char*** scaffold;
**    char* arg;
**
**    puts an additional arg into an argv, increasing the size
**    if necessary. Returns 0 on success, -1 if it runs out of memory.
**
** char**
** argv_from_str(str)
**   char* str
**
**    Parses a string and builds an argv from it.  It
**    recognizes quote-marks and escapes (\).
**
**    For example,
**
**       foo bar  "foo bar"  '\'foo\''  '"foo"'
**
**    gets parsed into
**
**       foo
**       bar
**       foo bar
**       'foo'
**       "foo"
**       (0)
**
**    The argv and its components are all allocated by calloc().
**    Returns 0 if it runs out of memory.
**    
**
************************************************************************/



struct argv_rec
  { char** value;
    int size;
    int place;
  };


argv_put(argv, str)
  struct argv_rec * argv;
  char* str;
{
  if (argv->place + 1 == argv->size) /* oops.. overflow. */
    {
      char** old_argv = argv->value;
      int old_size = argv->size;

      argv->size = argv->size *2;
      argv->value = (char**)calloc(1, argv->size*sizeof(char*));
      if(argv->value == 0) { return -1; }
      bcopy(old_argv, argv->value, old_size * sizeof(char*));
      free(old_argv);
    }

  argv->value[argv->place] = str;
  argv->place++;

  return 0;

}


struct argv_rec *
argv_new()
{
  struct argv_rec* retval = 
    (struct argv_rec*) calloc(1,sizeof(struct argv_rec));
  if (retval == 0) return 0;

  retval->value = (char**)calloc(1, 2*sizeof(char*));
  if(retval->value == 0) { free(retval); return 0; }

  retval->size = 2;
  retval->place = 0;

  return retval;
}


static char*
strip(strp)
  char** strp;
{
  char* str = strp? *strp: 0;
  char* buffer;
  char  quote = 0;
  char* next_p;

  if(str == 0 || *str == 0) return 0;

  buffer = (char*)malloc(strlen(str)+1);
  if(buffer == 0) return 0;

  next_p  = buffer;

  while (isspace(*str)) str++;

  if(*str == '\'' || *str == '"' ) quote = *str++;

  while(*str && !(isspace(*str) && !quote) && !(quote && *str == quote))
    {
      if(*str == '\\') str++;
      *next_p++ = *str++;
    }

  if(*str && (quote && *str == quote) ) str++; /* skip end-quote */

  *next_p = 0;
  { char* retval = (char*)calloc(1, strlen(buffer) +1 );
    if (retval) sprintf(retval, "%s", buffer);
    free(buffer);
    *strp = str;
    return retval;
  }
}


char**
argv_from_str(str)
  char* str;
{
  struct argv_rec* argv;
  char* next_arg;
  extern errno;

  errno = 0;

  argv = argv_new();
  if(argv == 0) return 0;

  while( (next_arg = strip(&str)) != 0)
    { argv_put(argv, next_arg);
    }

  { char** retval = argv->value;
    free(argv);
    return retval;
  }
  
  
}

fprintf_argv(fp,argv)
  FILE * fp;
  char** argv;
{
  if(argv)
    while(*argv) fprintf(fp, "%s\n", *argv++);
}

printf_argv(argv)
  char** argv;
{
  if(argv)
    while(*argv) printf("%s\n", *argv++);
}

int strcmp();

static
alcomp(p,q)
  char**p;
  char**q;
{
  return strcmp(*p,*q);
}

sort_argv(argc, argv)
  char** argv;
{

  qsort(argv, argc, sizeof(char*), alcomp );

}


#undef testing
#ifdef testing
#include <stdio.h>
main(argc, argv)
  char** argv;
{
  char  buf[256];
  char** argy;
  int argk = 0;
  char** aargh;
  scanf("%[^\n]", buf);
  argy = argv_from_str(buf);

  aargh = argy;

  while(*argy) { printf("%s\n", *argy++ ); }
  {
    char** p = aargh;
    while(*p++) argk++;
  }
  sort_argv(argk, aargh);
  while(*aargh) { printf("%s\n", *aargh++ ); }
  fflush(stdout);
}
#endif testing
