ngspice/src/frontend/inpcom.c

5021 lines
187 KiB
C
Raw Normal View History

2009-07-28 23:16:07 +02:00
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher
**********/
/*
2011-11-13 15:44:00 +01:00
For dealing with spice input decks and command scripts
2009-07-28 23:16:07 +02:00
2011-11-13 15:44:00 +01:00
Central function is inp_readall()
2009-07-28 23:16:07 +02:00
*/
#include "ngspice/ngspice.h"
2009-07-28 23:16:07 +02:00
#include "ngspice/cpdefs.h"
#include "ngspice/ftedefs.h"
#include "ngspice/fteext.h"
#include "ngspice/dvec.h"
#include "ngspice/fteinp.h"
#include "ngspice/compatmode.h"
2009-07-28 23:16:07 +02:00
#include "inpcom.h"
#include "variable.h"
2011-06-26 01:07:13 +02:00
#include "../misc/util.h" /* ngdirname() */
#include "ngspice/stringutil.h"
#include "ngspice/wordlist.h"
2009-07-28 23:16:07 +02:00
#ifdef XSPICE
/* gtri - add - 12/12/90 - wbk - include new stuff */
#include "ngspice/ipctiein.h"
#include "ngspice/enh.h"
2009-07-28 23:16:07 +02:00
/* gtri - end - 12/12/90 */
#endif
/* SJB - Uncomment this line for debug tracing */
/*#define TRACE*/
2010-01-30 14:21:27 +01:00
#include "error.h" /* controlled_exit() */
2009-07-28 23:16:07 +02:00
/* globals -- wanted to avoid complicating inp_readall interface */
static char *library_file[1000];
static char *library_name[1000][1000];
struct line *library_ll_ptr[1000][1000];
struct line *libraries[1000];
int num_libraries;
int num_lib_names[1000];
static char *global;
static char *subckt_w_params[1000];
static int num_subckt_w_params;
static char *func_names[1000];
static char *func_params[1000][1000];
static char *func_macro[5000];
static int num_functions;
static int num_parameters[1000];
2010-04-24 00:00:40 +02:00
static COMPATMODE_T inp_compat_mode;
2009-07-28 23:16:07 +02:00
/* Collect information for dynamic allocation of numparam arrays */
/* number of lines in input deck */
int dynmaxline; /* inpcom.c 1529 */
2011-08-06 09:53:48 +02:00
/* number of lines in deck after expansion */
2009-07-28 23:16:07 +02:00
int dynMaxckt = 0; /* subckt.c 307 */
/* number of parameter substitutions */
long dynsubst; /* spicenum.c 221 */
/* static declarations */
static char * readline(FILE *fd);
static int get_number_terminals( char *c );
static void inp_stripcomments_deck(struct line *deck);
static void inp_stripcomments_line(char * s);
static void inp_fix_for_numparam(struct line *deck);
static void inp_remove_excess_ws(struct line *deck);
static void inp_determine_libraries(struct line *deck, char *lib_name);
static void inp_init_lib_data(void);
2009-07-28 23:16:07 +02:00
static void inp_grab_func(struct line *deck);
static void inp_fix_inst_calls_for_numparam( struct line *deck);
static void inp_expand_macros_in_func(void);
2009-07-28 23:16:07 +02:00
static void inp_expand_macros_in_deck( struct line *deck );
static void inp_fix_param_values( struct line *deck );
static void inp_reorder_params( struct line *deck, struct line *list_head, struct line *end );
static int inp_split_multi_param_lines( struct line *deck, int line_number );
static void inp_sort_params( struct line *start_card, struct line *end_card, struct line *card_bf_start, struct line *s_c, struct line *e_c );
static char* inp_remove_ws( char *s );
2010-04-24 00:00:40 +02:00
static void inp_compat(struct line *deck);
static void inp_bsource_compat(struct line *deck);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
static bool chk_for_line_continuation( char *line );
static void comment_out_unused_subckt_models( struct line *start_card , int no_of_lines);
static void inp_fix_macro_param_func_paren_io( struct line *begin_card );
static void inp_fix_ternary_operator( struct line *start_card );
static void inp_fix_gnd_name( struct line *deck );
static void inp_chk_for_multi_in_vcvs( struct line *deck, int *line_number );
static void inp_add_control_section( struct line *deck, int *line_number );
2011-03-07 00:48:35 +01:00
2011-11-13 13:04:15 +01:00
/*-------------------------------------------------------------------------
2011-11-13 15:44:00 +01:00
Read the entire input file and return a pointer to the first line of
the linked list of 'card' records in data. The pointer is stored in
*data.
Called from fcn inp_spsource() in inp.c to load circuit or command files.
Called from fcn com_alter_mod() in device.c to load model files.
Called from here to load .library or .include files.
Procedure:
read in all lines & put them in the struct cc
read next line
process .TITLE line
store contents in string new_title
process .lib lines
read file and library name, open file using fcn inp_pathopen()
read file contents and put into struct libraries[], one entry per .lib line
process .inc lines
read file and library name, open file using fcn inp_pathopen()
read file contents and add lines to cc
make line entry lower case
allow for shell end of line continuation (\\)
add '+' to beginning of next line
add line entry to list cc
add '.global gnd'
add libraries
find library section
add lines
add .end card
strip end-of-line comments
make continuation lines a single line
*** end of processing for command files ***
start preparation of input deck for numparam
...
debug printout to debug-out.txt
2009-07-28 23:16:07 +02:00
*-------------------------------------------------------------------------*/
2011-11-13 13:04:15 +01:00
void
inp_readall(FILE *fp, struct line **data, int call_depth, char *dir_name, bool comfile)
/* fp: in, pointer to file to be read,
data: out, linked list of cards
call_depth: in, nested call to fcn
dir_name: in, name of directory of file to be read
comfile: in, TRUE if command file (e.g. spinit, .spiceinit
*/
2009-07-28 23:16:07 +02:00
{
2011-11-13 13:04:15 +01:00
struct line *end = NULL, *cc = NULL, *prev = NULL, *working, *newcard, *start_lib, *global_card, *tmp_ptr = NULL, *tmp_ptr2 = NULL;
2011-12-30 18:50:17 +01:00
char *buffer = NULL, *s, *t, c;
2011-11-13 13:04:15 +01:00
/* segfault fix */
#ifdef XSPICE
char big_buff[5000];
int line_count = 0;
Ipc_Status_t ipc_status;
char ipc_buffer[1025]; /* Had better be big enough */
int ipc_len;
#endif
char *new_title = NULL;
int line_number = 1; /* sjb - renamed to avoid confusion with struct line */
int line_number_orig = 1, line_number_lib = 1, line_number_inc = 1;
unsigned int no_braces = 0; /* number of '{' */
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
size_t max_line_length; /* max. line length in input deck */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
FILE *fdo;
struct line *tmp_ptr1 = NULL;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
int i, j;
2011-12-30 18:46:37 +01:00
bool found_lib_name, found_end = FALSE, shell_eol_continuation = FALSE;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( call_depth == 0 ) {
num_subckt_w_params = 0;
num_libraries = 0;
num_functions = 0;
global = NULL;
found_end = FALSE;
inp_compat_mode = ngspice_compat_mode() ;
2011-11-13 13:04:15 +01:00
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* gtri - modify - 12/12/90 - wbk - read from mailbox if ipc enabled */
#ifdef XSPICE
/* First read in all lines & put them in the struct cc */
for (;;) {
/* If IPC is not enabled, do equivalent of what SPICE did before */
if(! g_ipc.enabled) {
if ( call_depth == 0 && line_count == 0 ) {
line_count++;
if ( fgets( big_buff, 5000, fp ) ) {
buffer = copy(big_buff);
}
} else {
buffer = readline(fp);
if(! buffer) {
break;
}
}
} else {
/* else, get the line from the ipc channel. */
/* We assume that newlines are not sent by the client */
/* so we add them here */
ipc_status = ipc_get_line(ipc_buffer, &ipc_len, IPC_WAIT);
if(ipc_status == IPC_STATUS_END_OF_DECK) {
buffer = NULL;
break;
} else if(ipc_status == IPC_STATUS_OK) {
buffer = TMALLOC(char, strlen(ipc_buffer) + 3);
strcpy(buffer, ipc_buffer);
strcat(buffer, "\n");
} else { /* No good way to report this so just die */
controlled_exit(EXIT_FAILURE);
}
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
/* gtri - end - 12/12/90 */
#else
while ((buffer = readline(fp)) != NULL) {
#endif
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
#ifdef TRACE
/* SDB debug statement */
printf ("in inp_readall, just read %s", buffer);
#endif
if ( !buffer ) {
2011-08-06 09:53:48 +02:00
continue;
}
2011-11-13 13:04:15 +01:00
/* OK -- now we have loaded the next line into 'buffer'. Process it. */
/* If input line is blank, ignore it & continue looping. */
if ( (strcmp(buffer,"\n") == 0) || (strcmp(buffer,"\r\n") == 0) ) {
if ( call_depth != 0 || (call_depth == 0 && cc != NULL) ) {
line_number_orig++;
tfree(buffer); /* was allocated by readline() */
continue;
2011-08-06 09:53:48 +02:00
}
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if (*buffer == '@') {
tfree(buffer); /* was allocated by readline() */
break;
}
2010-10-25 12:45:55 +02:00
2011-11-13 13:04:15 +01:00
/* now handle .title statement */
if (ciprefix(".title", buffer)) {
for ( s = buffer; *s && !isspace(*s); s++ ) /* skip over .title */
;
while ( isspace(*s) ) s++; /* advance past space chars */
2010-12-25 09:35:19 +01:00
2011-11-13 13:04:15 +01:00
/* only the last title line remains valid */
if (new_title != NULL) tfree(new_title);
new_title = copy(s);
if ((s = strstr(new_title, "\n")) != NULL)
*s = ' ';
*buffer = '*'; /* change .TITLE line to comment line */
2010-12-25 09:35:19 +01:00
}
2011-11-13 13:04:15 +01:00
/* now handle .lib statements */
if (ciprefix(".lib", buffer)) {
2011-12-30 18:50:17 +01:00
char *y, *z;
2011-12-30 18:06:10 +01:00
inp_stripcomments_line(buffer);
2011-11-13 13:04:15 +01:00
for ( s = buffer; *s && !isspace(*s); s++ ) /* skip over .lib */
;
while ( isspace(*s) || isquote(*s) ) s++; /* advance past space chars */
if ( !*s ) { /* if at end of line, error */
fprintf(cp_err, "Error: .lib filename missing\n");
tfree(buffer); /* was allocated by readline() */
2011-12-27 09:46:19 +01:00
controlled_exit(EXIT_FAILURE);
2011-11-13 13:04:15 +01:00
} /* Now s points to first char after .lib */
for ( t = s; *t && !isspace(*t) && !isquote(*t); t++ ) /* skip to end of word */
;
y = t;
while ( isspace(*y) || isquote(*y) ) y++; /* advance past space chars */
2011-12-27 09:46:19 +01:00
2011-11-13 13:04:15 +01:00
// check if rest of line commented out
if ( *y && *y != '$' ) { /* .lib <file name> <lib name> */
2011-12-30 18:38:56 +01:00
char *copys = NULL;
char keep_char;
2011-12-30 18:38:56 +01:00
2011-11-13 13:04:15 +01:00
for ( z = y; *z && !isspace(*z) && !isquote(*z); z++ )
;
keep_char = *t;
2011-11-13 13:04:15 +01:00
*t = '\0';
*z = '\0';
2010-10-25 12:45:55 +02:00
2011-11-13 13:04:15 +01:00
if ( *s == '~' ) {
copys = cp_tildexpand(s); /* allocates memory, but can also return NULL */
2011-12-30 18:38:56 +01:00
if ( copys )
2011-11-13 13:04:15 +01:00
s = copys; /* reuse s, but remember, buffer still points to allocated memory */
2010-10-25 12:45:55 +02:00
}
2011-12-30 18:46:37 +01:00
for ( i = 0; i < num_libraries; i++ )
2011-12-30 19:08:48 +01:00
if ( cieq( library_file[i], s ) )
2011-11-13 13:04:15 +01:00
break;
2011-12-30 18:38:56 +01:00
2011-12-30 18:46:37 +01:00
if ( i >= num_libraries ) {
2011-12-30 18:38:56 +01:00
bool dir_name_flag = FALSE;
2011-12-30 18:44:52 +01:00
FILE *newfp = inp_pathopen( s, "r" );
if ( !newfp ) {
2011-12-30 18:43:41 +01:00
char big_buff2[5000];
if ( dir_name )
sprintf( big_buff2, "%s/%s", dir_name, s );
else
sprintf( big_buff2, "./%s", s );
newfp = inp_pathopen( big_buff2, "r" );
if ( !newfp ) {
2011-12-30 18:38:56 +01:00
if ( copys )
tfree(copys); /* allocated by the cp_tildexpand() above */
2011-12-30 18:06:10 +01:00
fprintf(cp_err, "Error: Could not find library file %s\n", s);
tfree(buffer);
controlled_exit(EXIT_FAILURE);
2011-11-13 13:04:15 +01:00
}
2011-12-30 18:43:41 +01:00
dir_name_flag = TRUE;
2011-11-13 13:04:15 +01:00
}
2009-07-28 23:16:07 +02:00
2011-12-30 19:08:48 +01:00
library_file[num_libraries++] = strdup(s);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( dir_name_flag == FALSE ) {
char *s_dup = strdup(s);
inp_readall(newfp, &libraries[num_libraries-1], call_depth+1, ngdirname(s_dup), FALSE);
tfree(s_dup);
} else {
2011-11-13 13:04:15 +01:00
inp_readall(newfp, &libraries[num_libraries-1], call_depth+1, dir_name, FALSE);
}
2011-11-13 13:04:15 +01:00
fclose(newfp);
2010-10-25 12:45:55 +02:00
}
2011-12-30 18:38:56 +01:00
*t = keep_char;
2009-07-28 23:16:07 +02:00
2011-12-30 18:38:56 +01:00
if ( copys )
tfree(copys); /* allocated by the cp_tildexpand() above */
2011-11-13 13:04:15 +01:00
/* Make the .lib a comment */
*buffer = '*';
} /*else { // no lib name given
2011-12-27 09:46:19 +01:00
fprintf(cp_err, "Warning: library name missing in line\n %s", buffer);
fprintf(cp_err, " File included as: .inc %s\n", s);
memcpy(buffer, ".inc",4);
} */
2011-12-27 09:46:19 +01:00
2011-11-13 13:04:15 +01:00
} /* end of .lib handling */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* now handle .include statements */
if (ciprefix(".include", buffer) || ciprefix(".inc", buffer)) {
2011-12-30 18:38:56 +01:00
char *copys = NULL;
2011-12-30 18:06:10 +01:00
inp_stripcomments_line(buffer);
2011-11-13 13:04:15 +01:00
for (s = buffer; *s && !isspace(*s); s++) /* advance past non-space chars */
;
2011-12-30 18:06:10 +01:00
while (isspace(*s)) /* now advance past space chars */
2011-11-13 13:04:15 +01:00
s++;
2011-12-30 18:06:10 +01:00
if(isquote(*s)) {
for (t = ++s; *t && !isquote(*t); t++)
;
if(!*t) /* teriminator quote not found */
t = s;
} else {
for (t = s; *t && !isspace(*t); t++)
;
}
if(t == s) {
2011-11-13 13:04:15 +01:00
fprintf(cp_err, "Error: .include filename missing\n");
tfree(buffer); /* was allocated by readline() */
controlled_exit(EXIT_FAILURE);
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
*t = '\0'; /* place \0 and end of file name in buffer */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if (*s == '~') {
copys = cp_tildexpand(s); /* allocates memory, but can also return NULL */
2011-12-30 18:38:56 +01:00
if ( copys )
2011-11-13 13:04:15 +01:00
s = copys; /* reuse s, but remember, buffer still points to allocated memory */
2010-10-25 12:45:55 +02:00
}
2009-07-28 23:16:07 +02:00
{
bool dir_name_flag = FALSE;
2011-12-30 18:44:52 +01:00
FILE *newfp = inp_pathopen(s, "r");
if ( !newfp ) {
2011-12-30 18:43:41 +01:00
char big_buff2[5000];
/* open file specified by .include statement */
if ( dir_name )
sprintf( big_buff2, "%s/%s", dir_name, s );
else
sprintf( big_buff2, "./%s", s );
newfp = inp_pathopen( big_buff2, "r" );
if ( !newfp ) {
perror(s);
if ( copys )
tfree(copys); /* allocated by the cp_tildexpand() above */
fprintf(cp_err, "Error: .include statement failed.\n");
tfree(buffer); /* allocated by readline() above */
controlled_exit(EXIT_FAILURE);
}
2011-12-30 18:43:41 +01:00
dir_name_flag = TRUE;
2011-11-13 13:04:15 +01:00
}
2011-08-06 09:53:48 +02:00
if ( dir_name_flag == FALSE ) {
char *s_dup = strdup(s);
inp_readall(newfp, &newcard, call_depth+1, ngdirname(s_dup), FALSE); /* read stuff in include file into netlist */
tfree(s_dup);
} else {
inp_readall(newfp, &newcard, call_depth+1, dir_name, FALSE); /* read stuff in include file into netlist */
}
2011-08-06 09:53:48 +02:00
(void) fclose(newfp);
}
2011-11-13 13:04:15 +01:00
2011-12-30 18:38:56 +01:00
if ( copys )
tfree(copys); /* allocated by the cp_tildexpand() above */
2011-11-13 13:04:15 +01:00
/* Make the .include a comment */
*buffer = '*';
/* now check if this is the first pass (i.e. end points to null) */
if (end) { /* end already exists */
end->li_next = alloc(struct line); /* create next card */
end = end->li_next; /* make end point to next card */
} else {
end = cc = alloc(struct line); /* create the deck & end. cc will
point to beginning of deck, end to
the end */
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
/* now fill out rest of struct end. */
end->li_next = NULL;
end->li_error = NULL;
end->li_actual = NULL;
end->li_line = copy(buffer);
end->li_linenum = end->li_linenum_orig = line_number++;
if (newcard) {
end->li_next = newcard;
/* Renumber the lines */
line_number_inc = 1;
for (end = newcard; end && end->li_next; end = end->li_next) {
end->li_linenum = line_number++;
end->li_linenum_orig = line_number_inc++;
}
end->li_linenum = line_number++; /* SJB - renumber the last line */
end->li_linenum_orig = line_number_inc++; /* SJB - renumber the last line */
}
/* Fix the buffer up a bit. */
(void) strncpy(buffer + 1, "end of:", 7);
} /* end of .include handling */
/* loop through 'buffer' until end is reached. Then test for
premature end. If premature end is reached, spew
error and zap the line. */
if ( !ciprefix( "write", buffer ) ) { // exclude 'write' command so filename case preserved
for (s = buffer; *s && (*s != '\n'); s++)
*s = (char) tolower(*s);
if (!*s) {
//fprintf(cp_err, "Warning: premature EOF\n");
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
*s = '\0'; /* Zap the newline. */
if((s-1) >= buffer && *(s-1) == '\r') /* Zop the carriage return under windows */
*(s-1) = '\0';
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
/* find the true .end command out of .endc, .ends, .endl, .end (comments may follow) */
if (ciprefix(".end", buffer)) {
if ((*(buffer+4) == '\0') || ( isspace(*(buffer+4)))) {
found_end = TRUE;
*buffer = '*';
}
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
if ( shell_eol_continuation ) {
char *new_buffer = TMALLOC(char, strlen(buffer) + 2);
sprintf( new_buffer, "+%s", buffer );
tfree(buffer);
buffer = new_buffer;
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
shell_eol_continuation = chk_for_line_continuation( buffer );
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* now check if this is the first pass (i.e. end points to null) */
if (end) { /* end already exists */
end->li_next = alloc(struct line); /* create next card */
end = end->li_next; /* point to next card */
} else { /* End doesn't exist. Create it. */
end = cc = alloc(struct line); /* note that cc points to beginning
of deck, end to the end */
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* now put buffer into li */
end->li_next = NULL;
end->li_error = NULL;
end->li_actual = NULL;
end->li_line = copy(buffer);
end->li_linenum = line_number++;
end->li_linenum_orig = line_number_orig++;
tfree(buffer);
} /* end while ((buffer = readline(fp)) != NULL) */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if (!end) { /* No stuff here */
*data = NULL;
return;
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( call_depth == 0 && found_end == TRUE) {
if ( global == NULL ) {
global = TMALLOC(char, strlen(".global gnd") + 1);
sprintf( global, ".global gnd" );
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
global_card = alloc(struct line);
global_card->li_error = NULL;
global_card->li_actual = NULL;
global_card->li_line = global;
global_card->li_linenum = 1;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
prev = cc->li_next;
cc->li_next = global_card;
global_card->li_next = prev;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
inp_init_lib_data();
inp_determine_libraries(cc, NULL);
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/*
add libraries
*/
found_lib_name = FALSE;
if ( call_depth == 0 ) {
for( i = 0; i < num_libraries; i++ ) {
working = libraries[i];
while ( working ) {
buffer = working->li_line;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( found_lib_name && ciprefix(".endl", buffer) ) {
/* Make the .endl a comment */
*buffer = '*';
found_lib_name = FALSE;
2010-05-12 23:02:58 +02:00
2011-11-13 13:04:15 +01:00
/* set pointer and continue to avoid deleting below */
tmp_ptr2 = working->li_next;
working->li_next = tmp_ptr;
working = tmp_ptr2;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* end = working;
* working = working->li_next;
* end->li_next = NULL; */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
continue;
} /* for ... */
if ( ciprefix(".lib", buffer) ) {
char keep_char;
2011-11-13 13:04:15 +01:00
if ( found_lib_name == TRUE ) {
fprintf( stderr, "ERROR: .lib is missing .endl!\n" );
controlled_exit(EXIT_FAILURE);
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
for ( s = buffer; *s && !isspace(*s); s++ ) /* skip over .lib */
;
while ( isspace(*s) || isquote(*s) ) s++; /* advance past space chars */
for ( t = s; *t && !isspace(*t) && !isquote(*t); t++ ) /* skip to end of word */
;
keep_char = *t;
*t = '\0';
/* see if library we want to copy */
found_lib_name = FALSE;
for( j = 0; j < num_lib_names[i]; j++ ) {
if ( strcmp( library_name[i][j], s ) == 0 ) {
found_lib_name = TRUE;
start_lib = working;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* make the .lib a comment */
*buffer = '*';
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
tmp_ptr = library_ll_ptr[i][j]->li_next;
library_ll_ptr[i][j]->li_next = working;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* renumber lines */
line_number_lib = 1;
for ( start_lib = working; !ciprefix(".endl", start_lib->li_line); start_lib = start_lib->li_next ) {
start_lib->li_linenum = line_number++;
start_lib->li_linenum_orig = line_number_lib++;
}
start_lib->li_linenum = line_number++; // renumber endl line
start_lib->li_linenum_orig = line_number_lib++;
break;
}
}
*t = keep_char;
}
prev = working;
working = working->li_next;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( found_lib_name == FALSE ) {
tfree(prev->li_line);
tfree(prev);
}
} /* end while */
} /* end for */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( found_end == TRUE ) {
end->li_next = alloc(struct line); /* create next card */
end = end->li_next; /* point to next card */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
buffer = TMALLOC(char, strlen( ".end" ) + 1);
sprintf( buffer, ".end" );
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* now put buffer into li */
end->li_next = NULL;
end->li_error = NULL;
end->li_actual = NULL;
end->li_line = buffer;
end->li_linenum = end->li_linenum_orig = line_number++;
end->li_linenum_orig = line_number_orig++;
}
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* Replace first line with the new title, if available */
if (new_title != NULL) {
if (cc->li_line) tfree(cc->li_line);
cc->li_line = new_title;
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* Now clean up li: remove comments & stitch together continuation lines. */
working = cc->li_next; /* cc points to head of deck. Start with the
next card. */
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* sjb - strip or convert end-of-line comments.
This must be cone before stitching continuation lines.
If the line only contains an end-of-line comment then it is converted
into a normal comment with a '*' at the start. This will then get
stripped in the following code. */
inp_stripcomments_deck(working);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
while (working) {
for (s = working->li_line; (c = *s) != '\0' && c <= ' '; s++)
;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
#ifdef TRACE
/* SDB debug statement */
printf("In inp_readall, processing linked list element line = %d, s = %s . . . \n", working->li_linenum,s);
#endif
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
switch (c) {
case '#':
case '$':
case '*':
case '\0':
/* this used to be commented out. Why? */
/* prev = NULL; */
working = working->li_next; /* for these chars, go to next card */
break;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
case '+': /* handle continuation */
if (!prev) {
working->li_error = copy(
"Illegal continuation line: ignored.");
working = working->li_next;
break;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/* create buffer and write last and current line into it. */
buffer = TMALLOC(char, strlen(prev->li_line) + strlen(s) + 2);
(void) sprintf(buffer, "%s %s", prev->li_line, s + 1);
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
s = prev->li_line;
prev->li_line = buffer;
prev->li_next = working->li_next;
working->li_next = NULL;
if (prev->li_actual) {
for (end = prev->li_actual; end->li_next; end = end->li_next)
;
end->li_next = working;
tfree(s);
} else {
newcard = alloc(struct line);
newcard->li_linenum = prev->li_linenum;
newcard->li_line = s;
newcard->li_next = working;
newcard->li_error = NULL;
newcard->li_actual = NULL;
prev->li_actual = newcard;
}
working = prev->li_next;
break;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
default: /* regular one-line card */
prev = working;
working = working->li_next;
break;
}
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* The following processing of an input file is not required for command files
like spinit or .spiceinit, so return command files here. */
if (comfile) {
/* save the return value (via **data) */
*data = cc;
return;
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
working = cc->li_next;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
inp_fix_for_numparam(working);
inp_remove_excess_ws(working);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( call_depth == 0 ) {
2011-11-13 13:04:15 +01:00
comment_out_unused_subckt_models(working, line_number);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
line_number = inp_split_multi_param_lines(working, line_number);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
inp_fix_macro_param_func_paren_io(working);
inp_fix_ternary_operator(working);
inp_grab_func(working);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
inp_expand_macros_in_func();
inp_expand_macros_in_deck(working);
inp_fix_param_values(working);
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* get end card as last card in list; end card pntr does not appear to always
be correct at this point */
for(newcard = working; newcard != NULL; newcard = newcard->li_next)
end = newcard;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
inp_reorder_params(working, cc, end);
inp_fix_inst_calls_for_numparam(working);
inp_fix_gnd_name(working);
inp_chk_for_multi_in_vcvs(working, &line_number);
2009-07-28 23:16:07 +02:00
2011-01-06 20:15:20 +01:00
2011-11-13 13:04:15 +01:00
if (cp_getvar("addcontrol", CP_BOOL, NULL))
inp_add_control_section(working, &line_number);
2011-11-13 13:04:15 +01:00
if (inp_compat_mode == COMPATMODE_ALL) {
/* Do all the compatibility stuff here */
working = cc->li_next;
/* E, G, L, R, C compatibility transformations */
inp_compat(working);
working = cc->li_next;
/* B source numparam compatibility transformation */
inp_bsource_compat(working);
2011-01-06 20:15:20 +01:00
}
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
/* save the return value (via **data) */
*data = cc;
/* get max. line length and number of lines in input deck,
and renumber the lines,
count the number of '{' per line as an upper estimate of the number
of parameter substitutions in a line*/
dynmaxline = 0;
max_line_length = 0;
for(tmp_ptr1 = cc; tmp_ptr1 != NULL; tmp_ptr1 = tmp_ptr1->li_next) {
char *s;
unsigned int braces_per_line = 0;
/* count number of lines */
dynmaxline++;
/* renumber the lines of the processed input deck */
tmp_ptr1->li_linenum = dynmaxline;
if (max_line_length < strlen(tmp_ptr1->li_line))
max_line_length = strlen(tmp_ptr1->li_line);
/* count '{' */
for (s = tmp_ptr1->li_line; *s; s++)
if (*s == '{') braces_per_line++;
if (no_braces < braces_per_line) no_braces = braces_per_line;
}
if (ft_ngdebug) {
/*debug: print into file*/
fdo = fopen("debug-out.txt", "w");
for(tmp_ptr1 = cc; tmp_ptr1 != NULL; tmp_ptr1 = tmp_ptr1->li_next)
fprintf(fdo, "%d %d %s\n", tmp_ptr1->li_linenum_orig, tmp_ptr1->li_linenum, tmp_ptr1->li_line);
(void) fclose(fdo);
fprintf(stdout, "max line length %d, max subst. per line %d, number of lines %d\n",
(int) max_line_length, no_braces, dynmaxline);
}
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
/*-------------------------------------------------------------------------*
Look up the variable sourcepath and try everything in the list in order
if the file isn't in . and it isn't an abs path name.
For MS Windows: First try the path of the source file.
*-------------------------------------------------------------------------*/
FILE *
inp_pathopen(char *name, char *mode)
2009-07-28 23:16:07 +02:00
{
2011-11-13 13:04:15 +01:00
FILE *fp;
char buf[BSIZE_SP];
struct variable *v;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
#if defined(HAS_WINDOWS)
char buf2[BSIZE_SP];
/* search in the path where the source (input) file has been found,
but only if "name" is just a file name */
if (!(index(name, DIR_TERM)) && !(index(name, DIR_TERM_LINUX)) && cp_getvar("sourcefile", CP_STRING, buf2)) {
/* If pathname is found, get path.
(char *dirname(const char *name) might have been used here) */
if (substring(DIR_PATHSEP, buf2) || substring(DIR_PATHSEP_LINUX, buf2)) {
int i,j=0;
for (i=0; i<BSIZE_SP-1; i++) {
if (buf2[i] == '\0') break;
if ((buf2[i] == DIR_TERM) || (buf2[i] == DIR_TERM_LINUX)) j=i;
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
buf2[j+1] = '\0'; /* include path separator */
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
/* add file name */
strcat(buf2, name);
/* try to open file */
if ((fp = fopen(buf2, mode)) != NULL)
return (fp);
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
/* If this is an abs pathname, or there is no sourcepath var, just
* do an fopen.
*/
if (index(name, DIR_TERM) || index(name, DIR_TERM_LINUX)
|| !cp_getvar("sourcepath", CP_LIST, &v))
return (fopen(name, mode));
#else
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/* If this is an abs pathname, or there is no sourcepath var, just
* do an fopen.
*/
if (index(name, DIR_TERM)
|| !cp_getvar("sourcepath", CP_LIST, &v))
return (fopen(name, mode));
#endif
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
while (v) {
switch (v->va_type) {
case CP_STRING:
cp_wstrip(v->va_string);
(void) sprintf(buf, "%s%s%s", v->va_string, DIR_PATHSEP, name);
break;
case CP_NUM:
(void) sprintf(buf, "%d%s%s", v->va_num, DIR_PATHSEP, name);
break;
case CP_REAL: /* This is foolish */
(void) sprintf(buf, "%g%s%s", v->va_real, DIR_PATHSEP, name);
break;
default: {
fprintf(stderr, "ERROR: enumeration value `CP_BOOL' or `CP_LIST' not handled in inp_pathopen\nAborting...\n" );
controlled_exit(EXIT_FAILURE);
}
}
if ((fp = fopen(buf, mode)) != NULL)
return (fp);
v = v->va_next;
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
return (NULL);
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/*-------------------------------------------------------------------------*
* This routine reads a line (of arbitrary length), up to a '\n' or 'EOF' *
* and returns a pointer to the resulting null terminated string. *
* The '\n' if found, is included in the returned string. *
* From: jason@ucbopal.BERKELEY.EDU (Jason Venner) *
* Newsgroups: net.sources *
*-------------------------------------------------------------------------*/
#define STRGROW 256
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
static char *
readline(FILE *fd)
{
int c;
int memlen;
char *strptr;
int strlen;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
strptr = NULL;
strlen = 0;
memlen = STRGROW;
strptr = TMALLOC(char, memlen);
memlen -= 1; /* Save constant -1's in while loop */
while((c = getc(fd)) != EOF) {
if (strlen == 0 && (c == '\t' || c == ' ')) /* Leading spaces away */
2011-08-06 09:53:48 +02:00
continue;
2011-11-13 13:04:15 +01:00
strptr[strlen] = (char) c;
strlen++;
if( strlen >= memlen ) {
memlen += STRGROW;
if((strptr = TREALLOC(char, strptr, memlen + 1)) == NULL) {
return (NULL);
}
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
if (c == '\n') {
break;
}
}
if (!strlen) {
tfree(strptr);
return (NULL);
}
// strptr[strlen] = '\0';
/* Trim the string */
strptr = TREALLOC(char, strptr, strlen + 1);
strptr[strlen] = '\0';
return (strptr);
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/* replace "gnd" by " 0 "
Delimiters of gnd may be ' ' or ',' or '(' or ')' */
static void
inp_fix_gnd_name( struct line *deck )
{
struct line *c = deck;
char *gnd;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
while ( c != NULL ) {
gnd = c->li_line;
// if there is a comment or no gnd, go to next line
if (( *gnd == '*' ) || (strstr( gnd, "gnd" ) == NULL)) {
c = c->li_next;
continue;
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
// replace "<22>gnd<6E>" by "<22> 0 <20>", <20> being a ' ' ',' '(' ')'.
while ((gnd = strstr( gnd, "gnd" )) != NULL) {
if (( isspace(*(gnd-1)) || *(gnd-1) == '(' || *(gnd-1) == ',' ) &&
( isspace(*(gnd+3)) || *(gnd+3) == ')' || *(gnd+3) == ',' )) {
memcpy( gnd, " 0 ", 3 );
}
gnd += 3;
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
// now remove the extra white spaces around 0
c->li_line = inp_remove_ws(c->li_line);
c = c->li_next;
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
static struct line*
create_new_card( char *card_str, int *line_number ) {
char *str = strdup(card_str);
struct line *newcard = alloc(struct line);
2010-01-17 17:40:22 +01:00
2011-11-13 13:04:15 +01:00
newcard->li_line = str;
newcard->li_linenum = *line_number;
newcard->li_error = NULL;
newcard->li_actual = NULL;
2010-01-17 17:40:22 +01:00
2011-11-13 13:04:15 +01:00
*line_number = *line_number + 1;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
return newcard;
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
static void
inp_chk_for_multi_in_vcvs( struct line *deck, int *line_number )
{
struct line *c, *a_card, *model_card, *next_card;
char *line, *bool_ptr, *str_ptr1, *str_ptr2, keep, *comma_ptr, *xy_values1[5], *xy_values2[5];
char *node_str, *ctrl_node_str, *xy_str1, *model_name, *fcn_name;
char big_buf[1000];
int xy_count1 = 0, xy_count2 = 0, skip_control = 0;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
for ( c = deck; c != NULL; c = c->li_next ) {
str_ptr1 = line = c->li_line;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
/* there is no e source inside .control ... .endc */
if ( ciprefix(".control", line) ) {
skip_control ++;
continue;
} else if( ciprefix(".endc", line) ) {
skip_control --;
continue;
} else if(skip_control > 0) {
continue;
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( *line == 'e' ) {
if ( (bool_ptr = strstr( line, "nand(" )) != NULL ||
(bool_ptr = strstr( line, "and(" )) != NULL ||
(bool_ptr = strstr( line, "nor(" )) != NULL ||
(bool_ptr = strstr( line, "or(" )) != NULL ) {
while ( !isspace(*str_ptr1) ) str_ptr1++;
keep = *str_ptr1;
*str_ptr1 = '\0';
model_name = strdup(line);
*str_ptr1 = keep;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
str_ptr2 = bool_ptr - 1;
while ( isspace(*str_ptr1) ) str_ptr1++;
while ( isspace(*str_ptr2) ) str_ptr2--;
str_ptr2++;
keep = *str_ptr2;
*str_ptr2 = '\0';
node_str = strdup(str_ptr1);
*str_ptr2 = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
str_ptr1 = bool_ptr + 1;
while ( *str_ptr1 != '(' ) str_ptr1++;
*str_ptr1 = '\0';
fcn_name = strdup(bool_ptr);
*str_ptr1 = '(';
str_ptr1 = strstr( str_ptr1, ")" );
comma_ptr = str_ptr2 = strstr( line, "," );
if ((str_ptr1 == NULL)|| (str_ptr1 == NULL)) {
fprintf(stderr,"ERROR: mal formed line: %s\n", line);
controlled_exit(EXIT_FAILURE);
}
str_ptr1++;
str_ptr2--;
while( isspace(*str_ptr2) ) str_ptr2--;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
while ( isspace(*str_ptr1) ) str_ptr1++;
if ( *str_ptr2 == '}' ) {
while ( *str_ptr2 != '{' ) str_ptr2--;
xy_str1 = str_ptr2;
str_ptr2--;
while ( isspace(*str_ptr2) ) str_ptr2--;
str_ptr2++;
} else {
while ( !isspace(*str_ptr2) ) str_ptr2--;
xy_str1 = str_ptr2 + 1;
while ( isspace(*str_ptr2) ) str_ptr2--;
str_ptr2++;
}
keep = *str_ptr2;
*str_ptr2 = '\0';
ctrl_node_str = strdup(str_ptr1);
*str_ptr2 = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
str_ptr1 = comma_ptr + 1;
while ( isspace(*str_ptr1) ) str_ptr1++;
if ( *str_ptr1 == '{' ) {
while ( *str_ptr1 != '}' ) str_ptr1++;
str_ptr1++;
} else {
while ( !isspace(*str_ptr1) ) str_ptr1++;
}
keep = *str_ptr1;
*str_ptr1 = '\0';
xy_count1 = get_comma_separated_values( xy_values1, xy_str1 );
*str_ptr1 = keep;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
while ( isspace(*str_ptr1) ) str_ptr1++;
xy_count2 = get_comma_separated_values( xy_values2, str_ptr1 );
// place restrictions on only having 2 point values; this can change later
if ( xy_count1 != 2 && xy_count2 != 2 ) {
fprintf(stderr,"ERROR: only expecting 2 pair values for multi-input vcvs!\n");
}
sprintf( big_buf, "%s %%vd[ %s ] %%vd( %s ) %s",
model_name, ctrl_node_str, node_str, model_name );
a_card = create_new_card( big_buf, line_number );
*a_card->li_line = 'a';
sprintf( big_buf, ".model %s multi_input_pwl ( x = [%s %s] y = [%s %s] model = \"%s\" )"
, model_name, xy_values1[0], xy_values2[0],
xy_values1[1], xy_values2[1], fcn_name );
model_card = create_new_card( big_buf, line_number );
tfree(model_name);
tfree(node_str);
tfree(fcn_name);
tfree(ctrl_node_str);
tfree(xy_values1[0]);
tfree(xy_values1[1]);
tfree(xy_values2[0]);
tfree(xy_values2[1]);
*c->li_line = '*';
next_card = c->li_next;
c->li_next = a_card;
a_card->li_next = model_card;
model_card->li_next = next_card;
2011-08-06 09:53:48 +02:00
}
}
2011-11-13 13:04:15 +01:00
}
}
static void
inp_add_control_section( struct line *deck, int *line_number )
{
struct line *c, *newcard, *prev_card = NULL;
bool found_control = FALSE, found_run = FALSE;
bool found_end = FALSE;
char *op_line = NULL, rawfile[1000], *line;
for ( c = deck; c != NULL; c = c->li_next ) {
if ( *c->li_line == '*' ) continue;
if ( ciprefix( ".op ", c->li_line ) ) {
*c->li_line = '*';
op_line = c->li_line + 1;
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
if ( ciprefix( ".end", c->li_line ) ) found_end = TRUE;
if ( found_control && ciprefix( "run", c->li_line ) ) found_run = TRUE;
if ( ciprefix( ".control", c->li_line ) ) found_control = TRUE;
if ( ciprefix( ".endc", c->li_line ) ) {
found_control = FALSE;
if ( !found_run ) {
newcard = create_new_card( "run", line_number );
prev_card->li_next = newcard;
newcard->li_next = c;
prev_card = newcard;
found_run = TRUE;
}
if ( cp_getvar( "rawfile", CP_STRING, rawfile ) ) {
line = TMALLOC(char, strlen("write") + strlen(rawfile) + 2);
sprintf(line, "write %s", rawfile);
newcard = create_new_card( line, line_number );
prev_card->li_next = newcard;
newcard->li_next = c;
prev_card = newcard;
tfree(line);
}
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
prev_card = c;
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
// check if need to add control section
if ( !found_run && found_end ) {
prev_card = deck->li_next;
newcard = create_new_card( ".endc", line_number );
deck->li_next = newcard;
newcard->li_next = prev_card;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( cp_getvar( "rawfile", CP_STRING, rawfile ) ) {
line = TMALLOC(char, strlen("write") + strlen(rawfile) + 2);
sprintf(line, "write %s", rawfile);
prev_card = deck->li_next;
newcard = create_new_card( line, line_number );
deck->li_next = newcard;
newcard->li_next = prev_card;
tfree(line);
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
if ( op_line != NULL ) {
prev_card = deck->li_next;
newcard = create_new_card( op_line, line_number );
deck->li_next = newcard;
newcard->li_next = prev_card;
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
prev_card = deck->li_next;
newcard = create_new_card( "run", line_number );
deck->li_next = newcard;
newcard->li_next = prev_card;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
prev_card = deck->li_next;
newcard = create_new_card( ".control", line_number );
deck->li_next = newcard;
newcard->li_next = prev_card;
}
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
// look for shell-style end-of-line continuation '\\'
static bool
chk_for_line_continuation( char *line )
2009-07-28 23:16:07 +02:00
{
2011-11-13 13:04:15 +01:00
char *ptr = line + strlen(line) - 1;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( *line != '*' && *line != '$' ) {
while ( ptr >= line && *ptr && isspace(*ptr) ) ptr--;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( (ptr-1) >= line && *ptr == '\\' && *(ptr-1) && *(ptr-1) == '\\' ) {
*ptr = ' ';
*(ptr-1) = ' ';
return TRUE;
2011-08-06 09:53:48 +02:00
}
}
2011-11-13 13:04:15 +01:00
return FALSE;
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
//
// change .macro --> .subckt
// .eom --> .ends
// .subckt name 1 2 3 params: w=9u l=180n --> .subckt name 1 2 3 w=9u l=180n
2011-11-13 13:04:15 +01:00
// .subckt name (1 2 3) --> .subckt name 1 2 3
// x1 (1 2 3) --> x1 1 2 3
// .param func1(x,y) = {x*y} --> .func func1(x,y) {x*y}
2011-11-13 13:04:15 +01:00
static void
inp_fix_macro_param_func_paren_io( struct line *begin_card )
2009-07-28 23:16:07 +02:00
{
2011-11-13 13:04:15 +01:00
struct line *card;
char *str_ptr, *new_str;
bool is_func = FALSE;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
for ( card = begin_card; card != NULL; card = card->li_next ) {
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( *card->li_line == '*' ) continue;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( ciprefix( ".macro", card->li_line ) || ciprefix( ".eom", card->li_line ) ) {
str_ptr = card->li_line;
while( !isspace(*str_ptr) ) str_ptr++;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( ciprefix( ".macro", card->li_line ) ) {
new_str = TMALLOC(char, strlen(".subckt") + strlen(str_ptr) + 1);
sprintf( new_str, ".subckt%s", str_ptr );
2011-08-06 09:53:48 +02:00
} else {
2011-11-13 13:04:15 +01:00
new_str = TMALLOC(char, strlen(".ends") + strlen(str_ptr) + 1);
sprintf( new_str, ".ends%s", str_ptr );
2009-07-28 23:16:07 +02:00
}
2011-11-13 13:04:15 +01:00
tfree( card->li_line );
card->li_line = new_str;
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
if ( ciprefix( ".subckt", card->li_line ) || ciprefix( "x", card->li_line ) ) {
/* remove ( ) */
2011-11-13 13:04:15 +01:00
str_ptr = card->li_line;
while( !isspace(*str_ptr) ) str_ptr++; // skip over .subckt, instance name
while( isspace(*str_ptr) ) str_ptr++;
if ( ciprefix( ".subckt", card->li_line ) ) {
while( !isspace(*str_ptr) ) str_ptr++; // skip over subckt name
while( isspace(*str_ptr) ) str_ptr++;
}
if ( *str_ptr == '(' ) {
*str_ptr = ' ';
while ( *str_ptr && *str_ptr != '\0' ) {
if ( *str_ptr == ')' ) {
*str_ptr = ' ';
break;
}
str_ptr++;
}
card->li_line = inp_remove_ws(card->li_line); /* remove the extra white spaces just introduced */
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
is_func = FALSE;
if ( ciprefix( ".param", card->li_line ) ) {
str_ptr = card->li_line;
while ( !isspace( *str_ptr ) ) str_ptr++; // skip over .param
while ( isspace( *str_ptr ) ) str_ptr++;
while ( !isspace( *str_ptr ) && *str_ptr != '=' ) {
if ( *str_ptr == '(' ) is_func = TRUE;
str_ptr++;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( is_func ) {
str_ptr = strstr( card->li_line, "=" );
if ( str_ptr )
*str_ptr = ' ';
str_ptr = card->li_line + 1;
*str_ptr = 'f';
*(str_ptr+1) = 'u';
*(str_ptr+2) = 'n';
*(str_ptr+3) = 'c';
*(str_ptr+4) = ' ';
}
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
}
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
static char *
get_instance_subckt( char *line )
{
char *equal_ptr = NULL, *end_ptr = line + strlen(line) - 1, *inst_name_ptr = NULL, *inst_name = NULL;
char keep = ' ';
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
// see if instance has parameters
if ((equal_ptr = strstr(line, "=")) != NULL) {
end_ptr = equal_ptr - 1;
while ( isspace(*end_ptr) ) end_ptr--;
while ( !isspace(*end_ptr) ) end_ptr--;
while ( isspace(*end_ptr) ) end_ptr--;
end_ptr++;
keep = *end_ptr;
*end_ptr = '\0';
}
inst_name_ptr = end_ptr;
while ( !isspace(*inst_name_ptr) ) inst_name_ptr--;
inst_name_ptr++;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
inst_name = strdup(inst_name_ptr);
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( equal_ptr ) *end_ptr = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
return inst_name;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
static char*
get_subckt_model_name( char *line )
{
char *name = line, *end_ptr = NULL, *subckt_name;
char keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
while ( !isspace( *name ) ) name++; // eat .subckt|.model
while ( isspace( *name ) ) name++;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
end_ptr = name;
while ( !isspace( *end_ptr ) ) end_ptr++;
keep = *end_ptr;
*end_ptr = '\0';
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
subckt_name = strdup(name);
*end_ptr = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
return subckt_name;
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
static char*
get_model_name( char *line, int num_terminals )
{
char *beg_ptr = line, *end_ptr, keep, *model_name = NULL;
int i = 0;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
while ( !isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++; /* eat device name */
while ( isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
for ( i = 0; i < num_terminals; i++ ) { /* skip the terminals */
while ( !isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++;
while ( isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++;
}
if ( *line == 'r' ) { /* special dealing for r models */
if((*beg_ptr=='+') || (*beg_ptr=='-') || isdigit(*beg_ptr)) { /* looking for a value before model */
while ( !isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++; /* skip the value */
while ( isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++;
}
}
end_ptr = beg_ptr;
while ( *end_ptr != '\0' && !isspace( *end_ptr ) ) end_ptr++;
keep = *end_ptr;
*end_ptr = '\0';
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
model_name = strdup( beg_ptr );
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
*end_ptr = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
return model_name;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
static char *
get_adevice_model_name( char *line )
{
char *model_name, *ptr_end = line + strlen(line), *ptr_beg, keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
while ( isspace( *(ptr_end-1) ) ) ptr_end--;
ptr_beg = ptr_end - 1;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
while ( !isspace(*ptr_beg) ) ptr_beg--;
ptr_beg++;
keep = *ptr_end;
*ptr_end = '\0';
model_name = strdup(ptr_beg);
*ptr_end = keep;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
return model_name;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
static void
get_subckts_for_subckt( struct line *start_card, char *subckt_name,
char *used_subckt_names[], int *num_used_subckt_names,
char *used_model_names[], int *num_used_model_names,
bool has_models )
{
struct line *card;
char *line = NULL, *curr_subckt_name, *inst_subckt_name, *model_name, *new_names[100];
bool found_subckt = FALSE, have_subckt = FALSE, found_model = FALSE;
int i, num_terminals = 0, tmp_cnt = 0;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
for ( card = start_card; card != NULL; card = card->li_next ) {
line = card->li_line;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( *line == '*' ) continue;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( ( ciprefix( ".ends", line ) || ciprefix( ".eom", line ) ) && found_subckt )
break;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( ciprefix( ".subckt", line ) || ciprefix( ".macro", line ) ) {
curr_subckt_name = get_subckt_model_name( line );
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( strcmp( curr_subckt_name, subckt_name ) == 0 ) {
found_subckt = TRUE;
}
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
tfree(curr_subckt_name);
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
if ( found_subckt ) {
if ( *line == 'x' ) {
inst_subckt_name = get_instance_subckt( line );
have_subckt = FALSE;
for ( i = 0; i < *num_used_subckt_names; i++ )
if ( strcmp( used_subckt_names[i], inst_subckt_name ) == 0 )
have_subckt = TRUE;
if ( !have_subckt ) {
new_names[tmp_cnt++] = used_subckt_names[*num_used_subckt_names] = inst_subckt_name;
*num_used_subckt_names = *num_used_subckt_names + 1;
} else tfree( inst_subckt_name );
} else if ( *line == 'a' ) {
model_name = get_adevice_model_name( line );
found_model = FALSE;
for ( i = 0; i < *num_used_model_names; i++ )
if ( strcmp( used_model_names[i], model_name ) == 0 ) found_model = TRUE;
if ( !found_model ) {
used_model_names[*num_used_model_names] = model_name;
*num_used_model_names = *num_used_model_names + 1;
} else tfree( model_name );
} else if ( has_models ) {
num_terminals = get_number_terminals( line );
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( num_terminals != 0 ) {
char *tmp_name, *tmp_name1;
tmp_name1 = tmp_name = model_name = get_model_name( line, num_terminals );
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( isalpha( *model_name ) ||
/* first character is digit, second is alpha, third is digit,
e.g. 1N4002 */
((strlen(model_name) > 2) && isdigit(*tmp_name) &&
isalpha(*(++tmp_name)) && isdigit(*(++tmp_name))) ||
/* first character is is digit, second is alpha, third is alpha, fourth is digit
e.g. 2SK456 */
((strlen(model_name) > 3) && isdigit(*tmp_name1) && isalpha(*(++tmp_name1)) &&
isalpha(*(++tmp_name1)) && isdigit(*(++tmp_name1)))) {
found_model = FALSE;
for ( i = 0; i < *num_used_model_names; i++ )
if ( strcmp( used_model_names[i], model_name ) == 0 ) found_model = TRUE;
if ( !found_model ) {
used_model_names[*num_used_model_names] = model_name;
*num_used_model_names = *num_used_model_names + 1;
} else tfree( model_name );
} else {
tfree( model_name );
}
}
}
2011-08-06 09:53:48 +02:00
}
}
2011-11-13 13:04:15 +01:00
// now make recursive call on instances just found above
for ( i = 0; i < tmp_cnt; i++ )
get_subckts_for_subckt( start_card, new_names[i], used_subckt_names, num_used_subckt_names,
used_model_names, num_used_model_names, has_models );
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/*
check if current token matches model bin name -- <token>.[0-9]+
*/
static bool
model_bin_match( char* token, char* model_name )
{
char* dot_char;
bool flag = FALSE;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( strncmp( model_name, token, strlen(token) ) == 0 ) {
if ((dot_char = strstr( model_name, "." )) != NULL) {
flag = TRUE;
dot_char++;
while( *dot_char != '\0' ) {
if ( !isdigit( *dot_char ) ) {
flag = FALSE;
break;
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
dot_char++;
}
2011-08-06 09:53:48 +02:00
}
}
2011-11-13 13:04:15 +01:00
return flag;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/*
iterate through the deck and comment out unused subckts, models
(don't want to waste time processing everything)
also comment out .param lines with no parameters defined
*/
static void
comment_out_unused_subckt_models( struct line *start_card , int no_of_lines)
{
struct line *card;
char **used_subckt_names, **used_model_names, *line = NULL, *subckt_name, *model_name;
int num_used_subckt_names = 0, num_used_model_names = 0, i = 0, num_terminals = 0, tmp_cnt = 0;
bool processing_subckt = FALSE, found_subckt = FALSE, remove_subckt = FALSE, found_model = FALSE, has_models = FALSE;
int skip_control = 0;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/* generate arrays of *char for subckt or model names. Start
with 1000, but increase, if number of lines in deck is larger */
if (no_of_lines < 1000) no_of_lines = 1000;
used_subckt_names = TMALLOC(char*, no_of_lines);
used_model_names = TMALLOC(char*, no_of_lines);
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
for ( card = start_card; card != NULL; card = card->li_next ) {
if ( ciprefix( ".model", card->li_line ) ) has_models = TRUE;
if ( ciprefix( ".cmodel", card->li_line ) ) has_models = TRUE;
if ( ciprefix( ".param", card->li_line ) && !strstr( card->li_line, "=" ) ) *card->li_line = '*';
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
for ( card = start_card; card != NULL; card = card->li_next ) {
line = card->li_line;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( *line == '*' ) continue;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/* there is no .subckt, .model or .param inside .control ... .endc */
if ( ciprefix(".control", line) ) {
skip_control ++;
continue;
} else if( ciprefix(".endc", line) ) {
skip_control --;
continue;
} else if(skip_control > 0) {
continue;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( ciprefix( ".subckt", line ) || ciprefix( ".macro", line ) ) processing_subckt = TRUE;
if ( ciprefix( ".ends", line ) || ciprefix( ".eom", line ) ) processing_subckt = FALSE;
if ( !processing_subckt ) {
if ( *line == 'x' ) {
subckt_name = get_instance_subckt( line );
found_subckt = FALSE;
for ( i = 0; i < num_used_subckt_names; i++ )
if ( strcmp( used_subckt_names[i], subckt_name ) == 0 ) found_subckt = TRUE;
if ( !found_subckt ) {
used_subckt_names[num_used_subckt_names++] = subckt_name;
tmp_cnt++;
} else tfree( subckt_name );
} else if ( *line == 'a' ) {
model_name = get_adevice_model_name( line );
found_model = FALSE;
for ( i = 0; i < num_used_model_names; i++ )
if ( strcmp( used_model_names[i], model_name ) == 0 ) found_model = TRUE;
if ( !found_model ) used_model_names[num_used_model_names++] = model_name;
else tfree( model_name );
} else if ( has_models ) {
/* This is a preliminary version, until we have found a reliable
method to detect the model name out of the input line (Many
options have to be taken into account.). */
num_terminals = get_number_terminals( line );
if ( num_terminals != 0 ) {
bool model_ok = FALSE;
char *tmp_name, *tmp_name1;
tmp_name = tmp_name1 = model_name = get_model_name( line, num_terminals );
/* first character of model name is character from alphabet */
if ( isalpha( *model_name ) ) model_ok = TRUE;
/* first character is digit, second is alpha, third is digit,
e.g. 1N4002 */
else if ((strlen(model_name) > 2) && isdigit(*tmp_name) && isalpha(*(++tmp_name)) &&
isdigit(*(++tmp_name))) model_ok = TRUE;
/* first character is is digit, second is alpha, third is alpha, fourth is digit
e.g. 2SK456 */
else if ((strlen(model_name) > 3) && isdigit(*tmp_name1) && isalpha(*(++tmp_name1)) &&
isalpha(*(++tmp_name1)) && isdigit(*(++tmp_name1))) model_ok = TRUE;
/* Check if model has already been recognized, if not, add its name to
list used_model_names[i] */
if (model_ok) {
found_model = FALSE;
for ( i = 0; i < num_used_model_names; i++ )
if ( strcmp( used_model_names[i], model_name ) == 0 ) found_model = TRUE;
if ( !found_model ) used_model_names[num_used_model_names++] = model_name;
else tfree( model_name );
} else {
tfree( model_name );
}
}
} /* if ( has_models ) */
} /* if ( !processing_subckt ) */
} /* for loop through all cards */
for ( i = 0; i < tmp_cnt; i++ )
get_subckts_for_subckt( start_card, used_subckt_names[i], used_subckt_names,
&num_used_subckt_names, used_model_names, &num_used_model_names, has_models );
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/* comment out any unused subckts */
for ( card = start_card; card != NULL; card = card->li_next ) {
line = card->li_line;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( *line == '*' ) continue;
2009-07-28 23:16:07 +02:00
2011-11-13 13:04:15 +01:00
if ( ciprefix( ".subckt", line ) || ciprefix( ".macro", line ) ) {
subckt_name = get_subckt_model_name( line );
remove_subckt = TRUE;
for ( i = 0; i < num_used_subckt_names; i++ )
if ( strcmp( used_subckt_names[i], subckt_name ) == 0 ) remove_subckt = FALSE;
tfree(subckt_name);
}
if ( ciprefix( ".ends", line ) || ciprefix( ".eom", line ) ) {
if ( remove_subckt ) *line = '*';
remove_subckt = FALSE;
}
if ( remove_subckt ) *line = '*';
else if ( has_models && (ciprefix( ".model", line ) || ciprefix( ".cmodel", line )) ) {
model_name = get_subckt_model_name( line );
found_model = FALSE;
for ( i = 0; i < num_used_model_names; i++ )
if ( strcmp( used_model_names[i], model_name ) == 0 || model_bin_match( used_model_names[i], model_name ) ) found_model = TRUE;
2011-12-15 21:44:45 +01:00
#if ADMS >= 3
/* ngspice strategy to detect unused models fails with dynamic models - reason: # of terms unknown during parsing */
#else
2011-11-13 13:04:15 +01:00
if ( !found_model ) *line = '*';
#endif
2011-11-13 13:04:15 +01:00
tfree(model_name);
2011-08-06 09:53:48 +02:00
}
}
2011-11-13 13:04:15 +01:00
for ( i = 0; i < num_used_subckt_names; i++ ) tfree(used_subckt_names[i]);
for ( i = 0; i < num_used_model_names; i++ ) tfree(used_model_names[i]);
tfree(used_subckt_names);
tfree(used_model_names);
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
/* replace ternary operator ? : by fcn ternary_fcn() in .param, .func, and .meas lines */
static char*
inp_fix_ternary_operator_str( char *line )
{
char *conditional, *if_str, *else_str, *question, *colon, keep, *str_ptr, *str_ptr2, *new_str;
char *paren_ptr = NULL, *end_str = NULL, *beg_str = NULL;
int count = 0;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( !strstr( line, "?" ) && !strstr( line, ":" ) ) return line;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
str_ptr = line;
if ( ciprefix( ".param", line ) || ciprefix( ".func", line ) || ciprefix( ".meas", line ) ) {
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
str_ptr = line;
if ( ciprefix( ".param", line ) || ciprefix( ".meas", line ) ) str_ptr = strstr( line, "=" );
else str_ptr = strstr( line, ")" );
if (str_ptr == NULL) {
fprintf(stderr,"ERROR: mal formed .param, .func or .meas line: %s\n", line);
controlled_exit(EXIT_FAILURE);
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
str_ptr++;
while( isspace(*str_ptr) ) str_ptr++;
if ( *str_ptr == '{' ) {
str_ptr++;
while( isspace(*str_ptr) ) str_ptr++;
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
question = strstr( str_ptr, "?" );
paren_ptr = strstr( str_ptr, "(" );
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( paren_ptr != NULL && paren_ptr < question ) {
paren_ptr = NULL;
}
} else return line;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
// get conditional
str_ptr2 = question = strstr( str_ptr, "?" );
str_ptr2--;
while ( isspace(*str_ptr2) ) str_ptr2--;
if ( *str_ptr2 == ')' ) {
count = 1;
str_ptr = str_ptr2;
while ( (count != 0) && (str_ptr != line) ) {
str_ptr--;
if ( *str_ptr == '(' ) count--;
if ( *str_ptr == ')' ) count++;
2011-08-06 09:53:48 +02:00
}
}
2011-11-13 13:04:15 +01:00
str_ptr2++;
keep = *str_ptr2;
*str_ptr2 = '\0';
conditional = strdup(str_ptr);
*str_ptr2 = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
// get beginning (whatever is left before the conditional)
keep = *str_ptr;
*str_ptr = '\0';
beg_str = strdup(line);
*str_ptr = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
// get if
str_ptr = question + 1;
while ( isspace(*str_ptr) ) str_ptr++;
if ( *str_ptr == '(' ) {
// find closing paren
count = 1;
str_ptr2 = str_ptr/* + 1*/;
while ( count != 0 && *str_ptr2 != '\0' ) {
str_ptr2++;
if ( *str_ptr2 == '(' ) count++;
if ( *str_ptr2 == ')' ) count--;
}
if ( count != 0 ) {
fprintf(stderr, "ERROR: problem parsing 'if' of ternary string %s!\n", line);
controlled_exit(EXIT_FAILURE);
}
colon = str_ptr2 + 1;
while ( *colon != ':' && *colon != '\0' ) colon++;
if ( *colon != ':' ) {
fprintf(stderr,"ERROR: problem parsing ternary string (finding ':') %s!\n", line);
controlled_exit(EXIT_FAILURE);
}
str_ptr2 = colon - 1;
while ( isspace(*str_ptr2) ) str_ptr2--;
} else if ((colon = strstr( str_ptr, ":" )) != NULL) {
str_ptr2 = colon - 1;
while ( isspace(*str_ptr2) ) str_ptr2--;
} else {
fprintf(stderr,"ERROR: problem parsing ternary string (missing ':') %s!\n", line);
controlled_exit(EXIT_FAILURE);
2011-08-06 09:53:48 +02:00
}
2011-11-13 13:04:15 +01:00
str_ptr2++;
keep = *str_ptr2;
*str_ptr2 = '\0';
if_str = inp_fix_ternary_operator_str(strdup(str_ptr));
*str_ptr2 = keep;
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
// get else
str_ptr = colon + 1;
while ( isspace(*str_ptr) ) str_ptr++;
if ( paren_ptr != NULL ) {
// find end paren ')'
bool found_paren = FALSE;
count = 0;
str_ptr2 = str_ptr;
while ( *str_ptr2 != '\0' ) {
if ( *str_ptr2 == '(' ) {
count++;
found_paren = TRUE;
}
if ( *str_ptr2 == ')' ) count--;
str_ptr2++;
if ( found_paren && count == 0 ) break;
}
if ( found_paren && count != 0 ) {
fprintf( stderr, "ERROR: problem parsing ternary line %s!\n", line );
controlled_exit(EXIT_FAILURE);
}
keep = *str_ptr2;
*str_ptr2 = '\0';
else_str = inp_fix_ternary_operator_str(strdup(str_ptr));
if ( keep != '}' ) {
end_str = inp_fix_ternary_operator_str(strdup(str_ptr2+1));
} else {
*str_ptr2 = keep;
end_str = strdup(str_ptr2);
}
*str_ptr2 = keep;
} else {
if ((str_ptr2 = strstr(str_ptr, "}")) != NULL) {
*str_ptr2 = '\0';
else_str = inp_fix_ternary_operator_str(strdup(str_ptr));
*str_ptr2 = '}';
end_str = strdup(str_ptr2);
} else {
else_str = inp_fix_ternary_operator_str(strdup(str_ptr));
}
}
2011-08-06 09:53:48 +02:00
2011-11-13 13:04:15 +01:00
if ( end_str != NULL ) {
if ( beg_str != NULL ) {
new_str = TMALLOC(char, strlen(beg_str) + strlen("ternary_fcn") + strlen(conditional) + strlen(if_str) + strlen(else_str) + strlen(end_str) + 5);
sprintf( new_str, "%sternary_fcn(%s,%s,%s)%s", beg_str, conditional, if_str, else_str, end_str );
} else {
new_str = TMALLOC(char, strlen("ternary_fcn") + strlen(conditional) + strlen(if_str) + strlen(else_str) + strlen(end_str) + 5);
sprintf( new_str, "ternary_fcn(%s,%s,%s)%s", conditional, if_str, else_str, end_str );
}
} else {
if ( beg_str != NULL ) {
new_str = TMALLOC(char, strlen(beg_str) + strlen("ternary_fcn") + strlen(conditional) + strlen(if_str) + strlen(else_str) + 5);
sprintf( new_str, "%sternary_fcn(%s,%s,%s)", beg_str, conditional, if_str, else_str );
} else {
new_str = TMALLOC(char, strlen("ternary_fcn") + strlen(conditional) + strlen(if_str) + strlen(else_str) + 5);
sprintf( new_str, "ternary_fcn(%s,%s,%s)", conditional, if_str, else_str );
}
}
tfree(line);
tfree(conditional);
tfree(if_str);
tfree(else_str);
if ( beg_str != NULL ) tfree(beg_str);
if ( end_str != NULL ) tfree(end_str);
return new_str;
}
static void
inp_fix_ternary_operator( struct line *start_card )
{
struct line *card;
char *line;
bool found_control = FALSE;
for ( card = start_card; card != NULL; card = card->li_next ) {
line = card->li_line;
/* exclude replacement of ternary function between .control and .endc */
if ( ciprefix( ".control", line ) ) found_control = TRUE;
if ( ciprefix( ".endc", line ) ) found_control = FALSE;
if (found_control) continue;
/* ternary operator for B source done elsewhere */
if ( *line == 'B' || *line == 'b' ) continue;
if ( *line == '*' ) continue;
if ( strstr( line, "?" ) && strstr( line, ":" ) ) {
card->li_line = inp_fix_ternary_operator_str( line );
}
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
}
/*-------------------------------------------------------------------------*
2011-08-06 09:53:48 +02:00
removes " " quotes, returns lower case letters,
2009-09-13 21:42:19 +02:00
replaces non-printable characterss with '_' *
2009-07-28 23:16:07 +02:00
*-------------------------------------------------------------------------*/
void
inp_casefix(char *string)
{
#ifdef HAVE_CTYPE_H
2011-08-06 09:53:48 +02:00
if (string)
while (*string) {
2009-07-28 23:16:07 +02:00
#ifdef HAS_ASCII
2011-08-06 09:53:48 +02:00
/* ((*string) & 0177): mask off all but the first seven bits, 0177: octal */
*string = (char) strip(*string);
2009-07-28 23:16:07 +02:00
#endif
2011-08-06 09:53:48 +02:00
if (*string == '"') {
*string++ = ' ';
while (*string && *string != '"')
string++;
if (*string== '\0') continue; /* needed if string is "something ! */
if (*string == '"')
*string = ' ';
}
if (!isspace(*string) && !isprint(*string))
*string = '_';
if (isupper(*string))
*string = (char) tolower(*string);
string++;
}
return;
2009-07-28 23:16:07 +02:00
#endif
}
2011-08-06 09:53:48 +02:00
2009-07-28 23:16:07 +02:00
/* Strip all end-of-line comments from a deck */
static void
inp_stripcomments_deck(struct line *deck)
{
struct line *c=deck;
while( c!=NULL) {
2011-08-06 09:53:48 +02:00
inp_stripcomments_line(c->li_line);
c= c->li_next;
2009-07-28 23:16:07 +02:00
}
}
2011-11-13 13:04:15 +01:00
/*
* SJB 21 April 2005
* Added support for end-of-line comments that begin with any of the following:
* ';'
* '$ '
* '//' (like in c++ and as per the numparam code)
* '--' (as per the numparam code)
* Any following text to the end of the line is ignored.
* Note requirement for $ to be followed by a space. This is to avoid conflict
* with use in front of a variable.
* Comments on a contunuation line (i.e. line begining with '+') are allowed
* and are removed before lines are stitched.
* Lines that contain only an end-of-line comment with or without leading white
* space are also allowed.
2009-07-28 23:16:07 +02:00
If there is only white space before the end-of-line comment the
the whole line is converted to a normal comment line (i.e. one that
begins with a '*').
2011-08-06 09:53:48 +02:00
BUG: comment characters in side of string literals are not ignored. */
2009-07-28 23:16:07 +02:00
static void
inp_stripcomments_line(char * s)
{
char c = ' '; /* anything other than a comment character */
char * d = s;
2010-05-16 13:55:07 +02:00
if(*s=='\0') return; /* empty line */
2011-08-06 09:53:48 +02:00
if(*s=='*') return; /* line is already a comment */
2009-07-28 23:16:07 +02:00
/* look for comments */
while((c=*d)!='\0') {
2011-08-06 09:53:48 +02:00
d++;
if (*d==';') {
break;
} else if ((c=='$') && (*d==' ')) {
d--; /* move d back to first comment character */
break;
} else if( (*d==c) && ((c=='/') || (c=='-'))) {
d--; /* move d back to first comment character */
break;
}
2009-07-28 23:16:07 +02:00
}
/* d now points to the first comment character of the null at the string end */
2011-08-06 09:53:48 +02:00
2009-07-28 23:16:07 +02:00
/* check for special case of comment at start of line */
if(d==s) {
2011-08-06 09:53:48 +02:00
*s = '*'; /* turn into normal comment */
return;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
2009-07-28 23:16:07 +02:00
if(d>s) {
2011-08-06 09:53:48 +02:00
d--;
/* d now points to character just before comment */
/* eat white space at end of line */
while(d>=s) {
if( (*d!=' ') && (*d!='\t' ) )
break;
d--;
}
d++;
/* d now points to the first white space character before the
end-of-line or end-of-line comment, or it points to the first
end-of-line comment character, or to the begining of the line */
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
/* Check for special case of comment at start of line
2009-07-28 23:16:07 +02:00
with or without preceeding white space */
if(d<=s) {
2011-08-06 09:53:48 +02:00
*s = '*'; /* turn the whole line into normal comment */
return;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
*d='\0'; /* terminate line in new location */
2009-07-28 23:16:07 +02:00
}
static void
inp_change_quotes( char *s )
{
2011-08-06 09:53:48 +02:00
bool first_quote = FALSE;
while ( *s ) {
if ( *s == '\'' ) {
if ( first_quote == FALSE ) {
*s = '{';
first_quote = TRUE;
} else {
*s = '}';
first_quote = FALSE;
}
}
s++;
}
2009-07-28 23:16:07 +02:00
}
static char*
inp_fix_subckt( char *s )
{
2011-08-06 09:53:48 +02:00
struct line *head=NULL, *newcard=NULL, *start_card=NULL, *end_card=NULL, *prev_card=NULL, *c=NULL;
char *equal = strstr( s, "=" );
char *beg, *buffer, *ptr1, *ptr2, *str, *new_str = NULL;
char keep;
int num_params = 0, i = 0;
if ( !strstr( s, "params:" ) && equal != NULL ) {
/* get subckt name (ptr1 will point to name) */
for ( ptr1 = s; *ptr1 && !isspace(*ptr1); ptr1++ )
;
while ( isspace(*ptr1) ) ptr1++;
for ( ptr2 = ptr1; *ptr2 && !isspace(*ptr2) && !isquote(*ptr2); ptr2++ )
;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
keep = *ptr2;
*ptr2 = '\0';
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
subckt_w_params[num_subckt_w_params++] = strdup(ptr1);
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
*ptr2 = keep;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
/* go to beginning of first parameter word */
/* s will contain only subckt definition */
/* beg will point to start of param list */
for ( beg = equal-1; *beg && isspace(*beg); beg-- )
;
for ( ; *beg && !isspace(*beg); beg-- )
;
*beg = '\0';
beg++;
head = alloc(struct line);
/* create list of parameters that need to get sorted */
while ( *beg && (ptr1 = strstr( beg, "=" )) != NULL ) {
ptr2 = ptr1+1;
ptr1--;
while ( isspace(*ptr1) ) ptr1--;
while ( !isspace(*ptr1) && *ptr1 != '\0' ) ptr1--;
ptr1++; /* ptr1 points to beginning of parameter */
while ( isspace(*ptr2) ) ptr2++;
while ( *ptr2 && !isspace(*ptr2) ) ptr2++; /* ptr2 points to end of parameter */
keep = *ptr2;
if( keep == '\0' ) {
/* End of string - don't go over end. This needed to change because
* strings don't store line size here anymore since we use dynamic
* strings. Previously, we could step on string size which was stored
* at string[length+2] and string[length+2] */
beg = ptr2 ;
} else {
*ptr2 = '\0' ;
beg = ptr2+1 ;
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
newcard = alloc(struct line);
str = strdup(ptr1);
newcard->li_line = str;
newcard->li_next = NULL;
if ( start_card == NULL ) head->li_next = start_card = newcard;
else prev_card->li_next = newcard;
prev_card = end_card = newcard;
num_params++;
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
/* now sort parameters in order of dependencies */
inp_sort_params( start_card, end_card, head, start_card, end_card );
/* create new ordered parameter string for subckt call */
c=head->li_next;
tfree(head);
for( i = 0; i < num_params && c!= NULL; i++ ) {
if ( new_str == NULL ) new_str = strdup(c->li_line);
else {
str = new_str;
new_str = TMALLOC(char, strlen(str) + strlen(c->li_line) + 2);
sprintf( new_str, "%s %s", str, c->li_line );
tfree(str);
}
tfree(c->li_line);
head = c;
c = c->li_next;
tfree(head);
}
/* create buffer and insert params: */
buffer = TMALLOC(char, strlen(s) + 9 + strlen(new_str) + 1);
sprintf( buffer, "%s params: %s", s, new_str );
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
tfree(s);
tfree(new_str);
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
s = buffer;
}
return s;
2009-07-28 23:16:07 +02:00
}
static char*
inp_remove_ws( char *s )
{
2011-08-06 09:53:48 +02:00
char *big_buff;
int big_buff_index = 0;
char *buffer, *curr;
bool is_expression = FALSE;
big_buff = TMALLOC(char, strlen(s) + 1);
curr = s;
while ( *curr != '\0' ) {
if ( *curr == '{' ) is_expression = TRUE;
if ( *curr == '}' ) is_expression = FALSE;
big_buff[big_buff_index++] = *curr;
if ( *curr == '=' || (is_expression && (is_arith_char(*curr) || *curr == ',')) ) {
curr++;
while ( isspace(*curr) ) curr++;
if ( *curr == '{' ) is_expression = TRUE;
if ( *curr == '}' ) is_expression = FALSE;
big_buff[big_buff_index++] = *curr;
}
curr++;
if ( isspace(*curr) ) {
while ( isspace(*curr) ) curr++;
if ( is_expression ) {
if ( *curr != '=' && !is_arith_char(*curr) && *curr != ',' ) big_buff[big_buff_index++] = ' ';
} else {
if ( *curr != '=' ) big_buff[big_buff_index++] = ' ';
}
}
}
2009-07-28 23:16:07 +02:00
// big_buff[big_buff_index++] = *curr;
2011-08-06 09:53:48 +02:00
big_buff[big_buff_index] = '\0';
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
buffer = copy(big_buff);
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
tfree(s);
tfree(big_buff);
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
return buffer;
2009-07-28 23:16:07 +02:00
}
2011-11-13 15:44:00 +01:00
/*
change quotes from '' to {}
.subckt name 1 2 3 params: l=1 w=2 --> .subckt name 1 2 3 l=1 w=2
x1 1 2 3 params: l=1 w=2 --> x1 1 2 3 l=1 w=2
modify .subckt lines by calling inp_fix_subckt()
*/
2009-07-28 23:16:07 +02:00
static void
inp_fix_for_numparam(struct line *deck)
{
2011-08-06 09:53:48 +02:00
bool found_control = FALSE;
struct line *c=deck;
char *str_ptr;
2011-08-06 09:53:48 +02:00
while( c!=NULL) {
if ( ciprefix( ".modif", c->li_line ) ) *c->li_line = '*';
if ( ciprefix( "*lib", c->li_line ) ) {
c = c->li_next;
continue;
}
/* exclude echo, let, set, plot line between .control and .endc from getting quotes changed */
if ( ciprefix( ".control", c->li_line ) ) found_control = TRUE;
if ( ciprefix( ".endc", c->li_line ) ) found_control = FALSE;
if ((found_control) && ((ciprefix( "plot", c->li_line )) || (ciprefix( "echo", c->li_line ))
|| (ciprefix( "let", c->li_line )) || (ciprefix( "set", c->li_line )))) {
c = c->li_next;
continue;
}
if ( !ciprefix( "*lib", c->li_line ) && !ciprefix( "*inc", c->li_line ) )
inp_change_quotes(c->li_line);
if (inp_compat_mode == COMPATMODE_ALL) {
if ( ciprefix( ".subckt", c->li_line ) || ciprefix( "x", c->li_line ) ) {
/* remove params: */
str_ptr = strstr(c->li_line, "params:");
if (str_ptr) {
memcpy(str_ptr, " ", 7);
}
}
}
2011-08-06 09:53:48 +02:00
if ( ciprefix( ".subckt", c->li_line ) ) {
c->li_line = inp_fix_subckt(c->li_line);
}
c = c->li_next;
}
2009-07-28 23:16:07 +02:00
}
static void
inp_remove_excess_ws(struct line *deck )
{
2011-08-06 09:53:48 +02:00
struct line *c = deck;
bool found_control = FALSE;
while ( c != NULL ) {
if ( *c->li_line == '*' ) {
c = c->li_next;
continue;
}
/* exclude echo lines between .control and .endc from removing white spaces */
if ( ciprefix( ".control", c->li_line ) ) found_control = TRUE;
if ( ciprefix( ".endc", c->li_line ) ) found_control = FALSE;
if ((found_control) && (ciprefix( "echo", c->li_line ))) {
c = c->li_next;
continue;
}
c->li_line = inp_remove_ws(c->li_line); /* freed in fcn */
2010-07-01 22:29:53 +02:00
c = c->li_next;
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
}
static void
inp_determine_libraries( struct line *deck, char *lib_name )
{
2011-08-06 09:53:48 +02:00
struct line *c = deck;
2011-12-30 18:38:56 +01:00
char *line, *s, *t, *y, *z, keep_char1, keep_char2;
2011-08-06 09:53:48 +02:00
int i, j;
bool found_lib_name = FALSE;
bool read_line = FALSE;
if ( lib_name == NULL ) read_line = TRUE;
while ( c != NULL ) {
line = c->li_line;
if ( ciprefix( ".endl", line ) && lib_name != NULL ) read_line = FALSE;
if ( ciprefix( "*lib", line ) || ciprefix( ".lib", line ) ) {
for ( s = line; *s && !isspace(*s); s++)
;
while ( isspace(*s) || isquote(*s) ) s++;
for ( t = s; *t && !isspace(*t) && !isquote(*t); t++ )
;
y = t;
while ( isspace(*y) || isquote(*y) ) y++;
/* .lib <lib name> */
if ( !*y ) {
keep_char1 = *t;
*t = '\0';
if ( lib_name != NULL && strcmp( lib_name, s ) == 0 ) read_line = TRUE;
*t = keep_char1;
}
/* .lib <file name> <lib name> */
else if ( read_line == TRUE ) {
2011-12-30 18:38:56 +01:00
char *copys = NULL;
2011-08-06 09:53:48 +02:00
for ( z = y; *z && !isspace(*z) && !isquote(*z); z++ )
;
keep_char1 = *t;
keep_char2 = *z;
*t = '\0';
*z = '\0';
if ( *s == '~' ) {
copys = cp_tildexpand(s);
2011-12-30 18:38:56 +01:00
if ( copys )
2011-08-06 09:53:48 +02:00
s = copys;
}
for ( i = 0; i < num_libraries; i++ )
2011-12-30 19:08:48 +01:00
if ( cieq( library_file[i], s ) ) {
2011-08-06 09:53:48 +02:00
found_lib_name = FALSE;
for ( j = 0; j < num_lib_names[i] && found_lib_name == FALSE; j++ )
if ( strcmp( library_name[i][j], y ) == 0 ) found_lib_name = TRUE;
if ( found_lib_name == FALSE ) {
library_ll_ptr[i][num_lib_names[i]] = c;
library_name[i][num_lib_names[i]++] = strdup(y);
/* see if other libraries referenced */
inp_determine_libraries( libraries[i], y );
}
}
*line = '*'; /* comment out .lib line */
*t = keep_char1;
*z = keep_char2;
2011-12-30 18:38:56 +01:00
/* FIXME, copys not freed ?! */
2011-08-06 09:53:48 +02:00
}
}
c = c->li_next;
}
2009-07-28 23:16:07 +02:00
}
static void
inp_init_lib_data(void)
2009-07-28 23:16:07 +02:00
{
2011-08-06 09:53:48 +02:00
int i;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
for ( i = 0; i < num_libraries; i++ )
num_lib_names[i] = 0;
2009-07-28 23:16:07 +02:00
}
static char*
inp_get_subckt_name( char *s )
{
2011-08-06 09:53:48 +02:00
char *end_ptr = strstr( s, "=" );
char *subckt_name, *subckt_name_copy;
char keep;
if ( end_ptr != NULL ) {
end_ptr--;
while ( isspace(*end_ptr) ) end_ptr--;
for(; *end_ptr && !isspace(*end_ptr); end_ptr--)
;
} else {
end_ptr = s + strlen(s);
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
subckt_name = end_ptr;
while ( isspace( *subckt_name ) ) subckt_name--;
for(; !isspace(*subckt_name); subckt_name-- )
;
subckt_name++;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
keep = *end_ptr;
*end_ptr = '\0';
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
subckt_name_copy = strdup( subckt_name );
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
*end_ptr = keep;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
return subckt_name_copy;
2009-07-28 23:16:07 +02:00
}
static int
inp_get_params( char *line, char *param_names[], char *param_values[] )
{
2011-08-06 09:53:48 +02:00
char *equal_ptr = strstr( line, "=" );
char *end, *name, *value;
int num_params = 0;
char tmp_str[1000];
char keep;
bool is_expression = FALSE;
while ( (equal_ptr = strstr( line, "=" )) != NULL ) {
// check for equality '=='
if ( *(equal_ptr+1) == '=' ) {
line = equal_ptr+2;
continue;
}
// check for '!=', '<=', '>='
if ( *(equal_ptr-1) == '!' || *(equal_ptr-1) == '<' || *(equal_ptr-1) == '>' ) {
line = equal_ptr+1;
continue;
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
is_expression = FALSE;
/* get parameter name */
name = equal_ptr - 1;
while ( *name && isspace(*name) ) name--;
end = name + 1;
while ( *name && !isspace(*name) ) name--;
name++;
keep = *end;
*end = '\0';
param_names[num_params++] = strdup(name);
*end = keep;
/* get parameter value */
value = equal_ptr + 1;
while ( *value && isspace(*value) ) value++;
if ( *value == '{' ) is_expression = TRUE;
end = value;
if ( is_expression ) {
while ( *end && *end != '}' ) end++;
} else {
while ( *end && !isspace(*end) ) end++;
}
if ( is_expression ) end++;
keep = *end;
*end = '\0';
if ( *value != '{' &&
!( isdigit( *value ) || ( *value == '.' && isdigit(*(value+1)) ) ) ) {
sprintf( tmp_str, "{%s}", value );
value = tmp_str;
}
param_values[num_params-1] = strdup(value);
*end = keep;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
line = end;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
return num_params;
2009-07-28 23:16:07 +02:00
}
static char*
inp_fix_inst_line( char *inst_line,
2011-08-06 09:53:48 +02:00
int num_subckt_params, char *subckt_param_names[], char *subckt_param_values[],
int num_inst_params, char *inst_param_names[], char *inst_param_values[] )
2009-07-28 23:16:07 +02:00
{
2011-08-06 09:53:48 +02:00
char *end = strstr( inst_line, "=" ), *inst_name, *inst_name_end = inst_line;
char *curr_line = inst_line, *new_line = NULL;
char keep;
int i, j;
while ( !isspace(*inst_name_end) ) inst_name_end++;
keep = *inst_name_end;
*inst_name_end = '\0';
inst_name = strdup( inst_line );
*inst_name_end = keep;
if ( end != NULL ) {
end--;
while ( isspace( *end ) ) end--;
while ( !isspace( *end ) ) end--;
*end = '\0';
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
for ( i = 0; i < num_subckt_params; i++ ) {
for ( j = 0; j < num_inst_params; j++ ) {
if ( strcmp( subckt_param_names[i], inst_param_names[j] ) == 0 ) {
tfree( subckt_param_values[i] );
subckt_param_values[i] = strdup( inst_param_values[j] );
}
}
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
for ( i = 0; i < num_subckt_params; i++ ) {
new_line = TMALLOC(char, strlen( curr_line ) + strlen( subckt_param_values[i] ) + 2);
sprintf( new_line, "%s %s", curr_line, subckt_param_values[i] );
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
tfree( curr_line );
tfree( subckt_param_names[i] );
tfree( subckt_param_values[i] );
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
curr_line = new_line;
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
for ( i = 0; i < num_inst_params; i++ ) {
tfree( inst_param_names[i] );
tfree( inst_param_values[i] );
}
tfree( inst_name );
return curr_line;
2009-07-28 23:16:07 +02:00
}
static bool
found_mult_param( int num_params, char *param_names[] )
{
2011-08-06 09:53:48 +02:00
bool found_mult = FALSE;
int i;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
for ( i = 0; i < num_params; i++ ) {
if ( strcmp( param_names[i], "m" ) == 0 ) {
found_mult = TRUE;
}
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
return found_mult;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
2009-07-28 23:16:07 +02:00
static int
inp_fix_subckt_multiplier( struct line *subckt_card,
2011-08-06 09:53:48 +02:00
int num_subckt_params, char *subckt_param_names[], char *subckt_param_values[] )
2009-07-28 23:16:07 +02:00
{
2011-08-06 09:53:48 +02:00
struct line *card;
char *new_str;
subckt_param_names[num_subckt_params] = strdup("m");
subckt_param_values[num_subckt_params] = strdup("1");
num_subckt_params = num_subckt_params + 1;
if ( !strstr( subckt_card->li_line, "params:" ) ) {
new_str = TMALLOC(char, strlen( subckt_card->li_line ) + 13);
sprintf( new_str, "%s params: m=1", subckt_card->li_line );
subckt_w_params[num_subckt_w_params++] = get_subckt_model_name( subckt_card->li_line );
} else {
new_str = TMALLOC(char, strlen( subckt_card->li_line ) + 5);
sprintf( new_str, "%s m=1", subckt_card->li_line );
}
tfree( subckt_card->li_line );
subckt_card->li_line = new_str;
for ( card = subckt_card->li_next;
card != NULL && !ciprefix( ".ends", card->li_line );
card = card->li_next ) {
/* no 'm' for B line or comment line */
if ((*(card->li_line) == '*') || (*(card->li_line) == 'b'))
continue;
/* no 'm' for model cards */
if (ciprefix(".model", card->li_line))
continue;
new_str = TMALLOC(char, strlen( card->li_line ) + 7);
sprintf( new_str, "%s m={m}", card->li_line );
tfree( card->li_line );
card->li_line = new_str;
}
return num_subckt_params;
2009-07-28 23:16:07 +02:00
}
static void
inp_fix_inst_calls_for_numparam(struct line *deck)
{
2011-08-06 09:53:48 +02:00
struct line *c = deck;
struct line *d, *p = NULL;
char *inst_line;
char *subckt_line;
char *subckt_name;
char *subckt_param_names[1000];
char *subckt_param_values[1000];
char *inst_param_names[1000];
char *inst_param_values[1000];
char name_w_space[1000];
int num_subckt_params = 0;
int num_inst_params = 0;
int i,j,k;
bool flag = FALSE;
bool found_subckt = FALSE;
bool found_param_match = FALSE;
// first iterate through instances and find occurences where 'm' multiplier needs to be
// added to the subcircuit -- subsequent instances will then need this parameter as well
for ( c = deck; c != NULL; c = c->li_next ) {
inst_line = c->li_line;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
if ( *inst_line == '*' ) {
continue;
}
if ( ciprefix( "x", inst_line ) ) {
num_inst_params = inp_get_params( inst_line, inst_param_names, inst_param_values );
subckt_name = inp_get_subckt_name( inst_line );
if ( found_mult_param( num_inst_params, inst_param_names ) ) {
flag = FALSE;
// iterate through the deck to find the subckt (last one defined wins)
d = deck;
while ( d != NULL ) {
subckt_line = d->li_line;
if ( ciprefix( ".subckt", subckt_line ) ) {
for ( ; *subckt_line && !isspace(*subckt_line); subckt_line++ )
;
while ( isspace(*subckt_line) ) subckt_line++;
sprintf( name_w_space, "%s ", subckt_name );
if ( strncmp( subckt_line, name_w_space, strlen(name_w_space) ) == 0 ) {
p = d;
flag = TRUE;
}
}
d = d->li_next;
}
if ( flag ) {
num_subckt_params = inp_get_params( p->li_line, subckt_param_names, subckt_param_values );
if ( num_subckt_params == 0 || !found_mult_param( num_subckt_params, subckt_param_names ) ) {
inp_fix_subckt_multiplier( p, num_subckt_params, subckt_param_names, subckt_param_values );
}
}
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
tfree(subckt_name );
if ( flag )
for (i=0; i < num_subckt_params; i++) {
tfree(subckt_param_names[i]);
tfree(subckt_param_values[i]);
}
for (i=0; i < num_inst_params; i++) {
tfree(inst_param_names[i]);
tfree(inst_param_values[i]);
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
}
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
c = deck;
while ( c != NULL ) {
inst_line = c->li_line;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
if ( *inst_line == '*' ) {
c = c->li_next;
continue;
}
if ( ciprefix( "x", inst_line ) ) {
subckt_name = inp_get_subckt_name( inst_line );
for ( i = 0; i < num_subckt_w_params; i++ ) {
if ( strcmp( subckt_w_params[i], subckt_name ) == 0 ) {
sprintf( name_w_space, "%s ", subckt_name );
/* find .subckt line */
found_subckt = FALSE;
d = deck;
while ( d != NULL ) {
subckt_line = d->li_line;
if ( ciprefix( ".subckt", subckt_line ) ) {
for ( ; *subckt_line && !isspace(*subckt_line); subckt_line++ )
;
while ( isspace(*subckt_line) ) subckt_line++;
if ( strncmp( subckt_line, name_w_space, strlen(name_w_space) ) == 0 ) {
num_subckt_params = inp_get_params( subckt_line, subckt_param_names, subckt_param_values );
num_inst_params = inp_get_params( inst_line, inst_param_names, inst_param_values );
// make sure that if have inst params that one matches subckt
found_param_match = FALSE;
if ( num_inst_params == 0 ) found_param_match = TRUE;
else {
for ( j = 0; j < num_inst_params; j++ ) {
for ( k = 0; k < num_subckt_params; k++ ) {
if ( strcmp( subckt_param_names[k], inst_param_names[j] ) == 0 ) {
found_param_match = TRUE;
break;
}
}
if ( found_param_match ) break;
}
}
if ( !found_param_match ) {
// comment out .subckt and continue
while ( d != NULL && !ciprefix( ".ends", d->li_line ) ) {
*(d->li_line) = '*';
d = d->li_next;
}
*(d->li_line) = '*';
d = d->li_next;
continue;
}
c->li_line = inp_fix_inst_line( inst_line, num_subckt_params, subckt_param_names, subckt_param_values, num_inst_params, inst_param_names, inst_param_values );
found_subckt = TRUE;
for (i=0; i < num_subckt_params; i++) {
tfree(subckt_param_names[i]);
tfree(subckt_param_values[i]);
}
for (i=0; i < num_inst_params; i++) {
tfree(inst_param_names[i]);
tfree(inst_param_values[i]);
}
}
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
if ( found_subckt ) break;
d = d->li_next;
}
break;
}
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
tfree(subckt_name);
}
c = c->li_next;
}
2009-07-28 23:16:07 +02:00
}
static void
inp_get_func_from_line( char *line )
{
2011-08-06 09:53:48 +02:00
char *ptr, *end;
char keep;
char temp_buf[5000];
int num_params = 0;
int str_len = 0;
int i = 0;
/* get function name */
while ( !isspace( *line ) ) line++;
while ( isspace( *line ) ) line++;
end = line;
while ( !isspace( *end ) && *end != '(' ) end++;
keep = *end;
*end = '\0';
/* see if already encountered this function */
for ( i = 0; i < num_functions; i++ )
if ( strcmp( func_names[i], line ) == 0 ) break;
func_names[num_functions++] = strdup(line);
*end = keep;
num_params = 0;
/* get function parameters */
while ( *end != '(' ) end++;
while ( *end != ')' ) {
end++;
while ( isspace( *end ) ) end++;
ptr = end;
while ( !isspace( *end ) && *end != ',' && *end != ')' ) end++;
if(end > ptr)
func_params[num_functions-1][num_params++] = copy_substring(ptr, end);
}
num_parameters[num_functions-1] = num_params;
/* get function macro */
str_len = 0;
while ( *end != '{' ) end++;
2009-07-28 23:16:07 +02:00
end++;
2011-08-06 09:53:48 +02:00
while ( *end && *end != '}' ) {
if ( !isspace(*end) )
temp_buf[str_len++] = *end;
end++;
}
temp_buf[str_len++] = '\0';
func_macro[num_functions-1] = strdup(temp_buf);
2009-07-28 23:16:07 +02:00
}
//
// only grab global functions; skip subckt functions
//
static void
inp_grab_func( struct line *deck )
{
2011-08-06 09:53:48 +02:00
struct line *c = deck;
bool is_subckt = FALSE;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
while ( c != NULL ) {
if ( *c->li_line == '*' ) {
c = c->li_next;
continue;
}
if ( ciprefix( ".subckt", c->li_line ) ) is_subckt = TRUE;
if ( ciprefix( ".ends", c->li_line ) ) is_subckt = FALSE;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
if ( !is_subckt && ciprefix( ".func", c->li_line ) ) {
inp_get_func_from_line( c->li_line );
*c->li_line = '*';
}
c = c->li_next;
2009-07-28 23:16:07 +02:00
}
}
static void
inp_grab_subckt_func( struct line *subckt )
{
2011-08-06 09:53:48 +02:00
struct line *c = subckt;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
while ( !ciprefix( ".ends", c->li_line ) ) {
if ( ciprefix( ".func", c->li_line ) ) {
inp_get_func_from_line( c->li_line );
*c->li_line = '*';
}
c = c->li_next;
2009-07-28 23:16:07 +02:00
}
}
static char*
inp_do_macro_param_replace( int fcn_number, char *params[] )
{
2011-08-06 09:53:48 +02:00
char *param_ptr, *curr_ptr, *new_str, *curr_str = NULL, *search_ptr;
char keep, before, after;
int i;
if(num_parameters[fcn_number] == 0)
return strdup(func_macro[fcn_number]);
for ( i = 0; i < num_parameters[fcn_number]; i++ ) {
if ( curr_str == NULL )
search_ptr = curr_ptr = func_macro[fcn_number];
else {
search_ptr = curr_ptr = curr_str;
curr_str = NULL;
}
while ((param_ptr = strstr( search_ptr, func_params[fcn_number][i] ) ) != NULL ) {
/* make sure actually have the parameter name */
if (param_ptr == search_ptr) /* no valid 'before' */
before = '\0';
else
before = *(param_ptr-1);
after = *(param_ptr+strlen(func_params[fcn_number][i]));
if ( !(is_arith_char(before) || isspace(before) || before == ',' || before == '=' || (param_ptr-1) < curr_ptr ) ||
!(is_arith_char(after) || isspace(after) || after == ',' || after == '=' || after == '\0' ) ) {
search_ptr = param_ptr + 1;
continue;
}
keep = *param_ptr;
*param_ptr = '\0';
{
size_t curr_str_len = curr_str ? strlen(curr_str) : 0;
size_t len = strlen(curr_ptr) + strlen(params[i]) + 1;
if ( str_has_arith_char( params[i] ) ) {
curr_str = TREALLOC(char, curr_str, curr_str_len + len + 2);
sprintf( curr_str + curr_str_len, "%s(%s)", curr_ptr, params[i] );
} else {
curr_str = TREALLOC(char, curr_str, curr_str_len + len);
sprintf( curr_str + curr_str_len, "%s%s", curr_ptr, params[i] );
}
}
*param_ptr = keep;
search_ptr = curr_ptr = param_ptr + strlen(func_params[fcn_number][i]);
}
if ( param_ptr == NULL ) {
if ( curr_str == NULL ) {
curr_str = curr_ptr;
} else {
new_str = TMALLOC(char, strlen(curr_str) + strlen(curr_ptr) + 1);
sprintf( new_str, "%s%s", curr_str, curr_ptr );
tfree(curr_str);
curr_str = new_str;
}
}
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
return curr_str;
2009-07-28 23:16:07 +02:00
}
static char*
inp_expand_macro_in_str( char *str )
{
2011-08-06 09:53:48 +02:00
int i;
char *c;
char *open_paren_ptr, *close_paren_ptr, *fcn_name, *params[1000];
char *curr_ptr, *macro_str, *curr_str = NULL;
int num_parens, num_params;
char *orig_ptr = str, *search_ptr = str, *orig_str = strdup(str);
char keep;
// printf("%s: enter(\"%s\")\n", __FUNCTION__, str);
while ( (open_paren_ptr = strchr(search_ptr, '(')) != NULL ) {
fcn_name = open_paren_ptr;
while ( --fcn_name >= search_ptr )
if(!isalnum(*fcn_name) && *fcn_name != '_')
break;
fcn_name++;
search_ptr = open_paren_ptr + 1;
if ( open_paren_ptr == fcn_name )
continue;
*open_paren_ptr = '\0';
for ( i = 0; i < num_functions; i++ )
if ( strcmp( func_names[i], fcn_name ) == 0 )
break;
*open_paren_ptr = '(';
if(i >= num_functions)
continue;
/* find the closing paren */
num_parens = 1;
for ( c = open_paren_ptr + 1; *c; c++ ) {
if ( *c == '(' )
num_parens++;
if ( *c == ')' && --num_parens == 0)
break;
}
if ( num_parens ) {
fprintf( stderr, "ERROR: did not find closing parenthesis for function call in str: %s\n", orig_str );
controlled_exit(EXIT_FAILURE);
}
close_paren_ptr = c;
/* if ( ciprefix( "v(", curr_ptr ) ) {
// look for any commas and change to ' '
char *str_ptr = curr_ptr;
while ( *str_ptr != '\0' && *str_ptr != ')' ) {
if ( *str_ptr == ',' || *str_ptr == '(' ) *str_ptr = ' '; str_ptr++; }
if ( *str_ptr == ')' ) *str_ptr = ' ';
}*/
/* get the parameters */
curr_ptr = open_paren_ptr + 1;
for (num_params=0; curr_ptr < close_paren_ptr; curr_ptr++) {
char *beg_parameter;
int num_parens;
if( isspace(*curr_ptr) )
continue;
beg_parameter = curr_ptr;
num_parens = 0;
for(; curr_ptr < close_paren_ptr; curr_ptr++) {
if(*curr_ptr == '(')
num_parens++;
if(*curr_ptr == ')')
num_parens--;
if(*curr_ptr == ',' && num_parens == 0)
break;
}
params[num_params++] =
inp_expand_macro_in_str(copy_substring(beg_parameter, curr_ptr));
}
if ( num_parameters[i] != num_params ) {
fprintf( stderr, "ERROR: parameter mismatch for function call in str: %s\n", orig_str );
controlled_exit(EXIT_FAILURE);
}
macro_str = inp_do_macro_param_replace( i, params );
keep = *fcn_name;
*fcn_name = '\0';
{
size_t curr_str_len = curr_str ? strlen(curr_str) : 0;
size_t len = strlen(str) + strlen(macro_str) + 3;
curr_str = TREALLOC(char, curr_str, curr_str_len + len);
sprintf( curr_str + curr_str_len, "%s(%s)", str, macro_str );
}
*fcn_name = keep;
search_ptr = str = close_paren_ptr + 1;
}
if ( curr_str == NULL ) {
curr_str = orig_ptr;
} else {
if ( str != NULL ) {
size_t curr_str_len = strlen(curr_str);
size_t len = strlen(str) + 1;
curr_str = TREALLOC(char, curr_str, curr_str_len + len);
sprintf( curr_str + curr_str_len, "%s", str );
}
tfree(orig_ptr);
}
tfree(orig_str);
// printf("%s: --> \"%s\"\n", __FUNCTION__, curr_str);
return curr_str;
}
static void
inp_expand_macros_in_func(void)
{
int i;
for ( i = 0; i < num_functions; i++ ) {
func_macro[i] = inp_expand_macro_in_str( func_macro[i] );
}
}
static void
inp_expand_macros_in_deck( struct line *deck )
{
struct line *c = deck;
int prev_num_functions = 0, i, j;
while ( c != NULL ) {
if ( *c->li_line == '*' ) {
c = c->li_next;
continue;
}
if ( ciprefix( ".subckt", c->li_line ) ) {
prev_num_functions = num_functions;
inp_grab_subckt_func( c );
if ( prev_num_functions != num_functions ) inp_expand_macros_in_func();
}
if ( ciprefix( ".ends", c->li_line ) ) {
if ( prev_num_functions != num_functions ) {
for ( i = prev_num_functions; i < num_functions; i++ ) {
tfree( func_names[i] );
tfree( func_macro[i] );
for ( j = 0; j < num_parameters[i]; j++ ) tfree( func_params[i][j] );
num_functions = prev_num_functions;
}
}
}
if ( *c->li_line != '*' ) c->li_line = inp_expand_macro_in_str( c->li_line );
c = c->li_next;
}
}
/* Put {} around tokens for handling in numparam.
Searches for the next '=' in the line to become active.
Several exceptions (eg. no 'set' or 'b' lines, no .cmodel lines,
no lines between .control and .endc, no .option lines).
Special handling of vectors with [] and complex values with < >
2011-11-13 13:04:15 +01:00
h_vogt 20 April 2008
* For xspice and num_pram compatibility .cmodel added
* .cmodel will be replaced by .model in inp_fix_param_values()
* and then the entire line is skipped (will not be changed by this function).
* Usage of numparam requires {} around the parameters in the .cmodel line.
* May be obsolete?
*/
2011-08-06 09:53:48 +02:00
static void
inp_fix_param_values( struct line *deck )
{
struct line *c = deck;
char *line, *beg_of_str, *end_of_str, *old_str, *equal_ptr, *new_str;
char *vec_str, *natok, *buffer, *newvec, *whereisgt;
bool control_section = FALSE;
wordlist *wl, *nwl;
int parens;
while ( c != NULL ) {
line = c->li_line;
if ( *line == '*' || (ciprefix( ".param", line ) && strstr( line, "{" )) ) {
c = c->li_next;
continue;
}
if ( ciprefix( ".control", line ) ) {
control_section = TRUE;
c = c->li_next;
continue;
}
if ( ciprefix( ".endc", line ) ) {
control_section = FALSE;
c = c->li_next;
continue;
}
if ( control_section || ciprefix( ".option", line ) ) {
c = c->li_next; /* no handling of params in "option" lines */
continue;
}
if ( ciprefix( "set", line ) ) {
c = c->li_next; /* no handling of params in "set" lines */
continue;
}
if ( *line == 'b' ) {
c = c->li_next; /* no handling of params in B source lines */
continue;
}
/* for xspice .cmodel: replace .cmodel with .model and skip entire line) */
if ( ciprefix( ".cmodel", line ) ) {
*(++line) = 'm';
*(++line) = 'o';
*(++line) = 'd';
*(++line) = 'e';
*(++line) = 'l';
*(++line) = ' ';
c = c->li_next;
continue;
}
/* exclude CIDER models */
if ( ciprefix( ".model", line ) && ( strstr(line, "numos") || strstr(line, "numd") || strstr(line, "nbjt") ||
strstr(line, "nbjt2") || strstr(line, "numd2") ) ) {
c = c->li_next;
continue;
}
/* exclude CIDER devices with ic.file parameter */
if ( strstr(line, "ic.file")) {
c = c->li_next;
continue;
}
2009-12-11 17:26:17 +01:00
2011-08-06 09:53:48 +02:00
while ((equal_ptr = strstr( line, "=" )) != NULL ) {
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
// special case: .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=out_variable3
// no braces around out_variable3. out_variable3 may be v(...) or i(...)
if ( ciprefix( ".meas", line ))
if ((( *(equal_ptr+1) == 'v' ) || ( *(equal_ptr+1) == 'i' )) && ( *(equal_ptr+2) == '(' )) {
// find closing ')' and skip token v(...) or i(...)
while (*equal_ptr != ')' && *(equal_ptr+1) != '\0') equal_ptr++;
line = equal_ptr + 1;
continue;
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
// skip over equality '=='
if ( *(equal_ptr+1) == '=' ) {
line += 2;
continue;
}
// check for '!=', '<=', '>='
if ( *(equal_ptr-1) == '!' || *(equal_ptr-1) == '<' || *(equal_ptr-1) == '>' ) {
line += 1;
continue;
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
beg_of_str = equal_ptr + 1;
while ( isspace(*beg_of_str) ) beg_of_str++;
/* all cases where no {} have to be put around selected token */
if ( isdigit(*beg_of_str)
|| *beg_of_str == '{'
|| *beg_of_str == '.'
|| *beg_of_str == '"'
|| ( *beg_of_str == '-' && isdigit(*(beg_of_str+1)) )
|| ( *beg_of_str == '-' && (*(beg_of_str+1) == '.') && isdigit(*(beg_of_str+2)) )
|| ciprefix("true", beg_of_str)
|| ciprefix("false", beg_of_str) ) {
line = equal_ptr + 1;
} else if (*beg_of_str == '[') {
/* A vector following the '=' token: code to put curly brackets around all params
inside a pair of square brackets */
end_of_str = beg_of_str;
while (*end_of_str != ']')
end_of_str++;
/* string xx yyy from vector [xx yyy] */
vec_str = copy_substring(beg_of_str + 1, end_of_str);
/* work on vector elements inside [] */
nwl = NULL;
for (;;) {
natok = gettok(&vec_str);
if (!natok) break;
wl = alloc(struct wordlist);
buffer = TMALLOC(char, strlen(natok) + 4);
if ( isdigit(*natok) || *natok == '{' || *natok == '.' ||
*natok == '"' || ( *natok == '-' && isdigit(*(natok+1)) ) ||
ciprefix("true", natok) || ciprefix("false", natok) ||
eq(natok, "<") || eq(natok, ">")) {
(void) sprintf(buffer, "%s", natok);
/* A complex value found inside a vector [< x1 y1> <x2 y2>] */
/* < xx and yy > have been dealt with before */
/* <xx */
} else if (*natok == '<') {
if (isdigit(*(natok + 1)) || ( *(natok + 1) == '-' &&
isdigit(*(natok + 2)) )) {
(void) sprintf(buffer, "%s", natok);
} else {
*natok = '{';
(void) sprintf(buffer, "<%s}", natok);
}
/* yy> */
} else if (strchr(natok, '>')) {
if (isdigit(*natok) || ( *natok == '-' && isdigit(*(natok+1))) ) {
(void) sprintf(buffer, "%s", natok);
} else {
whereisgt = strchr(natok, '>');
*whereisgt = '}';
(void) sprintf(buffer, "{%s>", natok);
}
/* all other tokens */
} else {
(void) sprintf(buffer, "{%s}", natok);
}
tfree(natok);
wl->wl_word = copy(buffer);
tfree(buffer);
wl->wl_next = nwl;
if (nwl)
nwl->wl_prev = wl;
nwl = wl;
}
nwl = wl_reverse(nwl);
/* new vector elements */
newvec = wl_flatten(nwl);
wl_free(nwl);
/* insert new vector into actual line */
*equal_ptr = '\0';
new_str = TMALLOC(char, strlen(c->li_line) + strlen(newvec) + strlen(end_of_str + 1) + 5);
sprintf( new_str, "%s=[%s] %s", c->li_line, newvec, end_of_str+1 );
tfree(newvec);
old_str = c->li_line;
c->li_line = new_str;
line = new_str + strlen(old_str) + 1;
tfree(old_str);
} else if (*beg_of_str == '<') {
/* A complex value following the '=' token: code to put curly brackets around all params
inside a pair < > */
end_of_str = beg_of_str;
while (*end_of_str != '>')
end_of_str++;
/* string xx yyy from vector [xx yyy] */
vec_str = copy_substring(beg_of_str + 1, end_of_str);
/* work on tokens inside <> */
nwl = NULL;
for (;;) {
natok = gettok(&vec_str);
if (!natok) break;
wl = alloc(struct wordlist);
buffer = TMALLOC(char, strlen(natok) + 4);
if ( isdigit(*natok) || *natok == '{' || *natok == '.' ||
*natok == '"' || ( *natok == '-' && isdigit(*(natok+1)) ) ||
ciprefix("true", natok) || ciprefix("false", natok)) {
(void) sprintf(buffer, "%s", natok);
} else {
(void) sprintf(buffer, "{%s}", natok);
}
tfree(natok);
wl->wl_word = copy(buffer);
tfree(buffer);
wl->wl_next = nwl;
if (nwl)
nwl->wl_prev = wl;
nwl = wl;
}
nwl = wl_reverse(nwl);
/* new elements of complex variable */
newvec = wl_flatten(nwl);
wl_free(nwl);
/* insert new complex value into actual line */
*equal_ptr = '\0';
new_str = TMALLOC(char, strlen(c->li_line) + strlen(newvec) + strlen(end_of_str + 1) + 5);
sprintf( new_str, "%s=<%s> %s", c->li_line, newvec, end_of_str+1 );
tfree(newvec);
old_str = c->li_line;
c->li_line = new_str;
line = new_str + strlen(old_str) + 1;
tfree(old_str);
} else {
/* put {} around token to be accepted as numparam */
end_of_str = beg_of_str;
parens = 0;
while ( *end_of_str != '\0' && (!isspace(*end_of_str) || (parens > 0)) ) {
if ( *end_of_str == '(' ) parens++;
if ( *end_of_str == ')' ) parens--;
end_of_str++;
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
*equal_ptr = '\0';
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
if ( *end_of_str == '\0' ) {
new_str = TMALLOC(char, strlen(c->li_line) + strlen(beg_of_str) + 4);
sprintf( new_str, "%s={%s}", c->li_line, beg_of_str );
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
} else {
*end_of_str = '\0';
new_str = TMALLOC(char, strlen(c->li_line) + strlen(beg_of_str) + strlen(end_of_str + 1) + 5);
sprintf( new_str, "%s={%s} %s", c->li_line, beg_of_str, end_of_str+1 );
}
old_str = c->li_line;
c->li_line = new_str;
line = new_str + strlen(old_str) + 1;
tfree(old_str);
}
}
c = c->li_next;
2009-07-28 23:16:07 +02:00
}
}
static char*
get_param_name( char *line )
{
2011-08-06 09:53:48 +02:00
char *name = NULL, *equal_ptr, *beg;
char keep;
if (( equal_ptr = strstr( line, "=" ) ) != NULL ) {
equal_ptr--;
while ( isspace(*equal_ptr) ) equal_ptr--;
equal_ptr++;
beg = equal_ptr-1;
while ( !isspace(*beg) && beg != line ) beg--;
if ( beg != line ) beg++;
keep = *equal_ptr;
*equal_ptr = '\0';
name = strdup(beg);
*equal_ptr = keep;
} else {
fprintf( stderr, "ERROR: could not find '=' on parameter line '%s'!\n", line );
controlled_exit(EXIT_FAILURE);
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
return name;
2009-07-28 23:16:07 +02:00
}
static char*
get_param_str( char *line )
{
2011-08-06 09:53:48 +02:00
char *equal_ptr;
if (( equal_ptr = strstr( line, "=" ) ) != NULL ) {
equal_ptr++;
while ( isspace(*equal_ptr) ) equal_ptr++;
return equal_ptr;
}
return line;
2009-07-28 23:16:07 +02:00
}
static int
//inp_get_param_level( int param_num, char *depends_on[12000][100], char *param_names[12000], char *param_strs[12000], int total_params, int *level )
inp_get_param_level( int param_num, char ***depends_on, char **param_names, char **param_strs, int total_params, int *level )
{
2011-08-06 09:53:48 +02:00
int index1 = 0, comp_level = 0, temp_level = 0;
int index2 = 0;
if ( *(level+param_num) != -1 ) return *(level+param_num);
while ( depends_on[param_num][index1] != NULL ) {
index2 = 0;
while ( index2 <= total_params && param_names[index2] != depends_on[param_num][index1] ) index2++;
if ( index2 > total_params ) {
fprintf( stderr, "ERROR: unable to find dependency parameter for %s!\n", param_names[param_num] );
controlled_exit(EXIT_FAILURE);
}
temp_level = inp_get_param_level( index2, depends_on, param_names, param_strs, total_params, level );
temp_level++;
if ( temp_level > comp_level ) comp_level = temp_level;
index1++;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
*(level+param_num) = comp_level;
return comp_level;
2009-07-28 23:16:07 +02:00
}
static int
get_number_terminals( char *c )
{
2011-08-06 09:53:48 +02:00
int i, j, k;
char *name[12];
char nam_buf[33];
bool area_found = FALSE;
switch (*c) {
case 'r':
case 'c':
case 'l':
case 'k':
case 'f':
case 'h':
case 'b':
case 'v':
case 'i':
case 'd':
return 2;
break;
case 'u':
case 'j':
case 'w':
case 'z':
return 3;
break;
case 't':
case 'o':
case 'g':
case 'e':
case 's':
case 'y':
return 4;
break;
case 'm': /* recognition of 4, 5, 6, or 7 nodes for SOI devices needed */
i = 0;
/* find the first token with "off" or "=" in the line*/
while ( (i < 20) && (*c != '\0') ) {
char *inst = gettok_instance(&c);
strncpy(nam_buf, inst, 32);
txfree(inst);
if (strstr(nam_buf, "off") || strstr(nam_buf, "=")) break;
i++;
}
return i-2;
break;
case 'p': /* recognition of up to 100 cpl nodes */
i = j = 0;
/* find the last token in the line*/
while ( (i < 100) && (*c != '\0') ) {
strncpy(nam_buf, gettok_instance(&c), 32);
if (strstr(nam_buf, "=")) j++;
i++;
}
if (i == 100) return 0;
2009-07-28 23:16:07 +02:00
return i-j-2;
2011-08-06 09:53:48 +02:00
break;
case 'q': /* recognition of 3/4 terminal bjt's needed */
/* QXXXXXXX NC NB NE <NS> MNAME <AREA> <OFF> <IC=VBE, VCE> <TEMP=T> */
/* 12 tokens maximum */
i = j = 0;
while ( (i < 12) && (*c != '\0') ) {
char* comma;
name[i] = gettok_instance(&c);
if (strstr(name[i], "off") || strstr(name[i], "=")) j++;
/* If we have IC=VBE, VCE instead of IC=VBE,VCE we need to inc j */
if ((comma = strstr(name[i], ",")) != NULL && ( *(++comma) == '\0')) j++;
/* If we have IC=VBE , VCE ("," is a token) we need to inc j */
if (eq(name[i], ",")) j++;
i++;
}
i--;
area_found = FALSE;
for (k = i; k > i-j-1; k--) {
bool only_digits = TRUE;
char* nametmp = name[k];
/* MNAME has to contain at least one alpha character. AREA may be assumed
if we have a token with only digits, and where the previous token does not
end with a ',' */
while (*nametmp) {
if (isalpha(*nametmp) || (*nametmp == ',')) only_digits = FALSE;
nametmp++;
}
if (only_digits && (strstr(name[k-1],",") == NULL)) area_found = TRUE;
}
if (area_found) {
return i-j-2;
} else {
return i-j-1;
}
break;
default:
return 0;
break;
2009-07-28 23:16:07 +02:00
}
}
/* sort parameters based on parameter dependencies */
static void
inp_sort_params( struct line *start_card, struct line *end_card, struct line *card_bf_start, struct line *s_c, struct line *e_c )
{
2011-08-06 09:53:48 +02:00
char *param_name = NULL, *param_str = NULL, *param_ptr = NULL;
int i, j, num_params = 0, ind = 0, max_level = 0, num_terminals = 0, ioff = 1;
bool in_control = FALSE;
bool found_in_list = FALSE;
struct line *ptr;
char *curr_line;
char *str_ptr, *beg, *end, *new_str;
int skipped = 0;
int arr_size = 12000;
int *level;
int *param_skip;
char **param_names;
char **param_strs;
char ***depends_on;
struct line **ptr_array;
struct line **ptr_array_ordered;
NG_IGNORE(end_card);
if ( start_card == NULL ) return;
/* determine the number of lines with .param */
ptr = start_card;
while ( ptr != NULL ) {
if ( strstr( ptr->li_line, "=" ) ) {
num_params++;
}
ptr = ptr->li_next;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
arr_size = num_params;
num_params = 0; /* This is just to keep the code in row 2907ff. */
// dynamic memory allocation
level = TMALLOC(int, arr_size);
param_skip = TMALLOC(int, arr_size);
param_names = TMALLOC(char *, arr_size);
param_strs = TMALLOC(char *, arr_size);
/* array[row][column] -> depends_on[array_size][100] */
/* rows */
depends_on = TMALLOC(char **, arr_size);
/* columns */
for (i = 0; i < arr_size; i++) {
depends_on[i] = TMALLOC(char *, 100);
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
ptr_array = TMALLOC(struct line *, arr_size);
ptr_array_ordered = TMALLOC(struct line *, arr_size);
ptr = start_card;
while ( ptr != NULL ) {
// ignore .param lines without '='
if ( strstr( ptr->li_line, "=" ) ) {
depends_on[num_params][0] = NULL;
level[num_params] = -1;
param_names[num_params] = get_param_name( ptr->li_line ); /* strdup in fcn */
param_strs[num_params] = strdup( get_param_str( ptr->li_line ) );
ptr_array[num_params++] = ptr;
}
ptr = ptr->li_next;
}
// look for duplicately defined parameters and mark earlier one to skip
// param list is ordered as defined in netlist
for ( i = 0; i < num_params; i++ )
param_skip[i] = 0;
for ( i = 0; i < num_params; i++ )
for ( j = num_params-1; j >= 0; j-- ) {
if ( i != j && i < j && strcmp( param_names[i], param_names[j] ) == 0 ) {
// skip earlier one in list
param_skip[i] = 1;
skipped++;
}
}
for ( i = 0; i < num_params; i++ ) {
if ( param_skip[i] == 1 ) continue;
param_name = param_names[i];
for ( j = 0; j < num_params; j++ ) {
if ( j == i ) continue;
param_str = param_strs[j];
while ((param_ptr = strstr( param_str, param_name ) ) != NULL ) {
ioff = (strstr(param_ptr, "}") != NULL ? 1 : 0); /* want prevent wrong memory access below */
/* looking for curly braces or other string limiter */
if ( ( !isalnum( *(param_ptr-ioff) ) && *(param_ptr-ioff) != '_' &&
!isalnum( *(param_ptr+strlen(param_name)) ) && *(param_ptr+strlen(param_name)) != '_' )
|| strcmp( param_ptr, param_name ) == 0) { /* this are cases without curly braces */
ind = 0;
found_in_list = FALSE;
while ( depends_on[j][ind] != NULL ) {
if ( strcmp( param_name, depends_on[j][ind] ) == 0 ) {
found_in_list = TRUE;
break;
}
ind++;
}
if ( !found_in_list ) {
depends_on[j][ind++] = param_name;
depends_on[j][ind] = NULL;
}
break;
}
2011-08-06 09:53:48 +02:00
param_str = param_ptr + strlen(param_name);
}
}
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
for ( i = 0; i < num_params; i++ ) {
level[i] = inp_get_param_level( i, depends_on, param_names, param_strs, num_params, level );
if ( level[i] > max_level ) max_level = level[i];
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
/* look for unquoted parameters and quote them */
ptr = s_c;
in_control = FALSE;
while ( ptr != NULL && ptr != e_c ) {
curr_line = ptr->li_line;
if ( ciprefix( ".control", curr_line ) ) {
in_control = TRUE;
ptr = ptr->li_next;
continue;
}
if ( ciprefix( ".endc", curr_line ) ) {
in_control = FALSE;
ptr = ptr->li_next;
continue;
}
if ( in_control || curr_line[0] == '.' || curr_line[0] == '*' ) {
ptr = ptr->li_next;
continue;
}
num_terminals = get_number_terminals( curr_line );
if ( num_terminals <= 0 ) {
ptr = ptr->li_next;
continue;
}
for ( i = 0; i < num_params; i++ ) {
str_ptr = curr_line;
for ( j = 0; j < num_terminals+1; j++ ) {
while ( !isspace(*str_ptr) && *str_ptr != '\0' ) str_ptr++;
while ( isspace(*str_ptr) && *str_ptr != '\0' ) str_ptr++;
}
while ((str_ptr = strstr( str_ptr, param_names[i] ) ) != NULL ) {
/* make sure actually have the parameter name */
char before = *(str_ptr-1);
char after = *(str_ptr+strlen(param_names[i]));
if ( !( is_arith_char(before) || isspace(before) || (str_ptr-1) < curr_line ) ||
!( is_arith_char(after) || isspace(after) || after == '\0' ) ) {
str_ptr = str_ptr + 1;
continue;
}
beg = str_ptr - 1;
end = str_ptr + strlen(param_names[i]);
if ( ( isspace(*beg) || *beg == '=' ) &&
( isspace(*end) || *end == '\0' || *end == ')') ) { /* ')' added, any risks? h_vogt */
*str_ptr = '\0';
if ( *end != '\0' ) {
new_str = TMALLOC(char, strlen(curr_line) + strlen(param_names[i]) + strlen(end) + 3);
sprintf( new_str, "%s{%s}%s", curr_line, param_names[i], end );
} else {
new_str = TMALLOC(char, strlen(curr_line) + strlen(param_names[i]) + 3);
sprintf( new_str, "%s{%s}", curr_line, param_names[i] );
}
str_ptr = new_str + strlen(curr_line) + strlen(param_names[i]);
tfree(ptr->li_line);
curr_line = ptr->li_line = new_str;
}
str_ptr++;
}
}
ptr = ptr->li_next;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
ind = 0;
for ( i = 0; i <= max_level; i++ )
for ( j = num_params-1; j >= 0; j-- ) {
if ( level[j] == i ) {
if ( param_skip[j] == 0 ) {
ptr_array_ordered[ind++] = ptr_array[j];
}
}
}
num_params -= skipped;
if ( ind != num_params ) {
fprintf( stderr, "ERROR: found wrong number of parameters during levelization ( %d instead of %d parameter s)!\n", ind, num_params );
controlled_exit(EXIT_FAILURE);
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
/* fix next ptrs */
ptr = card_bf_start->li_next;
card_bf_start->li_next = ptr_array_ordered[0];
ptr_array_ordered[num_params-1]->li_next = ptr;
for ( i = 0; i < num_params-1; i++ )
ptr_array_ordered[i]->li_next = ptr_array_ordered[i+1];
// clean up memory
for ( i = 0; i < num_params; i++ ) {
tfree( param_names[i] );
tfree( param_strs[i] );
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
tfree(level);
tfree(param_skip);
tfree(param_names);
tfree(param_strs);
for (i = 0; i< arr_size; i++)
tfree(depends_on[i]);
tfree(depends_on);
tfree(ptr_array);
tfree(ptr_array_ordered);
2009-07-28 23:16:07 +02:00
}
static void
inp_add_params_to_subckt( struct line *subckt_card )
{
2011-08-06 09:53:48 +02:00
struct line *card = subckt_card->li_next;
char *curr_line = card->li_line;
char *subckt_line = subckt_card->li_line;
char *new_line, *param_ptr, *subckt_name, *end_ptr;
char keep;
while ( card != NULL && ciprefix( ".param", curr_line ) ) {
param_ptr = strstr( curr_line, " " );
while ( isspace(*param_ptr) ) param_ptr++;
if ( !strstr( subckt_line, "params:" ) ) {
new_line = TMALLOC(char, strlen(subckt_line) + strlen("params: ") + strlen(param_ptr) + 2);
sprintf( new_line, "%s params: %s", subckt_line, param_ptr );
subckt_name = subckt_card->li_line;
while ( !isspace(*subckt_name) ) subckt_name++;
while ( isspace(*subckt_name) ) subckt_name++;
end_ptr = subckt_name;
while ( !isspace(*end_ptr) ) end_ptr++;
keep = *end_ptr;
*end_ptr = '\0';
subckt_w_params[num_subckt_w_params++] = strdup(subckt_name);
*end_ptr = keep;
} else {
new_line = TMALLOC(char, strlen(subckt_line) + strlen(param_ptr) + 2);
sprintf( new_line, "%s %s", subckt_line, param_ptr );
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
tfree( subckt_line );
subckt_card->li_line = subckt_line = new_line;
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
*curr_line = '*';
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
card = card->li_next;
curr_line = card->li_line;
}
2009-07-28 23:16:07 +02:00
}
/*
* process a sequence of decks
* starting from a `.suckt' deck
* upto the corresponding `.ends' deck
* return a pointer to the terminating `.ends' deck
*
* recursivly descend
* when another `.subckt' is found
*
* parameters are removed from the main list
* and collected into a local list `first_param_card'
* then processed and reinserted into the main list
*
*/
static struct line *
inp_reorder_params_subckt(struct line *subckt_card)
2009-07-28 23:16:07 +02:00
{
struct line *first_param_card = NULL;
struct line *last_param_card = NULL;
struct line *prev_card = subckt_card;
struct line *c = subckt_card->li_next;
2011-08-06 09:53:48 +02:00
/* move .param lines to beginning of deck */
while ( c != NULL ) {
char *curr_line = c->li_line;
2011-08-06 09:53:48 +02:00
if ( *curr_line == '*' ) {
c = c->li_next;
continue;
}
2011-08-06 09:53:48 +02:00
if ( ciprefix( ".subckt", curr_line ) ) {
prev_card = inp_reorder_params_subckt(c);
c = prev_card->li_next;
continue;
}
if ( ciprefix( ".ends", curr_line ) ) {
if ( first_param_card ) {
inp_sort_params( first_param_card, last_param_card, subckt_card, subckt_card, c );
2011-08-06 09:53:48 +02:00
inp_add_params_to_subckt( subckt_card );
}
return c;
2011-08-06 09:53:48 +02:00
}
2009-07-28 23:16:07 +02:00
2011-08-06 09:53:48 +02:00
if ( ciprefix( ".param", curr_line ) ) {
if ( first_param_card )
last_param_card->li_next = c;
else
first_param_card = c;
last_param_card = c;
prev_card->li_next = c->li_next;
c = c->li_next;
last_param_card->li_next = NULL;
continue;
2011-08-06 09:53:48 +02:00
}
2011-08-06 09:53:48 +02:00
prev_card = c;
c = c->li_next;
2009-07-28 23:16:07 +02:00
}
/* the terminating `.ends' deck wasn't found */
controlled_exit(EXIT_FAILURE);
return NULL;
}
static void
inp_reorder_params( struct line *deck, struct line *list_head, struct line *end )
{
struct line *first_param_card = NULL;
struct line *last_param_card = NULL;
struct line *prev_card = list_head;
struct line *c = deck;
/* move .param lines to beginning of deck */
while ( c != NULL ) {
char *curr_line = c->li_line;
if ( *curr_line == '*' ) {
c = c->li_next;
continue;
}
if ( ciprefix( ".subckt", curr_line ) ) {
prev_card = inp_reorder_params_subckt(c);
c = prev_card->li_next;
continue;
}
/* check for an unexpected extra `.ends' deck */
2011-12-17 16:22:20 +01:00
if ( ciprefix( ".ends", curr_line ) ) {
fprintf(stderr, "Error: Unexpected extra .ends in line:\n %s.\n", curr_line);
controlled_exit(EXIT_FAILURE);
2011-12-17 16:22:20 +01:00
}
if ( ciprefix( ".param", curr_line ) ) {
if ( first_param_card )
last_param_card->li_next = c;
else
first_param_card = c;
last_param_card = c;
prev_card->li_next = c->li_next;
c = c->li_next;
last_param_card->li_next = NULL;
continue;
}
prev_card = c;
c = c->li_next;
}
inp_sort_params( first_param_card, last_param_card, list_head, deck, end );
2009-07-28 23:16:07 +02:00
}
// iterate through deck and find lines with multiply defined parameters
//
// split line up into multiple lines and place those new lines immediately
// afetr the current multi-param line in the deck
static int
inp_split_multi_param_lines( struct line *deck, int line_num )
{
2011-08-06 09:53:48 +02:00
struct line *card = deck, *param_end = NULL, *param_beg = NULL, *prev = NULL, *tmp_ptr;
char *curr_line, *equal_ptr, *beg_param, *end_param, *new_line;
char *array[5000];
int counter = 0, i;
bool get_expression = FALSE, get_paren_expression = FALSE;
char keep;
while ( card != NULL ) {
curr_line = card->li_line;
if ( *curr_line == '*' ) {
card = card->li_next;
continue;
}
if ( ciprefix( ".param", curr_line ) ) {
counter = 0;
while (( equal_ptr = strstr( curr_line, "=" ) ) != NULL ) {
// check for equality '=='
if ( *(equal_ptr+1) == '=' ) {
curr_line = equal_ptr+2;
continue;
}
// check for '!=', '<=', '>='
if ( *(equal_ptr-1) == '!' || *(equal_ptr-1) == '<' || *(equal_ptr-1) == '>' ) {
curr_line = equal_ptr+1;
continue;
}
counter++;
curr_line = equal_ptr + 1;
}
if ( counter <= 1 ) {
card = card->li_next;
continue;
}
// need to split multi param line
curr_line = card->li_line;
counter = 0;
while ( curr_line < card->li_line+strlen(card->li_line) && ( equal_ptr = strstr( curr_line, "=" ) ) != NULL ) {
// check for equality '=='
if ( *(equal_ptr+1) == '=' ) {
curr_line = equal_ptr+2;
continue;
}
// check for '!=', '<=', '>='
if ( *(equal_ptr-1) == '!' || *(equal_ptr-1) == '<' || *(equal_ptr-1) == '>' ) {
curr_line = equal_ptr+1;
continue;
}
beg_param = equal_ptr - 1;
end_param = equal_ptr + 1;
while ( isspace(*beg_param) ) beg_param--;
while ( !isspace(*beg_param) ) beg_param--;
while ( isspace(*end_param) ) end_param++;
while ( *end_param != '\0' && (!isspace(*end_param) || get_expression || get_paren_expression) ) {
if ( *end_param == '{' ) get_expression = TRUE;
if ( *end_param == '(' ) get_paren_expression = TRUE;
if ( *end_param == '}' ) get_expression = FALSE;
if ( *end_param == ')' ) get_paren_expression = FALSE;
end_param++;
}
beg_param++;
keep = *end_param;
*end_param = '\0';
new_line = TMALLOC(char, strlen(".param ") + strlen(beg_param) + 1);
sprintf( new_line, ".param %s", beg_param );
array[counter++] = new_line;
*end_param = keep;
curr_line = end_param;
}
tmp_ptr = card->li_next;
for ( i = 0; i < counter; i++ ) {
if ( param_end ) {
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
} else {
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = array[i];
param_end->li_linenum = line_num++;
}
// comment out current multi-param line
*(card->li_line) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
} // if ( ciprefix( ".param", curr_line ) )
prev = card;
card = card->li_next;
2009-07-28 23:16:07 +02:00
} // while ( card != NULL )
2011-08-06 09:53:48 +02:00
if ( param_end ) {
prev->li_next = param_beg;
prev = param_end;
2009-07-28 23:16:07 +02:00
}
2011-08-06 09:53:48 +02:00
return line_num;
2009-07-28 23:16:07 +02:00
}
2010-04-24 00:00:40 +02:00
2011-05-29 12:07:10 +02:00
/* ps compatibility:
ECOMP 3 0 TABLE {V(1,2)} = (-1 0V) (1, 10V)
2010-05-27 21:20:10 +02:00
-->
ECOMP 3 0 int3 int0 1
BECOMP int3 int0 V = pwl(V(1,2), -2, 0, -1, 0 , 1, 10V, 2, 10V)
2010-05-27 21:20:10 +02:00
GD16 16 1 TABLE {V(16,1)} ((-100V,-1pV)(0,0)(1m,1u)(2m,1m))
-->
GD16 16 1 int_16 int_1 1
BGD16 int_16 int_1 V = pwl (v(16,1) , -100V , -1pV , 0 , 0 , 1m , 1u , 2m , 1m )
*/
2010-04-24 00:00:40 +02:00
2011-05-29 12:07:10 +02:00
/* hs compatibility:
2010-04-24 00:00:40 +02:00
Exxx n1 n2 VCVS n3 n4 gain --> Exxx n1 n2 n3 n4 gain
Gxxx n1 n2 VCCS n3 n4 tr --> Exxx n1 n2 n3 n4 tr
2011-08-06 09:53:48 +02:00
Two step approach to keep the original names for reuse,
i.e. for current measurements like i(Exxx):
2011-08-06 09:53:48 +02:00
Exxx n1 n2 VOL = {equation}
-->
Exxx n1 n2 int1 0 1
BExxx int1 0 V = {equation}
2011-08-06 09:53:48 +02:00
Gxxx n1 n2 CUR = {equation}
-->
Gxxx n1 n2 int1 0 1
BGxxx int1 0 V = {equation}
2010-04-24 00:00:40 +02:00
2011-08-06 09:53:48 +02:00
Do the following transformations only if {equation} contains
2010-04-24 00:00:40 +02:00
simulation output like v(node), v(node1, node2), i(branch).
Otherwise let do numparam the substitutions (R=const is handled
in inp2r.c).
2011-08-06 09:53:48 +02:00
2010-04-24 00:00:40 +02:00
Rxxx n1 n2 R = {equation} or Rxxx n1 n2 {equation}
2011-08-06 09:53:48 +02:00
-->
2010-04-24 00:00:40 +02:00
BRxxx n1 n2 I = V(n1,n2)/{equation}
2011-08-06 09:53:48 +02:00
Unfortunately the capability for ac noise calculation of
2010-04-24 00:00:40 +02:00
resistance may be lost.
Cxxx n1 n2 C = {equation} or Cxxx n1 n2 {equation}
-->
Exxx n-aux 0 n1 n2 1
Cxxx n-aux 0 1
Bxxx n2 n1 I = i(Exxx) * equation
2011-08-06 09:53:48 +02:00
2010-04-24 00:00:40 +02:00
Lxxx n1 n2 L = {equation} or Lxxx n1 n2 {equation}
-->
Fxxx n-aux 0 Bxxx -1
Lxxx n-aux 0 1
Bxxx n1 n2 V = v(n-aux) * 1e-16
2010-04-24 00:00:40 +02:00
*/
static void inp_compat(struct line *deck)
{
char *str_ptr, *cut_line, *title_tok, *node1, *node2;
2010-07-10 13:27:57 +02:00
char *out_ptr, *exp_ptr, *beg_ptr, *end_ptr, *copy_ptr, *del_ptr;
char *xline;
2010-07-10 13:27:57 +02:00
size_t xlen, i, pai=0, paui=0, ii;
char *ckt_array[100];
2010-04-24 00:00:40 +02:00
struct line *new_line, *tmp_ptr;
struct line *param_end = NULL, *param_beg = NULL;
struct line *card;
int skip_control = 0;
for (card = deck; card; card = card->li_next) {
char *curr_line = card->li_line;
/* exclude any command inside .control ... .endc */
if ( ciprefix(".control", curr_line) ) {
skip_control ++;
continue;
} else if( ciprefix(".endc", curr_line) ) {
skip_control --;
continue;
} else if(skip_control > 0) {
continue;
}
if ( *curr_line == '*' )
continue;
2010-04-24 00:00:40 +02:00
if ( *curr_line == 'e' ) {
/* Exxx n1 n2 VCVS n3 n4 gain --> Exxx n1 n2 n3 n4 gain
remove vcvs */
2010-07-01 18:43:28 +02:00
if ((str_ptr = strstr( curr_line, "vcvs" )) != NULL) {
2011-08-06 09:53:48 +02:00
*str_ptr = ' ';
*(str_ptr + 1) = ' ';
*(str_ptr + 2) = ' ';
*(str_ptr + 3) = ' ';
2010-04-24 00:00:40 +02:00
}
2011-12-17 16:22:20 +01:00
/* Exxx n1 n2 value={equation}
-->
Exxx n1 n2 vol={equation} */
if ((str_ptr = strstr( curr_line, "value=" )) != NULL) {
*str_ptr = ' ';
*(str_ptr + 1) = ' ';
*(str_ptr + 2) = 'v';
*(str_ptr + 3) = 'o';
*(str_ptr + 4) = 'l';
}
/* Exxx n1 n2 TABLE {expression} = (x0, y0) (x1, y1) (x2, y2)
-->
Exxx n1 n2 int1 0 1
BExxx int1 0 V = pwl (expression, x0-(x2-x0)/2, y0, x0, y0, x1, y1, x2, y2, x2+(x2-x0)/2, y2)
*/
if ((str_ptr = strstr( curr_line, "table" )) != NULL) {
char *expression, *firstno, *ffirstno, *secondno, *midline, *lastno, *lastlastno;
double fnumber, lnumber, delta;
int nerror;
cut_line = curr_line;
/* title and nodes */
title_tok = gettok(&cut_line);
node1 = gettok(&cut_line);
node2 = gettok(&cut_line);
// Exxx n1 n2 int1 0 1
xlen = 2*strlen(title_tok) + strlen(node1) + strlen(node2)
+ 20 - 4*2 + 1;
ckt_array[0] = TMALLOC(char, xlen);
sprintf(ckt_array[0], "%s %s %s %s_int1 0 1",
title_tok, node1, node2, title_tok);
// get the expression
str_ptr = gettok(&cut_line); /* ignore 'table' */
tfree(str_ptr);
expression = gettok_char(&cut_line, '}', TRUE); /* expression */
if (!expression) {
fprintf(stderr, "Error: bad sytax in line %d\n %s\n",
card->li_linenum_orig, card->li_line);
controlled_exit(EXIT_BAD);
}
/* remove '{' and '}' from expression */
if ((str_ptr = strstr( expression, "{" )) != NULL)
*str_ptr = ' ';
if ((str_ptr = strstr( expression, "}" )) != NULL)
*str_ptr = ' ';
/* cut_line may now have a '=', if yes, it will have '{' and '}'
(braces around token after '=') */
if ((str_ptr = strstr( cut_line, "=" )) != NULL)
*str_ptr = ' ';
if ((str_ptr = strstr( cut_line, "{" )) != NULL)
*str_ptr = ' ';
if ((str_ptr = strstr( cut_line, "}" )) != NULL)
*str_ptr = ' ';
/* get first two numbers to establish extrapolation */
str_ptr = cut_line;
ffirstno = gettok_node(&cut_line);
firstno = copy(ffirstno);
fnumber = INPevaluate(&ffirstno, &nerror, TRUE);
secondno = gettok_node(&cut_line);
midline = cut_line;
cut_line = strrchr(str_ptr, '(');
/* replace '(' with ',' and ')' with ' ' */
while(*str_ptr) {
if (*str_ptr == '(')
*str_ptr = ',';
else if (*str_ptr == ')')
*str_ptr = ' ';
*str_ptr++;
}
/* scan for last two numbers */
lastno = gettok_node(&cut_line);
lnumber = INPevaluate(&lastno, &nerror, FALSE);
/* check for max-min and take half the difference for delta */
delta = (lnumber-fnumber)/2.;
lastlastno = gettok_node(&cut_line);
if (!secondno || (*midline == 0) || (delta <= 0.) || !lastlastno) {
fprintf(stderr, "Error: bad sytax in line %d\n %s\n",
card->li_linenum_orig, card->li_line);
controlled_exit(EXIT_BAD);
}
xlen = 2*strlen(title_tok) + strlen(expression) + 14 + strlen(firstno) +
2*strlen(secondno) + strlen(midline) + 14 +
strlen(lastlastno) + 50;
ckt_array[1] = TMALLOC(char, xlen);
sprintf(ckt_array[1], "b%s %s_int1 0 v = pwl(%s, %e, %s, %s, %s, %s, %e, %s)",
title_tok, title_tok, expression, fnumber-delta, secondno, firstno, secondno,
midline, lnumber + delta, lastlastno);
// insert new B source line immediately after current line
tmp_ptr = card->li_next;
for ( i = 0; i < 2; i++ ) {
if ( param_end ) {
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
} else {
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[i];
param_end->li_linenum = 0;
}
// comment out current variable e line
*(card->li_line) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
2011-12-17 16:22:20 +01:00
param_beg = param_end = NULL;
tfree(firstno);
tfree(lastlastno);
tfree(title_tok);
tfree(node1);
tfree(node2);
}
2011-08-06 09:53:48 +02:00
/* Exxx n1 n2 VOL = {equation}
-->
Exxx n1 n2 int1 0 1
BExxx int1 0 V = {equation}
*/
2010-07-01 18:43:28 +02:00
if ((str_ptr = strstr( curr_line, "vol" )) != NULL) {
cut_line = curr_line;
/* title and nodes */
title_tok = gettok(&cut_line);
node1 = gettok(&cut_line);
node2 = gettok(&cut_line);
/* Find equation, starts with '{', till end of line */
str_ptr = strstr(cut_line, "{");
2010-10-25 12:45:55 +02:00
if (str_ptr == NULL) {
fprintf(stderr,"ERROR: mal formed E line: %s\n",curr_line);
controlled_exit(EXIT_FAILURE);
}
// Exxx n1 n2 int1 0 1
xlen = 2*strlen(title_tok) + strlen(node1) + strlen(node2)
2011-08-06 09:53:48 +02:00
+ 20 - 4*2 + 1;
ckt_array[0] = TMALLOC(char, xlen);
sprintf(ckt_array[0], "%s %s %s %s_int1 0 1",
2011-08-06 09:53:48 +02:00
title_tok, node1, node2, title_tok);
// BExxx int1 0 V = {equation}
xlen = 2*strlen(title_tok) + strlen(str_ptr)
2011-08-06 09:53:48 +02:00
+ 20 - 3*2 + 1;
ckt_array[1] = TMALLOC(char, xlen);
sprintf(ckt_array[1], "b%s %s_int1 0 v = %s",
2011-08-06 09:53:48 +02:00
title_tok, title_tok, str_ptr);
// insert new B source line immediately after current line
2011-08-06 09:53:48 +02:00
tmp_ptr = card->li_next;
for ( i = 0; i < 2; i++ ) {
if ( param_end ) {
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
2011-08-06 09:53:48 +02:00
} else {
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[i];
param_end->li_linenum = 0;
2010-04-24 00:00:40 +02:00
}
// comment out current variable e line
*(card->li_line) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
2010-04-24 00:00:40 +02:00
}
2011-08-06 09:53:48 +02:00
} else if ( *curr_line == 'g' ) {
/* Gxxx n1 n2 VCCS n3 n4 tr --> Gxxx n1 n2 n3 n4 tr
2010-04-24 00:00:40 +02:00
remove vccs */
2010-07-01 18:43:28 +02:00
if ((str_ptr = strstr( curr_line, "vccs" )) != NULL) {
2011-08-06 09:53:48 +02:00
*str_ptr = ' ';
*(str_ptr + 1) = ' ';
*(str_ptr + 2) = ' ';
*(str_ptr + 3) = ' ';
2010-04-24 00:00:40 +02:00
}
2011-12-17 16:22:20 +01:00
/* Gxxx n1 n2 value={equation}
-->
Gxxx n1 n2 cur={equation} */
if ((str_ptr = strstr( curr_line, "value=" )) != NULL) {
*str_ptr = ' ';
*(str_ptr + 1) = ' ';
*(str_ptr + 2) = 'c';
*(str_ptr + 3) = 'u';
*(str_ptr + 4) = 'r';
}
/* Gxxx n1 n2 TABLE {expression} = (x0, y0) (x1, y1) (x2, y2)
-->
Gxxx n1 n2 int1 0 1
BGxxx int1 0 V = pwl (expression, x0-(x2-x0)/2, y0, x0, y0, x1, y1, x2, y2, x2+(x2-x0)/2, y2)
*/
if ((str_ptr = strstr( curr_line, "table" )) != NULL) {
char *expression, *firstno, *ffirstno, *secondno, *midline, *lastno, *lastlastno;
double fnumber, lnumber, delta;
int nerror;
cut_line = curr_line;
/* title and nodes */
title_tok = gettok(&cut_line);
node1 = gettok(&cut_line);
node2 = gettok(&cut_line);
// Gxxx n1 n2 int1 0 1
xlen = 2*strlen(title_tok) + strlen(node1) + strlen(node2)
+ 20 - 4*2 + 1;
ckt_array[0] = TMALLOC(char, xlen);
sprintf(ckt_array[0], "%s %s %s %s_int1 0 1",
title_tok, node1, node2, title_tok);
// get the expression
str_ptr = gettok(&cut_line); /* ignore 'table' */
tfree(str_ptr);
expression = gettok_char(&cut_line, '}', TRUE); /* expression */
if (!expression) {
fprintf(stderr, "Error: bad sytax in line %d\n %s\n",
card->li_linenum_orig, card->li_line);
controlled_exit(EXIT_BAD);
}
/* remove '{' and '}' from expression */
if ((str_ptr = strstr( expression, "{" )) != NULL)
*str_ptr = ' ';
if ((str_ptr = strstr( expression, "}" )) != NULL)
*str_ptr = ' ';
/* cut_line may now have a '=', if yes, it will have '{' and '}'
(braces around token after '=') */
if ((str_ptr = strstr( cut_line, "=" )) != NULL)
*str_ptr = ' ';
if ((str_ptr = strstr( cut_line, "{" )) != NULL)
*str_ptr = ' ';
if ((str_ptr = strstr( cut_line, "}" )) != NULL)
*str_ptr = ' ';
/* get first two numbers to establish extrapolation */
str_ptr = cut_line;
ffirstno = gettok_node(&cut_line);
firstno = copy(ffirstno);
fnumber = INPevaluate(&ffirstno, &nerror, TRUE);
secondno = gettok_node(&cut_line);
midline = cut_line;
cut_line = strrchr(str_ptr, '(');
/* replace '(' with ',' and ')' with ' ' */
while(*str_ptr) {
if (*str_ptr == '(')
*str_ptr = ',';
else if (*str_ptr == ')')
*str_ptr = ' ';
*str_ptr++;
}
/* scan for last two numbers */
lastno = gettok_node(&cut_line);
lnumber = INPevaluate(&lastno, &nerror, FALSE);
/* check for max-min and take half the difference for delta */
delta = (lnumber-fnumber)/2.;
lastlastno = gettok_node(&cut_line);
if (!secondno || (*midline == 0) || (delta <= 0.) || !lastlastno) {
fprintf(stderr, "Error: bad sytax in line %d\n %s\n",
card->li_linenum_orig, card->li_line);
controlled_exit(EXIT_BAD);
}
/* BGxxx int1 0 V = pwl (expression, x0-(x2-x0)/2, y0, x0, y0, x1, y1, x2, y2, x2+(x2-x0)/2, y2) */
xlen = 2*strlen(title_tok) + strlen(expression) + 14 + strlen(firstno) +
2*strlen(secondno) + strlen(midline) + 14 +
strlen(lastlastno) + 50;
ckt_array[1] = TMALLOC(char, xlen);
sprintf(ckt_array[1], "b%s %s_int1 0 v = pwl(%s, %e, %s, %s, %s, %s, %e, %s)",
title_tok, title_tok, expression, fnumber-delta, secondno, firstno, secondno,
midline, lnumber + delta, lastlastno);
// insert new B source line immediately after current line
tmp_ptr = card->li_next;
for ( i = 0; i < 2; i++ ) {
if ( param_end ) {
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
} else {
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[i];
param_end->li_linenum = 0;
}
// comment out current variable e line
*(card->li_line) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
tfree(firstno);
tfree(lastlastno);
tfree(title_tok);
tfree(node1);
tfree(node2);
}
/*
2011-08-06 09:53:48 +02:00
Gxxx n1 n2 CUR = {equation}
-->
Gxxx n1 n2 int1 0 1
BGxxx int1 0 V = {equation}
*/
2010-07-01 18:43:28 +02:00
if ((str_ptr = strstr( curr_line, "cur" )) != NULL) {
cut_line = curr_line;
/* title and nodes */
title_tok = gettok(&cut_line);
node1 = gettok(&cut_line);
node2 = gettok(&cut_line);
/* Find equation, starts with '{', till end of line */
str_ptr = strstr(cut_line, "{");
2010-10-25 12:45:55 +02:00
if (str_ptr == NULL) {
fprintf(stderr,"ERROR: mal formed G line: %s\n",curr_line);
controlled_exit(EXIT_FAILURE);
}
// Gxxx n1 n2 int1 0 1
xlen = 2*strlen(title_tok) + strlen(node1) + strlen(node2)
2011-08-06 09:53:48 +02:00
+ 20 - 4*2 + 1;
ckt_array[0] = TMALLOC(char, xlen);
sprintf(ckt_array[0], "%s %s %s %s_int1 0 1",
2011-08-06 09:53:48 +02:00
title_tok, node1, node2, title_tok);
// BGxxx int1 0 V = {equation}
xlen = 2*strlen(title_tok) + strlen(str_ptr)
2011-08-06 09:53:48 +02:00
+ 20 - 3*2 + 1;
ckt_array[1] = TMALLOC(char, xlen);
sprintf(ckt_array[1], "b%s %s_int1 0 v = %s",
2011-08-06 09:53:48 +02:00
title_tok, title_tok, str_ptr);
// insert new B source line immediately after current line
2011-08-06 09:53:48 +02:00
tmp_ptr = card->li_next;
for ( i = 0; i < 2; i++ ) {
if ( param_end ) {
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
2011-08-06 09:53:48 +02:00
} else {
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[i];
param_end->li_linenum = 0;
2010-04-24 00:00:40 +02:00
}
// comment out current variable g line
*(card->li_line) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
2010-04-24 00:00:40 +02:00
}
}
2011-08-06 09:53:48 +02:00
/* Rxxx n1 n2 R = {equation} or Rxxx n1 n2 {equation}
-->
BRxxx pos neg I = V(pos, neg)/{equation}
*/
2010-04-24 00:00:40 +02:00
else if ( *curr_line == 'r' ) {
if ((!strstr(curr_line, "v(")) && (!strstr(curr_line, "i(")))
continue;
2010-04-24 00:00:40 +02:00
cut_line = curr_line;
/* make BRxxx pos neg I = V(pos, neg)/{equation}*/
title_tok = gettok(&cut_line);
node1 = gettok(&cut_line);
node2 = gettok(&cut_line);
/* Find equation, starts with '{', till end of line */
str_ptr = strstr(cut_line, "{");
2010-10-25 12:45:55 +02:00
if (str_ptr == NULL) {
fprintf(stderr,"ERROR: mal formed R line: %s\n", curr_line);
controlled_exit(EXIT_FAILURE);
2011-08-06 09:53:48 +02:00
}
2010-04-24 00:00:40 +02:00
xlen = strlen(title_tok) + strlen(node1) + strlen(node2) +
2010-05-09 14:47:43 +02:00
strlen(node1) + strlen(node2) + strlen(str_ptr) +
28 - 6*2 + 1;
xline = TMALLOC(char, xlen);
2011-08-06 09:53:48 +02:00
sprintf(xline, "b%s %s %s i = v(%s, %s)/(%s)", title_tok, node1, node2,
node1, node2, str_ptr);
2010-04-24 00:00:40 +02:00
new_line = alloc(struct line);
2011-08-06 09:53:48 +02:00
new_line->li_next = NULL;
new_line->li_error = NULL;
new_line->li_actual = NULL;
new_line->li_line = xline;
new_line->li_linenum = 0;
// comment out current old R line
*(card->li_line) = '*';
// insert new B source line immediately after current line
tmp_ptr = card->li_next;
card->li_next = new_line;
new_line->li_next = tmp_ptr;
// point 'card' pointer to the new line
card = new_line;
}
/* Cxxx n1 n2 C = {equation} or Cxxx n1 n2 {equation}
-->
Exxx n-aux 0 n1 n2 1
Cxxx n-aux 0 1
Bxxx n2 n1 I = i(Exxx) * equation
*/
2010-04-24 00:00:40 +02:00
else if ( *curr_line == 'c' ) {
if ((!strstr(curr_line, "v(")) && (!strstr(curr_line, "i(")))
continue;
2010-04-24 00:00:40 +02:00
cut_line = curr_line;
/* title and nodes */
title_tok = gettok(&cut_line);
node1 = gettok(&cut_line);
node2 = gettok(&cut_line);
/* Find equation, starts with '{', till end of line */
str_ptr = strstr(cut_line, "{");
2010-10-25 12:45:55 +02:00
if (str_ptr == NULL) {
fprintf(stderr,"ERROR: mal formed C line: %s\n",curr_line);
controlled_exit(EXIT_FAILURE);
}
// Exxx n-aux 0 n1 n2 1
xlen = 2*strlen(title_tok) + strlen(node1) + strlen(node2)
2011-08-06 09:53:48 +02:00
+ 21 - 4*2 + 1;
ckt_array[0] = TMALLOC(char, xlen);
sprintf(ckt_array[0], "e%s %s_int2 0 %s %s 1",
title_tok, title_tok, node1, node2);
// Cxxx n-aux 0 1
xlen = 2*strlen(title_tok)
2011-08-06 09:53:48 +02:00
+ 15 - 2*2 + 1;
ckt_array[1] = TMALLOC(char, xlen);
sprintf(ckt_array[1], "c%s %s_int2 0 1", title_tok, title_tok);
// Bxxx n2 n1 I = i(Exxx) * equation
xlen = 2*strlen(title_tok) + strlen(node2) + strlen(node1)
2011-08-06 09:53:48 +02:00
+ strlen(str_ptr) + 27 - 2*5 + 1;
ckt_array[2] = TMALLOC(char, xlen);
sprintf(ckt_array[2], "b%s %s %s i = i(e%s) * (%s)",
title_tok, node2, node1, title_tok, str_ptr);
2010-04-24 00:00:40 +02:00
// insert new B source line immediately after current line
2011-08-06 09:53:48 +02:00
tmp_ptr = card->li_next;
for ( i = 0; i < 3; i++ ) {
if ( param_end ) {
2010-04-24 00:00:40 +02:00
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
2011-08-06 09:53:48 +02:00
} else {
2010-04-24 00:00:40 +02:00
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[i];
param_end->li_linenum = 0;
}
// comment out current variable capacitor line
*(card->li_line) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
}
2011-08-06 09:53:48 +02:00
/* Lxxx n1 n2 L = {equation} or Lxxx n1 n2 {equation}
-->
Fxxx n-aux 0 Bxxx -1
Lxxx n-aux 0 1
Bxxx n1 n2 V = v(n-aux) * equation
*/
2010-04-24 00:00:40 +02:00
else if ( *curr_line == 'l' ) {
if ((!strstr(curr_line, "v(")) && (!strstr(curr_line, "i(")))
continue;
2010-04-24 00:00:40 +02:00
cut_line = curr_line;
/* title and nodes */
title_tok = gettok(&cut_line);
node1 = gettok(&cut_line);
node2 = gettok(&cut_line);
/* Find equation, starts with '{', till end of line */
str_ptr = strstr(cut_line, "{");
2010-10-25 12:45:55 +02:00
if (str_ptr == NULL) {
fprintf(stderr,"ERROR: mal formed L line: %s\n", curr_line);
controlled_exit(EXIT_FAILURE);
}
// Fxxx n-aux 0 Bxxx 1
xlen = 3*strlen(title_tok)
2011-08-06 09:53:48 +02:00
+ 20 - 3*2 + 1;
ckt_array[0] = TMALLOC(char, xlen);
sprintf(ckt_array[0], "f%s %s_int2 0 b%s -1",
title_tok, title_tok, title_tok);
// Lxxx n-aux 0 1
xlen = 2*strlen(title_tok)
2011-08-06 09:53:48 +02:00
+ 15 - 2*2 + 1;
ckt_array[1] = TMALLOC(char, xlen);
sprintf(ckt_array[1], "l%s %s_int2 0 1", title_tok, title_tok);
// Bxxx n1 n2 V = v(n-aux) * equation
xlen = 2*strlen(title_tok) + strlen(node2) + strlen(node1)
2011-08-06 09:53:48 +02:00
+ strlen(str_ptr) + 31 - 2*5 + 1;
ckt_array[2] = TMALLOC(char, xlen);
sprintf(ckt_array[2], "b%s %s %s v = v(%s_int2) * (%s)",
title_tok, node1, node2, title_tok, str_ptr);
2010-04-24 00:00:40 +02:00
// insert new B source line immediately after current line
2011-08-06 09:53:48 +02:00
tmp_ptr = card->li_next;
for ( i = 0; i < 3; i++ ) {
if ( param_end ) {
2010-04-24 00:00:40 +02:00
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
2011-08-06 09:53:48 +02:00
} else {
2010-04-24 00:00:40 +02:00
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[i];
param_end->li_linenum = 0;
}
// comment out current variable capacitor line
*(card->li_line) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
}
2011-08-06 09:53:48 +02:00
/* .probe -> .save
.print, .plot, .save, .four,
An ouput vector may be replaced by the following:
myoutput=par('expression')
.meas
A vector out_variable may be replaced by
par('expression')
*/
2010-07-10 13:27:57 +02:00
else if ( *curr_line == '.' ) {
// replace .probe by .save
2010-07-24 20:51:06 +02:00
if((str_ptr = strstr(curr_line, ".probe")) != NULL)
2010-07-10 13:27:57 +02:00
memcpy(str_ptr, ".save ", 6);
2011-08-06 09:53:48 +02:00
/* Various formats for measure statement:
* .MEASURE {DC|AC|TRAN} result WHEN out_variable=val
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result WHEN out_variable=out_variable2
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=val
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=out_variable3
* + <TD=td>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable AT=val
* + <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result {AVG|MIN|MAX|MIN_AT|MAX_AT|PP|RMS} out_variable
* + <TD=td> <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result INTEG<RAL> out_variable
* + <TD=td> <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result DERIV<ATIVE> out_variable AT=val
*
* .MEASURE {DC|AC|TRAN} result DERIV<ATIVE> out_variable WHEN out_variable2=val
* + <TD=td>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result DERIV<ATIVE> out_variable WHEN out_variable2=out_variable3
* + <TD=td>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
The user may set any out_variable to par(' expr ').
We have to teplace this by v(pa_xx) and generate a B source line.
* ----------------------------------------------------------------- */
2010-07-10 13:27:57 +02:00
if ( ciprefix(".meas", curr_line) ) {
if (strstr(curr_line, "par") == NULL) continue;
2011-08-06 09:53:48 +02:00
cut_line = curr_line;
// search for 'par'
while((str_ptr = strstr(cut_line, "par")) != NULL) {
if (pai > 99) {
fprintf(stderr, "ERROR: No more than 99 'par' per input file\n");
controlled_exit(EXIT_FAILURE);
}
// we have ' par({ ... })', the right delimeter is a ' ' or '='
if ( ciprefix(" par({", (str_ptr-1)) ) {
// find expression
beg_ptr = end_ptr = str_ptr + 5;
while ((*end_ptr != ' ') && (*end_ptr != '=') && (*end_ptr != '\0'))
end_ptr++;
exp_ptr = copy_substring(beg_ptr, end_ptr-2);
cut_line = str_ptr;
// generate node
out_ptr = TMALLOC(char, 6);
sprintf(out_ptr, "pa_%02d", (int)pai);
// Bout_ptr out_ptr 0 V = v(expr_ptr)
xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1;
ckt_array[pai] = TMALLOC(char, xlen);
sprintf(ckt_array[pai], "b%s %s 0 v = %s",
out_ptr, out_ptr, exp_ptr);
ckt_array[++pai] = NULL;
// length of the replacement V(out_ptr)
xlen = strlen(out_ptr) + 4;
del_ptr = copy_ptr = TMALLOC(char, xlen);
sprintf(copy_ptr, "v(%s)", out_ptr);
// length of the replacement part in original line
xlen = strlen(exp_ptr) + 7;
// copy the replacement without trailing '\0'
for (ii = 0; ii < xlen; ii++)
if (*copy_ptr)
2010-07-10 13:27:57 +02:00
*cut_line++ = *copy_ptr++;
2011-08-06 09:53:48 +02:00
else
*cut_line++ = ' ';
tfree(del_ptr);
tfree(exp_ptr);
tfree(out_ptr);
}
// or we have '={par({ ... })}', the right delimeter is a ' '
else if ( ciprefix("={par({", (str_ptr-2)) ) {
// find expression
beg_ptr = end_ptr = str_ptr + 5;
while ((*end_ptr != ' ') && (*end_ptr != '\0'))
end_ptr++;
exp_ptr = copy_substring(beg_ptr, end_ptr-3);
// generate node
out_ptr = TMALLOC(char, 6);
sprintf(out_ptr, "pa_%02d", (int)pai);
// Bout_ptr out_ptr 0 V = v(expr_ptr)
xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1;
ckt_array[pai] = TMALLOC(char, xlen);
sprintf(ckt_array[pai], "b%s %s 0 v = %s",
out_ptr, out_ptr, exp_ptr);
ckt_array[++pai] = NULL;
// length of the replacement V(out_ptr)
xlen = strlen(out_ptr) + 4;
del_ptr = copy_ptr = TMALLOC(char, xlen);
sprintf(copy_ptr, "v(%s)", out_ptr);
// length of the replacement part in original line
xlen = strlen(exp_ptr) + 9;
// skip '='
cut_line++;
// copy the replacement without trailing '\0'
for (ii = 0; ii < xlen; ii++)
if (*copy_ptr)
2010-07-10 13:27:57 +02:00
*cut_line++ = *copy_ptr++;
2011-08-06 09:53:48 +02:00
else *cut_line++ = ' ';
tfree(del_ptr);
tfree(exp_ptr);
tfree(out_ptr);
}
// nothing to replace
else {
cut_line = str_ptr + 1;
continue;
}
} // while 'par'
// no replacement done, go to next line
if (pai == paui) continue;
// remove white spaces
card->li_line = inp_remove_ws(curr_line);
// insert new B source line immediately after current line
tmp_ptr = card->li_next;
for ( ii = paui; ii < pai; ii++ ) {
if ( param_end ) {
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
} else {
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[ii];
param_end->li_linenum = 0;
2010-07-10 13:27:57 +02:00
}
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
paui = pai;
2011-08-06 09:53:48 +02:00
} else if (( ciprefix(".save", curr_line) ) || ( ciprefix(".four", curr_line) )
|| ( ciprefix(".print", curr_line) ) || ( ciprefix(".plot", curr_line) )) {
2010-07-10 13:27:57 +02:00
if (strstr(curr_line, "par") == NULL) continue;
2011-08-06 09:53:48 +02:00
cut_line = curr_line;
// search for 'par'
while((str_ptr = strstr(cut_line, "par")) != NULL) {
if (pai > 99) {
fprintf(stderr, "ERROR: No more than 99 'par' per input file!\n");
controlled_exit(EXIT_FAILURE);
}
// we have ' par({ ... })'
if ( ciprefix(" par({", (str_ptr-1)) ) {
// find expression
beg_ptr = end_ptr = str_ptr + 5;
while ((*end_ptr != ' ') && (*end_ptr != '\0'))
end_ptr++;
exp_ptr = copy_substring(beg_ptr, end_ptr-2);
cut_line = str_ptr;
// generate node
out_ptr = TMALLOC(char, 6);
sprintf(out_ptr, "pa_%02d", (int)pai);
// Bout_ptr out_ptr 0 V = v(expr_ptr)
xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1;
ckt_array[pai] = TMALLOC(char, xlen);
sprintf(ckt_array[pai], "b%s %s 0 v = %s",
out_ptr, out_ptr, exp_ptr);
ckt_array[++pai] = NULL;
// length of the replacement V(out_ptr)
xlen = strlen(out_ptr) + 1;
del_ptr = copy_ptr = TMALLOC(char, xlen);
sprintf(copy_ptr, "%s", out_ptr);
// length of the replacement part in original line
xlen = strlen(exp_ptr) + 7;
// copy the replacement without trailing '\0'
for (ii = 0; ii < xlen; ii++)
if (*copy_ptr)
2010-07-10 13:27:57 +02:00
*cut_line++ = *copy_ptr++;
2011-08-06 09:53:48 +02:00
else
*cut_line++ = ' ';
tfree(del_ptr);
tfree(exp_ptr);
tfree(out_ptr);
}
// or we have '={par({ ... })}'
else if ( ciprefix("={par({", (str_ptr-2)) ) {
// find myoutput
beg_ptr = end_ptr = str_ptr - 2;
while (*beg_ptr != ' ')
beg_ptr--;
out_ptr = copy_substring(beg_ptr + 1, end_ptr);
cut_line = beg_ptr + 1;
// find expression
beg_ptr = end_ptr = str_ptr + 5;
while ((*end_ptr != ' ') && (*end_ptr != '\0'))
end_ptr++;
exp_ptr = copy_substring(beg_ptr, end_ptr-3);
// Bout_ptr out_ptr 0 V = v(expr_ptr)
xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1;
ckt_array[pai] = TMALLOC(char, xlen);
sprintf(ckt_array[pai], "b%s %s 0 v = %s",
out_ptr, out_ptr, exp_ptr);
ckt_array[++pai] = NULL;
// length of the replacement V(out_ptr)
xlen = strlen(out_ptr) + 1;
del_ptr = copy_ptr = TMALLOC(char, xlen);
sprintf(copy_ptr, "%s", out_ptr);
// length of the replacement part in original line
xlen = strlen(out_ptr) + strlen(exp_ptr) + 10;
// copy the replacement without trailing '\0'
for (ii = 0; ii < xlen; ii++)
if (*copy_ptr)
2010-07-10 13:27:57 +02:00
*cut_line++ = *copy_ptr++;
2011-08-06 09:53:48 +02:00
else *cut_line++ = ' ';
tfree(del_ptr);
tfree(exp_ptr);
tfree(out_ptr);
}
// nothing to replace
else
cut_line = str_ptr + 1;
} // while 'par'
// no replacement done, go to next line
if (pai == paui) continue;
// remove white spaces
card->li_line = inp_remove_ws(curr_line);
// insert new B source line immediately after current line
tmp_ptr = card->li_next;
for ( ii = paui; ii < pai; ii++ ) {
if ( param_end ) {
param_end->li_next = alloc(struct line);
param_end = param_end->li_next;
} else {
param_end = param_beg = alloc(struct line);
}
param_end->li_next = NULL;
param_end->li_error = NULL;
param_end->li_actual = NULL;
param_end->li_line = ckt_array[ii];
param_end->li_linenum = 0;
2010-07-10 13:27:57 +02:00
}
// comment out current variable capacitor line
// *(ckt_array[0]) = '*';
// insert new param lines immediately after current line
tmp_ptr = card->li_next;
card->li_next = param_beg;
param_end->li_next = tmp_ptr;
// point 'card' pointer to last in scalar list
card = param_end;
param_beg = param_end = NULL;
paui = pai;
2011-08-06 09:53:48 +02:00
// continue;
2010-07-10 13:27:57 +02:00
} // if .print etc.
} // if('.')
2010-04-24 00:00:40 +02:00
}
}
/* lines for B sources: no parsing in numparam code, just replacement of parameters.
Parsing done in B source parser.
To achive this, do the following:
Remove all '{' and '}' --> no parsing of equations in numparam
2011-08-06 09:53:48 +02:00
Place '{' and '}' directly around all potential parameters,
thus skip function names like exp (search for exp( to detect fcn name),
2010-04-24 00:00:40 +02:00
functions containing nodes like v(node), v(node1, node2), i(branch)
and other keywords. --> Only parameter replacement in numparam
*/
static void inp_bsource_compat(struct line *deck)
{
2010-05-15 00:39:56 +02:00
char *equal_ptr, *str_ptr, *tmp_char, *new_str, *final_str;
2010-04-24 00:00:40 +02:00
char actchar, prevchar = ' ';
2010-05-15 00:39:56 +02:00
struct line *card, *new_line, *tmp_ptr;
2010-04-24 00:00:40 +02:00
wordlist *wl = NULL, *wlist = NULL, *cwl;
2010-05-27 21:33:57 +02:00
char buf[512];
2010-04-24 00:00:40 +02:00
size_t i, xlen, ustate = 0;
2010-05-15 00:39:56 +02:00
int skip_control = 0;
2010-05-27 21:20:10 +02:00
int error1;
2010-05-15 00:39:56 +02:00
for (card = deck; card; card = card->li_next) {
char *curr_line = card->li_line;
/* exclude any command inside .control ... .endc */
if ( ciprefix(".control", curr_line) ) {
skip_control ++;
continue;
} else if( ciprefix(".endc", curr_line) ) {
skip_control --;
continue;
} else if(skip_control > 0) {
continue;
}
2010-04-24 00:00:40 +02:00
if ( *curr_line == 'b' ) {
2010-05-27 21:20:10 +02:00
/* remove white spaces of everything inside {}*/
card->li_line = inp_remove_ws(card->li_line);
curr_line = card->li_line;
2010-04-24 00:00:40 +02:00
/* store starting point for later parsing, beginning of {expression} */
equal_ptr = strstr(curr_line, "=");
2011-08-06 09:53:48 +02:00
/* check for errors */
if (equal_ptr == NULL) {
2010-10-25 12:45:55 +02:00
fprintf(stderr,"ERROR: mal formed B line: %s\n", curr_line);
2011-08-06 09:53:48 +02:00
controlled_exit(EXIT_FAILURE);
}
2010-04-24 00:00:40 +02:00
/* find the m={m} token and remove it */
2010-07-01 18:43:28 +02:00
if((str_ptr = strstr(curr_line, "m={m}")) != NULL)
2011-08-06 09:53:48 +02:00
memcpy( str_ptr, " ", 5 );
2010-04-24 00:00:40 +02:00
/* scan the line and remove all '{' and '}' */
str_ptr = curr_line;
while (*str_ptr) {
if ((*str_ptr == '{') || (*str_ptr == '}'))
*str_ptr = ' ';
str_ptr++;
}
/* scan the expression */
str_ptr = equal_ptr + 1;
while (*str_ptr != '\0') {
while ((*str_ptr != '\0') && isspace(*str_ptr))
str_ptr++;
if (*str_ptr == '\0') break;
actchar = *str_ptr;
cwl = alloc(struct wordlist);
cwl->wl_prev = wl;
if (wl)
wl->wl_next = cwl;
else {
wlist = cwl;
cwl->wl_next = NULL;
}
if ((actchar == ',') || (actchar == '(') || (actchar == ')')
2011-08-06 09:53:48 +02:00
|| (actchar == '*') || (actchar == '/') || (actchar == '^')
|| (actchar == '+') || (actchar == '?') || (actchar == ':')) {
2010-04-24 00:00:40 +02:00
if ((actchar == '*') && (*(str_ptr+1) == '*')) {
actchar = '^';
str_ptr++;
}
buf[0] = actchar;
buf[1] = '\0';
cwl->wl_word = copy(buf);
str_ptr++;
if (actchar == ')') ustate = 0;
else ustate = 1; /* we have an operator */
2011-08-06 09:53:48 +02:00
} else if ((actchar == '>') || (actchar == '<')
|| (actchar == '!') || (actchar == '=') ) {
/* >=, <=, !=, ==, <>, ... */
char *beg = str_ptr++;
if ((*str_ptr == '=') || (*str_ptr == '<') || (*str_ptr == '>'))
2010-04-24 00:00:40 +02:00
str_ptr++;
cwl->wl_word = copy_substring(beg, str_ptr);
2010-04-24 00:00:40 +02:00
ustate = 1; /* we have an operator */
2011-08-06 09:53:48 +02:00
} else if ((actchar == '|') || (actchar == '&')) {
char *beg = str_ptr++;
if ((*str_ptr == '|') || (*str_ptr == '&'))
str_ptr++;
cwl->wl_word = copy_substring(beg, str_ptr);
ustate = 1; /* we have an operator */
2011-08-06 09:53:48 +02:00
} else if ((actchar == '-') && (ustate == 0)) {
2010-04-24 00:00:40 +02:00
buf[0] = actchar;
buf[1] = '\0';
cwl->wl_word = copy(buf);
str_ptr++;
ustate = 1; /* we have an operator */
2011-08-06 09:53:48 +02:00
} else if ((actchar == '-') && (ustate == 1)) {
2010-04-24 00:00:40 +02:00
cwl->wl_word = copy("");
str_ptr++;
ustate = 2; /* place a '-' in front of token */
2011-08-06 09:53:48 +02:00
} else if (isalpha(actchar)) {
2010-04-24 00:00:40 +02:00
/* unary -, change sign */
if (ustate == 2) {
i = 1;
buf[0] = '-';
2011-08-06 09:53:48 +02:00
} else i = 0;
2010-04-24 00:00:40 +02:00
if (((actchar == 'v') || (actchar == 'i')) && (*(str_ptr+1) == '(')) {
while (*str_ptr != ')') {
buf[i] = *str_ptr;
i++;
str_ptr++;
}
buf[i] = *str_ptr;
2011-08-06 09:53:48 +02:00
buf[i+1] = '\0';
2010-04-24 00:00:40 +02:00
cwl->wl_word = copy(buf);
str_ptr++;
2011-08-06 09:53:48 +02:00
} else {
while (isalnum(*str_ptr) || (*str_ptr == '!') || (*str_ptr == '#')
|| (*str_ptr == '$')|| (*str_ptr == '%')|| (*str_ptr == '_')
|| (*str_ptr == '[')|| (*str_ptr == ']')) {
2010-04-24 00:00:40 +02:00
buf[i] = *str_ptr;
i++;
str_ptr++;
}
2011-08-06 09:53:48 +02:00
buf[i] = '\0';
2010-05-27 21:20:10 +02:00
/* no parens {} around time, hertz, temper, the constants
pi and e which are defined in inpptree.c and around pwl */
2011-08-06 09:53:48 +02:00
if ((*str_ptr == '(') || cieq(buf, "hertz") || cieq(buf, "temper")
|| cieq(buf, "time") || cieq(buf, "pi") || cieq(buf, "e")
|| cieq(buf, "pwl")) {
2010-05-27 21:20:10 +02:00
/* special handling of pwl lines:
Put braces around tokens and around expressions, use ','
as separator like:
2011-08-06 09:53:48 +02:00
pwl(i(Vin), {x0-1},{y0},
{x0},{y0},{x1},{y1}, {x2},{y2},{x3},{y3},
2010-05-27 21:20:10 +02:00
{x3+1},{y3})
*/
2011-08-06 09:53:48 +02:00
/*
if (cieq(buf, "pwl")) {
// go past i(Vin)
i = 3;
while (*str_ptr != ')') {
buf[i] = *str_ptr;
i++;
str_ptr++;
}
buf[i] = *str_ptr;
i++;
str_ptr++;
// find first ','
while (*str_ptr != ',') {
buf[i] = *str_ptr;
i++;
str_ptr++;
}
buf[i] = *str_ptr;
i++;
buf[i] = '{';
i++;
str_ptr++;
while (*str_ptr != ')') {
if (*str_ptr == ',') {
buf[i] = '}';
i++;
buf[i] = ',';
i++;
buf[i] = '{';
i++;
str_ptr++;
}
else {
buf[i] = *str_ptr;
i++;
str_ptr++;
}
}
buf[i] = '}';
i++;
buf[i] = *str_ptr;
i++;
buf[i] = '\0';
str_ptr++;
}
*/
2010-04-24 00:00:40 +02:00
cwl->wl_word = copy(buf);
}
2010-05-15 00:39:56 +02:00
/* {} around all other tokens */
2010-04-24 00:00:40 +02:00
else {
xlen = strlen(buf);
tmp_char = TMALLOC(char, xlen + 3);
2010-04-24 00:00:40 +02:00
sprintf(tmp_char, "{%s}", buf);
cwl->wl_word = tmp_char;
}
}
ustate = 0; /* we have a number */
2011-08-06 09:53:48 +02:00
} else if (isdigit(actchar)) {
2010-05-27 21:20:10 +02:00
/* allow 100p, 5MEG etc. */
2011-04-28 21:27:45 +02:00
double dvalue = INPevaluate(&str_ptr, &error1, 0);
char cvalue[19];
2010-04-24 00:00:40 +02:00
/* unary -, change sign */
2011-04-28 21:27:45 +02:00
if (ustate == 2)
dvalue *= -1;
sprintf(cvalue,"%18.10e", dvalue);
2010-05-27 21:20:10 +02:00
cwl->wl_word = copy(cvalue);
2010-04-24 00:00:40 +02:00
ustate = 0; /* we have a number */
2011-04-28 21:27:45 +02:00
/* skip the `unit', FIXME INPevaluate() should do this */
while(isalpha(*str_ptr))
str_ptr++;
2011-08-06 09:53:48 +02:00
} else { /* strange char */
2010-04-24 00:00:40 +02:00
printf("Preparing B line for numparam\nWhat is this?\n%s\n", str_ptr);
buf[0] = *str_ptr;
buf[1] = '\0';
cwl->wl_word = copy(buf);
str_ptr++;
}
wl = cwl;
prevchar = actchar;
}
new_str = wl_flatten(wlist);
wl_free(wlist);
2010-05-16 13:55:07 +02:00
wlist = NULL;
2010-04-24 00:00:40 +02:00
wl = NULL;
2011-08-06 09:53:48 +02:00
tmp_char = copy(curr_line);
2010-04-24 00:00:40 +02:00
equal_ptr = strstr(tmp_char, "=");
2010-10-25 12:45:55 +02:00
if (str_ptr == NULL) {
fprintf(stderr,"ERROR: mal formed B line: %s\n", curr_line);
controlled_exit(EXIT_FAILURE);
2011-08-06 09:53:48 +02:00
}
2010-04-24 00:00:40 +02:00
/* cut the tmp_char after the equal sign */
2011-08-06 09:53:48 +02:00
*(equal_ptr + 1) = '\0';
2010-04-24 00:00:40 +02:00
xlen = strlen(tmp_char) + strlen(new_str) + 2;
final_str = TMALLOC(char, xlen);
2010-04-24 00:00:40 +02:00
sprintf(final_str, "%s %s", tmp_char, new_str);
new_line = alloc(struct line);
2011-08-06 09:53:48 +02:00
new_line->li_next = NULL;
new_line->li_error = NULL;
new_line->li_actual = NULL;
new_line->li_line = final_str;
/* Copy old line numbers into new B source line */
new_line->li_linenum = card->li_linenum;
new_line->li_linenum_orig = card->li_linenum_orig;
// comment out current line (old B source line)
*(card->li_line) = '*';
// insert new B source line immediately after current line
tmp_ptr = card->li_next;
card->li_next = new_line;
new_line->li_next = tmp_ptr;
// point 'card' pointer to the new line
card = new_line;
2010-04-24 00:00:40 +02:00
tfree(new_str);
tfree(tmp_char);
} /* end of if 'b' */
2010-05-15 00:39:56 +02:00
} /* end of for loop */
2010-04-24 00:00:40 +02:00
}