From 92f32fb8e114beb2550165ffe3bf14bbe2ea94d9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 27 May 2024 15:41:17 +0200 Subject: [PATCH] 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. --- src/frontend/inpcom.c | 107 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index a92e6b242..6db722de6 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -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++;