# include "opihi.h"

/* return value on success is temp vector/buffer name or scalar value
   return value on error is NULL, all internals freed? */

char *dvomath (int argc, char **argv, int *size, int validsize) {
  
  int  i, Nstack, Ncstack;
  char   **cstack, *outname;
  StackVar *stack;
  Buffer *buf;
  Vector *vec;

  ALLOCATE (outname, char, 256);

  /* take char array with expression, convert to important elements */
  cstack = isolate_elements (argc, argv, &Ncstack); 

  /* generate RPN stack from cstack arguments */
  stack = convert_to_RPN (Ncstack, cstack, &Nstack);
  if (Nstack < 1) goto error;

  /* distinguish scalar, vector, matrix, check dimensions */
  *size = check_stack (stack, Nstack);
  if ((validsize != -1) && (validsize != *size)) goto error;
  if (*size < 0) goto error;

  switch (*size) {
    case 0:
      break;
    case 1:  /* allocate temp vector */
      vec = NULL;
      for (i = 0; (i < 1000) && (vec == NULL); i++) {
	sprintf (outname, "tmp%03d", i);
	vec = SelectVector (outname, NEWVECTOR, FALSE);
      }
      if (vec == NULL) { 
	push_error ("too many tmp vectors");
	goto error;
      }
      break;
    case 2:  /* allocate temp buffer */
      buf = NULL;
      for (i = 0; (i < 1000) && (buf == NULL); i++) {
	sprintf (outname, "tmp%03d", i);
	buf = SelectBuffer (outname, NEWBUFFER, FALSE);
      }
      if (buf == NULL) {
	push_error ("too many tmp buffers");
	goto error;
      }
      break;
    default:
      goto error;
  }

  /* evaluate operations, free stack on error */
  if (!evaluate_stack (stack, &Nstack)) {
    if (*size == 1) DeleteVector (vec);
    if (*size == 2) DeleteBuffer (buf);
    goto error;
  }

  switch (*size) {
    case 0:
      sprintf (outname, "%g", stack[0].Float);
      break;

    case 1:
      MoveVector (vec, stack[0].vector);
      free (stack[0].vector);
      break;
  
    case 2:
      MoveBuffer (buf, stack[0].buffer);
      free (stack[0].buffer);
      break;
  }

  clean_stack (stack, Nstack);
  free (stack);
  return (outname);

error:  
  clean_stack (stack, Nstack);
  free (stack);
  free (outname);
  return (NULL);
}
