/**********
Copyright 1990 Regents of the University of California.  All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
Modified: 2000 AlansFixes
$Id: runcoms.c,v 1.25 2010/07/24 18:51:08 rlar Exp $
**********/

/*
 * Circuit simulation commands.
 */

#include "ngspice.h"
#include "cpdefs.h"
#include "ftedefs.h"
#include "ftedev.h"
#include "ftedebug.h"
#include "dvec.h"

#include "circuits.h"
#include "completion.h"
#include "runcoms.h"
#include "variable.h"

#ifdef XSPICE
/* gtri - add - 12/12/90 - wbk - include ipc stuff */
#include "ipctiein.h"
/* gtri - end - 12/12/90 */
#endif

/* static declarations */
static int dosim(char *what, wordlist *wl);

/* Routines for the commands op, tran, ac, dc, listing, device, state,
 * resume, stop, trace, run, end.  Op, tran, ac, and dc cause the action
 * to be performed immediately, and run causes whatever actions were
 * present in the deck to be carried out. End has the effect of stopping
 * any simulations in progress, as opposed to ending the input deck as
 * the .end line does.
 */

FILE *rawfileFp;
bool rawfileBinary;
#define RAWBUF_SIZE 32768
char rawfileBuf[RAWBUF_SIZE];
/*To tell resume the rawfile name saj*/
char *last_used_rawfile = NULL;
/*end saj */

/* command "setcirc" */
void
com_scirc(wordlist *wl)
{
    struct circ *p;
    int i, j = 0;
    char buf[BSIZE_SP];

    if (ft_circuits == NULL) {
        fprintf(cp_err, "Error: there aren't any circuits loaded.\n");
        return;
    }
    if (wl == NULL) {
        fprintf(cp_out, 
            "\tType the number of the desired circuit:\n\n");
        for (p = ft_circuits; p; p = p->ci_next) {
            if (ft_curckt == p)
                fprintf(cp_out, "Current");
            fprintf(cp_out, "\t%d\t%s\n", ++j, p->ci_name);
        }
        fprintf(cp_out, "? ");
        (void) fflush(cp_out);
        (void) fgets(buf, BSIZE_SP, cp_in);
        clearerr(cp_in);
        if ((sscanf(buf, " %d ", &i) != 1) || (i < 0) || (i > j))
            return;
        for (p = ft_circuits; --i > 0; p = p->ci_next)
            ;
    } else {
	for (p = ft_circuits; p; p = p->ci_next) 
		j++;

	p=NULL;
	if ((sscanf(wl->wl_word, " %d ", &i) != 1) || (i < 0) || (i > j));
	else
		for (p = ft_circuits; --i > 0; p = p->ci_next)
		    ;
        /* for (p = ft_circuits; p; p = p->ci_next)
         *   if (ciprefix(wl->wl_word, p->ci_name))
	     *    break;
	     */
        if (p == NULL) 
        {
            fprintf(cp_err, "Warning: no such circuit \"%s\"\n",wl->wl_word);
            return;
        }
        fprintf(cp_out, "\t%s\n", p->ci_name);
    }
    if (ft_curckt) {
        /* Actually this can't be FALSE */
        ft_curckt->ci_devices = 
                cp_kwswitch(CT_DEVNAMES, p->ci_devices);
        ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES, p->ci_nodes);
    }
    ft_curckt = p;
    return;
}

void
com_pz(wordlist *wl)
{
    dosim("pz", wl);
    return;
}

void
com_op(wordlist *wl)
{
    dosim("op", wl);
    return;
}

void
com_dc(wordlist *wl)
{
    dosim("dc", wl);
    return;
}

void
com_ac(wordlist *wl)
{
    dosim("ac", wl);
    return;
}

void
com_tf(wordlist *wl)
{
    dosim("tf", wl);
    return;
}

void
com_tran(wordlist *wl)
{
    dosim("tran", wl);
    return;
}

