/* nodeset.c  93.12.22
 * Copyright 1983-1992   Albert Davis
 * nodeset and ic commands
 */
#include "ecah.h"
#include "argparse.h"
#include "error.h"
#include "io.h"
#include "nodeset.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	cmd_ic(const char*,int*);
	void	cmd_nodeset(const char*,int*);
static	void	nic(const char*,int*,nodeset_t*);
static	void	addnodeset(nodeset_t*,int,double);
static	void	clearnodeset(nodeset_t*,nodeset_t*);
static	void	deletenodeset(nodeset_t*,int);
static	void	listnodeset(const nodeset_t*);
/*--------------------------------------------------------------------------*/
extern const struct ioctrl io;
extern const char e_om[];
static nodeset_t ictop;
static nodeset_t nstop;
/*--------------------------------------------------------------------------*/
void cmd_ic(const char *cmd, int *cnt)
{
 nic(cmd,cnt,&ictop);
}
/*--------------------------------------------------------------------------*/
void cmd_nodeset(const char *cmd, int *cnt)
{
 nic(cmd,cnt,&nstop);
}
/*--------------------------------------------------------------------------*/
static void nic(const char *cmd, int *cnt, nodeset_t *top)
{
 if (!cmd[*cnt]){
   listnodeset(top);
   return;
 }

 if (pmatch(cmd,cnt,"CLEAR")){
    clearnodeset(top,top);
 }else{
    while (pmatch(cmd,cnt,"V")){
       int node = ctoi(cmd,cnt);
       int cntold = *cnt;
       double voltage = ctof(cmd,cnt);
       if (cntold == *cnt){		/* no voltage value = unset */
	  deletenodeset(top,node);
       }else{
	  addnodeset(top,node,voltage);
       }
    }
    syntax_check(cmd,cnt,bWARNING);
 }
}
/*--------------------------------------------------------------------------*/
/* addnodeset: add a new nodeset or ic
 */
static void addnodeset(nodeset_t *top, int node, double voltage)
{
 nodeset_t *ptr;

 for (ptr=top;  (ptr->next)&&(ptr->next->node<node);  ptr=ptr->next)
    /* nothing */;
    
 if ((ptr->next)&&(ptr->next->node==node)){
    error(bWARNING, "replacing nodeset/ic at node %u\n", node);
 }else{
    nodeset_t *newnode;
    newnode = (nodeset_t*)calloc(1,sizeof(nodeset_t));
    if (!newnode)
       error(bERROR, e_om, "addnodeset");
    newnode->node = node;
    newnode->next = ptr->next;
    ptr->next = newnode;
 }

 ptr = ptr->next;
 ptr->voltage = voltage;
}  
/*--------------------------------------------------------------------------*/
/* clearnodeset: deallocate and clear all from ptr on,
 * but leave top allocated  (recursive)
 */
static void clearnodeset(nodeset_t *top, nodeset_t *ptr)
{
 if (ptr->next)
    clearnodeset(top,ptr->next);
 if (ptr != top){
    free((void*)ptr);
 }else{
    top->next=NULL;
    top->node=0;
    top->voltage=0.;
 }
}
/*--------------------------------------------------------------------------*/
/* deletenodeset: delete a node set  (unset a node)
 */
static void deletenodeset(nodeset_t *top, int node)
{
 nodeset_t *ptr;

 for(ptr=top;  (ptr->next)&&(ptr->next->node<node);  ptr=ptr->next)
    /* nothing */;			/* scan for node match */

 if ((ptr->next)&&(ptr->next->node==node)){
    nodeset_t *link;
    link = ptr->next->next;
    free((void*)ptr->next);
    ptr->next = link;
 }
}
/*--------------------------------------------------------------------------*/
/* listnodeset: list all nodes set
 */
static void listnodeset(const nodeset_t *top)
{
 nodeset_t *ptr;

 for (ptr=top->next;  ptr;  ptr=ptr->next){
    mprintf(io.mstdout,"V(%d)=%s ",ptr->node,ftos(ptr->voltage,"",7,0));
 }  
 mprintf(io.mstdout,"\n");	
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
