From e065e1c2906b9a57e48e3da48832b8d5b97c2750 Mon Sep 17 00:00:00 2001 From: h_vogt Date: Sun, 13 Nov 2011 12:04:15 +0000 Subject: [PATCH] reordering, fcn prototypes --- ChangeLog | 1 + src/frontend/inpcom.c | 2864 +++++++++++++++++++++-------------------- 2 files changed, 1438 insertions(+), 1427 deletions(-) diff --git a/ChangeLog b/ChangeLog index bda457137..66b25c522 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 2011-11-13 Holger Vogt * inp.c: code beautify, indentations etc. + * inpcom.c: reordering, fcn prototypes added 2011-11-04 Holger Vogt * INSTALL: give more precise instructions diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 70ae47677..bddfab32b 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -7,28 +7,11 @@ Author: 1985 Wayne A. Christopher * For dealing with spice input decks and command scripts */ -/* 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. +/* + Central function inp_readall */ -/* - * 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 withou leading white - * space are also allowed. - */ + #include @@ -103,1633 +86,1641 @@ static char* inp_remove_ws( char *s ); static void inp_compat(struct line *deck); static void inp_bsource_compat(struct line *deck); +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 ); -/*-------------------------------------------------------------------------* - * 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 * +/*------------------------------------------------------------------------- + * 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. *-------------------------------------------------------------------------*/ -#define STRGROW 256 - -static char * -readline(FILE *fd) +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 +*/ { - int c; - int memlen; - char *strptr; - int strlen; + struct line *end = NULL, *cc = NULL, *prev = NULL, *working, *newcard, *start_lib, *global_card, *tmp_ptr = NULL, *tmp_ptr2 = NULL; + char *buffer = NULL, *s, *t, *y, *z, c; + /* 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 *copys=NULL, big_buff2[5000]; + char *new_title = NULL; + char keep_char; + 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 '{' */ - 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 */ - continue; - strptr[strlen] = (char) c; - strlen++; - if( strlen >= memlen ) { - memlen += STRGROW; - if((strptr = TREALLOC(char, strptr, memlen + 1)) == NULL) { - return (NULL); - } - } - 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); -} + size_t max_line_length; /* max. line length in input deck */ + FILE *newfp; + FILE *fdo; + struct line *tmp_ptr1 = NULL; -/*-------------------------------------------------------------------------* - 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) -{ - FILE *fp; - char buf[BSIZE_SP]; - struct variable *v; + int i, j; + bool found_library, found_lib_name, found_end = FALSE, shell_eol_continuation = FALSE; + bool dir_name_flag = FALSE; -#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; iva_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); - } + /* 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 = TMALLOC(char, strlen(big_buff) + 1); + strcpy(buffer, big_buff); */ + 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); + } } - if ((fp = fopen(buf, mode)) != NULL) - return (fp); - v = v->va_next; - } - return (NULL); -} -/* 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; + /* gtri - end - 12/12/90 */ +#else + while ((buffer = readline(fp)) != NULL) { +#endif - 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; +#ifdef TRACE + /* SDB debug statement */ + printf ("in inp_readall, just read %s", buffer); +#endif + + if ( !buffer ) { continue; } - // replace "§gnd§" by "§ 0 §", § 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 ); + /* 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; } - gnd += 3; } - // now remove the extra white spaces around 0 - c->li_line = inp_remove_ws(c->li_line); - c = c->li_next; - } -} - -static struct line* -create_new_card( char *card_str, int *line_number ) { - char *str = strdup(card_str); - struct line *newcard = alloc(struct line); - newcard->li_line = str; - newcard->li_linenum = *line_number; - newcard->li_error = NULL; - newcard->li_actual = NULL; - - *line_number = *line_number + 1; - - return newcard; -} - -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; + if (*buffer == '@') { + tfree(buffer); /* was allocated by readline() */ + break; + } - for ( c = deck; c != NULL; c = c->li_next ) { - str_ptr1 = line = c->li_line; + /* 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 */ - /* 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; + /* 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 */ } - 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; - - 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; + /* now handle .lib statements */ + if (ciprefix(".lib", buffer)) { + 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() */ + continue; + } /* 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 */ + // check if rest of line commented out + if ( *y && *y != '$' ) { /* .lib */ + for ( z = y; *z && !isspace(*z) && !isquote(*z); z++ ) + ; + c = *t; + *t = '\0'; + *z = '\0'; - 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); + if ( *s == '~' ) { + copys = cp_tildexpand(s); /* allocates memory, but can also return NULL */ + if( copys != NULL ) { + s = copys; /* reuse s, but remember, buffer still points to allocated memory */ + } } - str_ptr1++; - str_ptr2--; - while( isspace(*str_ptr2) ) str_ptr2--; + /* lower case the file name for later string compares */ + /* s_ptr = strdup(s); */ + s_lower = strdup(s); + for(s_ptr = s_lower; *s_ptr && (*s_ptr != '\n'); s_ptr++) + *s_ptr = (char) tolower(*s_ptr); - 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++; + found_library = FALSE; + for ( i = 0; i < num_libraries; i++ ) { + if ( strcmp( library_file[i], s_lower ) == 0 ) { + found_library = TRUE; + break; + } } - keep = *str_ptr2; - *str_ptr2 = '\0'; - ctrl_node_str = strdup(str_ptr1); - *str_ptr2 = keep; - - str_ptr1 = comma_ptr + 1; - while ( isspace(*str_ptr1) ) str_ptr1++; - if ( *str_ptr1 == '{' ) { - while ( *str_ptr1 != '}' ) str_ptr1++; - str_ptr1++; + if ( found_library ) { + if(copys) tfree(copys); /* allocated by the cp_tildexpand() above */ } 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; + if ( dir_name != NULL ) sprintf( big_buff2, "%s/%s", dir_name, s ); + else sprintf( big_buff2, "./%s", s ); + dir_name_flag = FALSE; + if ((newfp = inp_pathopen( s, "r" )) == NULL) { + dir_name_flag = TRUE; + if ((newfp = inp_pathopen( big_buff2, "r" )) == NULL ) { + perror(s); + if(copys) tfree(copys); /* allocated by the cp_tildexpand() above */ + tfree(buffer); /* allocated by readline() above */ + continue; + } + } + if(copys) tfree(copys); /* allocated by the cp_tildexpand() above */ - while ( isspace(*str_ptr1) ) str_ptr1++; - xy_count2 = get_comma_separated_values( xy_values2, str_ptr1 ); + library_file[num_libraries++] = strdup(s_lower); - // 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"); + if ( dir_name_flag == FALSE ) { + char *s_dup = strdup(s); + inp_readall(newfp, &libraries[num_libraries-1], call_depth+1, ngdirname(s_dup), FALSE); + tfree(s_dup); + } else + inp_readall(newfp, &libraries[num_libraries-1], call_depth+1, dir_name, FALSE); + + fclose(newfp); } + *t = c; + tfree(s_lower); - 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'; + /* Make the .lib a comment */ + *buffer = '*'; + } + } /* end of .lib handling */ - 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 ); + /* now handle .include statements */ + if (ciprefix(".include", buffer) || ciprefix(".inc", buffer)) { + for (s = buffer; *s && !isspace(*s); s++) /* advance past non-space chars */ + ; + while (isspace(*s) || isquote(*s)) /* now advance past space chars */ + s++; + if (!*s) { /* if at end of line, error */ + fprintf(cp_err, "Error: .include filename missing\n"); + tfree(buffer); /* was allocated by readline() */ + controlled_exit(EXIT_FAILURE); + } + /* Now s points to first char after .include */ + inp_stripcomments_line(s); + /* stop at trailing \n\r or quote */ + for (t = s; *t && !(*t=='\n') && !(*t=='\r') && !isquote(*t); t++) + ; - 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]); + *t = '\0'; /* place \0 and end of file name in buffer */ - *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; + if (*s == '~') { + copys = cp_tildexpand(s); /* allocates memory, but can also return NULL */ + if(copys != NULL) { + s = copys; /* reuse s, but remember, buffer still points to allocated memory */ + } } - } - } -} -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; + /* open file specified by .include statement */ + if ( dir_name != NULL ) sprintf( big_buff2, "%s/%s", dir_name, s ); + else sprintf( big_buff2, "./%s", s ); + dir_name_flag = FALSE; + if ((newfp = inp_pathopen(s, "r")) == NULL) { + dir_name_flag = TRUE; + if ((newfp = inp_pathopen( big_buff2, "r" )) == NULL ) { + 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); + } + } - 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; - } - if ( ciprefix( ".end", c->li_line ) ) found_end = TRUE; - if ( found_control && ciprefix( "run", c->li_line ) ) found_run = TRUE; + if(copys) { + tfree(copys); /* allocated by the cp_tildexpand() above */ + } - if ( ciprefix( ".control", c->li_line ) ) found_control = TRUE; - if ( ciprefix( ".endc", c->li_line ) ) { - found_control = FALSE; + 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 */ - 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; + (void) fclose(newfp); + + /* 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 */ } - 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); + + /* 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"); } + *s = '\0'; /* Zap the newline. */ + + if((s-1) >= buffer && *(s-1) == '\r') /* Zop the carriage return under windows */ + *(s-1) = '\0'; } - prev_card = c; - } - // 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; - 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); + /* 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 = '*'; + } } - 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; + + if ( shell_eol_continuation ) { + char *new_buffer = TMALLOC(char, strlen(buffer) + 2); + sprintf( new_buffer, "+%s", buffer ); + + tfree(buffer); + buffer = new_buffer; } - prev_card = deck->li_next; - newcard = create_new_card( "run", line_number ); - deck->li_next = newcard; - newcard->li_next = prev_card; + shell_eol_continuation = chk_for_line_continuation( buffer ); - prev_card = deck->li_next; - newcard = create_new_card( ".control", line_number ); - deck->li_next = newcard; - newcard->li_next = prev_card; - } -} + /* 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 */ + } -// look for shell-style end-of-line continuation '\\' -static bool -chk_for_line_continuation( char *line ) -{ - char *ptr = line + strlen(line) - 1; + /* 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) */ - if ( *line != '*' && *line != '$' ) { - while ( ptr >= line && *ptr && isspace(*ptr) ) ptr--; + if (!end) { /* No stuff here */ + *data = NULL; + return; + } - if ( (ptr-1) >= line && *ptr == '\\' && *(ptr-1) && *(ptr-1) == '\\' ) { - *ptr = ' '; - *(ptr-1) = ' '; - return TRUE; + if ( call_depth == 0 && found_end == TRUE) { + if ( global == NULL ) { + global = TMALLOC(char, strlen(".global gnd") + 1); + sprintf( global, ".global gnd" ); } - } + 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; - return FALSE; -} + prev = cc->li_next; + cc->li_next = global_card; + global_card->li_next = prev; -// -// change .macro --> .subckt -// .eom --> .ends -// .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} -// -static void -inp_fix_macro_param_func_paren_io( struct line *begin_card ) -{ - struct line *card; - char *str_ptr, *new_str; - bool is_func = FALSE; + inp_init_lib_data(); + inp_determine_libraries(cc, NULL); + } - for ( card = begin_card; card != NULL; card = card->li_next ) { + /* + 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; - if ( *card->li_line == '*' ) continue; + if ( found_lib_name && ciprefix(".endl", buffer) ) { + /* Make the .endl a comment */ + *buffer = '*'; + found_lib_name = FALSE; - if ( ciprefix( ".macro", card->li_line ) || ciprefix( ".eom", card->li_line ) ) { - str_ptr = card->li_line; - while( !isspace(*str_ptr) ) str_ptr++; + /* set pointer and continue to avoid deleting below */ + tmp_ptr2 = working->li_next; + working->li_next = tmp_ptr; + working = tmp_ptr2; - if ( ciprefix( ".macro", card->li_line ) ) { - new_str = TMALLOC(char, strlen(".subckt") + strlen(str_ptr) + 1); - sprintf( new_str, ".subckt%s", str_ptr ); - } else { - new_str = TMALLOC(char, strlen(".ends") + strlen(str_ptr) + 1); - sprintf( new_str, ".ends%s", str_ptr ); - } + /* end = working; + * working = working->li_next; + * end->li_next = NULL; */ - tfree( card->li_line ); - card->li_line = new_str; - } - if ( ciprefix( ".subckt", card->li_line ) || ciprefix( "x", card->li_line ) ) { - 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; + continue; + } /* for ... */ + + if ( ciprefix(".lib", buffer) ) { + if ( found_lib_name == TRUE ) { + fprintf( stderr, "ERROR: .lib is missing .endl!\n" ); + controlled_exit(EXIT_FAILURE); } - str_ptr++; - } - card->li_line = inp_remove_ws(card->li_line); /* remove the extra white spaces just introduced */ - } - } - 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++; - } - 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) = ' '; - } - } - } -} + 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; -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 = ' '; + /* make the .lib a comment */ + *buffer = '*'; - // 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++; + tmp_ptr = library_ll_ptr[i][j]->li_next; + library_ll_ptr[i][j]->li_next = working; - inst_name = strdup(inst_name_ptr); + /* 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; - if ( equal_ptr ) *end_ptr = keep; + if ( found_lib_name == FALSE ) { + tfree(prev->li_line); + tfree(prev); + } + } /* end while */ + } /* end for */ - return inst_name; -} + if ( found_end == TRUE ) { + end->li_next = alloc(struct line); /* create next card */ + end = end->li_next; /* point to next card */ -static char* -get_subckt_model_name( char *line ) -{ - char *name = line, *end_ptr = NULL, *subckt_name; - char keep; + buffer = TMALLOC(char, strlen( ".end" ) + 1); + sprintf( buffer, ".end" ); - while ( !isspace( *name ) ) name++; // eat .subckt|.model - while ( isspace( *name ) ) name++; + /* 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++; + } + } - end_ptr = name; - while ( !isspace( *end_ptr ) ) end_ptr++; - keep = *end_ptr; - *end_ptr = '\0'; + /* 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; + } - subckt_name = strdup(name); - *end_ptr = keep; + /* 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. */ - return subckt_name; -} + /* 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); -static char* -get_model_name( char *line, int num_terminals ) -{ - char *beg_ptr = line, *end_ptr, keep, *model_name = NULL; - int i = 0; + while (working) { + for (s = working->li_line; (c = *s) != '\0' && c <= ' '; s++) + ; - while ( !isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++; /* eat device name */ - while ( isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++; +#ifdef TRACE + /* SDB debug statement */ + printf("In inp_readall, processing linked list element line = %d, s = %s . . . \n", working->li_linenum,s); +#endif - 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'; + 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; - model_name = strdup( beg_ptr ); + case '+': /* handle continuation */ + if (!prev) { + working->li_error = copy( + "Illegal continuation line: ignored."); + working = working->li_next; + break; + } - *end_ptr = keep; + /* 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); - return model_name; -} + 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; -static char * -get_adevice_model_name( char *line ) -{ - char *model_name, *ptr_end = line + strlen(line), *ptr_beg, keep; + default: /* regular one-line card */ + prev = working; + working = working->li_next; + break; + } + } - while ( isspace( *(ptr_end-1) ) ) ptr_end--; - ptr_beg = ptr_end - 1; + /* 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; + } - while ( !isspace(*ptr_beg) ) ptr_beg--; - ptr_beg++; - keep = *ptr_end; - *ptr_end = '\0'; - model_name = strdup(ptr_beg); - *ptr_end = keep; + working = cc->li_next; - return model_name; -} + inp_fix_for_numparam(working); + inp_remove_excess_ws(working); -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; + if ( call_depth == 0 ) { + comment_out_unused_subckt_models(working, line_number); - for ( card = start_card; card != NULL; card = card->li_next ) { - line = card->li_line; + line_number = inp_split_multi_param_lines(working, line_number); - if ( *line == '*' ) continue; + inp_fix_macro_param_func_paren_io(working); + inp_fix_ternary_operator(working); + inp_grab_func(working); - if ( ( ciprefix( ".ends", line ) || ciprefix( ".eom", line ) ) && found_subckt ) - break; + inp_expand_macros_in_func(); + inp_expand_macros_in_deck(working); + inp_fix_param_values(working); - if ( ciprefix( ".subckt", line ) || ciprefix( ".macro", line ) ) { - curr_subckt_name = get_subckt_model_name( line ); + /* 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; - if ( strcmp( curr_subckt_name, subckt_name ) == 0 ) { - found_subckt = TRUE; - } + 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); - tfree(curr_subckt_name); - } - 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 ); - - if ( num_terminals != 0 ) { - char *tmp_name, *tmp_name1; - tmp_name1 = tmp_name = model_name = get_model_name( line, num_terminals ); - 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 ); - } - } - } + if (cp_getvar("addcontrol", CP_BOOL, NULL)) + inp_add_control_section(working, &line_number); + inp_compat_mode = ngspice_compat_mode() ; + 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); } } - // 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 ); + + /* 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); + } } -/* - check if current token matches model bin name -- .[0-9]+ - */ -static bool -model_bin_match( char* token, char* model_name ) + +/*-------------------------------------------------------------------------* + 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) { - char* dot_char; - bool flag = FALSE; + FILE *fp; + char buf[BSIZE_SP]; + struct variable *v; - 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; - } - dot_char++; +#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; ili_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 = '*'; + 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; } + return (NULL); +} - for ( card = start_card; card != NULL; card = card->li_next ) { - line = card->li_line; +/*-------------------------------------------------------------------------* + * 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 - if ( *line == '*' ) continue; +static char * +readline(FILE *fd) +{ + int c; + int memlen; + char *strptr; + int strlen; - /* 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) { + 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 */ continue; + strptr[strlen] = (char) c; + strlen++; + if( strlen >= memlen ) { + memlen += STRGROW; + if((strptr = TREALLOC(char, strptr, memlen + 1)) == NULL) { + return (NULL); + } } + 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); +} - 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 ); - - /* comment out any unused subckts */ - for ( card = start_card; card != NULL; card = card->li_next ) { - line = card->li_line; - if ( *line == '*' ) continue; +/* 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; - 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; + 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; } - 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; - if ( !found_model ) *line = '*'; - tfree(model_name); + // replace "§gnd§" by "§ 0 §", § 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; } + // now remove the extra white spaces around 0 + c->li_line = inp_remove_ws(c->li_line); + c = c->li_next; } - 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); } +static struct line* +create_new_card( char *card_str, int *line_number ) { + char *str = strdup(card_str); + struct line *newcard = alloc(struct line); + newcard->li_line = str; + newcard->li_linenum = *line_number; + newcard->li_error = NULL; + newcard->li_actual = NULL; -/* 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; + *line_number = *line_number + 1; - if ( !strstr( line, "?" ) && !strstr( line, ":" ) ) return line; + return newcard; +} - str_ptr = line; - if ( ciprefix( ".param", line ) || ciprefix( ".func", line ) || ciprefix( ".meas", line ) ) { +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; - 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); - } + for ( c = deck; c != NULL; c = c->li_next ) { + str_ptr1 = line = c->li_line; - str_ptr++; - while( isspace(*str_ptr) ) str_ptr++; - if ( *str_ptr == '{' ) { - str_ptr++; - while( isspace(*str_ptr) ) str_ptr++; + /* 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; } - question = strstr( str_ptr, "?" ); - paren_ptr = strstr( str_ptr, "(" ); + 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; - if ( paren_ptr != NULL && paren_ptr < question ) { - paren_ptr = NULL; - } - } else return line; + 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; - // 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++; - } - } - str_ptr2++; - keep = *str_ptr2; - *str_ptr2 = '\0'; - conditional = strdup(str_ptr); - *str_ptr2 = keep; + 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--; - // get beginning (whatever is left before the conditional) - keep = *str_ptr; - *str_ptr = '\0'; - beg_str = strdup(line); - *str_ptr = keep; + 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; - // 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); - } - str_ptr2++; - keep = *str_ptr2; - *str_ptr2 = '\0'; - if_str = inp_fix_ternary_operator_str(strdup(str_ptr)); - *str_ptr2 = keep; + 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; - // 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; + 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; } - 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); + } +} + +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; } - *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)); + 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); + } } + prev_card = c; } + // 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; - 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 ); + 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); } - } 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 ); + 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; } - } - tfree(line); - tfree(conditional); - tfree(if_str); - tfree(else_str); - if ( beg_str != NULL ) tfree(beg_str); - if ( end_str != NULL ) tfree(end_str); + prev_card = deck->li_next; + newcard = create_new_card( "run", line_number ); + deck->li_next = newcard; + newcard->li_next = prev_card; - return new_str; + prev_card = deck->li_next; + newcard = create_new_card( ".control", line_number ); + deck->li_next = newcard; + newcard->li_next = prev_card; + } } -static void -inp_fix_ternary_operator( struct line *start_card ) +// look for shell-style end-of-line continuation '\\' +static bool +chk_for_line_continuation( char *line ) { - struct line *card; - char *line; - bool found_control = FALSE; - - for ( card = start_card; card != NULL; card = card->li_next ) { - line = card->li_line; + char *ptr = line + strlen(line) - 1; - /* 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; + if ( *line != '*' && *line != '$' ) { + while ( ptr >= line && *ptr && isspace(*ptr) ) ptr--; - /* 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 ); + if ( (ptr-1) >= line && *ptr == '\\' && *(ptr-1) && *(ptr-1) == '\\' ) { + *ptr = ' '; + *(ptr-1) = ' '; + return TRUE; } } + + return FALSE; } -/*------------------------------------------------------------------------- - * 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. - *-------------------------------------------------------------------------*/ -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 coammnd file (e.g. spinit, .spiceinit -*/ +// +// change .macro --> .subckt +// .eom --> .ends +// .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} +// +static void +inp_fix_macro_param_func_paren_io( struct line *begin_card ) { - struct line *end = NULL, *cc = NULL, *prev = NULL, *working, *newcard, *start_lib, *global_card, *tmp_ptr = NULL, *tmp_ptr2 = NULL; - char *buffer = NULL, *s, *t, *y, *z, c; - /* 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 *copys=NULL, big_buff2[5000]; - char *new_title = NULL; - char keep_char; - 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 '{' */ + struct line *card; + char *str_ptr, *new_str; + bool is_func = FALSE; - size_t max_line_length; /* max. line length in input deck */ + for ( card = begin_card; card != NULL; card = card->li_next ) { - FILE *newfp; - FILE *fdo; - struct line *tmp_ptr1 = NULL; + if ( *card->li_line == '*' ) continue; - int i, j; - bool found_library, found_lib_name, found_end = FALSE, shell_eol_continuation = FALSE; - bool dir_name_flag = FALSE; - - char *s_ptr, *s_lower; - - /* Must set this to NULL or non-tilde includes segfault. -- Tim Molteno */ - /* copys = NULL; */ /* This caused a parse error with gcc 2.96. Why??? */ - - if ( call_depth == 0 ) { - num_subckt_w_params = 0; - num_libraries = 0; - num_functions = 0; - global = NULL; - found_end = FALSE; - } - - /* gtri - modify - 12/12/90 - wbk - read from mailbox if ipc enabled */ -#ifdef XSPICE + if ( ciprefix( ".macro", card->li_line ) || ciprefix( ".eom", card->li_line ) ) { + str_ptr = card->li_line; + while( !isspace(*str_ptr) ) str_ptr++; - /* 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 = TMALLOC(char, strlen(big_buff) + 1); - strcpy(buffer, big_buff); */ - buffer = copy(big_buff); - } + if ( ciprefix( ".macro", card->li_line ) ) { + new_str = TMALLOC(char, strlen(".subckt") + strlen(str_ptr) + 1); + sprintf( new_str, ".subckt%s", str_ptr ); } 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); + new_str = TMALLOC(char, strlen(".ends") + strlen(str_ptr) + 1); + sprintf( new_str, ".ends%s", str_ptr ); } - } - - /* gtri - end - 12/12/90 */ -#else - while ((buffer = readline(fp)) != NULL) { -#endif - -#ifdef TRACE - /* SDB debug statement */ - printf ("in inp_readall, just read %s", buffer); -#endif - if ( !buffer ) { - continue; + tfree( card->li_line ); + card->li_line = new_str; } - /* 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; + if ( ciprefix( ".subckt", card->li_line ) || ciprefix( "x", card->li_line ) ) { + 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 */ } } + 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++; + } - if (*buffer == '@') { - tfree(buffer); /* was allocated by readline() */ - break; + 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) = ' '; + } } + } +} - /* 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 */ +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 = ' '; - /* 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 */ - } + // 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++; - /* now handle .lib statements */ - if (ciprefix(".lib", buffer)) { - 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() */ - continue; - } /* 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 */ - // check if rest of line commented out - if ( *y && *y != '$' ) { /* .lib */ - for ( z = y; *z && !isspace(*z) && !isquote(*z); z++ ) - ; - c = *t; - *t = '\0'; - *z = '\0'; + inst_name = strdup(inst_name_ptr); - if ( *s == '~' ) { - copys = cp_tildexpand(s); /* allocates memory, but can also return NULL */ - if( copys != NULL ) { - s = copys; /* reuse s, but remember, buffer still points to allocated memory */ - } - } - /* lower case the file name for later string compares */ - /* s_ptr = strdup(s); */ - s_lower = strdup(s); - for(s_ptr = s_lower; *s_ptr && (*s_ptr != '\n'); s_ptr++) - *s_ptr = (char) tolower(*s_ptr); + if ( equal_ptr ) *end_ptr = keep; - found_library = FALSE; - for ( i = 0; i < num_libraries; i++ ) { - if ( strcmp( library_file[i], s_lower ) == 0 ) { - found_library = TRUE; - break; - } - } - if ( found_library ) { - if(copys) tfree(copys); /* allocated by the cp_tildexpand() above */ - } else { - if ( dir_name != NULL ) sprintf( big_buff2, "%s/%s", dir_name, s ); - else sprintf( big_buff2, "./%s", s ); - dir_name_flag = FALSE; - if ((newfp = inp_pathopen( s, "r" )) == NULL) { - dir_name_flag = TRUE; - if ((newfp = inp_pathopen( big_buff2, "r" )) == NULL ) { - perror(s); - if(copys) tfree(copys); /* allocated by the cp_tildexpand() above */ - tfree(buffer); /* allocated by readline() above */ - continue; - } - } - if(copys) tfree(copys); /* allocated by the cp_tildexpand() above */ + return inst_name; +} - library_file[num_libraries++] = strdup(s_lower); +static char* +get_subckt_model_name( char *line ) +{ + char *name = line, *end_ptr = NULL, *subckt_name; + char keep; - if ( dir_name_flag == FALSE ) { - char *s_dup = strdup(s); - inp_readall(newfp, &libraries[num_libraries-1], call_depth+1, ngdirname(s_dup), FALSE); - tfree(s_dup); - } else - inp_readall(newfp, &libraries[num_libraries-1], call_depth+1, dir_name, FALSE); + while ( !isspace( *name ) ) name++; // eat .subckt|.model + while ( isspace( *name ) ) name++; - fclose(newfp); - } - *t = c; - tfree(s_lower); + end_ptr = name; + while ( !isspace( *end_ptr ) ) end_ptr++; + keep = *end_ptr; + *end_ptr = '\0'; - /* Make the .lib a comment */ - *buffer = '*'; - } - } /* end of .lib handling */ + subckt_name = strdup(name); + *end_ptr = keep; - /* now handle .include statements */ - if (ciprefix(".include", buffer) || ciprefix(".inc", buffer)) { - for (s = buffer; *s && !isspace(*s); s++) /* advance past non-space chars */ - ; - while (isspace(*s) || isquote(*s)) /* now advance past space chars */ - s++; - if (!*s) { /* if at end of line, error */ - fprintf(cp_err, "Error: .include filename missing\n"); - tfree(buffer); /* was allocated by readline() */ - controlled_exit(EXIT_FAILURE); - } - /* Now s points to first char after .include */ - inp_stripcomments_line(s); - /* stop at trailing \n\r or quote */ - for (t = s; *t && !(*t=='\n') && !(*t=='\r') && !isquote(*t); t++) - ; + return subckt_name; +} - *t = '\0'; /* place \0 and end of file name in buffer */ +static char* +get_model_name( char *line, int num_terminals ) +{ + char *beg_ptr = line, *end_ptr, keep, *model_name = NULL; + int i = 0; - if (*s == '~') { - copys = cp_tildexpand(s); /* allocates memory, but can also return NULL */ - if(copys != NULL) { - s = copys; /* reuse s, but remember, buffer still points to allocated memory */ - } - } + while ( !isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++; /* eat device name */ + while ( isspace( *beg_ptr ) && *beg_ptr != '\0' ) beg_ptr++; - /* open file specified by .include statement */ - if ( dir_name != NULL ) sprintf( big_buff2, "%s/%s", dir_name, s ); - else sprintf( big_buff2, "./%s", s ); - dir_name_flag = FALSE; - if ((newfp = inp_pathopen(s, "r")) == NULL) { - dir_name_flag = TRUE; - if ((newfp = inp_pathopen( big_buff2, "r" )) == NULL ) { - 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); - } - } + 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'; - if(copys) { - tfree(copys); /* allocated by the cp_tildexpand() above */ - } + model_name = strdup( beg_ptr ); - 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 */ + *end_ptr = keep; - (void) fclose(newfp); + return model_name; +} - /* Make the .include a comment */ - *buffer = '*'; +static char * +get_adevice_model_name( char *line ) +{ + char *model_name, *ptr_end = line + strlen(line), *ptr_beg, keep; - /* 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 */ - } + while ( isspace( *(ptr_end-1) ) ) ptr_end--; + ptr_beg = ptr_end - 1; - /* 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 */ - } + while ( !isspace(*ptr_beg) ) ptr_beg--; + ptr_beg++; + keep = *ptr_end; + *ptr_end = '\0'; + model_name = strdup(ptr_beg); + *ptr_end = keep; - /* Fix the buffer up a bit. */ - (void) strncpy(buffer + 1, "end of:", 7); - } /* end of .include handling */ + return model_name; +} - /* 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"); - } - *s = '\0'; /* Zap the newline. */ +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; - if((s-1) >= buffer && *(s-1) == '\r') /* Zop the carriage return under windows */ - *(s-1) = '\0'; - } + for ( card = start_card; card != NULL; card = card->li_next ) { + line = card->li_line; - /* 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 = '*'; - } - } + if ( *line == '*' ) continue; - if ( shell_eol_continuation ) { - char *new_buffer = TMALLOC(char, strlen(buffer) + 2); - sprintf( new_buffer, "+%s", buffer ); + if ( ( ciprefix( ".ends", line ) || ciprefix( ".eom", line ) ) && found_subckt ) + break; - tfree(buffer); - buffer = new_buffer; - } + if ( ciprefix( ".subckt", line ) || ciprefix( ".macro", line ) ) { + curr_subckt_name = get_subckt_model_name( line ); - shell_eol_continuation = chk_for_line_continuation( buffer ); + if ( strcmp( curr_subckt_name, subckt_name ) == 0 ) { + found_subckt = TRUE; + } - /* 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 */ + tfree(curr_subckt_name); } + 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 ); - /* 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) */ - - if (!end) { /* No stuff here */ - *data = NULL; - return; - } + if ( num_terminals != 0 ) { + char *tmp_name, *tmp_name1; + tmp_name1 = tmp_name = model_name = get_model_name( line, num_terminals ); - if ( call_depth == 0 && found_end == TRUE) { - if ( global == NULL ) { - global = TMALLOC(char, strlen(".global gnd") + 1); - sprintf( global, ".global gnd" ); + 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 ); + } + } + } } - 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; - - prev = cc->li_next; - cc->li_next = global_card; - global_card->li_next = prev; - - inp_init_lib_data(); - inp_determine_libraries(cc, NULL); } + // 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 ); +} - /* - 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; +/* + check if current token matches model bin name -- .[0-9]+ + */ +static bool +model_bin_match( char* token, char* model_name ) +{ + char* dot_char; + bool flag = FALSE; - if ( found_lib_name && ciprefix(".endl", buffer) ) { - /* Make the .endl a comment */ - *buffer = '*'; - found_lib_name = FALSE; - - /* set pointer and continue to avoid deleting below */ - tmp_ptr2 = working->li_next; - working->li_next = tmp_ptr; - working = tmp_ptr2; - - /* end = working; - * working = working->li_next; - * end->li_next = NULL; */ - - continue; - } /* for ... */ - - if ( ciprefix(".lib", buffer) ) { - if ( found_lib_name == TRUE ) { - fprintf( stderr, "ERROR: .lib is missing .endl!\n" ); - controlled_exit(EXIT_FAILURE); - } - - 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; - - /* make the .lib a comment */ - *buffer = '*'; - - tmp_ptr = library_ll_ptr[i][j]->li_next; - library_ll_ptr[i][j]->li_next = working; - - /* 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; - - if ( found_lib_name == FALSE ) { - tfree(prev->li_line); - tfree(prev); + 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; } - } /* end while */ - } /* end for */ - - if ( found_end == TRUE ) { - end->li_next = alloc(struct line); /* create next card */ - end = end->li_next; /* point to next card */ - - buffer = TMALLOC(char, strlen( ".end" ) + 1); - sprintf( buffer, ".end" ); - - /* 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++; + dot_char++; + } } } + return flag; +} - /* 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; - } +/* + 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; - /* 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. */ + /* 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); - /* 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); + 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 = '*'; + } - while (working) { - for (s = working->li_line; (c = *s) != '\0' && c <= ' '; s++) - ; + for ( card = start_card; card != NULL; card = card->li_next ) { + line = card->li_line; -#ifdef TRACE - /* SDB debug statement */ - printf("In inp_readall, processing linked list element line = %d, s = %s . . . \n", working->li_linenum,s); -#endif + if ( *line == '*' ) continue; - 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; + /* 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; + } - case '+': /* handle continuation */ - if (!prev) { - working->li_error = copy( - "Illegal continuation line: ignored."); - working = working->li_next; - break; - } + 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 ); - /* 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); + /* comment out any unused subckts */ + for ( card = start_card; card != NULL; card = card->li_next ) { + line = card->li_line; - 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; + if ( *line == '*' ) continue; - default: /* regular one-line card */ - prev = working; - working = working->li_next; - break; + 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; + if ( !found_model ) *line = '*'; + tfree(model_name); } } + 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); +} - /* 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; - } - - working = cc->li_next; - inp_fix_for_numparam(working); - inp_remove_excess_ws(working); - if ( call_depth == 0 ) { - comment_out_unused_subckt_models(working, line_number); +/* 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; - line_number = inp_split_multi_param_lines(working, line_number); + if ( !strstr( line, "?" ) && !strstr( line, ":" ) ) return line; - inp_fix_macro_param_func_paren_io(working); - inp_fix_ternary_operator(working); - inp_grab_func(working); + str_ptr = line; + if ( ciprefix( ".param", line ) || ciprefix( ".func", line ) || ciprefix( ".meas", line ) ) { - inp_expand_macros_in_func(); - inp_expand_macros_in_deck(working); - inp_fix_param_values(working); + 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); + } - /* 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; + str_ptr++; + while( isspace(*str_ptr) ) str_ptr++; + if ( *str_ptr == '{' ) { + str_ptr++; + while( isspace(*str_ptr) ) str_ptr++; + } - 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); + question = strstr( str_ptr, "?" ); + paren_ptr = strstr( str_ptr, "(" ); + if ( paren_ptr != NULL && paren_ptr < question ) { + paren_ptr = NULL; + } + } else return line; - if (cp_getvar("addcontrol", CP_BOOL, NULL)) - inp_add_control_section(working, &line_number); - inp_compat_mode = ngspice_compat_mode() ; - 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); + // 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++; } } + str_ptr2++; + keep = *str_ptr2; + *str_ptr2 = '\0'; + conditional = strdup(str_ptr); + *str_ptr2 = keep; - /* save the return value (via **data) */ - *data = cc; + // get beginning (whatever is left before the conditional) + keep = *str_ptr; + *str_ptr = '\0'; + beg_str = strdup(line); + *str_ptr = keep; - /* 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; + // 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); } + str_ptr2++; + keep = *str_ptr2; + *str_ptr2 = '\0'; + if_str = inp_fix_ternary_operator_str(strdup(str_ptr)); + *str_ptr2 = keep; - 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); + // 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)); + } + } - (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); + 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 ); + } } } @@ -1776,9 +1767,22 @@ inp_stripcomments_deck(struct line *deck) } } -/* Strip end of line comment from a string and remove trailing white space - supports comments that begin with single characters ';' - or double characters '$ ' or '//' or '--' + +/* + * 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. + 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 '*'). @@ -2817,9 +2821,15 @@ inp_expand_macros_in_deck( struct line *deck ) 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). - .cmodel instead of .model to allow skipping {} in model line, may be obsolete. Special handling of vectors with [] and complex values with < > -*/ + + 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? + */ static void inp_fix_param_values( struct line *deck ) {