/* getckt.c  94.10.15
 * Copyright 1983-1992   Albert Davis
 * build, get, merge, "<" commands
 * process circuit files, and keyboard entry
 */
#include "ecah.h"
#include "argparse.h"
#include "branch.h"
#include "error.h"
#include "io.h"
#include "mode.h"
#include "options.h"
#include "status.h"
#include "types.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	cmd_build(const char*, int*);
	void	cmd_get(const char*,int*);
	void	cmd_merge(const char*,int*);
	void	cmd_run(const char*,int*);
static  void    getmerge(const char*,int*,int);
static	branch_t *parsebranch(char*,int);
static	branch_t *cparse(const char*);
/*--------------------------------------------------------------------------*/
extern const struct ioctrl io;
extern const struct options opt;
extern       struct status stats;

extern char head[];                 /* place to store title line            */
extern char e_int[];
extern int  run_mode;
extern branch_t *insertbefore;
/*--------------------------------------------------------------------------*/
/* cmd_build: build command
 * get circuit description direct from keyboard (or stdin if redirected)
 * Command syntax: build <before>
 * Bare command: add to end of list
 * If there is an arg: add before that element
 * null line exits this mode
 * preset, but do not execute "dot cards"
 */
void cmd_build(const char *cmd, int *cnt)
{
 branch_t *brh;

 time_zstart(&(stats.get));
 stats.iter[iTOTAL] = 1;
 run_mode = rPRESET;
 dealloc(YES);
 insertbefore = findbranch(cmd,cnt, firstbranch_all(), lastbranch_all());
 if (!(exists(insertbefore))){
    insertbefore = lastbranch_all()->next;
    if (!insertbefore)
       error(bWARNING, e_int, "build: insertbefore");
 }
 do {
    char buffer[BIGBUFLEN];
    (void)getcmd(">",buffer,BIGBUFLEN);
    brh = parsebranch(buffer,YES);
 } while (exists(brh));
 time_stop(&(stats.get));
}
/*--------------------------------------------------------------------------*/
/* cmd_get: get command
 * get circuit from a file, after clearing the old one
 * preset, but do not execute "dot cards"
 */
void cmd_get(const char *cmd, int *cnt)
{
 time_zstart(&(stats.get));
 run_mode = rPRESET;
 getmerge(cmd,cnt,YES);
 time_stop(&(stats.get));
}
/*--------------------------------------------------------------------------*/
/* cmd_merge: merge command
 * as get, but do not clear first
 */
void cmd_merge(const char *cmd, int *cnt)
{
 time_zstart(&(stats.get));
 run_mode = rPRESET;
 getmerge(cmd,cnt,NO);
 time_stop(&(stats.get));
}
/*--------------------------------------------------------------------------*/
/* cmd_run: "<" and "<<" commands
 * run in batch mode
 * "<<" clears old circuit first, "<" does not
 * get circuit from file, execute dot cards in sequence
 */
void cmd_run(const char *cmd, int *cnt)
{
 int deleteold = NO;
 time_zstart(&(stats.get));
 while (cmd[*cnt] == '<'){
    deleteold = YES;
    ++*cnt;
    skipbl(cmd,cnt);
 }
 run_mode = rEXECUTE;
 getmerge(cmd,cnt,deleteold);
 time_stop(&(stats.get));
}
/*--------------------------------------------------------------------------*/
/* getmerge: actually do the work for "get", "merge", etc.
 */
static void getmerge(const char *cmd, int *cnt, int deleteold)
{
 char buffer[BIGBUFLEN];
 int  echoon;		/* echo on/off flag (echo as read from file)        */
 int  liston;		/* list on/off flag (list actual values)            */
 int  quiet;		/* don't echo title                                 */
 static FILE *filen;	/* file number (static for safety)                  */

 stats.iter[iTOTAL] = 1;
 dealloc(YES);
 xclose(&filen);
 filen = xopen(cmd,cnt,"","r");
 if (!filen)
    error(bERROR, "");

 echoon = liston = quiet = NO;
 for (;;){
    if (argparse(cmd,cnt,REPEAT,
        "Echo",         aENUM,      &echoon,    YES,
        "List",         aENUM,      &liston,    YES,
        "Quiet",        aENUM,      &quiet,     YES,
        "")){
       ;
    }else if (cmd[*cnt]){
       xclose(&filen);
       syntax_msg(cmd, cnt, bERROR);
    }else{
       break;
    }
 }

 if (deleteold)
    cmd_clear();

 if (!getlines(buffer, BIGBUFLEN, filen))	/* title */
    error(bWARNING, "empty circuit file\n");
 (void)trim(buffer);
 if (!quiet)
    mprintf(io.mstdout, "%s\n", buffer);
 if (*buffer)
    strcpy(head, buffer);

 insertbefore = lastbranch_all()->next;
 if (!insertbefore)
    error(bWARNING, e_int, "getmerge: insertbefore");
 while (getlines(buffer, BIGBUFLEN, filen)){
    branch_t *brh;
    if (echoon)
       mprintf(io.mstdout, "%s\n", buffer);
    brh = parsebranch(buffer,NO);
    if (liston  &&  exists(brh)){
       print_branch(brh, io.mstdout, NO);
    }
 }
 xclose(&filen);
}
/*--------------------------------------------------------------------------*/
/* parsebranch: parse an input line, and process it
 */
