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
|
|
|
|
*/
|
|
|
|
|
|
|
2011-12-11 19:05:00 +01:00
|
|
|
|
#include "ngspice/ngspice.h"
|
2009-07-28 23:16:07 +02:00
|
|
|
|
|
2011-12-11 19:05:00 +01: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() */
|
2011-12-17 18:16:29 +01:00
|
|
|
|
#include "ngspice/stringutil.h"
|
2011-12-11 19:05:00 +01:00
|
|
|
|
#include "ngspice/wordlist.h"
|
2009-07-28 23:16:07 +02:00
|
|
|
|
|
|
|
|
|
|
#ifdef XSPICE
|
|
|
|
|
|
/* gtri - add - 12/12/90 - wbk - include new stuff */
|
2011-12-11 19:05:00 +01:00
|
|
|
|
#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);
|
2010-06-23 21:33:54 +02:00
|
|
|
|
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);
|
2010-06-23 21:33:54 +02:00
|
|
|
|
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;
|
2011-12-25 14:01:45 +01:00
|
|
|
|
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;
|
2011-12-30 18:48:55 +01:00
|
|
|
|
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++ )
|
|
|
|
|
|
;
|
2011-12-30 18:48:55 +01:00
|
|
|
|
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
|
|
|
|
|
2011-12-30 18:40:45 +01:00
|
|
|
|
bool dir_name_flag = FALSE;
|
2011-12-30 18:44:52 +01:00
|
|
|
|
FILE *newfp = inp_pathopen( s, "r" );
|
2011-12-30 18:40:45 +01:00
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
|
|
2011-12-30 18:40:45 +01:00
|
|
|
|
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);
|
2011-12-30 18:40:45 +01:00
|
|
|
|
} else {
|
2011-11-13 13:04:15 +01:00
|
|
|
|
inp_readall(newfp, &libraries[num_libraries-1], call_depth+1, dir_name, FALSE);
|
2011-12-30 18:40:45 +01:00
|
|
|
|
}
|
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
|
|
|
|
|
2011-12-30 18:48:55 +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 = '*';
|
2011-12-30 20:53:26 +01:00
|
|
|
|
} /*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-30 20:53:26 +01:00
|
|
|
|
} */
|
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
|
|
|
|
|
2011-12-30 18:40:45 +01:00
|
|
|
|
{
|
|
|
|
|
|
bool dir_name_flag = FALSE;
|
2011-12-30 18:44:52 +01:00
|
|
|
|
FILE *newfp = inp_pathopen(s, "r");
|
2011-12-30 18:40:45 +01:00
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
|
|
2011-12-30 18:40:45 +01:00
|
|
|
|
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
|
|
|
|
|
2011-12-30 18:40:45 +01: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
|
|
|
|
|
2011-12-30 18:40:45 +01: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) ) {
|
2011-12-30 18:48:55 +01:00
|
|
|
|
|
|
|
|
|
|
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-12-25 14:01:45 +01:00
|
|
|
|
|
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-12-25 14:01:45 +01:00
|
|
|
|
|
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
|
2011-12-25 14:01:45 +01:00
|
|
|
|
// .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-12-25 14:01:45 +01:00
|
|
|
|
|
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-12-25 14:01:45 +01:00
|
|
|
|
|
2011-11-13 13:04:15 +01:00
|
|
|
|
if ( ciprefix( ".subckt", card->li_line ) || ciprefix( "x", card->li_line ) ) {
|
2011-12-25 14:01:45 +01:00
|
|
|
|
/* 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
|
2011-12-15 16:34:50 +01:00
|
|
|
|
/* 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 = '*';
|
2011-12-15 16:34:50 +01:00
|
|
|
|
#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 {}
|
2011-12-25 14:01:45 +01:00
|
|
|
|
.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;
|
2011-12-25 14:01:45 +01:00
|
|
|
|
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);
|
|
|
|
|
|
|
2011-12-25 14:01:45 +01:00
|
|
|
|
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
|
2010-06-23 20:57:13 +02:00
|
|
|
|
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;
|
2009-12-06 19:30:59 +01:00
|
|
|
|
}
|
2011-08-06 09:53:48 +02:00
|
|
|
|
param_str = param_ptr + strlen(param_name);
|
2009-12-06 19:30:59 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
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
|
|
|
|
}
|
|
|
|
|
|
|
2011-11-30 19:02:27 +01: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
|
|
|
|
{
|
2011-11-30 19:02:27 +01: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 ) {
|
2011-11-30 19:02:27 +01:00
|
|
|
|
|
|
|
|
|
|
char *curr_line = c->li_line;
|
|
|
|
|
|
|
2011-08-06 09:53:48 +02:00
|
|
|
|
if ( *curr_line == '*' ) {
|
|
|
|
|
|
c = c->li_next;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2011-11-30 19:02:27 +01:00
|
|
|
|
|
2011-08-06 09:53:48 +02:00
|
|
|
|
if ( ciprefix( ".subckt", curr_line ) ) {
|
2011-11-30 19:02:27 +01:00
|
|
|
|
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 );
|
|
|
|
|
|
}
|
2011-11-30 19:02:27 +01:00
|
|
|
|
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 ) ) {
|
2011-11-30 19:02:27 +01:00
|
|
|
|
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-11-30 19:02:27 +01:00
|
|
|
|
|
2011-08-06 09:53:48 +02:00
|
|
|
|
prev_card = c;
|
|
|
|
|
|
c = c->li_next;
|
2009-07-28 23:16:07 +02:00
|
|
|
|
}
|
2011-11-30 19:02:27 +01: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);
|
2011-11-30 19:02:27 +01:00
|
|
|
|
controlled_exit(EXIT_FAILURE);
|
2011-12-17 16:22:20 +01:00
|
|
|
|
}
|
2011-11-30 19:02:27 +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:
|
2011-12-21 22:33:47 +01:00
|
|
|
|
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
|
2011-12-21 22:33:47 +01:00
|
|
|
|
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
|
2010-05-08 16:21:31 +02:00
|
|
|
|
|
2011-08-06 09:53:48 +02:00
|
|
|
|
Two step approach to keep the original names for reuse,
|
2010-05-08 16:21:31 +02:00
|
|
|
|
i.e. for current measurements like i(Exxx):
|
2011-08-06 09:53:48 +02:00
|
|
|
|
Exxx n1 n2 VOL = {equation}
|
2010-05-08 16:21:31 +02:00
|
|
|
|
-->
|
|
|
|
|
|
Exxx n1 n2 int1 0 1
|
|
|
|
|
|
BExxx int1 0 V = {equation}
|
|
|
|
|
|
|
2011-08-06 09:53:48 +02:00
|
|
|
|
Gxxx n1 n2 CUR = {equation}
|
|
|
|
|
|
-->
|
2010-05-08 16:21:31 +02:00
|
|
|
|
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}
|
|
|
|
|
|
-->
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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}
|
|
|
|
|
|
-->
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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)
|
|
|
|
|
|
{
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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;
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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;
|
2010-05-08 11:36:57 +02:00
|
|
|
|
struct line *card;
|
|
|
|
|
|
int skip_control = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (card = deck; card; card = card->li_next) {
|
|
|
|
|
|
|
|
|
|
|
|
char *curr_line = card->li_line;
|
|
|
|
|
|
|
2010-05-08 16:21:31 +02:00
|
|
|
|
/* exclude any command inside .control ... .endc */
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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
|
|
|
|
}
|
2010-05-08 16:21:31 +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';
|
|
|
|
|
|
}
|
2011-12-21 22:33:47 +01:00
|
|
|
|
/* 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
|
|
|
|
|
2011-12-21 22:33:47 +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}
|
2010-05-08 16:21:31 +02:00
|
|
|
|
-->
|
|
|
|
|
|
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) {
|
2010-05-08 16:21:31 +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 E line: %s\n",curr_line);
|
|
|
|
|
|
controlled_exit(EXIT_FAILURE);
|
|
|
|
|
|
}
|
2010-05-08 16:21:31 +02:00
|
|
|
|
|
|
|
|
|
|
// 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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[0] = TMALLOC(char, xlen);
|
2010-05-08 16:21:31 +02:00
|
|
|
|
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}
|
2010-05-08 16:21:31 +02:00
|
|
|
|
xlen = 2*strlen(title_tok) + strlen(str_ptr)
|
2011-08-06 09:53:48 +02:00
|
|
|
|
+ 20 - 3*2 + 1;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[1] = TMALLOC(char, xlen);
|
2010-05-08 16:21:31 +02:00
|
|
|
|
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);
|
2010-05-08 16:21:31 +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 < 2; i++ ) {
|
|
|
|
|
|
if ( param_end ) {
|
2010-05-08 16:21:31 +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-05-08 16:21:31 +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;
|
2010-04-24 00:00:40 +02:00
|
|
|
|
}
|
2010-05-08 16:21:31 +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' ) {
|
2010-05-08 16:21:31 +02:00
|
|
|
|
/* 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
|
|
|
|
}
|
2010-05-08 16:21:31 +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';
|
|
|
|
|
|
}
|
2011-12-21 22:33:47 +01:00
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
}
|
2010-05-08 16:21:31 +02:00
|
|
|
|
/*
|
2011-08-06 09:53:48 +02:00
|
|
|
|
Gxxx n1 n2 CUR = {equation}
|
|
|
|
|
|
-->
|
2010-05-08 16:21:31 +02:00
|
|
|
|
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) {
|
2010-05-08 16:21:31 +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 G line: %s\n",curr_line);
|
|
|
|
|
|
controlled_exit(EXIT_FAILURE);
|
|
|
|
|
|
}
|
2010-05-08 16:21:31 +02:00
|
|
|
|
// 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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[0] = TMALLOC(char, xlen);
|
2010-05-08 16:21:31 +02:00
|
|
|
|
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}
|
2010-05-08 16:21:31 +02:00
|
|
|
|
xlen = 2*strlen(title_tok) + strlen(str_ptr)
|
2011-08-06 09:53:48 +02:00
|
|
|
|
+ 20 - 3*2 + 1;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[1] = TMALLOC(char, xlen);
|
2010-05-08 16:21:31 +02:00
|
|
|
|
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);
|
2010-05-08 16:21:31 +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 < 2; i++ ) {
|
|
|
|
|
|
if ( param_end ) {
|
2010-05-08 16:21:31 +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-05-08 16:21:31 +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;
|
2010-04-24 00:00:40 +02:00
|
|
|
|
}
|
2010-05-08 16:21:31 +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(")))
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
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(")))
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2010-05-08 11:36:57 +02:00
|
|
|
|
// 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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[0] = TMALLOC(char, xlen);
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[1] = TMALLOC(char, xlen);
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[2] = TMALLOC(char, xlen);
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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(")))
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2010-05-08 11:36:57 +02:00
|
|
|
|
// Fxxx n-aux 0 Bxxx 1
|
|
|
|
|
|
xlen = 3*strlen(title_tok)
|
2011-08-06 09:53:48 +02:00
|
|
|
|
+ 20 - 3*2 + 1;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[0] = TMALLOC(char, xlen);
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[1] = TMALLOC(char, xlen);
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
ckt_array[2] = TMALLOC(char, xlen);
|
2010-05-08 11:36:57 +02:00
|
|
|
|
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 == '=') ) {
|
2010-12-11 19:51:43 +01:00
|
|
|
|
/* >=, <=, !=, ==, <>, ... */
|
|
|
|
|
|
char *beg = str_ptr++;
|
|
|
|
|
|
if ((*str_ptr == '=') || (*str_ptr == '<') || (*str_ptr == '>'))
|
2010-04-24 00:00:40 +02:00
|
|
|
|
str_ptr++;
|
2010-12-11 19:51:43 +01:00
|
|
|
|
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 == '&')) {
|
2010-12-11 19:34:29 +01:00
|
|
|
|
char *beg = str_ptr++;
|
|
|
|
|
|
if ((*str_ptr == '|') || (*str_ptr == '&'))
|
|
|
|
|
|
str_ptr++;
|
|
|
|
|
|
cwl->wl_word = copy_substring(beg, str_ptr);
|
2010-12-11 18:26:22 +01:00
|
|
|
|
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);
|
2010-10-28 21:32:34 +02:00
|
|
|
|
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;
|
2010-10-28 21:32:34 +02:00
|
|
|
|
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
|
|
|
|
}
|