Search path for .lib and .include has been enhanced to read complete

or partial paths from environmental variables. The env variable
names have to start with '$' as the first character after the .inc
or .lib token. Two consecutive env variables are possible. They are
read each until directory separator '/' or '\\', or if none is found,
until the end of the line. In this case the filename has to be included
in the env variable. A .lib line may look like
.lib "$ENVS1\$ENVS2/libraries\sky130_fd_pr\latest\models\sky130.lib.spice" tt

If an env variable is read successfully, a ngspice variable with
the same name (without leading '$') and contents is defined for
use in a .control section.
This commit is contained in:
Holger Vogt 2024-05-27 15:41:17 +02:00
parent 94522f5c14
commit 92f32fb8e1
1 changed files with 102 additions and 5 deletions

View File

@ -122,7 +122,7 @@ static bool has_if = FALSE; /* if we have an .if ... .endif pair */
static char *readline(FILE *fd);
int get_number_terminals(char *c);
static void inp_stripcomments_deck(struct card *deck, bool cs);
static void inp_stripcomments_line(char *s, bool cs);
static void inp_stripcomments_line(char *s, bool cs, bool inc);
static void inp_fix_for_numparam(
struct names *subckt_w_params, struct card *deck);
static void inp_remove_excess_ws(struct card *deck);
@ -1417,7 +1417,7 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
struct card* newcard;
inp_stripcomments_line(buffer, FALSE);
inp_stripcomments_line(buffer, FALSE, TRUE);
s = skip_non_ws(buffer); /* advance past non-space chars */
@ -1942,9 +1942,99 @@ char *inp_pathresolve(const char *name)
} /* end of function inp_pathresolve */
/* Figure out if name starts with: environmental variables (replace them),
~/ (expand the tilde), absolute path name, all others and return the
path, if file exists. */
static char *inp_pathresolve_at(const char *name, const char *dir)
{
/* the string might contain one or two environmental variables at its front:
.lib $ENV1/filename
.lib $ENV1\$ENV2\filename
.lib $ENV1
.lib $ENV1/$ENV2
*/
if (name[0] == '$') {
char* s, * s1 = NULL, * tmpnam, * tmpcurr, * tmpcurr2 = NULL;
char* envvar, * envvar2 = NULL;
bool secenv = FALSE;
tmpcurr = tmpnam = copy(name);
while (*tmpcurr != '\0') {
if (*tmpcurr == '\\')
*tmpcurr = '/';
tmpcurr++;
}
tmpcurr = tmpnam;
/* extract env variable, add rest of token to its contents */
/* MS Windows directory separators */
envvar = gettok_char(&tmpcurr, '/', FALSE, FALSE);
if (envvar && ciprefix("/$", tmpcurr)) {
tmpcurr2 = tmpcurr + 1;
envvar2 = gettok_char(&tmpcurr2, '/', FALSE, FALSE);
secenv = TRUE;
}
if (envvar && !secenv) {
s = getenv(envvar + 1);
if (s) {
cp_vset(s, CP_STRING, envvar + 1);
char* newname = tprintf("%s%s", s, tmpcurr);
char* const r = inp_pathresolve(newname);
tfree(newname);
tfree(envvar);
return r;
}
fprintf(stderr, "Error: Cannot read environmental variable %s\n", envvar + 1);
controlled_exit(EXIT_BAD);
}
else if (envvar && envvar2) {
s = getenv(envvar + 1);
s1 = getenv(envvar2 + 1);
if (s && s1) {
char* newname = tprintf("%s/%s%s", s, s1, tmpcurr2);
char* const r = inp_pathresolve(newname);
tfree(newname);
tfree(envvar);
tfree(envvar2);
return r;
}
if (!s)
fprintf(stderr, "Error: Cannot read environmental variable %s\n", envvar + 1);
if (!s1)
fprintf(stderr, "Error: Cannot read environmental variable %s\n", envvar2 + 1);
controlled_exit(EXIT_BAD);
}
else if (envvar && !envvar2 && secenv) {
s = getenv(envvar + 1);/* skip "$" */
envvar2 = copy(tmpcurr);
s1 = getenv(envvar2 + 2);/* skip "$/" */
if (s && s1) {
char* newname = tprintf("%s/%s", s, s1);
char* const r = inp_pathresolve(newname);
tfree(newname);
tfree(envvar);
tfree(envvar2);
return r;
}
if (!s)
fprintf(stderr, "Error: Cannot read environmental variable %s\n", envvar + 1);
if (!s1)
fprintf(stderr, "Error: Cannot read environmental variable %s\n", envvar2 + 1);
controlled_exit(EXIT_BAD);
}
/* no directory separator found, just use the env entry (must include file name) */
envvar = tmpnam;
s = getenv(envvar + 1);/* skip '$' */
if (s) {
cp_vset(s, CP_STRING, envvar + 1);
char* const r = inp_pathresolve(s);
tfree(envvar);
return r;
}
fprintf(stderr, "Error: Cannot read environmental variable %s\n", envvar + 1);
tfree(envvar);
controlled_exit(EXIT_BAD);
}
/* if name is an absolute path name,
* or if we haven't anything to prepend anyway
*/
@ -1952,6 +2042,7 @@ static char *inp_pathresolve_at(const char *name, const char *dir)
return inp_pathresolve(name);
}
/* expand "~/" */
if (name[0] == '~' && name[1] == '/') {
char * const y = cp_tildexpand(name);
if (y) {
@ -3239,7 +3330,7 @@ static void inp_stripcomments_deck(struct card *c, bool cf)
found_control = TRUE;
if (ciprefix(".endc", c->line))
found_control = FALSE;
inp_stripcomments_line(c->line, found_control | cf);
inp_stripcomments_line(c->line, found_control | cf, FALSE);
}
}
@ -3267,7 +3358,7 @@ static void inp_stripcomments_deck(struct card *c, bool cf)
character, not as end-of-line comment delimiter, except for that it is
located at the beginning of a line. If inside of a control section,
still '$ ' is read a an end-of-line comment delimiter.*/
static void inp_stripcomments_line(char *s, bool cs)
static void inp_stripcomments_line(char *s, bool cs, bool inc)
{
char c = ' '; /* anything other than a comment character */
char *d = s;
@ -3280,6 +3371,12 @@ static void inp_stripcomments_line(char *s, bool cs)
return;
}
if (inc) {
d = nexttok(d);
if (*d == '$')
d = nexttok(d);
}
/* Look for comments in body of line. */
while ((c = *d) != '\0') {
d++;