void
com_sens(wordlist *wl)
{
    dosim("sens", wl);
    return;
}

void
com_disto(wordlist *wl)
{
    dosim("disto", wl);
    return;
}

void
com_noise(wordlist *wl)
{
    dosim("noise", wl);
    return;
}

static int
dosim(
   char *what, /* in: command (pz,op,dc,ac,tf,tran,sens,disto,noise,run) */
   wordlist *wl /* in: command option */
   /* global variables in: ft_curckt, ft_circuits, 
                      out: ft_setflag, ft_intrpt, rawfileFp, rawfileBinary,
                           last_used_rawfile 
    */
 )
{
   wordlist *ww = NULL;
   bool dofile = FALSE;
   char buf[BSIZE_SP];
   struct circ *ct;
   int err = 0;
   /* set file type to binary or to what is given by environmental 
      variable SPICE_ASCIIRAWFILE in ivars.c */
   bool ascii = AsciiRawFile;
   if (eq(what, "run") && wl)
      dofile = TRUE;
   /* add "what" to beginning of wordlist wl, except "what" equals "run" 
      and a rawfile name is given (in wl) */
   if (!dofile) {
      ww = alloc(struct wordlist);
      ww->wl_next = wl;
      if (wl)
         wl->wl_prev = ww;
      ww->wl_word = copy(what);
   }
   /* reset output file type according to variable given in spinit */
   if (cp_getvar("filetype", CP_STRING, buf)) {
      if (eq(buf, "binary"))
         ascii = FALSE;
      else if (eq(buf, "ascii"))
         ascii = TRUE;
      else {
         fprintf(cp_err,
            "Warning: strange file type \"%s\" (using \"ascii\")\n", buf);
         ascii = TRUE;
      }
   }

   if (!ft_curckt) {
      fprintf(cp_err, "Error: there aren't any circuits loaded.\n");
      return 1;
   } else if (ft_curckt->ci_ckt == NULL) { /* Set noparse? */
      fprintf(cp_err, "Error: circuit not parsed.\n");
      return 1;
   }
   for (ct = ft_circuits; ct; ct = ct->ci_next)
      if (ct->ci_inprogress && (ct != ft_curckt)) {
         fprintf(cp_err, 
            "Warning: losing old state for circuit '%s'\n",
            ct->ci_name);
         ct->ci_inprogress = FALSE;
      }
   /* "resume" will never occur in ngspice */
   if (ft_curckt->ci_inprogress && eq(what, "resume")) {
      ft_setflag = TRUE;  /* don't allow abort upon interrupt during run  */
      ft_intrpt = FALSE;
      fprintf(cp_err, "Warning: resuming run in progress.\n");
      com_resume(NULL);
      ft_setflag = FALSE;  /* Now allow aborts again  */
      return 0;
   }

   /* From now on until the next prompt, an interrupt will just
    * set a flag and let spice finish up, then control will be
    * passed back to the user.
    */
   ft_setflag = TRUE;  /* Don't allow abort upon interrupt during run.  */
   ft_intrpt = FALSE;
   /* command "run" is given with rawfile name in wl */
   if (dofile) {
#ifdef PARALLEL_ARCH
      if (ARCHme == 0) {
#endif /* PARALLEL_ARCH */
      if (!*wl->wl_word)
         rawfileFp = stdout;
#if defined(__MINGW32__) || defined(_MSC_VER)
/* ask if binary or ASCII, open file with wb or w */
      else if (ascii) { 
         if(!(rawfileFp = fopen(wl->wl_word, "w"))) {
            perror(wl->wl_word);
            ft_setflag = FALSE;
            return 1;
         }
         fprintf(cp_out,"ASCII raw file\n");
      }    
      else if (!ascii) { 
         if(!(rawfileFp = fopen(wl->wl_word, "wb"))) {
            perror(wl->wl_word);
            ft_setflag = FALSE;
            return 1;
         }
         fprintf(cp_out,"binary raw file\n");
      }
/*---------------------------------------------------------------------------*/
#else	    
      else if (!(rawfileFp = fopen(wl->wl_word, "w"))) {
         setvbuf(rawfileFp, rawfileBuf, _IOFBF, RAWBUF_SIZE);
         perror(wl->wl_word);
         ft_setflag = FALSE;
         return 1;
      }
#endif /* __MINGW32__ */
      rawfileBinary = !ascii;
#ifdef PARALLEL_ARCH
   } else {
      rawfileFp = NULL;
   }
#endif /* PARALLEL_ARCH */
   } else {
      rawfileFp = NULL;
   }

   /*save rawfile name */
   if(last_used_rawfile) 
      tfree(last_used_rawfile);
   if(rawfileFp){
      last_used_rawfile = copy(wl->wl_word);
   } else {
      last_used_rawfile = NULL;
   }

   ft_curckt->ci_inprogress = TRUE;
   /* "sens2" not used in ngspice */
   if (eq(what,"sens2")) {
      if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) {
         /* The circuit was interrupted somewhere. */
         fprintf(cp_err, "%s simulation interrupted\n", what);
#ifdef XSPICE
  /* gtri - add - 12/12/90 - wbk - record error and return errchk */
         g_ipc.run_error = IPC_TRUE;
         if(g_ipc.enabled)
            ipc_send_errchk();
        /* gtri - end - 12/12/90 */
#endif
      } else
         ft_curckt->ci_inprogress = FALSE;
   /* Do a run of the circuit */
   } else {
      err = if_run(ft_curckt->ci_ckt, what, ww, ft_curckt->ci_symtab);
      if (err == 1) {
         /* The circuit was interrupted somewhere. */
         fprintf(cp_err, "%s simulation interrupted\n", what);
#ifdef XSPICE
         /* record error and return errchk */
         g_ipc.run_error = IPC_TRUE;
         if(g_ipc.enabled)
            ipc_send_errchk();
         /* gtri - end - 12/12/90 */
#endif
         err = 0;
      } else if (err == 2) {
         fprintf(cp_err, "%s simulation(s) aborted\n", what);
         ft_curckt->ci_inprogress = FALSE;
         err = 1;
      } else
         ft_curckt->ci_inprogress = FALSE;
   }
   /* close the rawfile */
   if (rawfileFp){
      if (ftell(rawfileFp)==0) {
         (void) fclose(rawfileFp);
         (void) remove(wl->wl_word);
      } else {
         (void) fclose(rawfileFp);
      }
   }
   ft_curckt->ci_runonce = TRUE;
   ft_setflag = FALSE;

   /* va: garbage collection: unlink first word (inserted here) and tfree it */
   if (!dofile) {
      tfree(ww->wl_word);
      if (wl)
         wl->wl_prev = NULL;
      tfree(ww);
   }

   /* execute the .measure statements */
   if ( !err && ft_curckt->ci_last_an && ft_curckt->ci_meas) 
      do_measure( ft_curckt->ci_last_an, FALSE );

   return err;
}

/* Usage is run [filename] */

void
com_run(wordlist *wl)
{
/*    ft_getsaves(); */
    dosim("run", wl);
    return;
}

int
ft_dorun(char *file)
{
    static wordlist wl = { NULL, NULL, NULL } ;

    wl.wl_word = file;
    if (file)
      return dosim("run", &wl);
    else
      return dosim("run", (wordlist *) NULL);
}

/* ARGSUSED */ /* until the else clause gets put back */
bool
ft_getOutReq(FILE **fpp, struct plot **plotp, bool *binp, char *name, char *title)
{
   if (rawfileFp) {
       *fpp = rawfileFp;
       *binp = rawfileBinary;
       return (TRUE);
   } else {
       return (FALSE);
   }
}