static branch_t *parsebranch(char *buffer, int alwaysdupcheck)
{
 branch_t *brh;			/* place for cparse to return data	    */
 branch_t *before;		/* actually insert here			    */

 brh = (branch_t*)NULL;
 before = insertbefore;		/* save insert place in case something like */
 				/* a subckt changes it			    */

 if (opt.dupcheck ||  alwaysdupcheck){
    int dummy = 0;
    brh = findbranch(buffer, &dummy, insertbefore, insertbefore->prev);
 }
 
 if (exists(brh)){
    int dummy = 0;
    error(bWARNING, "replacing: %s\n", brh->label);
    parse_branch(brh,buffer,&dummy);
 }else{
    brh = cparse(buffer);
    if (exists(brh)){
       brh->next = before;
       brh = insertbranch(brh);
    }
 }

 if (isdevice(brh)){
    dealloc(YES);
 }
 return brh;
}
/*--------------------------------------------------------------------------*/
/* cparse: circuit parse: parse one line of a netlist
 * mostly, dispatches to the proper function.
 */
static branch_t *cparse(const char *cmd)
{
 branch_t *brh;
 int i = 0;
 int *cnt = &i;

 skipbl(cmd,cnt);
 if (isdigit(cmd[*cnt]))
    (void)ctoi(cmd,cnt);	/* ignore line numbers			    */

 brh = (branch_t*)NULL;
 switch (to_upper(cmd[*cnt])){
    case '\0':	/* nothing */			break;
    case '.':	brh = create_branch(&dev_dotcard);	break;
    case '\'':
    case '"':
    case ';':
    case '#':
    case '*':	brh = create_branch(&dev_comment);	break;
    case 'A':	syntax_msg(cmd,cnt,bWARNING);		break;
    case 'B':	syntax_msg(cmd,cnt,bWARNING);		break;
    case 'C':	brh = create_branch(&dev_cap);		break;
    case 'D':	brh = create_branch(&dev_diode);	break;
    case 'E':	brh = create_branch(&dev_vcvs);		break;
    case 'F':	brh = create_branch(&dev_cccs);		break;
    case 'G':	brh = create_branch(&dev_vccs);		break;
    case 'H':	brh = create_branch(&dev_ccvs);		break;
    case 'I':	brh = create_branch(&dev_cs);		break;
    case 'J':	syntax_msg(cmd,cnt,bWARNING);		break;
    case 'K':	brh = create_branch(&dev_coil_mutual);	break;
    case 'L':	brh = create_branch(&dev_coil);		break;
    case 'M':	brh = create_branch(&dev_mos);		break;
    case 'N':	syntax_msg(cmd,cnt,bWARNING);		break;
    case 'O':	syntax_msg(cmd,cnt,bWARNING);		break;
    case 'P':	syntax_msg(cmd,cnt,bWARNING);		break;
    case 'Q':	brh = create_branch(&dev_bjt);		break;
    case 'R':	brh = create_branch(&dev_resistor);	break;
    case 'S':	brh = create_branch(&dev_vswtch);	break;
    case 'T':	brh = create_branch(&dev_trnlin);	break;
    case 'U':	brh = create_branch(&dev_logic);	break;
    case 'V':	brh = create_branch(&dev_vs);		break;
    case 'W':	brh = create_branch(&dev_cswtch);	break;
    case 'X':	brh = create_branch(&dev_subckt);	break;
    case 'Y':	brh = create_branch(&dev_admittance);	break;
    case 'Z':	syntax_msg(cmd,cnt,bWARNING);		break;
    default:	syntax_msg(cmd,cnt,bWARNING);		break;
 }
 
 if (exists(brh)){
    parse_branch(brh,cmd,cnt);
 }else if (brh){
    error(bWARNING, "internal error: branch has no type <%s>\n", cmd);
    free((void*)brh);
    brh = (branch_t*)NULL;
 }

 return brh;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
