/* probe.c  94.07.13
 * Copyright 1983-1992   Albert Davis
 * probe and plot commands
 * set up print and plot (select points, maintain probe lists)
 * command line operations
 */
#include "ecah.h"
#include "argparse.h"
#include "branch.h"
#include "error.h"
#include "io.h"
#include "mode.h"
#include "nodestat.h"
#include "probh.h"
#include "status.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	cmd_alarm(const char*,int*);
	void	cmd_plot(const char*,int*);
	void	cmd_print(const char*,int*);
static	void	do_probe(const char*,int*,probe_t*[]);
static	void	alloc_probe_list(probe_t**);
static	int	add_probes(const char*,int*,int,probe_t*);
static	int	 add_all_nodes(int,probe_t*,probe_t*);
static	int	 add_branches(const char*,int*,int,probe_t*,probe_t*);
static	int	 add_node_list(const char*,int*,int,probe_t*,probe_t*);
static	void	clear_probes(probe_t*);
static	void	list_probes(const probe_t*,const char*);
static	int	rm_probes(const char*,int*,int,probe_t*);
/*--------------------------------------------------------------------------*/
extern       struct ioctrl io;
extern const struct status stats;
extern const struct nodestat *nstat;
extern const struct nodestuff ns;
extern probe_t *alarmlist[];
extern probe_t *plotlist[];
extern probe_t *probelist[];
extern char e_om[], e_int[];
/*--------------------------------------------------------------------------*/
void cmd_alarm(
	const char *cmd, 
	int *cnt)
{
 do_probe(cmd,cnt,alarmlist);
}
/*--------------------------------------------------------------------------*/
void cmd_plot(
	const char *cmd, 
	int *cnt)
{
 io.plotset = YES;
 do_probe(cmd,cnt,plotlist);
}
/*--------------------------------------------------------------------------*/
void cmd_print(
	const char *cmd, 
	int *cnt)
{
 io.plotset = NO;
 do_probe(cmd,cnt,probelist);
}
/*--------------------------------------------------------------------------*/
static void do_probe(
	const char *cmd, 
	int *cnt, 
	probe_t *probes[])
{
 enum {ADD, DELETE, NEW} action;
 int simtype = sNONE;

 if (cmd[*cnt] == '-'){
    action = DELETE;
    (*cnt)++;
 }else if (cmd[*cnt] == '+'){
    action = ADD;
    (*cnt)++;
 }else{
    action = NEW;
 }

 (void)argparse(cmd,cnt,ONEPASS,
	"TRan",	   aENUM,   &simtype,	sTRAN,
	"AC",	   aENUM,   &simtype,	sAC,
	"DC",	   aENUM,   &simtype,	sDC,
	"OP",	   aENUM,   &simtype,	sOP,
	"FOurier", aENUM,   &simtype,	sFOURIER,
	"");
 if (!simtype){
    if (!cmd[*cnt]){
       list_probes(probes[sTRAN]   ,"tran");
       list_probes(probes[sAC]     ,"ac");
       list_probes(probes[sDC]     ,"dc");
       list_probes(probes[sOP]     ,"op");
       list_probes(probes[sFOURIER],"fourier");
    }else if (pmatch(cmd,cnt,"CLEAR")){
       int ii;
       for (ii = sSTART;  ii < sCOUNT;  ++ii)
	  clear_probes(probes[ii]);
    }else{
       syntax_msg(cmd,cnt,bERROR);
    }
 }else{
    if (!cmd[*cnt]){
       list_probes(probes[simtype],"");
    }else if (pmatch(cmd,cnt,"CLEAR")){
       clear_probes(probes[simtype]);
    }else{
       int probecount;
       allocate(sSTATUS);
       alloc_probe_list(&(probes[simtype]));
       if (cmd[*cnt] == '-'){
	  action = DELETE;
	  (*cnt)++;
       }else if (cmd[*cnt] == '+'){
	  action = ADD;
	  (*cnt)++;
       }
       if (action == NEW){
          probecount = 0;
	  action = ADD;
       }else{
          probecount = count_probes(probes[simtype]);
       }
       while (cmd[*cnt]){
	  if (cmd[*cnt] == '-'){
	     action = DELETE;
	     (*cnt)++;
	  }else if (cmd[*cnt] == '+'){
	     action = ADD;
	     (*cnt)++;
	  }
	  if (action == DELETE){
	     probecount = rm_probes(cmd,cnt,probecount,probes[simtype]);
	  }else{
             probecount = add_probes(cmd,cnt,probecount,probes[simtype]);
	  }
       }
       *probes[simtype][probecount].what = '\0';
    }
 }
}
/*--------------------------------------------------------------------------*/
static void alloc_probe_list(
	probe_t **probes)
{
 if (!*probes)
    *probes=(probe_t*)calloc(PROBECOUNT,sizeof(probe_t));
 if (!*probes)
    error(bERROR, e_om, "alloc_probe_list");
}
/*--------------------------------------------------------------------------*/
static int add_probes(
	const char *cmd, 
	int *cnt, 
	int  probecount,
	probe_t *probes)
{    					/* BUG: ctostr may not advance */
 					/* if its 1st char is a term */
 					/* can cause loss of rest of str */
 probe_t prb;
 int oldcount = probecount;
 int paren = 0;
 prb.lo = prb.hi = 0.;
 (void)ctostr(cmd,cnt,prb.what,LABELEN,TOKENTERM);	/* parameter */
 if (!*(prb.what))
    syntax_msg(cmd,cnt,bWARNING);
 paren += skiplparen(cmd,cnt);			/* device, node, etc. */
 if (pmatch(cmd,cnt,"NODES")){			/* all nodes */
    prb.brh = (branch_t*)NULL;
    probecount = add_all_nodes(probecount,probes,&prb);
 }else if (isdigit(cmd[*cnt])){			/* listed nodes (numbered) */
    prb.brh = (branch_t*)NULL;
    probecount = add_node_list(cmd,cnt,probecount,probes,&prb);
 }else{						/* branches */
    prb.node = 0;
    probecount = add_branches(cmd,cnt,probecount,probes,&prb);
 }
 if (probecount == oldcount)
    syntax_msg(cmd,cnt,bWARNING);
 paren -= skiprparen(cmd,cnt);
 if (paren != 0)
    syntax_msg(cmd,cnt,bWARNING);
 if (skiplparen(cmd,cnt)){			/* range for plotting */
    double lo, hi;
    lo = ctof(cmd,cnt);
    hi = ctof(cmd,cnt);
    while (oldcount < probecount){
       probes[oldcount].lo = lo;
       probes[oldcount].hi = hi;
       ++oldcount;
    }
    if (!skiprparen(cmd,cnt))
       syntax_check(cmd,cnt,bWARNING);
 }
 if (probecount > PROBECOUNT)
    error(bERROR, e_int, "too many probes (missed trap)");
 return probecount;
}
/*--------------------------------------------------------------------------*/
static int add_all_nodes(
	int probecount, 
	probe_t *probes, 
	probe_t *prb)
{
 for (prb->node = 1;
      prb->node <= stats.user_nodes  &&  prb->node < PROBECOUNT;
      prb->node++){
    if (nstat[ns.nm[prb->node]].needsanalog) /* if it exists */
       probes[probecount++] = *prb;
    if (probecount > PROBECOUNT-1)
       error(bDANGER, e_int, "too many probes");
 }
 return probecount;
}
/*--------------------------------------------------------------------------*/
static int add_branches(
	const char *cmd,
	int  *cnt,
	int  probecount,
	probe_t *probes,
	probe_t *prb)
{    
 int savecnt;
 const branch_t *stop;
 savecnt = *cnt;
 stop = prb->brh = firstbranch_dev();
 if (exists(stop)){
    int newcnt;
    newcnt = savecnt = *cnt;
    do {				/* look for all matching branches */
       *cnt = savecnt;
       prb->brh = findbranch(cmd, cnt, prb->brh, lastbranch_dev());
       if (exists(prb->brh)){
	  probes[probecount++] = *prb;
	  if (probecount > PROBECOUNT-1){
	     error(bDANGER, e_int, "too many probes");
	     break;
	  }
	  newcnt = *cnt;
	  while (exists(prb->brh->parent)){	/* don't get lost */
	     prb->brh = prb->brh->parent;	/* in a subckt */
	  }
       }else{
	  *cnt = newcnt;
	  break; /* didn't find, this time */
       }
    } while (prb->brh = nextbranch_dev(prb->brh),  prb->brh != stop);
 }
 if (savecnt == *cnt){			/* didn't find matching branch */
    syntax_msg(cmd,&savecnt,bWARNING);
    skiparg(cmd,cnt);
 }
 return probecount;
}
/*--------------------------------------------------------------------------*/
static int add_node_list(
	const char *cmd,
	int *cnt,
	int probecount,
	probe_t *probes,
	probe_t *prb)
{    
 while (isdigit(cmd[*cnt])){
    int savecnt;
    savecnt = *cnt;
    prb->node = ctoi(cmd,cnt);
    if (prb->node <= stats.total_nodes){
       probes[probecount++] = *prb;
       if (probecount > PROBECOUNT-1){
	  error(bDANGER, e_int, "too many probes");
	  break;
       }
    }else{
       syntax_msg(cmd,&savecnt,bWARNING);
    }
 }
 return probecount;
}
/*--------------------------------------------------------------------------*/
static void clear_probes(
	probe_t *probes)
{
 if (probes)
    *probes[0].what = '\0';
}
/*--------------------------------------------------------------------------*/
static void list_probes(
	const probe_t *probes, 
	const char *label)
{
 mprintf(io.mstdout, "%-7s", label);
 if (probes){
    int ii;
    for (ii = 0;  *probes[ii].what;  ii++){
       mprintf(io.mstdout, " %s", probename(probes[ii]));
       if (probes[ii].lo != probes[ii].hi){
          mprintf(io.mstdout, "(%s,%s)",
	  		 ftos(probes[ii].lo,"",5,io.formaat),
			 ftos(probes[ii].hi,"",5,io.formaat));
       }
    }
 }
 mprintf(io.mstdout, "\n");
}
/*--------------------------------------------------------------------------*/
static int rm_probes(
	const char *cmd, 
	int *cnt, 
	int  probecount,
	probe_t *probes)
{    					/* BUG: ctostr may not advance */
 int paren = 0;				/* if its 1st char is a term */
 int ii;				/* can cause loss of rest of str */
 char parameter[BUFLEN+1];
 int dropcount = 0;
 int savecnt;
 savecnt = *cnt;
 (void)ctostr(cmd,cnt,parameter,BUFLEN,TOKENTERM);
 strcat(parameter,"(");
 paren += skiplparen(cmd,cnt);			/* device, node, etc. */
 (void)ctostr(cmd, cnt, &(parameter[strlen(parameter)]), 
 				BUFLEN-(int)strlen(parameter), TOKENTERM);
 strcat(parameter,")");
 paren -= skiprparen(cmd,cnt);
 if (paren != 0  || !*parameter)
    syntax_msg(cmd,cnt,bWARNING);
    
 for (ii = 0;  ii < probecount;  ii++){
    if (dropcount > 0){
       probes[ii-dropcount] = probes[ii];
    }
    if (wmatch(parameter,probename(probes[ii]))){
       dropcount++;
    }
 }
 if (dropcount == 0){
    syntax_msg(cmd,&savecnt,bWARNING);
 }
 probecount -= dropcount;
 return probecount;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
