# include "basic.h"
# define D_NLINES 100
static char prompt[] = ">> ";

int list (int argc, char **argv) {

  int ThisList, depth, i, done, found;
  char *input, line[1024];
  int N, Nbytes, NBYTES, Nread, status;
  int RunCommand;
  char *A, *B, *val, *Cmd;
  FILE *f;

  Cmd = NULL;
  RunCommand = FALSE;
  if ((N = get_argument (argc, argv, "-x"))) {
    remove_argument (N, &argc, argv);
    Cmd = strcreate (argv[N]);
    remove_argument (N, &argc, argv);
    RunCommand = TRUE;
  }

  // return an error if -add is given with no other args
  if ((argc > 2) && (!strcmp (argv[2], "-split"))) {
    if (argc == 3) {
      gprint (GP_ERR, "USAGE: list (root) -split (word) (word) ...\n");
      return (FALSE);
    }
    
    for (i = 0; i < argc - 3; i++) {
      sprintf (line, "%s:%d", argv[1], i);
      set_str_variable (line, argv[i+3]);
    }
    sprintf (line, "%s:n", argv[1]);
    set_int_variable (line, i);

    return (TRUE);
  }

  // return an error if -add is given with no other args
  if ((argc > 2) && (!strcmp (argv[2], "-splitbychar"))) {
    if (argc < 4) {
      gprint (GP_ERR, "USAGE: list (root) -splitbychar (char) (word) [(word)...]\n");
      return (FALSE);
    }
    
    int j, nWords;
    char splitter;
    char *new, *word, *ptr;

    nWords = 0;
    splitter = argv[3][0];

    for (i = 0; i < argc - 3; i++) {
      new = strcreate (argv[i+3]);
      for (j = 0; new[j]; j++) {
	if (new[j] == splitter) new[j] = ' ';
      }

      ptr = new;
      while (ptr) {
	word = thisword (ptr);
	if (!word) break;
	
	sprintf (line, "%s:%d", argv[1], nWords);
	set_str_variable (line, word);
	FREE (word);
	ptr = nextword (ptr);
	nWords ++;
      }
      FREE (new);
    }
    sprintf (line, "%s:n", argv[1]);
    set_int_variable (line, nWords);

    return (TRUE);
  }

  // return an error if -copy is given with no other args
  if ((argc > 2) && (!strcmp (argv[2], "-copy"))) {
    char *value;
    if (argc == 3) {
      gprint (GP_ERR, "USAGE: list (newlist) -copy (oldlist) ...\n");
      return (FALSE);
    }
    
    sprintf (line, "%s:n", argv[3]);
    N = get_int_variable (line, &found);
    sprintf (line, "%s:n", argv[1]);
    set_int_variable (line, N);
    for (i = 0; i < N; i++) {
      sprintf (line, "%s:%d", argv[3], i);
      value = get_variable (line);
      sprintf (line, "%s:%d", argv[1], i);
      set_str_variable (line, value);
    }
    return (TRUE);
  }

  // return an error if -add is given with no other args
  if ((argc > 2) && (!strcmp (argv[2], "-add"))) {
    if (argc == 3) {
      gprint (GP_ERR, "USAGE: list (root) -add (word) (word) ...\n");
      return (FALSE);
    }
    
    sprintf (line, "%s:n", argv[1]);
    N = get_int_variable (line, &found);
    for (i = 0; i < argc - 3; i++) {
      sprintf (line, "%s:%d", argv[1], N + i);
      set_str_variable (line, argv[i+3]);
    }
    sprintf (line, "%s:n", argv[1]);
    set_int_variable (line, N + i);

    return (TRUE);
  }

  // remove the single named entry from the list (finds entry with given name, reduces list length by one)
  // return an error if -add is given with no other args
  if ((argc > 2) && (!strcmp (argv[2], "-del"))) {
    if (argc != 4) {
      gprint (GP_ERR, "USAGE: list (root) -del (word)\n");
      return (FALSE);
    }
    
    int j;
    char *value, *next_value;
    char line2[1024];

    sprintf (line, "%s:n", argv[1]);
    N = get_int_variable (line, &found);
    for (i = 0; i < N; i++) {
      sprintf (line, "%s:%d", argv[1], i);
      value = get_variable (line);
      if (value == NULL) continue;
      if (!strcmp (value, argv[3])) {
	free (value);
	for (j = i + 1; j < N; j++) {
	  sprintf (line2, "%s:%d", argv[1], j);
	  next_value = get_variable (line2);
	  set_str_variable (line, next_value);
	  strcpy (line, line2);
	}
	DeleteNamedScalar (line);
	sprintf (line2, "%s:n", argv[1]);
	set_int_variable (line2, N - 1);
	return (TRUE);
      }
      free (value);
    }      
    gprint (GP_ERR, "value %s not found in list\n", argv[3]);
    return (FALSE);
  }

  if (argc != 2) {
    gprint (GP_ERR, "USAGE: list (root)                : supply list data, terminate with 'END'\n");
    gprint (GP_ERR, "USAGE: list (root) -x (command)   : create list from shell output\n");
    gprint (GP_ERR, "USAGE: list (root) -split (words) : create list from words\n");
    gprint (GP_ERR, "USAGE: list (root) -add (words)   : extend a list\n");
    return (FALSE);
  }

  if (RunCommand) {
    
    /* val will hold the result */
    NBYTES = 1024;
    ALLOCATE (val, char, NBYTES);
    
    /* need to loop until command produces no more output, 
       REALLOCATING as needed. */
    f = popen (Cmd, "r");
    done = FALSE;
    Nbytes = 0;
    while (!done) {
      Nread = fread (&val[Nbytes], 1, 1023, f);
      if (Nread < 0) { 
	gprint (GP_ERR, "error reading from command\n");
	done = TRUE;
      }
      if (Nread > 0) {
	Nbytes += Nread;
	NBYTES = 1024 + Nbytes;
	REALLOCATE (val, char, NBYTES);
      }
      if (Nread == 0) {
	done = TRUE;
      }
      
    }
    val[Nbytes] = 0;
    status = pclose (f);
    free (Cmd);
    
    if (status) {
      gprint (GP_ERR, "warning: exit status of command %d\n", status);
    }
      
    A = B = val;
    for (i = 0; B != (char *) NULL;) {
      while (isspace (*A) && (*A != 0)) A++;
      B = strchr (A, '\n');
      if (B != (char *) NULL) { *B = 0; }
      if (*A != 0) {
	sprintf (line, "%s:%d", argv[1], i);
	set_str_variable (line, A);
	A = B + 1;
	i++;
      }
    }      
    free (val);
    
    sprintf (line, "%s:n", argv[1]);
    set_int_variable (line, i);
    return (TRUE);
  }

  /* read in loop */
  depth = 0;
  ThisList = current_list_depth();
  for (i = 0, done = FALSE; !done; ) {

    /* get the next line (from correct place) */
    if (ThisList == 0) {
      input = readline (prompt);
    } else {
      input = get_next_listentry (ThisList);
    }

    if ((ThisList == 0) && (input == NULL)) {
      gprint (GP_ERR, "end list with 'END'\n");
      continue;
    }
    if ((ThisList >  0) && (input == NULL)) {
      gprint (GP_ERR, "missing 'END' in list\n");
      input = strcreate ("end");
    }
    if (ThisList == 0) ohana_memregister (input);

    stripwhite (input);

    /* test for end of nested list -- if not nested, END refers to this macro */
    if (!strncasecmp (input, "END", 3)) {
      depth --;
      if (depth < 0) { /* we hit the last "END", loop is done */
	sprintf (line, "%s:n", argv[1]);
	set_int_variable (line, i);
	free (input);
	return (TRUE);
      }
    }

    if (*input) { 
      sprintf (line, "%s:%d", argv[1], i);
      set_str_variable (line, input);
      free (input);
      i++;
   }
  }
  return (TRUE);
}
