From a46bb7b1083c37289721f4c8e8f8314bfbdf4736 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 2 Feb 2020 17:50:06 +0100 Subject: [PATCH 01/36] In VDMOS device, if instance parameter tnodeout is set, check for exactly five nodes --- src/frontend/inpcom.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 577ef2898..bd2e4d64e 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -157,7 +157,7 @@ static void inp_add_series_resistor(struct card *deck); static void subckt_params_to_param(struct card *deck); static void inp_fix_temper_in_param(struct card *deck); static void inp_fix_agauss_in_param(struct card *deck, char *fcn); -static void inp_vdmos_model(struct card *deck); +static int inp_vdmos_model(struct card *deck); static void inp_check_syntax(struct card *deck); static char *inp_spawn_brace(char *s); @@ -636,7 +636,9 @@ struct card *inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile, inp_remove_excess_ws(working); - inp_vdmos_model(working); + if(inp_vdmos_model(working)) + return NULL;; + /* don't remove unused model if we have an .if clause, because we cannot yet decide here which model we finally will need */ if (!has_if) { @@ -6840,13 +6842,14 @@ static void inp_quote_params(struct card *c, struct card *end_c, Assemble all other tokens in a wordlist, and flatten it to become the new .model line. */ -static void inp_vdmos_model(struct card *deck) +static int inp_vdmos_model(struct card *deck) { struct card *card; for (card = deck; card; card = card->nextcard) { char *curr_line, *cut_line, *token, *new_line; wordlist *wl = NULL, *wlb; + int i; curr_line = cut_line = card->line; @@ -6881,7 +6884,22 @@ static void inp_vdmos_model(struct card *deck) tfree(card->line); card->line = new_line; } + /* we have a VDMOS instance line with 'tnodeout' and thus need exactly 5 nodes + */ + else if (strstr(curr_line, "tnodeout")) { + for (i = 0; i < 7; i++) + curr_line = nexttok(curr_line); + if (!ciprefix("tnodeout", curr_line)) { + fprintf(cp_err, + "Error: We need exactly 5 nodes\n" + " drain, gate, source, tjunction, tcase\n" + " in VDMOS instance line\n" + " %s\n", card->line); + return 1; + } + } } + return 0; } From f09d1d451e99732b53f081ee22eeeec339b3120c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 2 Feb 2020 17:51:07 +0100 Subject: [PATCH 02/36] increase max. number of threads for BSIM4 to 8 --- examples/various/ro_17_4.cir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/various/ro_17_4.cir b/examples/various/ro_17_4.cir index 9a4704f72..c4dccaa89 100644 --- a/examples/various/ro_17_4.cir +++ b/examples/various/ro_17_4.cir @@ -62,7 +62,7 @@ c1 18 0 .1p option xmu = 0.49 * set xmu=0.49 -set num_threads=4 +set num_threads=8 set noinit run From 9889f0f277f4096c572f70b98213ac7899e00a55 Mon Sep 17 00:00:00 2001 From: dwarning Date: Mon, 3 Feb 2020 20:40:36 +0100 Subject: [PATCH 03/36] alternative temperature model for extrinsic resistances and subthreshold range --- src/spicelib/devices/vdmos/vdmos.c | 10 ++++++ src/spicelib/devices/vdmos/vdmosdefs.h | 37 +++++++++++++++++++-- src/spicelib/devices/vdmos/vdmosload.c | 2 +- src/spicelib/devices/vdmos/vdmosmask.c | 34 +++++++++++++++++-- src/spicelib/devices/vdmos/vdmosmpar.c | 46 ++++++++++++++++++++++++-- src/spicelib/devices/vdmos/vdmosset.c | 30 +++++++++++++++++ src/spicelib/devices/vdmos/vdmostemp.c | 15 +++++++-- 7 files changed, 162 insertions(+), 12 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c index 859d4501f..d6802652b 100644 --- a/src/spicelib/devices/vdmos/vdmos.c +++ b/src/spicelib/devices/vdmos/vdmos.c @@ -89,10 +89,20 @@ IFparm VDMOSmPTable[] = { /* model parameters */ IOPR("bex", VDMOS_MOD_MU, IF_REAL, "Exponent of gain temperature dependency"), IOP( "texp0", VDMOS_MOD_TEXP0, IF_REAL, "Drain resistance rd0 temperature exponent"), IOP( "texp1", VDMOS_MOD_TEXP1, IF_REAL, "Drain resistance rd1 temperature exponent"), + IOP( "trd1", VDMOS_MOD_TRD1, IF_REAL, "Drain resistance linear temperature coefficient"), + IOP( "trd2", VDMOS_MOD_TRD2, IF_REAL, "Drain resistance quadratic temperature coefficient"), + IOP( "trg1", VDMOS_MOD_TRG1, IF_REAL, "Gate resistance linear temperature coefficient"), + IOP( "trg2", VDMOS_MOD_TRG2, IF_REAL, "Gate resistance quadratic temperature coefficient"), + IOP( "trs1", VDMOS_MOD_TRS1, IF_REAL, "Source resistance linear temperature coefficient"), + IOP( "trs2", VDMOS_MOD_TRS2, IF_REAL, "Source resistance quadratic temperature coefficient"), + IOP( "trb1", VDMOS_MOD_TRB1, IF_REAL, "Body resistance linear temperature coefficient"), + IOP( "trb2", VDMOS_MOD_TRB2, IF_REAL, "Body resistance quadratic temperature coefficient"), /* weak inversion */ IOP("subshift", VDMOS_MOD_SUBSHIFT, IF_REAL, "Shift of weak inversion plot on the vgs axis"), IOP("ksubthres", VDMOS_MOD_KSUBTHRES, IF_REAL, "Slope of weak inversion log current versus vgs"), + IOP("tksubthres1", VDMOS_MOD_TKSUBTHRES1, IF_REAL, "Linear temperature coefficient of ksubthres"), + IOP("tksubthres2", VDMOS_MOD_TKSUBTHRES2, IF_REAL, "Quadratic temperature coefficient of ksubthres"), /* body diode */ IOP("bv", VDMOS_MOD_BV, IF_REAL, "Vds breakdown voltage"), diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 8fe805a0d..5e227f90b 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -69,6 +69,7 @@ typedef struct sVDMOSinstance { double VDMOStTransconductance; /* temperature corrected transconductance*/ double VDMOStPhi; /* temperature corrected Phi */ double VDMOStVth; /* temperature corrected Vth */ + double VDMOStksubthres; /* temperature weak inversion slope */ double VDMOSicVDS; /* initial condition D-S voltage */ double VDMOSicVGS; /* initial condition G-S voltage */ @@ -332,13 +333,23 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDIOgradCoeffTemp1; double VDIOgradCoeffTemp2; + double VDMOStcvth; double VDMOSrthjc; double VDMOSrthca; double VDMOScthj; double VDMOSmu; double VDMOStexp0; double VDMOStexp1; - double VDMOStcvth; + double VDMOStrd1; + double VDMOStrd2; + double VDMOStrg1; + double VDMOStrg2; + double VDMOStrs1; + double VDMOStrs2; + double VDMOStrb1; + double VDMOStrb2; + double VDMOStksubthres1; + double VDMOStksubthres2; double VDMOSvgsMax; double VDMOSvgdMax; @@ -385,13 +396,23 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOSegGiven :1; unsigned VDMOSxtiGiven :1; + unsigned VDMOStcvthGiven :1; unsigned VDMOSrthjcGiven :1; unsigned VDMOSrthcaGiven :1; unsigned VDMOScthjGiven :1; unsigned VDMOSmuGiven :1; unsigned VDMOStexp0Given :1; unsigned VDMOStexp1Given :1; - unsigned VDMOStcvthGiven :1; + unsigned VDMOStrd1Given :1; + unsigned VDMOStrd2Given :1; + unsigned VDMOStrg1Given :1; + unsigned VDMOStrg2Given :1; + unsigned VDMOStrs1Given :1; + unsigned VDMOStrs2Given :1; + unsigned VDMOStrb1Given :1; + unsigned VDMOStrb2Given :1; + unsigned VDMOStksubthres1Given :1; + unsigned VDMOStksubthres2Given :1; unsigned VDMOSvgsMaxGiven :1; unsigned VDMOSvgdMaxGiven :1; @@ -462,13 +483,23 @@ enum { VDMOS_MOD_TT, VDMOS_MOD_EG, VDMOS_MOD_XTI, + VDMOS_MOD_TCVTH, VDMOS_MOD_RTHJC, VDMOS_MOD_RTHCA, VDMOS_MOD_CTHJ, VDMOS_MOD_MU, VDMOS_MOD_TEXP0, VDMOS_MOD_TEXP1, - VDMOS_MOD_TCVTH, + VDMOS_MOD_TRD1, + VDMOS_MOD_TRD2, + VDMOS_MOD_TRG1, + VDMOS_MOD_TRG2, + VDMOS_MOD_TRS1, + VDMOS_MOD_TRS2, + VDMOS_MOD_TRB1, + VDMOS_MOD_TRB2, + VDMOS_MOD_TKSUBTHRES1, + VDMOS_MOD_TKSUBTHRES2, VDMOS_MOD_VGS_MAX, VDMOS_MOD_VGD_MAX, VDMOS_MOD_VDS_MAX, diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 233eb6100..0fbb15a47 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -372,7 +372,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) * Scale the voltage overdrive vgst logarithmically in weak inversion. * Best fits LTSPICE curves with shift=0 */ - double slope = model->VDMOSksubthres; + double slope = here->VDMOStksubthres; double lambda = model->VDMOSlambda; double theta = model->VDMOStheta; double shift = model->VDMOSsubshift; diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c index de8f9437d..9b5c1f956 100644 --- a/src/spicelib/devices/vdmos/vdmosmask.c +++ b/src/spicelib/devices/vdmos/vdmosmask.c @@ -125,6 +125,9 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case VDMOS_MOD_XTI: value->rValue = model->VDMOSxti; return(OK); + case VDMOS_MOD_TCVTH: + value->rValue = model->VDMOStcvth; + return(OK); case VDMOS_MOD_RTHJC: value->rValue = model->VDMOSrthjc; return(OK); @@ -143,8 +146,35 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case VDMOS_MOD_TEXP1: value->rValue = model->VDMOStexp1; return(OK); - case VDMOS_MOD_TCVTH: - value->rValue = model->VDMOStcvth; + case VDMOS_MOD_TRD1: + value->rValue = model->VDMOStrd1; + return(OK); + case VDMOS_MOD_TRD2: + value->rValue = model->VDMOStrd2; + return(OK); + case VDMOS_MOD_TRG1: + value->rValue = model->VDMOStrg1; + return(OK); + case VDMOS_MOD_TRG2: + value->rValue = model->VDMOStrg2; + return(OK); + case VDMOS_MOD_TRS1: + value->rValue = model->VDMOStrs1; + return(OK); + case VDMOS_MOD_TRS2: + value->rValue = model->VDMOStrs2; + return(OK); + case VDMOS_MOD_TRB1: + value->rValue = model->VDMOStrb1; + return(OK); + case VDMOS_MOD_TRB2: + value->rValue = model->VDMOStrb2; + return(OK); + case VDMOS_MOD_TKSUBTHRES1: + value->rValue = model->VDMOStksubthres1; + return(OK); + case VDMOS_MOD_TKSUBTHRES2: + value->rValue = model->VDMOStksubthres2; return(OK); case VDMOS_MOD_VGS_MAX: value->rValue = model->VDMOSvgsMax; diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c index 615cc6948..44fa84ccc 100644 --- a/src/spicelib/devices/vdmos/vdmosmpar.c +++ b/src/spicelib/devices/vdmos/vdmosmpar.c @@ -174,6 +174,10 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDMOSxti = value->rValue; model->VDMOSxtiGiven = TRUE; break; + case VDMOS_MOD_TCVTH: + model->VDMOStcvth = value->rValue; + model->VDMOStcvthGiven = TRUE; + break; case VDMOS_MOD_RTHJC: model->VDMOSrthjc = value->rValue; model->VDMOSrthjcGiven = TRUE; @@ -198,9 +202,45 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDMOStexp1 = value->rValue; model->VDMOStexp1Given = TRUE; break; - case VDMOS_MOD_TCVTH: - model->VDMOStcvth = value->rValue; - model->VDMOStcvthGiven = TRUE; + case VDMOS_MOD_TRD1: + model->VDMOStrd1 = value->rValue; + model->VDMOStrd1Given = TRUE; + break; + case VDMOS_MOD_TRD2: + model->VDMOStrd2 = value->rValue; + model->VDMOStrd2Given = TRUE; + break; + case VDMOS_MOD_TRG1: + model->VDMOStrg1 = value->rValue; + model->VDMOStrg1Given = TRUE; + break; + case VDMOS_MOD_TRG2: + model->VDMOStrg2 = value->rValue; + model->VDMOStrg2Given = TRUE; + break; + case VDMOS_MOD_TRS1: + model->VDMOStrs1 = value->rValue; + model->VDMOStrs1Given = TRUE; + break; + case VDMOS_MOD_TRS2: + model->VDMOStrs2 = value->rValue; + model->VDMOStrs2Given = TRUE; + break; + case VDMOS_MOD_TRB1: + model->VDMOStrb1 = value->rValue; + model->VDMOStrb1Given = TRUE; + break; + case VDMOS_MOD_TRB2: + model->VDMOStrb2 = value->rValue; + model->VDMOStrb2Given = TRUE; + break; + case VDMOS_MOD_TKSUBTHRES1: + model->VDMOStksubthres1 = value->rValue; + model->VDMOStksubthres1Given = TRUE; + break; + case VDMOS_MOD_TKSUBTHRES2: + model->VDMOStksubthres2 = value->rValue; + model->VDMOStksubthres2Given = TRUE; break; case VDMOS_MOD_VGS_MAX: model->VDMOSvgsMax = value->rValue; diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index c763b76bc..1bd415a91 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -139,6 +139,36 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (!model->VDMOStexp1Given) model->VDMOStexp1 = 0.3; + if (!model->VDMOStrd1Given) + model->VDMOStrd1 = 0.0; + + if (!model->VDMOStrd2Given) + model->VDMOStrd2 = 0.0; + + if (!model->VDMOStrg1Given) + model->VDMOStrg1 = 0.0; + + if (!model->VDMOStrg2Given) + model->VDMOStrg2 = 0.0; + + if (!model->VDMOStrs1Given) + model->VDMOStrs1 = 0.0; + + if (!model->VDMOStrs2Given) + model->VDMOStrs2 = 0.0; + + if (!model->VDMOStrb1Given) + model->VDMOStrb1 = 0.0; + + if (!model->VDMOStrb2Given) + model->VDMOStrb2 = 0.0; + + if (!model->VDMOStksubthres1Given) + model->VDMOStksubthres1 = 0.0; + + if (!model->VDMOStksubthres2Given) + model->VDMOStksubthres2 = 0.0; + if (!model->VDMOSvgsMaxGiven) model->VDMOSvgsMax = 1e99; diff --git a/src/spicelib/devices/vdmos/vdmostemp.c b/src/spicelib/devices/vdmos/vdmostemp.c index 4b9fda07b..dbd81fe84 100644 --- a/src/spicelib/devices/vdmos/vdmostemp.c +++ b/src/spicelib/devices/vdmos/vdmostemp.c @@ -98,7 +98,16 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) here->VDMOStVth = model->VDMOSvth0 - model->VDMOStype * model->VDMOStcvth * dt; - here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * pow(ratio, model->VDMOStexp0); + here->VDMOStksubthres = model->VDMOSksubthres * (1.0 + (model->VDMOStksubthres1 * dt) + (model->VDMOStksubthres2 * dt * dt)); + + if (model->VDMOStexp0Given) + here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * pow(ratio, model->VDMOStexp0); + else + here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * (1.0 + (model->VDMOStrd1 * dt) + (model->VDMOStrd2 * dt * dt)); + + here->VDMOSgateConductance = here->VDMOSgateConductance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt)); + + here->VDMOSsourceConductance = here->VDMOSsourceConductance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt)); if (model->VDMOSqsGiven) here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1); @@ -206,8 +215,8 @@ VDMOStemp(GENmodel *inModel, CKTcircuit *ckt) + (model->VDIOtranTimeTemp2 * dt * dt); here->VDIOtTransitTime = model->VDIOtransitTime * factor; - /* Series resistance temperature adjust (not implemented yet) */ - here->VDIOtConductance = here->VDIOconductance; + /* Series resistance temperature adjust */ + here->VDIOtConductance = here->VDIOconductance / (1.0 + (model->VDMOStrb1 * dt) + (model->VDMOStrb2 * dt * dt)); here->VDIOtF2 = exp((1 + here->VDIOtGradingCoeff)*xfc); here->VDIOtF3 = 1 - model->VDIOdepletionCapCoeff* From 8a6f431f4b3b8b89f4db9f0323cc841f370ddd08 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 11 Feb 2020 10:48:38 +0100 Subject: [PATCH 04/36] simplify beta derivation --- src/spicelib/devices/vdmos/vdmosload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index 0fbb15a47..042a31178 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -314,7 +314,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) if (selfheat) { double TempRatio = Temp / here->VDMOStemp; Beta = here->VDMOStTransconductance * pow(TempRatio,model->VDMOSmu); - dBeta_dT = here->VDMOStTransconductance * model->VDMOSmu / (here->VDMOStemp * pow(TempRatio,1-model->VDMOSmu)); + dBeta_dT = Beta * model->VDMOSmu / Temp; rd0T = here->VDMOSdrainResistance * pow(TempRatio, model->VDMOStexp0); drd0T_dT = rd0T * model->VDMOStexp0 / Temp; rd1T = 0.0; From faf01c03769e0d67c6be86b44dd86d80bce413f7 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sat, 21 Dec 2019 21:09:30 -0500 Subject: [PATCH 05/36] Modified calculation to determine when memory is nearly exhausted. Also changed prototypes of memory reporting functions to match their definitions. --- src/frontend/resource.c | 28 ++++++++++++++-------------- src/frontend/resource.h | 8 ++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/frontend/resource.c b/src/frontend/resource.c index 7952e6963..608b7ee44 100644 --- a/src/frontend/resource.c +++ b/src/frontend/resource.c @@ -123,33 +123,33 @@ com_rusage(wordlist *wl) /* Find out if the user is approaching his maximum data size. If usage is withing 95% of total available then a warning message is sent to the error stream (cp_err) */ -void -ft_ckspace(void) +void ft_ckspace(void) { #ifdef SHARED_MODULE /* False warning on some OSs, especially on Linux when loaded during runtime. The caller then has to take care of memory available */ return; #else - unsigned long long freemem, totalmem, usage, avail; - freemem = getAvailableMemorySize(); - totalmem = getMemorySize(); - usage = getCurrentRSS(); - avail = usage + freemem; + const unsigned long long freemem = getAvailableMemorySize(); + const unsigned long long usage = getCurrentRSS(); - if (totalmem == 0 || freemem == 0 || usage == 0) + if (freemem == 0 || usage == 0) { /* error obtaining data */ return; + } - if ((double)freemem < (double)totalmem * 0.05) { - fprintf(cp_err, "Warning - approaching max data size: "); - fprintf(cp_err, "current size = "); + const unsigned long long avail = usage + freemem; + if ((double) usage > (double) avail * 0.95) { + (void) fprintf(cp_err, + "Warning - approaching max data size: " + "current size = "); fprintmem(cp_err, usage); - fprintf(cp_err, ", limit = "); + (void) fprintf(cp_err, ", limit = "); fprintmem(cp_err, avail); - fprintf(cp_err, "\n"); + (void) fprintf(cp_err, "\n"); } #endif -} +} /* end of function ft_chkspace */ + /* Print out one piece of resource usage information. */ diff --git a/src/frontend/resource.h b/src/frontend/resource.h index 21cad8912..15b99c399 100644 --- a/src/frontend/resource.h +++ b/src/frontend/resource.h @@ -6,10 +6,10 @@ #ifndef ngspice_RESOURCE_H #define ngspice_RESOURCE_H -extern size_t getMemorySize(void); -extern size_t getPeakRSS(void); -extern size_t getCurrentRSS(void); -extern size_t getAvailableMemorySize(void); +extern unsigned long long getMemorySize(void); +extern unsigned long long getPeakRSS(void); +extern unsigned long long getCurrentRSS(void); +extern unsigned long long getAvailableMemorySize(void); void init_rlimits(void); void init_time(void); From 6385c7a900ba51d92c1b48aed3fe92eeda89ac7b Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Mon, 23 Dec 2019 01:03:35 -0500 Subject: [PATCH 06/36] Removed unnecessary comparisons when lowercasing a string. --- src/xspice/cmpp/util.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/xspice/cmpp/util.c b/src/xspice/cmpp/util.c index 1a0a0ef5a..635083c64 100644 --- a/src/xspice/cmpp/util.c +++ b/src/xspice/cmpp/util.c @@ -85,9 +85,7 @@ void str_to_lower(char *s) char c; for(i = 0; (c = s[i]) != '\0'; i++) - if(isalpha_c(c)) - if(isupper_c(c)) - s[i] = tolower_c(c); + s[i] = tolower_c(c); } From 4392ccc520423b3b0f96d64505d82f54476b4d18 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Mon, 23 Dec 2019 01:16:10 -0500 Subject: [PATCH 07/36] Formatting and comments added --- src/xspice/cmpp/util.c | 49 ++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/xspice/cmpp/util.c b/src/xspice/cmpp/util.c index 635083c64..6debc4bab 100644 --- a/src/xspice/cmpp/util.c +++ b/src/xspice/cmpp/util.c @@ -38,13 +38,13 @@ NON-STANDARD FEATURES ============================================================================*/ -#include "cmpp.h" -#include #include -#include #include +#include +#include #include +#include "cmpp.h" /* *********************************************************************** */ @@ -52,17 +52,17 @@ NON-STANDARD FEATURES char *prog_name; -/* Initialize print_error() with the name of the program */ - -void init_error (char *program_name) +/* Initialize external variable prog_name with the name of the program. + * A copy is not made. */ +void init_error(char *program_name) { prog_name = program_name; -} +} /* end of function init_error */ -/* Print an error message to stderr */ - +/* Print an error message to stderr. The message is prefixed with the + * name of the program and a newline character is added to the end. */ void print_error(const char *fmt, ...) { va_list ap; @@ -73,37 +73,41 @@ void print_error(const char *fmt, ...) fprintf(stderr, "\n"); va_end(ap); -} +} /* end of function print_error */ /* Convert a string to all lower case */ - void str_to_lower(char *s) { - int i; - char c; + int i; + char c; - for(i = 0; (c = s[i]) != '\0'; i++) + for(i = 0; (c = s[i]) != '\0'; i++) { s[i] = tolower_c(c); -} + } +} /* end of function str_to_lower */ + +/* If *path_p is relative, prefix with the CMPP output or input string + * build the path and open the file and return the path that was created. */ FILE *fopen_cmpp(const char **path_p, const char *mode) { const char *path = *path_p; - char buf[MAX_PATH_LEN+1]; + char buf[MAX_PATH_LEN + 1]; - if(path[0] != '/') { + if (path[0] != '/') { const char *e = getenv((*mode == 'w') ? "CMPP_ODIR" : "CMPP_IDIR"); - if(e) { - if(strlen(e) + 1 + strlen(path) < sizeof(buf)) { + if (e) { + if (strlen(e) + 1 + strlen(path) < sizeof(buf)) { strcpy(buf, e); strcat(buf, "/"); strcat(buf, path); path = buf; - } else { + } + else { path = NULL; } } @@ -112,4 +116,7 @@ FILE *fopen_cmpp(const char **path_p, const char *mode) *path_p = strdup(path); return fopen(path, mode); -} +} /* end of function fopen_cmpp */ + + + From affa528cb56c870e63b2e727430a872bbf780713 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Wed, 18 Dec 2019 23:25:03 -0500 Subject: [PATCH 08/36] Rework of let command. Added support for slices as described in feature #69 and fixed several crashes and issues described in bugs #443, #444, #446, #447, and #448. --- src/frontend/com_let.c | 860 +++++++++++++++++++++++++++++-------- src/frontend/dvec.c | 5 +- src/include/ngspice/dvec.h | 2 +- 3 files changed, 678 insertions(+), 189 deletions(-) diff --git a/src/frontend/com_let.c b/src/frontend/com_let.c index d6edb7c22..d1fb41754 100644 --- a/src/frontend/com_let.c +++ b/src/frontend/com_let.c @@ -1,238 +1,726 @@ #include +#include -#include "ngspice/dvec.h" -#include "ngspice/ngspice.h" -#include "ngspice/fteext.h" +#include "ngspice/bool.h" #include "ngspice/cpextern.h" +#include "ngspice/dvec.h" +#include "ngspice/fteext.h" +#include "ngspice/ngspice.h" #include "ngspice/stringskip.h" -#include "com_let.h" #include "com_display.h" +#include "com_let.h" #include "completion.h" +/* Range of index values, such as 2:3 */ +typedef struct index_range { + int low; + int high; +} index_range_t; -void -com_let(wordlist *wl) +static void copy_vector_data(struct dvec *vec_dst, + const struct dvec *vec_src); +static void copy_vector_data_with_stride(struct dvec *vec_dst, + const struct dvec *vec_src, + int n_dst_index, const index_range_t *p_dst_index); +static int find_indices(char *s, index_range_t *p_index, int *p_n_index); +static int get_index_values(char *s, index_range_t *p_range); +int get_one_index_value(char *s, int *p_index); + +/* let = + * let [] = + * = ... + * + * = | : + * = "," | "] [" + * = standard ngspice expression + */ +void com_let(wordlist *wl) { - char *p, *q, *s; - int indices[MAXDIMS]; - int numdims; - int need_open; - int offset, length; - struct pnode *names; - struct dvec *n, *t; - int i, cube; - int j, depth; - int newvec; + char *p, *s; + index_range_t p_dst_index[MAXDIMS]; + int n_dst_index; + struct pnode *names = (struct pnode *) NULL; + struct dvec *vec_src = (struct dvec *) NULL; char *rhs; + /* let with no arguments is equivalent to display */ if (!wl) { com_display(NULL); return; } - p = wl_flatten(wl); + p = wl_flatten(wl); /* Everything after let -> string */ - /* extract indices */ - numdims = 0; - if ((rhs = strchr(p, '=')) != NULL) { - *rhs++ = '\0'; - } else { + /* Separate vector name from RHS of assignment */ + n_dst_index = 0; + if ((rhs = strchr(p, '=')) == (char *) NULL) { fprintf(cp_err, "Error: bad let syntax\n"); - tfree(p); + txfree(p); return; } + *rhs++ = '\0'; + /* Handle indexing. At start, p = LHS; rhs = RHS. If index is found + * p = leftmost part of orig p up to first '['. So p always + * becomes the vector name, possibly with some spaces at the end. */ if ((s = strchr(p, '[')) != NULL) { - need_open = 0; - *s++ = '\0'; - while (!need_open || *s == '[') { - depth = 0; - if (need_open) - s++; - for (q = s; *q && (*q != ']' && (*q != ',' || depth > 0)); q++) { - switch (*q) { - case '[': - depth += 1; - break; - case ']': - depth -= 1; - break; - } - } - - if (depth != 0 || !*q) { - printf("syntax error specifying index\n"); - tfree(p); - return; - } - - if (*q == ']') - need_open = 1; - else - need_open = 0; - - if (*q) - *q++ = '\0'; - - /* evaluate expression between s and q */ - /* va, indexing */ - names = ft_getpnames_from_string(s, TRUE); - if (!names) { - /* XXX error message */ - tfree(p); - return; - } - t = ft_evaluate(names); - if (!t) { - fprintf(cp_err, "Error: Can't evaluate %s\n", s); - free_pnode(names); - tfree(p); - return; - } - if (!isreal(t) || t->v_link2 || t->v_length != 1 || !t->v_realdata) { - fprintf(cp_err, "Error: index is not a scalar.\n"); - goto quit; - } - j = (int)floor(t->v_realdata[0]+0.5); /* ignore sanity checks for now, va, which checks? */ - - if (j < 0) { - printf("negative index (%d) is not allowed\n", j); - goto quit; - } - - indices[numdims++] = j; - - /* va: garbage collection for t, if pnode `names' is no simple value */ - if (names && !names->pn_value && t) - vec_free(t); - free_pnode(names); /* frees also t, if pnode `names' is simple value */ - - s = skip_ws(q); + *s = '\0'; + if (find_indices(s + 1, p_dst_index, &n_dst_index) != 0) { + txfree(p); + return; } - } - /* vector name at p */ + } /* end of case that an indexing bracket '[' was found */ - for (q = p + strlen(p) - 1; *q <= ' ' && p <= q; q--) - ; - *++q = '\0'; - - /* sanity check */ - if (eq(p, "all") || strchr(p, '@') || isdigit_c(*p)) { - fprintf(cp_err, "Error: bad variable name %s\n", p); - tfree(p); - return; + /* "Remove" any spaces at the end of the vector name at p */ + { + char *q; + for (q = p + strlen(p) - 1; *q <= ' ' && p <= q; q--) { + ; + } + *++q = '\0'; } - /* evaluate rhs */ + /* Sanity check */ + if (eq(p, "all") || strchr(p, '@') || *p == '\0' || isdigit_c(*p)) { + fprintf(cp_err, "Error: bad variable name \"%s\"\n", p); + goto quit; + } + + /* Evaluate rhs */ names = ft_getpnames_from_string(rhs, TRUE); - if (names == NULL) { + if (names == (struct pnode *) NULL) { fprintf(cp_err, "Error: RHS \"%s\" invalid\n", rhs); - tfree(p); - return; + goto quit; } - t = ft_evaluate(names); - if (!t) { - fprintf(cp_err, "Error: Can't evaluate %s\n", rhs); - free_pnode(names); - tfree(p); - return; + vec_src = ft_evaluate(names); + if (!vec_src) { + fprintf(cp_err, "Error: Can't evaluate \"%s\"\n", rhs); + goto quit; } - if (t->v_link2) + if (vec_src->v_link2) { fprintf(cp_err, "Warning: extra wildcard values ignored\n"); + } - n = vec_get(p); + /* Fix-up dimension count and limit. Sometimes these are + * not set properly. If not set, make 1-d vector and ensure + * the right length */ + if (vec_src->v_numdims < 1) { + vec_src->v_numdims = 1; + } + if (vec_src->v_numdims == 1) { + vec_src->v_dims[0] = vec_src->v_length; + } - if (n) { - /* re-allocate? */ - /* vec_free(n); */ - newvec = 0; - } else { - if (numdims) { - fprintf(cp_err, "Can't assign into a subindex of a new vector\n"); + /* Locate the vector being assigned values. If NULL, the vector + * does not exist */ + struct dvec * vec_dst = vec_get(p); + + if (vec_dst == (struct dvec *) NULL) { + /* p is not an existing vector. So make a new one equal to vec_src + * in all ways, except enforce that it is a permanent vector. */ + if (n_dst_index > 0) { + fprintf(cp_err, + "When creating a new vector, it cannot be indexed.\n"); goto quit; } - /* create and assign a new vector */ - n = dvec_alloc(copy(p), - t->v_type, - t->v_flags | VF_PERMANENT, - t->v_length, NULL); + /* Create and assign a new vector */ + vec_dst = dvec_alloc(copy(p), + vec_src->v_type, + vec_src->v_flags | VF_PERMANENT, + vec_src->v_length, NULL); - if ((t->v_numdims) <= 1) { // changed from "!t->v_numdims" by Friedrich Schmidt - n->v_numdims = 1; - n->v_dims[0] = n->v_length; - } else { - n->v_numdims = t->v_numdims; - for (i = 0; i < t->v_numdims; i++) - n->v_dims[i] = t->v_dims[i]; + copy_vector_data(vec_dst, vec_src); + vec_new(vec_dst); /* Add tp current plot */ + cp_addkword(CT_VECTOR, vec_dst->v_name); + } /* end of case of new vector */ + else { + /* Existing vector.*/ + /* Fix-up dimension count and limit. Sometimes these are + * not set properly. If not set, make 1-d vector and ensure + * the right length */ + if (vec_dst->v_numdims < 1) { + vec_dst->v_numdims = 1; + } + if (vec_dst->v_numdims == 1) { + vec_dst->v_dims[0] = vec_dst->v_length; } - newvec = 1; - vec_new(n); - } + if (n_dst_index == 0) { + /* Not indexed, so make equal to source vector as if it + * was a new vector, except reuse the allocation if it + * is the same type (real/complex) and the allocation size + * is sufficient but not too large (>2X) . */ + if (isreal(vec_dst) == isreal(vec_src) && + vec_dst->v_alloc_length >= vec_src->v_length && + vec_dst->v_alloc_length <= 2 * vec_src->v_length) { + vec_dst->v_length = vec_src->v_length; + copy_vector_data(vec_dst, vec_src); + } + else { /* Something not OK, so free and allocate again */ + int n_elem_alloc = vec_src->v_alloc_length; + if (isreal(vec_dst)) { + tfree(vec_dst->v_realdata); + } + else { /* complex */ + tfree(vec_dst->v_compdata); + } + if (isreal(vec_src)) { + vec_dst->v_realdata = TMALLOC(double, n_elem_alloc); + } + else { /* complex source */ + vec_dst->v_compdata = TMALLOC(ngcomplex_t, n_elem_alloc); + } - /* fix-up dimensions; va, also for v_dims */ - if (n->v_numdims < 1 || n->v_dims[0] == 0 ) { - n->v_numdims = 1; - n->v_dims[0] = n->v_length; - } - - /* Compare dimensions */ - offset = 0; - length = n->v_length; - - cube = 1; - for (i = n->v_numdims - 1; i >= numdims; i--) - cube *= n->v_dims[i]; - - for (i = numdims - 1; i >= 0; i--) { - offset += cube * indices[i]; - if (i < n->v_numdims) { - cube *= n->v_dims[i]; - length /= n->v_dims[i]; + /* Make the destination vector the right data type. A few + * extra () added to keep some compilers from warning. */ + vec_dst->v_flags = + (vec_dst->v_flags & ~(VF_REAL | VF_COMPLEX)) | + (vec_src->v_flags & (VF_REAL | VF_COMPLEX)); + vec_dst->v_alloc_length = vec_src->v_alloc_length; + vec_dst->v_length = vec_src->v_length; + copy_vector_data(vec_dst, vec_src); + } } - } + /* Else indexed. In this case, the source data must fit the indexed + * range */ + else { + { + int n_dst_elem = 1; + int i; + for (i = 0; i < n_dst_index; ++i) { + index_range_t *p_range_cur = p_dst_index + i; + n_dst_elem *= p_range_cur->high - p_range_cur->low + 1; + } - /* length is the size of the unit refered to */ - /* cube ends up being the length */ + /* Check # elem required vs available */ + if (n_dst_elem != vec_src->v_length) { + (void) fprintf(cp_err, "Data for an index vector must " + "fit exactly. The indexed range required %d " + "elements to fill it, but there were %d " + "elements supplied.\n", + n_dst_elem, vec_src->v_length); + goto quit; + } + } - if (length > t->v_length) { - fprintf(cp_err, "left-hand expression is too small (need %d)\n", - length * cube); - if (newvec) - n->v_flags &= ~VF_PERMANENT; - goto quit; - } - if (isreal(t) != isreal(n)) { - fprintf(cp_err, - "Types of vectors are not the same (real vs. complex)\n"); - if (newvec) - n->v_flags &= ~VF_PERMANENT; - goto quit; - } else if (isreal(t)) { - memcpy(n->v_realdata + offset, t->v_realdata, - (size_t) length * sizeof(double)); - } else { - memcpy(n->v_compdata + offset, t->v_compdata, - (size_t) length * sizeof(ngcomplex_t)); - } + /* Real source data can be put into a complex destination, + * but the other way around is not possible */ + if (isreal(vec_dst) && iscomplex(vec_src)) { + (void) fprintf(cp_err, "Complex data cannot be used " + "to fill an array of real data.\n"); + goto quit; + } - n->v_minsignal = 0.0; /* How do these get reset ??? */ - n->v_maxsignal = 0.0; + /* Check dimension numbers */ + if (n_dst_index != vec_dst->v_numdims) { + fprintf(cp_err, "Number of vector indices given (%d) " + "does not match the dimension of the vector (%d).\n", + n_dst_index, vec_dst->v_numdims); + goto quit; + } - n->v_scale = t->v_scale; + /* Check dimension ranges */ + { + int i; + int *vec_dst_dims = vec_dst->v_dims; + for (i = 0; i < n_dst_index; ++i) { + const int n_dst_cur = vec_dst_dims[i]; + if (p_dst_index[i].high >= n_dst_cur) { + fprintf(cp_err, + "Vector index %d out of range (%d).\n", + i + 1, n_dst_cur); + goto quit; + } + } /* end of loop over dimensions */ + } - if (newvec) - cp_addkword(CT_VECTOR, n->v_name); + /* OK to copy, so copy */ + copy_vector_data_with_stride(vec_dst, vec_src, + n_dst_index, p_dst_index); + } /* end of indexed vector */ + } /* end of existing vector */ + + vec_dst->v_minsignal = 0.0; /* How do these get reset ??? */ + vec_dst->v_maxsignal = 0.0; + vec_dst->v_scale = vec_src->v_scale; quit: - /* va: garbage collection for t, if pnode `names' is no simple value */ - if (names && !names->pn_value && t) - vec_free(t); - free_pnode(names); /* frees also t, if pnode `names' is simple value */ - tfree(p); -} + /* va: garbage collection for vec_src, if ft_evaluate() created a + * new vector while evaluating pnode `names' */ + if (names != (struct pnode *) NULL) { + if (!names->pn_value && vec_src) { + vec_free(vec_src); + } + /* frees also vec_src, if pnode `names' is simple value */ + free_pnode(names); + } + txfree(p); +} /* end of function com_let */ + + + +/* Process indexing portion of a let command. On entry, s is the address + * of the first byte after the first opening index bracket */ +static int find_indices(char *s, index_range_t *p_index, int *p_n_index) +{ + /* Can be either comma-separated or individual dimensions */ + if (strchr(s, ',') != 0) { /* has commas */ + char *p_end; + int dim_cur = 0; + const int dim_max = MAXDIMS - 1; + while ((p_end = strchr(s, ',')) != (char *) NULL) { + *p_end = '\0'; + if (dim_cur == dim_max) { + (void) fprintf(cp_err, "Too many dimensions given.\n"); + return -1; + } + if (get_index_values(s, p_index + dim_cur) != 0) { + (void) fprintf(cp_err, "Dimension ranges " + "for dimension %d could not be found.\n", + dim_cur + 1); + return -1; + } + ++dim_cur; + s = p_end + 1; /* after (former) comma */ + } /* end of loop over comma-separated indices */ + + /* Must be one more index ending with a bracket */ + if ((p_end = strchr(s, ']')) == (char *) NULL) { + (void) fprintf(cp_err, + "Final dimension was not found.\n"); + return -1; + } + + *p_end = '\0'; + if (dim_cur == dim_max) { + (void) fprintf(cp_err, + "Final dimension exceded maximum number.\n"); + return -1; + } + if (get_index_values(s, p_index + dim_cur) != 0) { + (void) fprintf(cp_err, "Dimension ranges " + "for last dimension (%d) could not be found.\n", + dim_cur + 1); + return -1; + } + ++dim_cur; + s = p_end + 1; + + /* Only white space is allowed after closing brace */ + if ((s = skip_ws(s)) != '\0') { + (void) fprintf(cp_err, "Invalid text was found " + "after dimension data for vector.\n"); + return -1; + } + + *p_n_index = dim_cur; + return 0; + } /* end of case x[ , , ] */ + else { /* x[][][] */ + char *p_end; + int dim_cur = 0; + const int dim_max = MAXDIMS - 1; + while ((p_end = strchr(s, ']')) != (char *) NULL) { + *p_end = '\0'; + if (dim_cur == dim_max) { + (void) fprintf(cp_err, "Too many dimensions given.\n"); + return -1; + } + if (get_index_values(s, p_index + dim_cur) != 0) { + (void) fprintf(cp_err, "Dimension ranges " + "for dimension %d could not be found.\n", + dim_cur + 1); + return -1; + } + ++dim_cur; + s = p_end + 1; /* after (former) ']' */ + if (*(s = skip_ws(s)) == '\0') { /* reached end */ + *p_n_index = dim_cur; + return 0; + } + + /* Not end of expression, so must be '[' */ + if (*s != '[') { + (void) fprintf(cp_err, "Dimension bracket '[' " + "for dimension %d could not be found.\n", + dim_cur + 1); + return -1; + } + s++; /* past '[' */ + } /* end of loop over individual bracketed entries */ + + /* Did not find a single ']' in the string */ + (void) fprintf(cp_err, "The ']' for dimension 1 " + "could not be found.\n"); + return -1; + } /* end of case x[][][][] */ +} /* end of function find_indices */ + + + +/* Convert expresion expr -> low and high ranges equal or + * expression expr1 : epr2 -> low = expr1 and high = expr2. + * Values are tested to ensure they are positive and that the low + * value does not exceed the high value. Since the extent of the index + * is not known, that cannot be checked. */ +static int get_index_values(char *s, index_range_t *p_range) +{ + char *p_colon; + if ((p_colon = strchr(s, ':')) == (char *) NULL) { /* One expression */ + if (get_one_index_value(s, &p_range->low) != 0) { + (void) fprintf(cp_err, "Error geting index.\n"); + return -1; + } + p_range->high = p_range->low; + } + else { /* l:h */ + *p_colon = '\0'; + if (get_one_index_value(s, &p_range->low) != 0) { + (void) fprintf(cp_err, "Error geting low range.\n"); + return -1; + } + s = p_colon + 1; /* past (former) colon */ + if (get_one_index_value(s, &p_range->high) != 0) { + (void) fprintf(cp_err, "Error geting high range.\n"); + return -1; + } + if (p_range->low > p_range->high) { + (void) fprintf(cp_err, "Error low range (%d) is greater " + "than high range (%d).\n", + p_range->low, p_range->high); + return -1; + } + } + return 0; +} /* end of function get_index_values */ + + + +/* Get an index value */ +int get_one_index_value(char *s, int *p_index) +{ + /* Parse the expression */ + struct pnode * const names = ft_getpnames_from_string(s, TRUE); + if (names == (struct pnode *) NULL) { + (void) fprintf(cp_err, "Unable to parse index expression.\n"); + return -1; + } + + /* Evaluate the parsing */ + struct dvec * const t = ft_evaluate(names); + if (t == (struct dvec *) NULL) { + (void) fprintf(cp_err, "Unable to evaluate index expression.\n"); + free_pnode_x(names); + return -1; + } + + int xrc = 0; + if (t->v_link2 || t->v_length != 1 || !t->v_realdata) { + fprintf(cp_err, "Index expression is not a real scalar.\n"); + xrc = -1; + } + else { + const int index = (int) floor(t->v_realdata[0] + 0.5); + if (index < 0) { + printf("Negative index (%d) is not allowed.\n", index); + xrc = -1; + } + else { /* index found ok */ + *p_index = index; + } + } + + /* Free resources */ + if (names->pn_value != (struct dvec *) NULL) { + /* allocated value given to t */ + vec_free_x(t); + } + free_pnode_x(names); + + return xrc; + } /* end of function get_one_index_value */ + + + +/* Copy vector data and its metadata */ +static void copy_vector_data(struct dvec *vec_dst, + const struct dvec *vec_src) +{ + const size_t length = (size_t) vec_src->v_length; + int n_dim = vec_dst->v_numdims = vec_src->v_numdims; + (void) memcpy(vec_dst->v_dims, vec_src->v_dims, + n_dim * sizeof(int)); + if (isreal(vec_src)) { + (void) memcpy(vec_dst->v_realdata, vec_src->v_realdata, + length * sizeof(double)); + } + else { + (void) memcpy(vec_dst->v_compdata, vec_src->v_compdata, + length * sizeof(ngcomplex_t)); + } +} /* end of function copy_vector_data */ + + + +/* Copy vector data and its metadata using stride info */ +static void copy_vector_data_with_stride(struct dvec *vec_dst, + const struct dvec *vec_src, + int n_dim, const index_range_t *p_range) +{ + /* Offsets and related expressions at different levels of indexing + * given in elements + * + * Example + * Dimensions: 4 + * Dimension extents: 10 X 8 X 100 X 5 + * Selected ranges: 2:5 X 3:4 X 20:30 X 3:4 + * Strides: 4000, 500, 5, 1 + * Min offsets: 8000, 1500, 100, 3 -- offset to 1st + * element of range + * Cur cum offsets: 8000, 9500, 9600, 9603 (initial) + * Cur index: 2, 3, 20, X (initial) + * + * Note that the strides are built from the highest dimension, + * which always has stride 1, backwards. + */ + int p_stride_level[MAXDIMS]; + /* Stride changing index by 1 at each level */ + int p_offset_level_min[MAXDIMS]; /* Offset to 1st elem at level */ + + /* Current cumulative offset at each level. A -1 index is created + * to handle the case of a single dimension more uniformly */ + int p_offset_level_cum_full[MAXDIMS + 1]; + int *p_offset_level_cum = p_offset_level_cum_full + 1; + + int p_index_cur[MAXDIMS]; /* Current range value at each level */ + + { + const int index_max = n_dim - 1; + p_stride_level[index_max] = 1; + int *p_dim_ext = vec_dst->v_dims; + int i; + for (i = n_dim - 2; i >= 0; --i) { + const int i1 = i + 1; + p_stride_level[i] = p_stride_level[i1] * p_dim_ext[i1]; + } + } + + /* Initialize the minimum offsets, cumulative current offsets, and + * current index based on ranges and strides */ + { + const int low_cur = p_index_cur[0] = p_range[0].low; + p_offset_level_cum[0] = p_offset_level_min[0] = + low_cur * p_stride_level[0]; + } + + { + int i; + for (i = 1; i < n_dim; ++i) { + const int low_cur = p_index_cur[i] = p_range[i].low; + p_offset_level_cum[i] = p_offset_level_cum[i - 1] + + (p_offset_level_min[i] = low_cur * p_stride_level[i]); + } + } + + /* There are three cases to consider: + * 1) real dst <- real src + * 2) complex dst <- complex src + * 3) complex dst <- real src + * + * The first two can copy blocks at the highest dimesion and the can + * be combined by generalizing to the data size (sizeof(double) or + * sizeof(ngcomplex_t)) and offset of the data array. The third one + * must be assigned element by element with 0's given to the imaginary + * part of the data. + */ + + if (isreal(vec_src) && iscomplex(vec_dst)) { + /* complex dst <- real src */ + int n_elem_topdim; /* # elements copied in top (stride 1) dimension */ + ngcomplex_t *p_vec_data_dst = vec_dst->v_compdata; + /* Location of data in dvec struct */ + double *p_vec_data_src = vec_src->v_realdata; + /* Location of data in dvec struct */ + + { + const int index_max = n_dim - 1; + const index_range_t * const p_range_max = p_range + index_max; + n_elem_topdim = p_range_max->high - p_range_max->low + 1; + } + + /* Copy all data. Each loop iteration copies all of the elements + * at the highest dimension (which are contiguous). On entry to + * the loop, the arrays are initialized so that the first element + * can be copied, and they are updated in each iteration to + * process the next element. Note that if this function is called, + * there will always be at least one element to copy, so it + * is always safe to copy then check for the end of data. */ + { + const int n_cpy = n_dim - 1; /* index where copying done */ + const double *p_vec_data_src_end = p_vec_data_src + + vec_src->v_length; /* end of copying */ + for ( ; ; ) { + /* Copy the data currently being located by the cumulative + * offset and the source location */ + { + ngcomplex_t *p_dst_cur = p_vec_data_dst + + p_offset_level_cum[n_cpy]; + ngcomplex_t *p_dst_end = p_dst_cur + n_elem_topdim; + for ( ; p_dst_cur < p_dst_end; + ++p_dst_cur, ++p_vec_data_src) { + p_dst_cur->cx_real = *p_vec_data_src; + p_dst_cur->cx_imag = 0.0; + } + } + + /* Test for end of source data and exit if reached */ + if (p_vec_data_src == p_vec_data_src_end) { + break; /* Copy is complete */ + } + + /* Move to the next destination location. Since the loop + * was not exited yet, it must exist */ + { + int level_cur = n_cpy; + + /* Move back to the first dimension that is not at its + * last element */ + while (p_index_cur[level_cur] == + p_range[level_cur].high) { + --level_cur; + } + + /* Now at the first dimension level that is not full. + * Increment here and reset the highe ones to their + * minimum values to "count up." */ + ++p_index_cur[level_cur]; + p_offset_level_cum[level_cur] += + p_stride_level[level_cur]; + for (++level_cur; level_cur <= n_cpy; ++level_cur) { + p_index_cur[level_cur] = p_range[level_cur].low; + p_offset_level_cum[level_cur] = + p_offset_level_cum[level_cur - 1] + + p_offset_level_min[level_cur]; + } + } /* end of block updating destination */ + } /* end of loop copying from source to destination */ + } /* end of block */ + } /* end of case both real or complex */ + else { /* Both real or complex (complex src and real dst not allowed) */ + int n_byte_elem; /* Size of element */ + int n_elem_topdim; /* # elements copied in top (stride 1) dimension */ + int n_byte_topdim; /* contiguous bytes */ + void *p_vec_data_dst; /* Location of data in dvec struct */ + void *p_vec_data_src; /* Location of data in dvec struct */ + + { + const int index_max = n_dim - 1; + const index_range_t * const p_range_max = p_range + index_max; + n_elem_topdim = p_range_max->high - p_range_max->low + 1; + } + + if (isreal(vec_src)) { /* Both real */ + n_byte_elem = (int) sizeof(double); + n_byte_topdim = (int) n_elem_topdim * sizeof(double); + p_vec_data_dst = vec_dst->v_realdata; + p_vec_data_src = vec_src->v_realdata; + } + else { + n_byte_elem = (int) sizeof(ngcomplex_t); + n_byte_topdim = (int) n_elem_topdim * sizeof(ngcomplex_t); + p_vec_data_dst = vec_dst->v_compdata; + p_vec_data_src = vec_src->v_compdata; + } + + /* Add the offset of the top dimension to all of the lower ones + * since it will always be added when copying */ + { + int i; + const int n_max = n_dim - 1; + int offset_top = p_range[n_max].low; + p_offset_level_cum[-1] = offset_top; + for (i = 0; i < n_max; ++i) { + p_offset_level_cum[i] += offset_top; + } + } + + /* Because the copies are being done in terms of bytes rather + * than complex data elements or real data elements, convert + * the strides and offsets from elements to bytes */ + { + p_offset_level_cum[-1] *= n_byte_elem; + int i; + const int n_max = n_dim - 1; + for (i = 0; i < n_max; i++) { + p_stride_level[i] *= n_byte_elem; + p_offset_level_min[i] *= n_byte_elem; + p_offset_level_cum[i] *= n_byte_elem; + } + } + + /* Copy all data. Each loop iteration copies all of the elements + * at the highest dimension (which are contiguous). On entry to + * the loop, the arrays are initialized so that the first element + * can be copied, and they are updated in each iteration to + * process the next element. Note that if this function is called, + * there will always be at least one element to copy, so it + * is always safe to copy then check for the end of data. */ + { + const int n_cpy = n_dim - 2; /* index where copying done */ + const void *p_vec_data_src_end = (char *) p_vec_data_src + + (size_t) vec_src->v_length * + n_byte_elem; /* end of copying */ + for ( ; ; ) { + /* Copy the data currently being located by the cumulative + * offset and the source location */ + (void) memcpy( + (char *) p_vec_data_dst + p_offset_level_cum[n_cpy], + p_vec_data_src, + n_byte_topdim); + + /* Move to the next source data and exit the loop if + * the end is reached. + * NOTE: EXITING BEFORE UPDATING THE DESTINATION WILL + * PREVENT OVERRUNNING BUFFERS */ + if ((p_vec_data_src = (char *) p_vec_data_src + + n_byte_topdim) == p_vec_data_src_end) { + break; /* Copy is complete */ + } + + /* Move to the next destination location. Since the loop + * was not exited yet, it must exist */ + { + int level_cur = n_cpy; + + /* Move back to the first dimension that is not at its + * last element */ + while (p_index_cur[level_cur] == + p_range[level_cur].high) { + --level_cur; + } + + /* Now at the first dimension level that is not full. + * Increment here and reset the highe ones to their + * minimum values to "count up." */ + ++p_index_cur[level_cur]; + p_offset_level_cum[level_cur] += + p_stride_level[level_cur]; + for (++level_cur; level_cur <= n_cpy; ++level_cur) { + p_index_cur[level_cur] = p_range[level_cur].low; + p_offset_level_cum[level_cur] = + p_offset_level_cum[level_cur - 1] + + p_offset_level_min[level_cur]; + } + } /* end of block updating destination */ + } /* end of loop copying from source to destination */ + } /* end of block */ + } /* end of case both real or complex */ +} /* end of function copy_vector_data_with_stride */ + + + diff --git a/src/frontend/dvec.c b/src/frontend/dvec.c index 303f2455f..5bc7b5df6 100644 --- a/src/frontend/dvec.c +++ b/src/frontend/dvec.c @@ -2,7 +2,7 @@ #include "ngspice/dvec.h" -struct dvec *dvec_alloc(const char *name, +struct dvec *dvec_alloc(/* NOT const -- assigned to char */ char *name, int type, short flags, int length, void *storage) { struct dvec * const rv = TMALLOC(struct dvec, 1); @@ -26,6 +26,8 @@ struct dvec *dvec_alloc(const char *name, rv->v_flags = flags; rv->v_length = length; rv->v_alloc_length = length; + rv->v_numdims = 1; /* Assume 1 D */ + rv->v_dims[0] = length; if (length == 0) { /* Redundant due to ZERO() call above */ rv->v_realdata = NULL; @@ -51,7 +53,6 @@ struct dvec *dvec_alloc(const char *name, * the ZERO() call */ rv->v_plot = NULL; rv->v_scale = NULL; - rv->v_numdims = 0; /* Really "unknown" */ return rv; } /* end of function dvec_alloc */ diff --git a/src/include/ngspice/dvec.h b/src/include/ngspice/dvec.h index 888e31242..3833295b7 100644 --- a/src/include/ngspice/dvec.h +++ b/src/include/ngspice/dvec.h @@ -75,7 +75,7 @@ struct dveclist { bool f_own_vector; }; -struct dvec *dvec_alloc(const char *name, +struct dvec *dvec_alloc(/* NOT CONST -- assigned to const */ char *name, int type, short flags, int length, void *storage); void dvec_realloc(struct dvec *v, int length, void *storage); void dvec_extend(struct dvec *v, int length); From 344fa243bd7291fbbdc6c298de9d94a41c593a7c Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Mon, 23 Dec 2019 22:40:56 -0500 Subject: [PATCH 09/36] File path built more efficiently and now allows an arbitrary length. Prevented strdup() of NULL if path too long. Similarly prevented fopen with a NULL file name. Added function to determine Windows absolute paths properly. Fixed numerous issues that were caused by including Windows system header due to conflicting names. Generally a CMPP_ prefix was added as a "namespace". Also used the standard C bool type instead of defining one. --- src/xspice/cmpp/Makefile.am | 8 ++ src/xspice/cmpp/cmpp.h | 76 +++++------- src/xspice/cmpp/ifs_yacc.y | 144 +++++++++++------------ src/xspice/cmpp/ifs_yacc_y.h | 8 +- src/xspice/cmpp/mod_yacc.y | 65 ++++++----- src/xspice/cmpp/mod_yacc_y.h | 3 +- src/xspice/cmpp/pp_ifs.c | 6 +- src/xspice/cmpp/pp_lst.c | 220 ++++++++++++++++------------------- src/xspice/cmpp/pp_mod.c | 4 +- src/xspice/cmpp/read_ifs.c | 18 +-- src/xspice/cmpp/util.c | 84 ++++++++++--- src/xspice/cmpp/writ_ifs.c | 143 +++++++++++------------ 12 files changed, 397 insertions(+), 382 deletions(-) diff --git a/src/xspice/cmpp/Makefile.am b/src/xspice/cmpp/Makefile.am index e38bfe107..c5fce8cc3 100644 --- a/src/xspice/cmpp/Makefile.am +++ b/src/xspice/cmpp/Makefile.am @@ -16,6 +16,14 @@ cmpp_SOURCES = main.c cmpp.h \ ifs_lex.l ifs_yacc.y ifs_yacc_y.h \ mod_lex.l mod_yacc.y mod_yacc_y.h +if WINGUI +cmpp_LDADD = -lShlwapi +endif + +if WINCONSOLE +cmpp_LDADD = -lShlwapi +endif + mod_lex.c : mod_lex.l $(am__skiplex) $(LEXCOMPILE) -o $@ $< diff --git a/src/xspice/cmpp/cmpp.h b/src/xspice/cmpp/cmpp.h index 5d3865a86..e719fa850 100644 --- a/src/xspice/cmpp/cmpp.h +++ b/src/xspice/cmpp/cmpp.h @@ -38,6 +38,7 @@ NON-STANDARD FEATURES ============================================================================*/ +#include #include #define IFSPEC_FILENAME "ifspec.ifs" @@ -47,6 +48,7 @@ NON-STANDARD FEATURES #ifdef _MSC_VER #include +#include #define strdup _strdup #define unlink _unlink #define isatty _isatty @@ -55,15 +57,6 @@ NON-STANDARD FEATURES /* *********************************************************************** */ -typedef enum { - - OK, /* Returned with no error */ - ERROR, /* Returned with error */ - -} Status_t; - - - #define GET_IFS_TABLE 0 /* Read the entire ifs table */ #define GET_IFS_NAME 1 /* Get the C function name out of the table only */ @@ -76,24 +69,14 @@ typedef enum { /* Structures used by parser to check for valid connections/parameters */ /* ******************************************************************** */ -/* - * The boolean type - */ - -typedef enum { - FALSE, - TRUE, -} Boolean_t; - - /* * The direction of a connector */ typedef enum { - IN, - OUT, - INOUT, + CMPP_IN, + CMPP_OUT, + CMPP_INOUT, } Dir_t; @@ -122,14 +105,13 @@ typedef enum { */ typedef enum { - BOOLEAN, - INTEGER, - REAL, - COMPLEX, - STRING, - POINTER, /* NOTE: POINTER should not be used for Parameters - only - * Static_Vars - this is enforced by the cmpp. - */ + CMPP_BOOLEAN, + CMPP_INTEGER, + CMPP_REAL, + CMPP_COMPLEX, + CMPP_STRING, + CMPP_POINTER, /* NOTE: CMPP_POINTER should not be used for Parameters - + * only Static_Vars - this is enforced by the cmpp. */ } Data_Type_t; @@ -157,7 +139,7 @@ typedef struct { typedef struct { - Boolean_t bvalue; /* For BOOLEAN parameters */ + bool bvalue; /* For BOOLEAN parameters */ int ivalue; /* For INTEGER parameters */ double rvalue; /* For REAL parameters */ Complex_t cvalue; /* For COMPLEX parameters */ @@ -198,14 +180,14 @@ typedef struct { int num_allowed_types; /* The size of the allowed type arrays */ Port_Type_t *allowed_port_type; /* Array of allowed types */ char **allowed_type; /* Array of allowed types in string form */ - Boolean_t is_array; /* True if connection is an array */ - Boolean_t has_conn_ref; /* True if there is associated with an array conn */ + bool is_array; /* True if connection is an array */ + bool has_conn_ref; /* True if there is associated with an array conn */ int conn_ref; /* Subscript of the associated array conn */ - Boolean_t has_lower_bound; /* True if there is an array size lower bound */ + bool has_lower_bound; /* True if there is an array size lower bound */ int lower_bound; /* Array size lower bound */ - Boolean_t has_upper_bound; /* True if there is an array size upper bound */ + bool has_upper_bound; /* True if there is an array size upper bound */ int upper_bound; /* Array size upper bound */ - Boolean_t null_allowed; /* True if null is allowed for this connection */ + bool null_allowed; /* True if null is allowed for this connection */ } Conn_Info_t; @@ -221,20 +203,20 @@ typedef struct { char *name; /* Name of this parameter */ char *description; /* Description of this parameter */ Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */ - Boolean_t has_default; /* True if there is a default value */ + bool has_default; /* True if there is a default value */ Value_t default_value; /* The default value */ - Boolean_t has_lower_limit; /* True if there is a lower limit */ + bool has_lower_limit; /* True if there is a lower limit */ Value_t lower_limit; /* The lower limit for this parameter */ - Boolean_t has_upper_limit; /* True if there is a upper limit */ + bool has_upper_limit; /* True if there is a upper limit */ Value_t upper_limit; /* The upper limit for this parameter */ - Boolean_t is_array; /* True if parameter is an array */ - Boolean_t has_conn_ref; /* True if there is associated with an array conn */ + bool is_array; /* True if parameter is an array */ + bool has_conn_ref; /* True if there is associated with an array conn */ int conn_ref; /* Subscript of the associated array conn */ - Boolean_t has_lower_bound; /* True if there is an array size lower bound */ + bool has_lower_bound; /* True if there is an array size lower bound */ int lower_bound; /* Array size lower bound */ - Boolean_t has_upper_bound; /* True if there is an array size upper bound */ + bool has_upper_bound; /* True if there is an array size upper bound */ int upper_bound; /* Array size upper bound */ - Boolean_t null_allowed; /* True if null is allowed for this parameter */ + bool null_allowed; /* True if null is allowed for this parameter */ } Param_Info_t; @@ -248,7 +230,7 @@ typedef struct { char *name; /* Name of this parameter */ char *description; /* Description of this parameter */ Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */ - Boolean_t is_array; /* True if parameter is an array */ + bool is_array; /* True if parameter is an array */ } Inst_Var_Info_t; @@ -294,9 +276,9 @@ void print_error(const char *fmt, ...); void str_to_lower(char *s); -Status_t read_ifs_file(const char *filename, int mode, Ifs_Table_t *ifs_table); +int read_ifs_file(const char *filename, int mode, Ifs_Table_t *ifs_table); -Status_t write_ifs_c_file(const char *filename, Ifs_Table_t *ifs_table); +int write_ifs_c_file(const char *filename, Ifs_Table_t *ifs_table); FILE *fopen_cmpp(const char **path_p, const char *mode); diff --git a/src/xspice/cmpp/ifs_yacc.y b/src/xspice/cmpp/ifs_yacc.y index 57320932f..3f9688ca1 100644 --- a/src/xspice/cmpp/ifs_yacc.y +++ b/src/xspice/cmpp/ifs_yacc.y @@ -94,21 +94,21 @@ extern double yydval; extern char *ifs_yytext; extern int ifs_yylex(void); -Boolean_t parser_just_names; -static Boolean_t saw_model_name; -static Boolean_t saw_function_name; +bool parser_just_names; +static bool saw_model_name; +static bool saw_function_name; static char *dtype_to_str[] = { "BOOLEAN", "INTEGER", "REAL", "COMPLEX", "STRING", "POINTER" }; -static Boolean_t did_default_type; -static Boolean_t did_allowed_types; +static bool did_default_type; +static bool did_allowed_types; static int num_items; static int item; static int item_offset; -static Boolean_t num_items_fixed; +static bool num_items_fixed; Ifs_Table_t *parser_ifs_table; #define TBL parser_ifs_table @@ -149,21 +149,21 @@ Context_t context; #define ASSIGN_BOUNDS(struct_name, i) \ if (ITEM_BUF(i).range.is_named) {\ - TBL->struct_name[i].has_conn_ref = TRUE;\ + TBL->struct_name[i].has_conn_ref = true;\ TBL->struct_name[i].conn_ref = find_conn_ref (ITEM_BUF(i).range.u.name);\ } else {\ - TBL->struct_name[i].has_conn_ref = FALSE;\ + TBL->struct_name[i].has_conn_ref = false;\ TBL->struct_name[i].has_lower_bound =\ ITEM_BUF(i).range.u.bounds.lower.has_bound;\ TBL->struct_name[i].has_upper_bound =\ ITEM_BUF(i).range.u.bounds.upper.has_bound;\ if (TBL->struct_name[i].has_lower_bound) {\ - assert (ITEM_BUF(i).range.u.bounds.lower.bound.kind == INTEGER);\ + assert (ITEM_BUF(i).range.u.bounds.lower.bound.kind == CMPP_INTEGER);\ TBL->struct_name[i].lower_bound =\ ITEM_BUF(i).range.u.bounds.lower.bound.u.ivalue;\ }\ if (TBL->struct_name[i].has_upper_bound) {\ - assert (ITEM_BUF(i).range.u.bounds.upper.bound.kind == INTEGER);\ + assert (ITEM_BUF(i).range.u.bounds.upper.bound.kind == CMPP_INTEGER);\ TBL->struct_name[i].upper_bound =\ ITEM_BUF(i).range.u.bounds.upper.bound.u.ivalue;\ }\ @@ -228,7 +228,7 @@ static void check_port_type_direction (Dir_t dir, Port_Type_t port_type) */ break; case VSOURCE_CURRENT: - if (dir != IN) { + if (dir != CMPP_IN) { yyerror ("Port type `vnam' is only valid for `in' ports"); ifs_num_errors++; } @@ -237,7 +237,7 @@ static void check_port_type_direction (Dir_t dir, Port_Type_t port_type) case DIFF_CONDUCTANCE: case RESISTANCE: case DIFF_RESISTANCE: - if (dir != INOUT) { + if (dir != CMPP_INOUT) { yyerror ("Port types `g', `gd', `h', `hd' are only valid for `inout' ports"); ifs_num_errors++; } @@ -250,7 +250,7 @@ static void check_port_type_direction (Dir_t dir, Port_Type_t port_type) /*---------------------------------------------------------------------------*/ static void check_dtype_not_pointer (Data_Type_t dtype) { - if (dtype == POINTER) { + if (dtype == CMPP_POINTER) { yyerror("Invalid parameter type - POINTER type valid only for STATIC_VARs"); ifs_num_errors++; } @@ -312,7 +312,7 @@ static void assign_value (Data_Type_t type, Value_t *dest_value, My_Value_t src_value) { char str[200]; - if ((type == REAL) && (src_value.kind == INTEGER)) { + if ((type == CMPP_REAL) && (src_value.kind == CMPP_INTEGER)) { dest_value->rvalue = src_value.u.ivalue; return; } else if (type != src_value.kind) { @@ -323,19 +323,19 @@ assign_value (Data_Type_t type, Value_t *dest_value, My_Value_t src_value) ifs_num_errors++; } switch (type) { - case BOOLEAN: + case CMPP_BOOLEAN: dest_value->bvalue = src_value.u.bvalue; break; - case INTEGER: + case CMPP_INTEGER: dest_value->ivalue = src_value.u.ivalue; break; - case REAL: + case CMPP_REAL: dest_value->rvalue = src_value.u.rvalue; break; - case COMPLEX: + case CMPP_COMPLEX: dest_value->cvalue = src_value.u.cvalue; break; - case STRING: + case CMPP_STRING: dest_value->svalue = src_value.u.svalue; break; default: @@ -421,7 +421,7 @@ check_end_item_num (void) } } else { num_items = item; - num_items_fixed = TRUE; + num_items_fixed = true; switch (context.table) { case TBL_NAME: break; @@ -439,7 +439,7 @@ check_end_item_num (void) item = item_offset; } -#define INIT(n) item = (n); item_offset = (n); num_items = (n); num_items_fixed = FALSE +#define INIT(n) item = (n); item_offset = (n); num_items = (n); num_items_fixed = false #define ITEM check_item_num() #define END check_end_item_num() @@ -499,7 +499,7 @@ check_end_item_num (void) %union { Ctype_List_t *ctype_list; Dir_t dir; - Boolean_t bool; + bool btype; Range_t range; Data_Type_t dtype; My_Port_Type_t ctype; @@ -518,7 +518,7 @@ check_end_item_num (void) %type range int_range %type value number integer_value value_or_dash %type identifier string -%type bool +%type btype %type int_or_dash number_or_dash %type integer %type real @@ -545,8 +545,8 @@ ifs_file : {TBL->num_conn = 0; TBL->num_param = 0; TBL->num_inst_var = 0; - saw_function_name = FALSE; - saw_model_name = FALSE; + saw_function_name = false; + saw_model_name = false; alloced_size [TBL_PORT] = DEFAULT_SIZE_CONN; alloced_size [TBL_PARAMETER] = DEFAULT_SIZE_PARAM; @@ -579,8 +579,8 @@ table : TOK_NAME_TABLE name_table | TOK_PORT_TABLE {context.table = TBL_PORT; - did_default_type = FALSE; - did_allowed_types = FALSE; + did_default_type = false; + did_allowed_types = false; INIT (TBL->num_conn);} port_table {TBL->num_conn = num_items;} @@ -602,11 +602,11 @@ name_table : /* empty */ name_table_item : TOK_C_FUNCTION_NAME identifier {TBL->name.c_fcn_name =strdup (ifs_yytext); - saw_function_name = TRUE; + saw_function_name = true; if (parser_just_names && saw_model_name) return 0;} | TOK_SPICE_MODEL_NAME identifier {TBL->name.model_name = strdup (ifs_yytext); - saw_model_name = TRUE; + saw_model_name = true; if (parser_just_names && saw_function_name) return 0;} | TOK_DESCRIPTION string {TBL->name.description = strdup (ifs_yytext);} @@ -637,7 +637,7 @@ port_table_item : TOK_PORT_NAME list_of_ids | TOK_DEFAULT_TYPE list_of_ctypes {int i; END; - did_default_type = TRUE; + did_default_type = true; FOR_ITEM (i) { TBL->conn[i].default_port_type = ITEM_BUF(i).ctype.kind; @@ -649,7 +649,7 @@ port_table_item : TOK_PORT_NAME list_of_ids | TOK_ALLOWED_TYPES list_of_ctype_lists {int i; END; - did_allowed_types = TRUE; + did_allowed_types = true; FOR_ITEM (i) { assign_ctype_list (&TBL->conn[i], ITEM_BUF(i).ctype_list); @@ -661,7 +661,7 @@ port_table_item : TOK_PORT_NAME list_of_ids {int i; END; FOR_ITEM (i) { - TBL->conn[i].is_array = ITEM_BUF(i).bool; + TBL->conn[i].is_array = ITEM_BUF(i).btype; }} | TOK_ARRAY_BOUNDS list_of_array_bounds {int i; @@ -674,7 +674,7 @@ port_table_item : TOK_PORT_NAME list_of_ids {int i; END; FOR_ITEM (i) { - TBL->conn[i].null_allowed = ITEM_BUF(i).bool; + TBL->conn[i].null_allowed = ITEM_BUF(i).btype; }} ; @@ -725,7 +725,7 @@ parameter_table_item : TOK_PARAMETER_NAME list_of_ids {int i; END; FOR_ITEM (i) { - TBL->param[i].is_array = ITEM_BUF(i).bool; + TBL->param[i].is_array = ITEM_BUF(i).btype; }} | TOK_ARRAY_BOUNDS list_of_array_bounds {int i; @@ -737,7 +737,7 @@ parameter_table_item : TOK_PARAMETER_NAME list_of_ids {int i; END; FOR_ITEM (i) { - TBL->param[i].null_allowed = ITEM_BUF(i).bool; + TBL->param[i].null_allowed = ITEM_BUF(i).btype; }} ; @@ -767,7 +767,7 @@ static_var_table_item : TOK_STATIC_VAR_NAME list_of_ids {int i; END; FOR_ITEM (i) { - TBL->inst_var[i].is_array = ITEM_BUF(i).bool; + TBL->inst_var[i].is_array = ITEM_BUF(i).btype; }} ; @@ -781,7 +781,7 @@ list_of_array_bounds : /* empty */ BUF.range = $2;} | list_of_array_bounds identifier {ITEM; - BUF.range.is_named = TRUE; + BUF.range.is_named = true; BUF.range.u.name = $2;} ; @@ -793,13 +793,13 @@ list_of_directions : /* empty */ | list_of_directions direction {ITEM; BUF.dir = $2;} ; -direction : TOK_DIR_IN {$$ = IN;} - | TOK_DIR_OUT {$$ = OUT;} - | TOK_DIR_INOUT {$$ = INOUT;} +direction : TOK_DIR_IN {$$ = CMPP_IN;} + | TOK_DIR_OUT {$$ = CMPP_OUT;} + | TOK_DIR_INOUT {$$ = CMPP_INOUT;} ; list_of_bool : /* empty */ - | list_of_bool bool {ITEM; BUF.bool = $2;} + | list_of_bool btype {ITEM; BUF.btype = $2;} ; list_of_ctypes : /* empty */ @@ -824,24 +824,24 @@ list_of_dtypes : /* empty */ | list_of_dtypes dtype {ITEM; BUF.dtype = $2;} ; -dtype : TOK_DTYPE_REAL {$$ = REAL;} - | TOK_DTYPE_INT {$$ = INTEGER;} - | TOK_DTYPE_BOOLEAN {$$ = BOOLEAN;} - | TOK_DTYPE_COMPLEX {$$ = COMPLEX;} - | TOK_DTYPE_STRING {$$ = STRING;} - | TOK_DTYPE_POINTER {$$ = POINTER;} +dtype : TOK_DTYPE_REAL {$$ = CMPP_REAL;} + | TOK_DTYPE_INT {$$ = CMPP_INTEGER;} + | TOK_DTYPE_BOOLEAN {$$ = CMPP_BOOLEAN;} + | TOK_DTYPE_COMPLEX {$$ = CMPP_COMPLEX;} + | TOK_DTYPE_STRING {$$ = CMPP_STRING;} + | TOK_DTYPE_POINTER {$$ = CMPP_POINTER;} ; list_of_ranges : /* empty */ | list_of_ranges range {ITEM; BUF.range = $2;} ; -int_range : TOK_DASH {$$.is_named = FALSE; - $$.u.bounds.lower.has_bound = FALSE; - $$.u.bounds.upper.has_bound = FALSE;} +int_range : TOK_DASH {$$.is_named = false; + $$.u.bounds.lower.has_bound = false; + $$.u.bounds.upper.has_bound = false;} | TOK_LBRACKET int_or_dash maybe_comma int_or_dash TOK_RBRACKET - {$$.is_named = FALSE; + {$$.is_named = false; $$.u.bounds.lower = $2; $$.u.bounds.upper = $4;} ; @@ -850,23 +850,23 @@ maybe_comma : /* empty */ | TOK_COMMA ; -int_or_dash : TOK_DASH {$$.has_bound = FALSE;} - | integer_value {$$.has_bound = TRUE; +int_or_dash : TOK_DASH {$$.has_bound = false;} + | integer_value {$$.has_bound = true; $$.bound = $1;} ; -range : TOK_DASH {$$.is_named = FALSE; - $$.u.bounds.lower.has_bound = FALSE; - $$.u.bounds.upper.has_bound = FALSE;} +range : TOK_DASH {$$.is_named = false; + $$.u.bounds.lower.has_bound = false; + $$.u.bounds.upper.has_bound = false;} | TOK_LBRACKET number_or_dash maybe_comma number_or_dash TOK_RBRACKET - {$$.is_named = FALSE; + {$$.is_named = false; $$.u.bounds.lower = $2; $$.u.bounds.upper = $4;} ; -number_or_dash : TOK_DASH {$$.has_bound = FALSE;} - | number {$$.has_bound = TRUE; +number_or_dash : TOK_DASH {$$.has_bound = false;} + | number {$$.has_bound = true; $$.bound = $1;} ; @@ -874,18 +874,18 @@ list_of_values : /* empty */ | list_of_values value_or_dash {ITEM; BUF.value = $2;} ; -value_or_dash : TOK_DASH {$$.has_value = FALSE;} +value_or_dash : TOK_DASH {$$.has_value = false;} | value ; -value : string {$$.has_value = TRUE; - $$.kind = STRING; +value : string {$$.has_value = true; + $$.kind = CMPP_STRING; $$.u.svalue = $1;} - | bool {$$.has_value = TRUE; - $$.kind = BOOLEAN; + | btype {$$.has_value = true; + $$.kind = CMPP_BOOLEAN; $$.u.bvalue = $1;} - | complex {$$.has_value = TRUE; - $$.kind = COMPLEX; + | complex {$$.has_value = true; + $$.kind = CMPP_COMPLEX; $$.u.cvalue = $1;} | number ; @@ -924,8 +924,8 @@ ctype_list : ctype $1->next = $$;*/} ; -bool : TOK_BOOL_YES {$$ = TRUE;} - | TOK_BOOL_NO {$$ = FALSE;} +btype : TOK_BOOL_YES {$$ = true;} + | TOK_BOOL_NO {$$ = false;} ; string : TOK_STRING_LITERAL {$$ = strdup(ifs_yytext);} @@ -934,14 +934,14 @@ string : TOK_STRING_LITERAL {$$ = strdup(ifs_yytext);} identifier : TOK_IDENTIFIER {$$ = strdup(ifs_yytext);} ; -number : real {$$.has_value = TRUE; - $$.kind = REAL; +number : real {$$.has_value = true; + $$.kind = CMPP_REAL; $$.u.rvalue = $1;} | integer_value ; -integer_value : integer {$$.has_value = TRUE; - $$.kind = INTEGER; +integer_value : integer {$$.has_value = true; + $$.kind = CMPP_INTEGER; $$.u.ivalue = $1;} ; diff --git a/src/xspice/cmpp/ifs_yacc_y.h b/src/xspice/cmpp/ifs_yacc_y.h index b9a7a4c9e..208d101f7 100644 --- a/src/xspice/cmpp/ifs_yacc_y.h +++ b/src/xspice/cmpp/ifs_yacc_y.h @@ -41,10 +41,10 @@ NON-STANDARD FEATURES #include "cmpp.h" typedef struct { - Boolean_t has_value; + bool has_value; Data_Type_t kind; union { - Boolean_t bvalue; + bool bvalue; int ivalue; double rvalue; Complex_t cvalue; @@ -53,12 +53,12 @@ typedef struct { } My_Value_t; typedef struct { - Boolean_t has_bound; + bool has_bound; My_Value_t bound; } Bound_t; typedef struct { - Boolean_t is_named; + bool is_named; union { char *name; struct { diff --git a/src/xspice/cmpp/mod_yacc.y b/src/xspice/cmpp/mod_yacc.y index 8dcf8f5b0..4d3e00aa3 100644 --- a/src/xspice/cmpp/mod_yacc.y +++ b/src/xspice/cmpp/mod_yacc.y @@ -49,6 +49,7 @@ NON-STANDARD FEATURES #include +#include #include #include #include "mod_yacc_y.h" @@ -147,22 +148,22 @@ static void put_type (FILE *fp, Data_Type_t type) char ch = ' '; switch (type) { - case INTEGER: + case CMPP_INTEGER: ch = 'i'; break; - case REAL: + case CMPP_REAL: ch = 'r'; break; - case COMPLEX: + case CMPP_COMPLEX: ch = 'c'; break; - case BOOLEAN: + case CMPP_BOOLEAN: ch = 'b'; break; - case STRING: + case CMPP_STRING: ch = 's'; break; - case POINTER: + case CMPP_POINTER: ch = 'p'; break; } @@ -199,13 +200,13 @@ static void check_dir (int conn_number, Dir_t dir, char *context) * an error. */ conn_dir = mod_ifs_table->conn[conn_number].direction; - if ((conn_dir != dir) && (conn_dir != INOUT)) { + if ((conn_dir != dir) && (conn_dir != CMPP_INOUT)) { char error_str[200]; sprintf (error_str, "Direction of port `%s' in %s() is not %s or INOUT", mod_ifs_table->conn[conn_number].name, context, - (dir == IN) ? "IN" : "OUT"); + (dir == CMPP_IN) ? "IN" : "OUT"); yyerror (error_str); mod_num_errors++; } @@ -213,8 +214,8 @@ static void check_dir (int conn_number, Dir_t dir, char *context) } /*---------------------------------------------------------------------------*/ -static void check_subscript (Boolean_t formal, Boolean_t actual, - Boolean_t missing_actual_ok, +static void check_subscript (bool formal, bool actual, + bool missing_actual_ok, char *context, char *id) { char error_str[200]; @@ -237,7 +238,7 @@ static void check_subscript (Boolean_t formal, Boolean_t actual, } /*---------------------------------------------------------------------------*/ -static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, Boolean_t do_subscript) +static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, bool do_subscript) { int i; char error_str[200]; @@ -248,7 +249,7 @@ static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, Boolean_t do_subscript) if (0 == local_strcmpi (sub_id.id, mod_ifs_table->conn[i].name)) { if (do_subscript) { check_subscript (mod_ifs_table->conn[i].is_array, - sub_id.has_subscript, FALSE, "Port", + sub_id.has_subscript, false, "Port", sub_id.id); } return i; @@ -260,7 +261,7 @@ static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, Boolean_t do_subscript) if (0 == local_strcmpi (sub_id.id, mod_ifs_table->param[i].name)) { if (do_subscript) { check_subscript (mod_ifs_table->param[i].is_array, - sub_id.has_subscript, FALSE, "Parameter", + sub_id.has_subscript, false, "Parameter", sub_id.id); } return i; @@ -272,7 +273,7 @@ static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, Boolean_t do_subscript) if (0 == local_strcmpi (sub_id.id, mod_ifs_table->inst_var[i].name)) { if (do_subscript) { check_subscript (mod_ifs_table->inst_var[i].is_array, - sub_id.has_subscript, TRUE, + sub_id.has_subscript, true, "Static Variable", sub_id.id); } @@ -297,13 +298,13 @@ static int check_id (Sub_Id_t sub_id, Id_Kind_t kind, Boolean_t do_subscript) /*---------------------------------------------------------------------------*/ static int valid_id (Sub_Id_t sub_id, Id_Kind_t kind) { - return check_id (sub_id, kind, FALSE); + return check_id (sub_id, kind, false); } /*---------------------------------------------------------------------------*/ static int valid_subid (Sub_Id_t sub_id, Id_Kind_t kind) { - return check_id (sub_id, kind, TRUE); + return check_id (sub_id, kind, true); } /*---------------------------------------------------------------------------*/ @@ -467,16 +468,16 @@ macro : TOK_INIT subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); int j = valid_subid ($5, CONN); - check_dir (i, OUT, "PARTIAL"); - check_dir (j, IN, "PARTIAL"); + check_dir (i, CMPP_OUT, "PARTIAL"); + check_dir (j, CMPP_IN, "PARTIAL"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->partial[%d].port[%s]", i, subscript($3), j, subscript($5));} | TOK_AC_GAIN TOK_LPAREN subscriptable_id TOK_COMMA subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); int j = valid_subid ($5, CONN); - check_dir (i, OUT, "AC_GAIN"); - check_dir (j, IN, "AC_GAIN"); + check_dir (i, CMPP_OUT, "AC_GAIN"); + check_dir (j, CMPP_IN, "AC_GAIN"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->ac_gain[%d].port[%s]", i, subscript($3), j, subscript($5));} @@ -502,19 +503,19 @@ macro : TOK_INIT i);} | TOK_OUTPUT_DELAY TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, OUT, "OUTPUT_DELAY"); + check_dir (i, CMPP_OUT, "OUTPUT_DELAY"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->delay", i, subscript($3));} | TOK_CHANGED TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, OUT, "CHANGED"); + check_dir (i, CMPP_OUT, "CHANGED"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->changed", i, subscript($3));} | TOK_INPUT TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, IN, "INPUT"); + check_dir (i, CMPP_IN, "INPUT"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->input", i, subscript($3)); @@ -522,19 +523,19 @@ macro : TOK_INIT mod_ifs_table->conn[i].allowed_port_type[0]);} | TOK_INPUT_TYPE TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, IN, "INPUT_TYPE"); + check_dir (i, CMPP_IN, "INPUT_TYPE"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->type_str", i, subscript($3)); } | TOK_OUTPUT_TYPE TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, OUT, "OUTPUT_TYPE"); + check_dir (i, CMPP_OUT, "OUTPUT_TYPE"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->type_str", i, subscript($3)); } | TOK_INPUT_STRENGTH TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, IN, "INPUT_STRENGTH"); + check_dir (i, CMPP_IN, "INPUT_STRENGTH"); fprintf (mod_yyout, "((Digital_t*)(mif_private->conn[%d]->port[%s]->input", i, subscript($3)); @@ -543,7 +544,7 @@ macro : TOK_INIT fprintf (mod_yyout, "))->strength");} | TOK_INPUT_STATE TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, IN, "INPUT_STATE"); + check_dir (i, CMPP_IN, "INPUT_STATE"); fprintf (mod_yyout, "((Digital_t*)(mif_private->conn[%d]->port[%s]->input", i, subscript($3)); @@ -552,7 +553,7 @@ macro : TOK_INIT fprintf (mod_yyout, "))->state");} | TOK_OUTPUT TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, OUT, "OUTPUT"); + check_dir (i, CMPP_OUT, "OUTPUT"); fprintf (mod_yyout, "mif_private->conn[%d]->port[%s]->output", i, subscript($3)); @@ -560,7 +561,7 @@ macro : TOK_INIT mod_ifs_table->conn[i].allowed_port_type[0]);} | TOK_OUTPUT_STRENGTH TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, OUT, "OUTPUT_STRENGTH"); + check_dir (i, CMPP_OUT, "OUTPUT_STRENGTH"); fprintf (mod_yyout, "((Digital_t*)(mif_private->conn[%d]->port[%s]->output", i, subscript($3)); @@ -569,7 +570,7 @@ macro : TOK_INIT fprintf (mod_yyout, "))->strength");} | TOK_OUTPUT_STATE TOK_LPAREN subscriptable_id TOK_RPAREN {int i = valid_subid ($3, CONN); - check_dir (i, OUT, "OUTPUT_STATE"); + check_dir (i, CMPP_OUT, "OUTPUT_STATE"); fprintf (mod_yyout, "((Digital_t*)(mif_private->conn[%d]->port[%s]->output", i, subscript($3)); @@ -601,12 +602,12 @@ macro : TOK_INIT subscriptable_id : id | id TOK_LBRACKET buffered_c_code TOK_RBRACKET {$$ = $1; - $$.has_subscript = TRUE; + $$.has_subscript = true; $$.subscript = $3;} ; id : TOK_IDENTIFIER - {$$.has_subscript = FALSE; + {$$.has_subscript = false; $$.id = strdup (mod_yytext);} ; diff --git a/src/xspice/cmpp/mod_yacc_y.h b/src/xspice/cmpp/mod_yacc_y.h index 1138d6289..2e818c322 100644 --- a/src/xspice/cmpp/mod_yacc_y.h +++ b/src/xspice/cmpp/mod_yacc_y.h @@ -37,12 +37,13 @@ NON-STANDARD FEATURES None. ============================================================================*/ +#include #include "cmpp.h" typedef struct { char *id; - Boolean_t has_subscript; + bool has_subscript; char *subscript; } Sub_Id_t; diff --git a/src/xspice/cmpp/pp_ifs.c b/src/xspice/cmpp/pp_ifs.c index f0830b51a..ce840b0c4 100644 --- a/src/xspice/cmpp/pp_ifs.c +++ b/src/xspice/cmpp/pp_ifs.c @@ -68,13 +68,13 @@ void preprocess_ifs_file(void) Ifs_Table_t ifs_table; /* Repository for info read from ifspec.ifs file */ - Status_t status; /* Return status */ + int status; /* Return status */ /* Read the entire ifspec.ifs file and load the data into ifs_table */ status = read_ifs_file(IFSPEC_FILENAME,GET_IFS_TABLE,&ifs_table); - if(status != OK) { + if(status != 0) { exit(1); } @@ -83,7 +83,7 @@ void preprocess_ifs_file(void) status = write_ifs_c_file("ifspec.c",&ifs_table); - if(status != OK) { + if(status != 0) { exit(1); } rem_ifs_table(&ifs_table); diff --git a/src/xspice/cmpp/pp_lst.c b/src/xspice/cmpp/pp_lst.c index 5c3b3b02f..01a624a3a 100644 --- a/src/xspice/cmpp/pp_lst.c +++ b/src/xspice/cmpp/pp_lst.c @@ -63,15 +63,15 @@ typedef struct { char *path_name; /* Pathname read from model path file */ char *spice_name; /* Name of model from ifspec.ifs */ char *cfunc_name; /* Name of C fcn from ifspec.ifs */ - Boolean_t spice_unique; /* True if spice name unique */ - Boolean_t cfunc_unique; /* True if C fcn name unique */ + bool spice_unique; /* True if spice name unique */ + bool cfunc_unique; /* True if C fcn name unique */ } Model_Info_t; typedef struct { char *path_name; /* Pathname read from udn path file */ char *node_name; /* Name of node type */ - Boolean_t unique; /* True if node type name unique */ + bool unique; /* True if node type name unique */ } Node_Info_t; @@ -79,19 +79,19 @@ typedef struct { /* *********************************************************************** */ -static Status_t read_modpath(int *num_models, Model_Info_t **model_info); -static Status_t read_udnpath(int *num_nodes, Node_Info_t **node_info); -static Status_t read_model_names(int num_models, Model_Info_t *model_info); -static Status_t read_node_names(int num_nodes, Node_Info_t *node_info); -static Status_t check_uniqueness(int num_models, Model_Info_t *model_info, +static int read_modpath(int *num_models, Model_Info_t **model_info); +static int read_udnpath(int *num_nodes, Node_Info_t **node_info); +static int read_model_names(int num_models, Model_Info_t *model_info); +static int read_node_names(int num_nodes, Node_Info_t *node_info); +static int check_uniqueness(int num_models, Model_Info_t *model_info, int num_nodes, Node_Info_t *node_info); -static Status_t write_CMextrn(int num_models, Model_Info_t *model_info); -static Status_t write_CMinfo(int num_models, Model_Info_t *model_info); -static Status_t write_UDNextrn(int num_nodes, Node_Info_t *node_info); -static Status_t write_UDNinfo(int num_nodes, Node_Info_t *node_info); -static Status_t write_objects_inc(int num_models, Model_Info_t *model_info, +static int write_CMextrn(int num_models, Model_Info_t *model_info); +static int write_CMinfo(int num_models, Model_Info_t *model_info); +static int write_UDNextrn(int num_nodes, Node_Info_t *node_info); +static int write_UDNinfo(int num_nodes, Node_Info_t *node_info); +static int write_objects_inc(int num_models, Model_Info_t *model_info, int num_nodes, Node_Info_t *node_info); -static Status_t read_udn_type_name(const char *path, char **node_name); +static int read_udn_type_name(const char *path, char **node_name); /* *********************************************************************** */ @@ -119,7 +119,7 @@ into the simulator. void preprocess_lst_files(void) { - Status_t status; /* Return status */ + int status; /* Return status */ Model_Info_t *model_info; /* Info about each model */ Node_Info_t *node_info; /* Info about each user-defined node type */ int num_models; /* The number of models */ @@ -128,26 +128,26 @@ void preprocess_lst_files(void) /* Get list of models from model pathname file */ status = read_modpath(&num_models, &model_info); - if(status != OK) { + if(status != 0) { exit(1); } /* Get list of node types from udn pathname file */ status = read_udnpath(&num_nodes, &node_info); - if(status != OK) { + if(status != 0) { exit(1); } /* Get the spice and C function names from the ifspec.ifs files */ status = read_model_names(num_models, model_info); - if(status != OK) { + if(status != 0) { exit(1); } /* Get the user-defined node type names */ status = read_node_names(num_nodes, node_info); - if(status != OK) { + if(status != 0) { exit(1); } @@ -155,33 +155,33 @@ void preprocess_lst_files(void) /* Check to be sure the names are unique */ status = check_uniqueness(num_models, model_info, num_nodes, node_info); - if(status != OK) { + if(status != 0) { exit(1); } /* Write out the CMextrn.h file used to compile SPIinit.c */ status = write_CMextrn(num_models, model_info); - if(status != OK) { + if(status != 0) { exit(1); } /* Write out the CMinfo.h file used to compile SPIinit.c */ status = write_CMinfo(num_models, model_info); - if(status != OK) { + if(status != 0) { exit(1); } /* Write out the UDNextrn.h file used to compile SPIinit.c */ status = write_UDNextrn(num_nodes, node_info); - if(status != OK) { + if(status != 0) { exit(1); } /* Write out the UDNinfo.h file used to compile SPIinit.c */ status = write_UDNinfo(num_nodes, node_info); - if(status != OK) { + if(status != 0) { exit(1); } @@ -190,7 +190,7 @@ void preprocess_lst_files(void) /* user-defined node functions with the simulator */ status = write_objects_inc(num_models, model_info, num_nodes, node_info); - if(status != OK) { + if(status != 0) { exit(1); } /* remove model_info and node_info */ @@ -219,7 +219,7 @@ processing. */ -static Status_t read_modpath( +static int read_modpath( int *num_models, /* Number of model pathnames found */ Model_Info_t **model_info /* Info about each model */ ) @@ -243,9 +243,9 @@ static Status_t read_modpath( /* Open the model pathname file */ fp = fopen_cmpp(&filename, "r"); - if(fp == NULL) { + if (fp == NULL) { print_error("ERROR - File not found: %s", filename); - return(ERROR); + return -1; } /* Read the pathnames from the file, one line at a time until EOF */ @@ -260,7 +260,7 @@ static Status_t read_modpath( if(len > MAX_PATH_LEN) { print_error("ERROR - Line %d of %s exceeds %d characters", line_num, filename, MAX_PATH_LEN); - return(ERROR); + return -1; } /* Strip white space including newline */ @@ -289,7 +289,7 @@ static Status_t read_modpath( if(len > (MAX_PATH_LEN - (MAX_FN_LEN + 1)) ) { print_error("ERROR - Pathname on line %d of %s exceeds %d characters", line_num, filename, (MAX_PATH_LEN - (MAX_FN_LEN + 1))); - return(ERROR); + return -1; } /* Allocate and initialize a new model info structure */ @@ -300,8 +300,8 @@ static Status_t read_modpath( model[n].path_name = NULL; model[n].spice_name = NULL; model[n].cfunc_name = NULL; - model[n].spice_unique = TRUE; - model[n].cfunc_unique = TRUE; + model[n].spice_unique = true; + model[n].cfunc_unique = true; /* Put pathname into info structure */ model[n].path_name = (char *) malloc((size_t) (len+1)); @@ -318,11 +318,7 @@ static Status_t read_modpath( *num_models = n; *model_info = model; - if(filename) - free((char*)filename); - - return(OK); - + return 0; } @@ -338,7 +334,7 @@ processing. */ -static Status_t read_udnpath( +static int read_udnpath( int *num_nodes, /* Number of node pathnames found */ Node_Info_t **node_info /* Info about each node */ ) @@ -365,7 +361,7 @@ static Status_t read_udnpath( /* For backward compatibility, return with WARNING only if file not found */ if(fp == NULL) { print_error("WARNING - File not found: %s", filename); - return(OK); + return 0; } /* Read the pathnames from the file, one line at a time until EOF */ @@ -380,7 +376,7 @@ static Status_t read_udnpath( if(len > MAX_PATH_LEN) { print_error("ERROR - Line %d of %s exceeds %d characters", line_num, filename, MAX_PATH_LEN); - return(ERROR); + return -1; } /* Strip white space including newline */ @@ -409,7 +405,7 @@ static Status_t read_udnpath( if(len > (MAX_PATH_LEN - (MAX_FN_LEN + 1)) ) { print_error("ERROR - Pathname on line %d of %s exceeds %d characters", line_num, filename, (MAX_PATH_LEN - (MAX_FN_LEN + 1))); - return(ERROR); + return -1; } /* Allocate and initialize a new node info structure */ @@ -419,7 +415,7 @@ static Status_t read_udnpath( node = (Node_Info_t *) realloc(node, (size_t) (n + 1) * sizeof(Node_Info_t)); node[n].path_name = NULL; node[n].node_name = NULL; - node[n].unique = TRUE; + node[n].unique = true; /* Put pathname into info structure */ node[n].path_name = (char *) malloc((size_t) (len+1)); @@ -436,11 +432,7 @@ static Status_t read_udnpath( *num_nodes = n; *node_info = node; - if(filename) - free((char*)filename); - - return(OK); - + return 0; } @@ -455,22 +447,22 @@ This function opens each of the models and gets the names of the model and the C function into the internal model information structure. */ -static Status_t read_model_names( +static int read_model_names( int num_models, /* Number of model pathnames */ Model_Info_t *model_info /* Info about each model */ ) { - Boolean_t all_found; /* True if all ifspec files read */ + bool all_found; /* True if all ifspec files read */ int i; /* A temporary counter */ char path[MAX_PATH_LEN+1]; /* full pathname to ifspec file */ - Status_t status; /* Return status */ + int status; /* Return status */ Ifs_Table_t ifs_table; /* Repository for info read from ifspec file */ /* For each model found in model pathname file, read the interface */ /* spec file to get the SPICE and C function names into model_info */ - for(i = 0, all_found = TRUE; i < num_models; i++) { + for(i = 0, all_found = true; i < num_models; i++) { /* Form the full pathname to the interface spec file */ strcpy(path, model_info[i].path_name); @@ -481,12 +473,12 @@ static Status_t read_model_names( status = read_ifs_file(path, GET_IFS_NAME, &ifs_table); /* Transfer the names into the model_info structure */ - if(status == OK) { - model_info[i].spice_name = strdup(ifs_table.name.model_name); - model_info[i].cfunc_name = strdup(ifs_table.name.c_fcn_name); + if(status == 0) { + model_info[i].spice_name = ifs_table.name.model_name; + model_info[i].cfunc_name = ifs_table.name.c_fcn_name; } else { - all_found = FALSE; + all_found = false; print_error("ERROR - Problems reading %s in directory %s", IFSPEC_FILENAME, model_info[i].path_name); } @@ -496,9 +488,9 @@ static Status_t read_model_names( } if(all_found) - return(OK); + return 0; else - return(ERROR); + return -1; } @@ -514,21 +506,21 @@ and gets the names of the node into the internal information structure. */ -static Status_t read_node_names( +static int read_node_names( int num_nodes, /* Number of node pathnames */ Node_Info_t *node_info /* Info about each node */ ) { - Boolean_t all_found; /* True if all files read OK */ + bool all_found; /* True if all files read OK */ int i; /* A temporary counter */ char path[MAX_PATH_LEN+1]; /* full pathname to file */ - Status_t status; /* Return status */ + int status; /* Return status */ char *node_name; /* Name of node type read from file */ /* For each node found in node pathname file, read the udnfunc.c */ /* file to get the node type names into node_info */ - for(i = 0, all_found = TRUE; i < num_nodes; i++) { + for(i = 0, all_found = true; i < num_nodes; i++) { /* Form the full pathname to the interface spec file */ strcpy(path, node_info[i].path_name); @@ -539,20 +531,20 @@ static Status_t read_node_names( status = read_udn_type_name(path, &node_name); /* Transfer the names into the node_info structure */ - if(status == OK) { + if(status == 0) { node_info[i].node_name = node_name; } else { - all_found = FALSE; + all_found = false; print_error("ERROR - Problems reading %s in directory %s", UDNFUNC_FILENAME, node_info[i].path_name); } } if(all_found) - return(OK); + return 0; else - return(ERROR); + return -1; } @@ -569,7 +561,7 @@ names are unique with respect to each other and to the models and functions internal to SPICE 3C1. */ -static Status_t check_uniqueness( +static int check_uniqueness( int num_models, /* Number of model pathnames */ Model_Info_t *model_info, /* Info about each model */ int num_nodes, /* Number of node type pathnames */ @@ -578,7 +570,7 @@ static Status_t check_uniqueness( { int i; /* A temporary counter */ int j; /* A temporary counter */ - Boolean_t all_unique; /* true if names are unique */ + bool all_unique; /* true if names are unique */ /* Define a list of model names used internally by XSPICE */ /* These names (except 'poly') are defined in src/sim/INP/INPdomodel.c and */ @@ -627,19 +619,19 @@ static Status_t check_uniqueness( /* Then, loop through all model names and report errors if same as SPICE */ /* model name or same as another model name in list */ - for(i = 0, all_unique = TRUE; i < num_models; i++) { + for(i = 0, all_unique = true; i < num_models; i++) { /* First check against list of SPICE internal names */ for(j = 0; j < numSPICEmodels; j++) { if(strcmp(model_info[i].spice_name, SPICEmodel[j]) == 0) { - all_unique = FALSE; + all_unique = false; print_error("ERROR - Model name '%s' is same as internal SPICE model name\n", model_info[i].spice_name); } } /* Skip if already seen once */ - if(model_info[i].spice_unique == FALSE) + if(model_info[i].spice_unique == false) continue; /* Then check against other names in list */ @@ -651,9 +643,9 @@ static Status_t check_uniqueness( /* Compare the names */ if(strcmp(model_info[i].spice_name, model_info[j].spice_name) == 0) { - all_unique = FALSE; - model_info[i].spice_unique = FALSE; - model_info[j].spice_unique = FALSE; + all_unique = false; + model_info[i].spice_unique = false; + model_info[j].spice_unique = false; print_error("ERROR - Model name '%s' in directory: %s", model_info[i].spice_name, model_info[i].path_name); @@ -670,7 +662,7 @@ static Status_t check_uniqueness( for(i = 0; i < num_models; i++) { /* Skip if already seen once */ - if(model_info[i].cfunc_unique == FALSE) + if(model_info[i].cfunc_unique == false) continue; /* Check against other names in list only, not against SPICE identifiers */ @@ -683,9 +675,9 @@ static Status_t check_uniqueness( /* Compare the names */ if(strcmp(model_info[i].cfunc_name, model_info[j].cfunc_name) == 0) { - all_unique = FALSE; - model_info[i].cfunc_unique = FALSE; - model_info[j].cfunc_unique = FALSE; + all_unique = false; + model_info[i].cfunc_unique = false; + model_info[j].cfunc_unique = false; print_error("ERROR - C function name '%s' in directory: %s", model_info[i].cfunc_name, model_info[i].path_name); @@ -705,14 +697,14 @@ static Status_t check_uniqueness( /* First check against list of internal names */ for(j = 0; j < numUDNidentifiers; j++) { if(strcmp(node_info[i].node_name, UDNidentifier[j]) == 0) { - all_unique = FALSE; + all_unique = false; print_error("ERROR - Node type '%s' is same as internal node type\n", node_info[i].node_name); } } /* Skip if already seen once */ - if(node_info[i].unique == FALSE) + if(node_info[i].unique == false) continue; /* Then check against other names in list */ @@ -724,9 +716,9 @@ static Status_t check_uniqueness( /* Compare the names */ if(strcmp(node_info[i].node_name, node_info[j].node_name) == 0) { - all_unique = FALSE; - node_info[i].unique = FALSE; - node_info[j].unique = FALSE; + all_unique = false; + node_info[i].unique = false; + node_info[j].unique = false; print_error("ERROR - Node type '%s' in directory: %s", node_info[i].node_name, node_info[i].path_name); @@ -741,9 +733,9 @@ static Status_t check_uniqueness( /* Return error status */ if(all_unique) - return(OK); + return 0; else - return(ERROR); + return -1; } @@ -761,7 +753,7 @@ mentioned in the include file to define the models known to the simulator. */ -static Status_t write_CMextrn( +static int write_CMextrn( int num_models, /* Number of model pathnames */ Model_Info_t *model_info /* Info about each model */ ) @@ -775,7 +767,7 @@ static Status_t write_CMextrn( fp = fopen_cmpp(&filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); - return(ERROR); + return -1; } /* Write out the data */ @@ -785,9 +777,7 @@ static Status_t write_CMextrn( /* Close the file and return */ fclose(fp); - if(filename) - free((char*)filename); - return(OK); + return 0; } @@ -804,7 +794,7 @@ the include file to define the models known to the simulator. */ -static Status_t write_CMinfo( +static int write_CMinfo( int num_models, /* Number of model pathnames */ Model_Info_t *model_info /* Info about each model */ ) @@ -818,7 +808,7 @@ static Status_t write_CMinfo( fp = fopen_cmpp(&filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); - return(ERROR); + return -1; } /* Write out the data */ @@ -828,9 +818,7 @@ static Status_t write_CMinfo( /* Close the file and return */ fclose(fp); - if(filename) - free((char*)filename); - return(OK); + return 0; } @@ -851,7 +839,7 @@ simulator. -static Status_t write_UDNextrn( +static int write_UDNextrn( int num_nodes, /* Number of node pathnames */ Node_Info_t *node_info /* Info about each node */ ) @@ -865,7 +853,7 @@ static Status_t write_UDNextrn( fp = fopen_cmpp(&filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); - return(ERROR); + return -1; } /* Write out the data */ @@ -875,9 +863,7 @@ static Status_t write_UDNextrn( /* Close the file and return */ fclose(fp); - if(filename) - free((char*)filename); - return(OK); + return 0; } @@ -896,7 +882,7 @@ simulator. -static Status_t write_UDNinfo( +static int write_UDNinfo( int num_nodes, /* Number of node pathnames */ Node_Info_t *node_info /* Info about each node */ ) @@ -910,7 +896,7 @@ static Status_t write_UDNinfo( fp = fopen_cmpp(&filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); - return(ERROR); + return -1; } /* Write out the data */ @@ -919,10 +905,8 @@ static Status_t write_UDNinfo( } /* Close the file and return */ - if(filename) - free((char*)filename); fclose(fp); - return(OK); + return 0; } @@ -936,7 +920,7 @@ the make utility to locate the object modules needed to link the simulator with the code models and user-defined node types. */ -static Status_t write_objects_inc( +static int write_objects_inc( int num_models, /* Number of model pathnames */ Model_Info_t *model_info, /* Info about each model */ int num_nodes, /* Number of udn pathnames */ @@ -952,7 +936,7 @@ static Status_t write_objects_inc( fp = fopen_cmpp(&filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); - return(ERROR); + return -1; } /* Write out the data */ @@ -973,9 +957,7 @@ static Status_t write_objects_inc( /* Close the file and return */ fclose(fp); - if(filename) - free((char*)filename); - return(OK); + return 0; } @@ -988,14 +970,14 @@ is found, and then gets the name of the node type from the first member of the structure. */ -static Status_t read_udn_type_name( +static int read_udn_type_name( const char *path, /* the path to the node definition file */ char **node_name /* the node type name found in the file */ ) { FILE *fp; /* file pointer for opened file */ - Boolean_t found; /* true if name found successfully */ - Boolean_t in_struct; /* true if found struct with name */ + bool found; /* true if name found successfully */ + bool in_struct; /* true if found struct with name */ char name[MAX_NAME_LEN + 1]; /* temporary storage for name read */ int c; /* a character read from the file */ int i; /* a counter */ @@ -1006,12 +988,12 @@ static Status_t read_udn_type_name( fp = fopen_cmpp(&path, "r"); free((char*)path); if(fp == NULL) - return(ERROR); + return -1; /* Read the file until the definition of the Evt_Udn_Info_t struct */ /* is found, then get the name of the node type from the first */ /* member of the structure */ - found = FALSE; + found = false; do { /* read the next character */ c = fgetc(fp); @@ -1036,11 +1018,11 @@ static Status_t read_udn_type_name( break; /* read until "Evt_Udn_Info_t" is encountered */ - for(i = 0, in_struct = FALSE; ; i++) { + for(i = 0, in_struct = false; ; i++) { if(c != struct_type[i]) break; else if(i == (sizeof(struct_type) - 2)) { - in_struct = TRUE; + in_struct = true; break; } else @@ -1056,7 +1038,7 @@ static Status_t read_udn_type_name( do { c = fgetc(fp); if(c == '"') { - found = TRUE; + found = true; name[i] = '\0'; } else if(c != EOF) @@ -1074,11 +1056,11 @@ static Status_t read_udn_type_name( if(found) { *node_name = (char *) malloc(strlen(name) + 1); strcpy(*node_name, name); - return(OK); + return 0; } else { *node_name = NULL; - return(ERROR); + return -1; } } diff --git a/src/xspice/cmpp/pp_mod.c b/src/xspice/cmpp/pp_mod.c index 240371ed6..fe31be4f0 100644 --- a/src/xspice/cmpp/pp_mod.c +++ b/src/xspice/cmpp/pp_mod.c @@ -113,7 +113,7 @@ void preprocess_mod_file ( Ifs_Table_t ifs_table; /* info read from ifspec.ifs file */ - Status_t status; /* Return status */ + int status; /* Return status */ const char *output_filename; /* @@ -122,7 +122,7 @@ void preprocess_mod_file ( status = read_ifs_file (IFSPEC_FILENAME, GET_IFS_TABLE, &ifs_table); - if (status != OK) { + if (status != 0) { exit(1); } diff --git a/src/xspice/cmpp/read_ifs.c b/src/xspice/cmpp/read_ifs.c index 9a2bb0197..51b72184d 100644 --- a/src/xspice/cmpp/read_ifs.c +++ b/src/xspice/cmpp/read_ifs.c @@ -59,11 +59,11 @@ extern int ifs_yylineno; extern char *ifs_yytext; extern Ifs_Table_t *parser_ifs_table; -extern Boolean_t parser_just_names; +extern bool parser_just_names; extern int ifs_num_errors; -static Status_t read_ifs_table(FILE *fp, int mode, Ifs_Table_t *ifs_table); +static int read_ifs_table(FILE *fp, int mode, Ifs_Table_t *ifs_table); const char *current_filename; @@ -89,7 +89,7 @@ from read_ifs_table(), the file is closed. -Status_t read_ifs_file( +int read_ifs_file( const char *filename, /* File to read */ int mode, /* Get names only or get everything? */ Ifs_Table_t *ifs_table) /* Table to put info in */ @@ -97,7 +97,7 @@ Status_t read_ifs_file( FILE *fp; /* Ifs file pointer */ - Status_t status; /* returned status from function */ + int status; /* returned status from function */ /* Open the ifs file for read access */ @@ -107,7 +107,7 @@ Status_t read_ifs_file( if(fp == NULL) { perror (prog_name); print_error("ERROR - File not found: %s", filename); - return(ERROR); + return -1; } current_filename = filename; @@ -141,7 +141,7 @@ automatically generated by UNIX lex/yacc. -static Status_t read_ifs_table( +static int read_ifs_table( FILE *fp, /* File to read from */ int mode, /* Get names only or get everything? */ Ifs_Table_t *ifs_table) /* Table to put info in */ @@ -156,7 +156,7 @@ static Status_t read_ifs_table( ifs_yylineno = 1; ifs_yyin = fp; - parser_just_names = (mode == GET_IFS_NAME) ? TRUE : FALSE; + parser_just_names = (mode == GET_IFS_NAME) ? true : false; parser_ifs_table = ifs_table; ifs_num_errors = 0; @@ -164,10 +164,10 @@ static Status_t read_ifs_table( if (ifs_yyparse() || (ifs_num_errors > 0)) { print_error ("Error parsing interface specification file"); ifs_yyrestart(NULL); - return ERROR; + return -1; } ifs_yyrestart(NULL); - return OK; + return 0; } /*---------------------------------------------------------------------------*/ diff --git a/src/xspice/cmpp/util.c b/src/xspice/cmpp/util.c index 6debc4bab..da6a27163 100644 --- a/src/xspice/cmpp/util.c +++ b/src/xspice/cmpp/util.c @@ -40,18 +40,35 @@ NON-STANDARD FEATURES #include #include +#include #include #include #include +#if defined(_WIN32) +#include /* for definition of PathIsRelativeA() */ +#if defined(_MSC_VER) +#pragma comment(lib, "Shlwapi.lib") +#endif +#endif + #include "cmpp.h" +/* Using only Unix directory separator since it is used to build directory + * paths in include files that must work on any supported operating + * system */ +#define DIR_TERM_UNIX '/' + + /* *********************************************************************** */ char *prog_name; +inline static bool is_absolute_pathname(const char *path); + + /* Initialize external variable prog_name with the name of the program. * A copy is not made. */ void init_error(char *program_name) @@ -90,33 +107,68 @@ void str_to_lower(char *s) -/* If *path_p is relative, prefix with the CMPP output or input string - * build the path and open the file and return the path that was created. */ +/* If *path_p is relative, prefix with the value of the CMPP output or + * input environment variable. Open the file and return the path that + * was used to open it. */ FILE *fopen_cmpp(const char **path_p, const char *mode) { const char *path = *path_p; + char *buf = (char *) NULL; - char buf[MAX_PATH_LEN + 1]; + /* If absoulte path, prefix with CMPP_ODIR/CMPP_IDIR env value */ + if (!is_absolute_pathname(path)) { /* relative path */ + const char *e = getenv((*mode == 'w' || *mode == 'a') ? + "CMPP_ODIR" : "CMPP_IDIR"); + if (e) { /* have env var */ + const size_t len_prefix = strlen(e); + const size_t len_path = strlen(path); + const size_t n_char = len_prefix + len_path + 1; - if (path[0] != '/') { - const char *e = getenv((*mode == 'w') ? "CMPP_ODIR" : "CMPP_IDIR"); - if (e) { - if (strlen(e) + 1 + strlen(path) < sizeof(buf)) { - strcpy(buf, e); - strcat(buf, "/"); - strcat(buf, path); - path = buf; + /* Allocate buffer to build full file name */ + if ((buf = (char *) malloc(n_char + 1)) == (char *) NULL) { + *path_p = (char *) NULL; + return (FILE *) NULL; } - else { - path = NULL; + + /* Build the full file name */ + { + char *p_cur = buf; + (void) memcpy(p_cur, e, len_prefix); + p_cur += len_prefix; + *p_cur++ = DIR_TERM_UNIX; + (void) memcpy(p_cur, path, len_path + 1); } + } /* end of case that env variable found */ + } /* end of case that path is absolute */ + + /* If did not build full file name yet, copy the original + * name of the file */ + if (buf == (char *) NULL) { + if ((buf = strdup(path)) == (char *) NULL) { /* failed */ + *path_p = (char *) NULL; + return (FILE *) NULL; } } - *path_p = strdup(path); - - return fopen(path, mode); + /* Return copy of file name and opened file */ + *path_p = buf; + return fopen(buf, mode); } /* end of function fopen_cmpp */ +/* Returns true if path is an absolute path and false if it is a + * relative path. No check is done for the existance of the path. */ +/*** NOTE: Same as in inpcom.c Currently the cmpp project is "isolated + * from others. It would be good to make into one function used in common */ +inline static bool is_absolute_pathname(const char *path) +{ +#ifdef _WIN32 + return !PathIsRelativeA(path); +#else + return path[0] == DIR_TERM_UNIX; +#endif +} /* end of funciton is_absolute_pathname */ + + + diff --git a/src/xspice/cmpp/writ_ifs.c b/src/xspice/cmpp/writ_ifs.c index a09f61c99..9e9129fa7 100644 --- a/src/xspice/cmpp/writ_ifs.c +++ b/src/xspice/cmpp/writ_ifs.c @@ -74,7 +74,7 @@ static char *value_to_str(Data_Type_t type, Value_t value); static char *no_value_to_str(void); -static char *boolean_to_str(Boolean_t value); +static char *boolean_to_str(bool value); static char *integer_to_str(int value); @@ -109,7 +109,7 @@ The output file is then closed. -Status_t write_ifs_c_file( +int write_ifs_c_file( const char *filename, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { @@ -123,7 +123,7 @@ Status_t write_ifs_c_file( if(fp == NULL) { print_error("ERROR - Can't create file: %s", filename); - return(ERROR); + return -1; } @@ -155,12 +155,13 @@ Status_t write_ifs_c_file( /* Close the ifspec.c file and return */ int_status = fclose(fp); - if(filename) - free((char*)filename); - if(int_status == 0) - return(OK); - else - return(ERROR); + + if (int_status == 0) { + return 0; + } + else { + return -1; + } } @@ -244,7 +245,7 @@ static void write_pTable( int i; char str[80]; - Boolean_t is_array; + bool is_array; Data_Type_t type; @@ -284,33 +285,33 @@ static void write_pTable( strcpy(str,""); - if(is_array == TRUE) { + if(is_array == true) { strcat(str,"("); } - if(type == BOOLEAN) { + if(type == CMPP_BOOLEAN) { strcat(str,"IF_FLAG"); /* There is no BOOLEAN in SPICE3 */ } - else if(type == INTEGER) { + else if(type == CMPP_INTEGER) { strcat(str,"IF_INTEGER"); } - else if(type == REAL) { + else if(type == CMPP_REAL) { strcat(str,"IF_REAL"); } - else if(type == COMPLEX) { + else if(type == CMPP_COMPLEX) { strcat(str,"IF_COMPLEX"); } - else if(type == STRING) { + else if(type == CMPP_STRING) { strcat(str,"IF_STRING"); } - else if(type == POINTER) { + else if(type == CMPP_POINTER) { strcat(str,"IF_STRING"); } else { print_error("INTERNAL ERROR - write_pTable() - Impossible data type."); } - if(is_array == TRUE) { + if(is_array == true) { strcat(str,"|IF_VECTOR)"); } @@ -351,7 +352,7 @@ static void write_mPTable( int i; char str[80]; - Boolean_t is_array; + bool is_array; Data_Type_t type; @@ -391,30 +392,30 @@ static void write_mPTable( strcpy(str,""); - if(is_array == TRUE) { + if(is_array == true) { strcat(str,"("); } - if(type == BOOLEAN) { + if(type == CMPP_BOOLEAN) { strcat(str,"IF_FLAG"); /* There is no BOOLEAN in SPICE3 */ } - else if(type == INTEGER) { + else if(type == CMPP_INTEGER) { strcat(str,"IF_INTEGER"); } - else if(type == REAL) { + else if(type == CMPP_REAL) { strcat(str,"IF_REAL"); } - else if(type == COMPLEX) { + else if(type == CMPP_COMPLEX) { strcat(str,"IF_COMPLEX"); } - else if(type == STRING) { + else if(type == CMPP_STRING) { strcat(str,"IF_STRING"); } else { print_error("INTERNAL ERROR - write_mPTable() - Impossible data type."); } - if(is_array == TRUE) { + if(is_array == true) { strcat(str,"|IF_VECTOR)"); } @@ -541,26 +542,26 @@ static void write_conn_info( str = boolean_to_str(ifs_table->conn[i].is_array); fprintf(fp, " %s,\n", str); - if(ifs_table->conn[i].is_array == FALSE) { + if(ifs_table->conn[i].is_array == false) { - str = boolean_to_str(FALSE); /* has_lower_bound */ + str = boolean_to_str(false); /* has_lower_bound */ fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* lower_bound */ fprintf(fp, " %s,\n", str); - str = boolean_to_str(FALSE); /* has_upper_bound */ + str = boolean_to_str(false); /* has_upper_bound */ fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* upper_bound */ fprintf(fp, " %s,\n", str); } - else { /* is_array == TRUE */ + else { /* is_array == true */ str = boolean_to_str(ifs_table->conn[i].has_lower_bound); fprintf(fp, " %s,\n", str); - if(ifs_table->conn[i].has_lower_bound == TRUE) + if(ifs_table->conn[i].has_lower_bound == true) str = integer_to_str(ifs_table->conn[i].lower_bound); else str = integer_to_str(0); @@ -569,7 +570,7 @@ static void write_conn_info( str = boolean_to_str(ifs_table->conn[i].has_upper_bound); fprintf(fp, " %s,\n", str); - if(ifs_table->conn[i].has_upper_bound == TRUE) + if(ifs_table->conn[i].has_upper_bound == true) str = integer_to_str(ifs_table->conn[i].upper_bound); else str = integer_to_str(0); @@ -648,7 +649,7 @@ static void write_param_info( str = boolean_to_str(ifs_table->param[i].has_default); fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_default == TRUE) + if(ifs_table->param[i].has_default == true) str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].default_value); else str = no_value_to_str(); @@ -657,7 +658,7 @@ static void write_param_info( str = boolean_to_str(ifs_table->param[i].has_lower_limit); fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_lower_limit == TRUE) + if(ifs_table->param[i].has_lower_limit == true) str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].lower_limit); else str = no_value_to_str(); @@ -666,7 +667,7 @@ static void write_param_info( str = boolean_to_str(ifs_table->param[i].has_upper_limit); fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_upper_limit == TRUE) + if(ifs_table->param[i].has_upper_limit == true) str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].upper_limit); else str = no_value_to_str(); @@ -675,49 +676,49 @@ static void write_param_info( str = boolean_to_str(ifs_table->param[i].is_array); fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].is_array == FALSE) { + if(ifs_table->param[i].is_array == false) { - str = boolean_to_str(FALSE); /* has_conn_ref */ + str = boolean_to_str(false); /* has_conn_ref */ fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* conn_ref */ fprintf(fp, " %s,\n", str); - str = boolean_to_str(FALSE); /* has_lower_bound */ + str = boolean_to_str(false); /* has_lower_bound */ fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* lower_bound */ fprintf(fp, " %s,\n", str); - str = boolean_to_str(FALSE); /* has_upper_bound */ + str = boolean_to_str(false); /* has_upper_bound */ fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* upper_bound */ fprintf(fp, " %s,\n", str); } - else { /* is_array == TRUE */ + else { /* is_array == true */ str = boolean_to_str(ifs_table->param[i].has_conn_ref); fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_conn_ref == TRUE) { + if(ifs_table->param[i].has_conn_ref == true) { str = integer_to_str(ifs_table->param[i].conn_ref); fprintf(fp, " %s,\n", str); - str = boolean_to_str(FALSE); /* has_lower_bound */ + str = boolean_to_str(false); /* has_lower_bound */ fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* lower_bound */ fprintf(fp, " %s,\n", str); - str = boolean_to_str(FALSE); /* has_upper_bound */ + str = boolean_to_str(false); /* has_upper_bound */ fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* upper_bound */ fprintf(fp, " %s,\n", str); } - else { /* has_conn_ref == FALSE */ + else { /* has_conn_ref == false */ str = integer_to_str(0); /* conn_ref */ fprintf(fp, " %s,\n", str); @@ -725,7 +726,7 @@ static void write_param_info( str = boolean_to_str(ifs_table->param[i].has_lower_bound); fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_lower_bound == TRUE) + if(ifs_table->param[i].has_lower_bound == true) str = integer_to_str(ifs_table->param[i].lower_bound); else str = integer_to_str(0); @@ -734,7 +735,7 @@ static void write_param_info( str = boolean_to_str(ifs_table->param[i].has_upper_bound); fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_upper_bound == TRUE) + if(ifs_table->param[i].has_upper_bound == true) str = integer_to_str(ifs_table->param[i].upper_bound); else str = integer_to_str(0); @@ -981,27 +982,27 @@ static char *data_type_to_str(Data_Type_t type) switch(type) { - case BOOLEAN: + case CMPP_BOOLEAN: strcpy(str,"MIF_BOOLEAN"); break; - case INTEGER: + case CMPP_INTEGER: strcpy(str,"MIF_INTEGER"); break; - case REAL: + case CMPP_REAL: strcpy(str,"MIF_REAL"); break; - case COMPLEX: + case CMPP_COMPLEX: strcpy(str,"MIF_COMPLEX"); break; - case STRING: + case CMPP_STRING: strcpy(str,"MIF_STRING"); break; - case POINTER: + case CMPP_POINTER: strcpy(str,"MIF_STRING"); break; @@ -1151,15 +1152,15 @@ static char *dir_to_str(Dir_t dir) switch(dir) { - case IN: + case CMPP_IN: strcpy(str,"MIF_IN"); break; - case OUT: + case CMPP_OUT: strcpy(str,"MIF_OUT"); break; - case INOUT: + case CMPP_INOUT: strcpy(str,"MIF_INOUT"); break; @@ -1190,25 +1191,25 @@ static char *value_to_str(Data_Type_t type, Value_t value) switch(type) { - case BOOLEAN: + case CMPP_BOOLEAN: bool_str = boolean_to_str(value.bvalue); sprintf(str, "{%s, 0, 0.0, {0.0, 0.0}, NULL}", bool_str); break; - case INTEGER: + case CMPP_INTEGER: sprintf(str, "{MIF_FALSE, %d, 0.0, {0.0, 0.0}, NULL}", value.ivalue); break; - case REAL: + case CMPP_REAL: sprintf(str, "{MIF_FALSE, 0, %e, {0.0, 0.0}, NULL}", value.rvalue); break; - case COMPLEX: + case CMPP_COMPLEX: sprintf(str, "{MIF_FALSE, 0, 0.0, {%e, %e}, NULL}", value.cvalue.real, value.cvalue.imag); break; - case STRING: + case CMPP_STRING: /* be careful, the string could conceivably be very long... */ str_len = (int) strlen(value.svalue); if((str_len + BASE_STR_LEN) > max_len) { @@ -1229,29 +1230,17 @@ static char *value_to_str(Data_Type_t type, Value_t value) /* *********************************************************************** */ -static char *boolean_to_str(Boolean_t value) +static char *boolean_to_str(bool value) { static char *str = NULL; - if(str == NULL) + if (str == NULL) { str = (char *) malloc(BASE_STR_LEN+1); - - switch(value) { - - case TRUE: - strcpy(str,"MIF_TRUE"); - break; - - case FALSE: - strcpy(str,"MIF_FALSE"); - break; - - default: - print_error("INTERNAL ERROR - boolean_to_str() - Impossible boolean value."); - } - return(str); + strcpy(str, value ? "MIF_TRUE" : "MIF_FALSE"); + + return str; } From 8ead6c1b77df8f851ac311b3b6652c38b2258e94 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Mon, 23 Dec 2019 22:42:01 -0500 Subject: [PATCH 10/36] Minor fix to end-of-index processing of let command --- src/frontend/com_let.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/frontend/com_let.c b/src/frontend/com_let.c index d1fb41754..2884840fe 100644 --- a/src/frontend/com_let.c +++ b/src/frontend/com_let.c @@ -312,9 +312,10 @@ static int find_indices(char *s, index_range_t *p_index, int *p_n_index) s = p_end + 1; /* Only white space is allowed after closing brace */ - if ((s = skip_ws(s)) != '\0') { + if (*(s = skip_ws(s)) != '\0') { (void) fprintf(cp_err, "Invalid text was found " - "after dimension data for vector.\n"); + "after dimension data for vector: \"%s\".\n", + s); return -1; } From 8afb9635c1981eef04202239b93772d890efb957 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sun, 12 Jan 2020 21:02:19 -0500 Subject: [PATCH 11/36] Formatting --- src/frontend/inp.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index b84623b6d..729102dc9 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -522,14 +522,14 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) } } endTime = seconds(); - /* store input directory to a variable*/ + /* store input directory to a variable */ if (fp) { cp_vset("inputdir", CP_STRING, dir_name); } tfree(dir_name); /* if nothing came back from inp_readall, e.g. after calling ngspice without parameters, - just close fp and return to caller */ + just close fp and return to caller */ if (!deck) { if (!intfile && fp) fclose(fp); @@ -550,11 +550,13 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) /* Save the title before INPgetTitle gets it. */ tt = copy(deck->line); - if (!deck->nextcard) + if (!deck->nextcard) { fprintf(cp_err, "Warning: no lines in input\n"); + } } - if (fp && !intfile) + if (fp && !intfile) { fclose(fp); + } /* Now save the IO context and start a new control set. After we are done with the source we'll put the old file descriptors @@ -600,14 +602,15 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) ft_dotsaves(); } /* end if (comfile) */ - else { /* must be regular deck . . . . */ + else { /* must be regular deck . . . . */ /* loop through deck and handle control cards */ for (dd = deck->nextcard; dd; dd = ld->nextcard) { /* get temp from deck */ if (ciprefix(".temp", dd->line)) { s = skip_ws(dd->line + 5); - if (temperature) + if (temperature) { txfree(temperature); + } temperature = copy(s); } /* Ignore comment lines, but not lines begining with '*#', From 60ad18d2639764263d02d5b03e74d3ed66cedd3d Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sun, 12 Jan 2020 21:03:43 -0500 Subject: [PATCH 12/36] Formatting and added comments --- src/frontend/subckt.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index fcdcce9ee..dbfcd9451 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -700,8 +700,7 @@ doit(struct card *deck, wordlist *modnames) { /*-------------------------------------------------------------------*/ /* Copy a deck, including the actual lines. */ /*-------------------------------------------------------------------*/ -struct card * -inp_deckcopy(struct card *deck) { +struct card * inp_deckcopy(struct card *deck) { struct card *d = NULL, *nd = NULL; while (deck) { @@ -727,8 +726,7 @@ inp_deckcopy(struct card *deck) { * without .control section(s). * First line is always copied (except being .control). */ -struct card * -inp_deckcopy_oc(struct card *deck) +struct card *inp_deckcopy_oc(struct card * deck) { struct card *d = NULL, *nd = NULL; int skip_control = 0, i = 0; @@ -749,26 +747,29 @@ inp_deckcopy_oc(struct card *deck) deck = deck->nextcard; continue; } - if (nd) { - d->nextcard = TMALLOC(struct card, 1); - d = d->nextcard; + if (nd) { /* First card already found */ + /* d is the card at the end of the deck */ + d = d->nextcard = TMALLOC(struct card, 1); } - else { + else { /* This is the first card */ nd = d = TMALLOC(struct card, 1); } d->linenum_orig = deck->linenum; d->linenum = i++; d->line = copy(deck->line); - if (deck->error) + if (deck->error) { d->error = copy(deck->error); + } d->actualLine = NULL; deck = deck->nextcard; - while (deck && *(deck->line) == '*') + while (deck && *(deck->line) == '*') { /* skip comments */ deck = deck->nextcard; - } + } + } /* end of loop over cards in the source deck */ + + return nd; +} /* end of function inp_deckcopy_oc */ - return (nd); -} /*------------------------------------------------------------------- From 5652afc87d56c5596d6780ace809cac5650bad63 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sun, 12 Jan 2020 21:06:14 -0500 Subject: [PATCH 13/36] Gave structure defining Mif_Complex_t a name so that it could be forward referenced. --- src/include/ngspice/miftypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/ngspice/miftypes.h b/src/include/ngspice/miftypes.h index b18663d9c..a9ae17c96 100644 --- a/src/include/ngspice/miftypes.h +++ b/src/include/ngspice/miftypes.h @@ -188,7 +188,7 @@ typedef enum { * Complex numbers */ -typedef struct { +typedef struct Mif_Complex { double real; double imag; From 31c7b69d39209b557be4209d37515a9f1a5e6fb0 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sun, 12 Jan 2020 21:06:51 -0500 Subject: [PATCH 14/36] Fixed compile warning about signed/unsigned comparison. --- src/misc/dstring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc/dstring.c b/src/misc/dstring.c index d5cb4cac5..51df2f55a 100644 --- a/src/misc/dstring.c +++ b/src/misc/dstring.c @@ -276,7 +276,7 @@ int ds_cat_vprintf(DSTRING *p_ds, const char *sz_fmt, va_list p_arg) } /* Else check for buffer large enough and set length if it is */ - if (rc < n_byte_free) { + if ((size_t) rc < n_byte_free) { p_ds->length += rc; return DS_E_OK; } From 4e510606843616ca1c5c92fc3705e7f15545b2f4 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sun, 12 Jan 2020 21:08:02 -0500 Subject: [PATCH 15/36] Clarified error message --- src/spicelib/analysis/dctrcurv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/spicelib/analysis/dctrcurv.c b/src/spicelib/analysis/dctrcurv.c index c373160a7..e8e4e592d 100644 --- a/src/spicelib/analysis/dctrcurv.c +++ b/src/spicelib/analysis/dctrcurv.c @@ -150,7 +150,9 @@ DCtrCurv(CKTcircuit *ckt, int restart) } SPfrontEnd->IFerrorf (ERR_FATAL, - "DCtrCurv: source / resistor %s not in circuit", job->TRCVvName[i]); + "DC Transfer Function: Voltage source, current source, or " + "resistor named \"%s\" is not in the circuit", + job->TRCVvName[i]); return(E_NODEV); found:; From 46b6ab8994d325ab172c2b1b1a62ca36180a827d Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sun, 12 Jan 2020 21:10:58 -0500 Subject: [PATCH 16/36] Added support for DSTRING in code modules with makefile builds --- src/xspice/icm/GNUmakefile.in | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index 8c73ef7d4..1958103fe 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -10,7 +10,8 @@ include makedefs CMDIRS = spice2poly digital analog xtradev xtraevt table -all: +#Invoke $(MAKE) for each of the CMDDIRS +all: dstring.o # One common dstring object file for all code modules for cm in $(CMDIRS) ; do \ $(MAKE) cm=$$cm $$cm/$$cm.cm \ || exit 1; \ @@ -34,6 +35,7 @@ uninstall: clean: + rm -f dstring.o for cm in $(CMDIRS) ; do \ $(MAKE) cm=$$cm cm-clean \ || exit 1; \ @@ -41,6 +43,10 @@ clean: #----------------------------------------------------------------------------- +NGSRCDIR = $(CURDIR)/../../../../src + +dstring.o : $(NGSRCDIR)/misc/dstring.c $(NGSRCDIR)/include/ngspice/dstring.h + $(COMPILE) -I $(NGSRCDIR)/include/ngspice -o $@ -c $< ifdef cm @@ -57,6 +63,7 @@ cm-gens := \ cm-objs := \ $(cm)/dlmain.o \ + dstring.o \ $(modlst:%=$(cm)/%/cfunc.o) \ $(modlst:%=$(cm)/%/ifspec.o) \ $(udnlst:%=$(cm)/%/udnfunc.o) From aee256e211673c09a9c3e0140da50c749b2b175e Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Sun, 12 Jan 2020 23:02:36 -0500 Subject: [PATCH 17/36] Fix of buffer overrun in interpolation at endpoint of interval. Made cfunc.mod for tables more modular. Prevented buffer overrun when building file name. Added error checking for allocation failures in many locations. Made binary search for interpolation more efficient. --- src/xspice/icm/dlmain.c | 105 ++- src/xspice/icm/table/mada/alloc.c | 20 +- src/xspice/icm/table/mada/eno.c | 57 +- src/xspice/icm/table/mada/eno2.c | 71 +- src/xspice/icm/table/mada/eno3.c | 85 +- src/xspice/icm/table/support/gettokens.c | 163 +++- src/xspice/icm/table/support/interp.c | 87 +- src/xspice/icm/table/table2D/cfunc.mod | 945 +++++++++---------- src/xspice/icm/table/table3D/cfunc.mod | 1055 +++++++++++----------- visualc/xspice/analog.vcxproj | 6 +- visualc/xspice/digital.vcxproj | 6 +- visualc/xspice/spice2poly.vcxproj | 6 +- visualc/xspice/table.vcxproj | 15 +- visualc/xspice/xtradev.vcxproj | 6 +- visualc/xspice/xtraevt.vcxproj | 6 +- 15 files changed, 1484 insertions(+), 1149 deletions(-) diff --git a/src/xspice/icm/dlmain.c b/src/xspice/icm/dlmain.c index d993ff374..93afe745e 100644 --- a/src/xspice/icm/dlmain.c +++ b/src/xspice/icm/dlmain.c @@ -7,17 +7,18 @@ // Author: Arpad Buermen ////////////////////////////////////////////////////////////////////////////// -#include "ngspice/inpdefs.h" -#include "ngspice/devdefs.h" -#include "ngspice/evtudn.h" -#include "ngspice/dllitf.h" -#include "cmextrn.h" -#include "udnextrn.h" - +#include #include #include -#include +#include "ngspice/devdefs.h" +#include "ngspice/dstring.h" +#include "ngspice/dllitf.h" +#include "ngspice/evtudn.h" +#include "ngspice/inpdefs.h" +#include "cmextrn.h" +#include "udnextrn.h" + ////////////////////////////////////////////////////////////////////////////// @@ -416,44 +417,76 @@ Infile_Path/ NGSPICE_INPUT_DIR/, where the path is given by the environmental variable , where the path is the current directory */ - -#define MAX_PATH_LEN 1024 - +#define DFLT_BUF_SIZE 256 FILE *fopen_with_path(const char *path, const char *mode) { - char buf[MAX_PATH_LEN+1]; FILE *fp; - if((path[0] != '/') && (path[1] != ':')) { + if((path[0] != '/') && (path[1] != ':')) { /* path absolue (probably) */ // const char *x = getenv("ngspice_vpath"); const char *x = cm_get_path(); - if(x) { - strncpy(buf, x, MAX_PATH_LEN); - strcat(buf, "/"); - strcat(buf, path); - fp = fopen(buf, mode); - if (fp) - return fp; - else { - char *y = getenv( "NGSPICE_INPUT_DIR" ); - if (y && *y) { - char *a; - strncpy(buf, y, MAX_PATH_LEN); - a = strrchr(buf, '/'); - if(a && a[1] == '\0') - a[0] = '\0'; - strcat(buf, "/"); - strcat(buf, path); - fp = fopen(buf, mode); - if (fp) - return fp; - } + if (x) { + DS_CREATE(ds, DFLT_BUF_SIZE); + + /* Build file /path> */ + if (ds_cat_printf(&ds, "%s/%s", x, path) != 0) { + cm_message_printf( + "Unable to build cm_get_path() path for opening file."); + ds_free(&ds); + return (FILE *) NULL; } + + /* Try opening file. If fail, try using NGSPICE_INPUT_DIR + * env variable location */ + if ((fp = fopen(ds_get_buf(&ds), mode)) == (FILE *) NULL) { + char *y = getenv("NGSPICE_INPUT_DIR"); + if (y && *y) { /* have env var and not "" */ + int rc_ds = 0; + /* Build /path and try opening. If the env var + * ends with a slash, do not add a second slash */ + ds_clear(&ds); + rc_ds |= ds_cat_str(&ds, y); + + /* Add slash if not present. Note that check for + * length > 0 is done on the remote chance that the + * ds_cat_str() failed. */ + const size_t len = ds_get_length(&ds); + if (len > 0 && ds_get_buf(&ds)[len - 1] != '/') { + rc_ds |= ds_cat_char(&ds, '/'); /* add dir sep */ + } + rc_ds |= ds_cat_str(&ds, path); /* add input path */ + + /* Ensure path built OK */ + if (rc_ds != 0) { + cm_message_printf( + "Unable to build NGSPICE_INPUT_DIR " + "path for opening file."); + ds_free(&ds); + return (FILE *) NULL; + } + + /* Try opening file name that was built */ + if ((fp = fopen(ds_get_buf(&ds), + mode)) != (FILE *) NULL) { + ds_free(&ds); + return fp; + } + } + } /* end of open using prefix from cm_get_path() failed */ + else { /* Opened OK */ + ds_free(&ds); + return fp; + } + ds_free(&ds); /* free dstring resources, if any */ } - } + } /* end of case that path is not absolute */ + + /* If not opened yet, try opening exactly as given */ fp = fopen(path, mode); + return fp; -} +} /* end of function fopen_with_path */ + int diff --git a/src/xspice/icm/table/mada/alloc.c b/src/xspice/icm/table/mada/alloc.c index cc0753581..b45d611aa 100644 --- a/src/xspice/icm/table/mada/alloc.c +++ b/src/xspice/icm/table/mada/alloc.c @@ -33,15 +33,19 @@ sf_alloc(int n /* number of elements */, { void *ptr; - size *= (size_t) n; + if (n < 0) { + cm_message_printf("%s: illegal allocation(%d X %zd bytes)", + __FILE__, n, size); + return NULL; + } - if (0 >= size) - cm_message_printf("%s: illegal allocation(%d bytes)", __FILE__, (int) size); - - ptr = malloc(size); - - if (NULL == ptr) - cm_message_printf("%s: cannot allocate %d bytes : ", __FILE__, (int) size); + /* Use calloc so that any internal allocations will be set to NULL to + * facilitate error recovery */ + if ((ptr = calloc(n, size)) == NULL) { + cm_message_printf("%s: cannot allocate %zd bytes : ", + __FILE__, n * size); + return NULL; + } return ptr; } diff --git a/src/xspice/icm/table/mada/eno.c b/src/xspice/icm/table/mada/eno.c index e6fc11126..36acbe338 100644 --- a/src/xspice/icm/table/mada/eno.c +++ b/src/xspice/icm/table/mada/eno.c @@ -21,8 +21,9 @@ #include #include -#include "eno.h" +#include "../xspice/icm/dlmain.h" #include "alloc.h" +#include "eno.h" #define SF_MAX(a,b) ((a) < (b) ? (b) : (a)) #define SF_MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -39,16 +40,49 @@ sf_eno_init (int order, /* interpolation order */ int n /* data size */) /*< Initialize interpolation object. >*/ { - sf_eno ent; - int i; + int xrc = 0; + sf_eno ent = (sf_eno) NULL; + + if ((ent = (sf_eno) sf_alloc( + 1, sizeof(*ent))) == (sf_eno) NULL) { + cm_message_printf("Unable to allocate sf_eno structure " + "in sf_eno_init"); + xrc = -1; + goto EXITPOINT; + } - ent = (sf_eno) sf_alloc(1, sizeof(*ent)); ent->order = order; ent->n = n; - ent->diff = (double**) sf_alloc(order, sizeof(double*)); - for (i = 0; i < order; i++) - ent->diff[i] = sf_doublealloc(n - i); + + if ((ent->diff = (double **) sf_alloc( + order, sizeof(double *))) == (double **) NULL) { + cm_message_printf("Unable to allocate diff field " + "in sf_eno_init"); + xrc = -1; + goto EXITPOINT; + } + { + int i; + for (i = 0; i < order; i++) { + if ((ent->diff[i] = sf_doublealloc( + n - i)) == (double *) NULL) { + cm_message_printf("Unable to allocate in sf_eno_init " + "at index %d.", + i); + xrc = -1; + goto EXITPOINT; + } + } + } + +EXITPOINT: + if (xrc != 0) { + if (ent != (sf_eno) NULL) { + sf_eno_close(ent); + ent = (sf_eno) NULL; + } + } return ent; } @@ -56,10 +90,15 @@ void sf_eno_close (sf_eno ent) /*< Free internal storage >*/ { - int i; + if (ent == (sf_eno) NULL) { + return; + } - for (i = 0; i < ent->order; i++) + int i; + const int n = ent->order; + for (i = 0; i < n; i++) { free (ent->diff[i]); + } free (ent->diff); free (ent); } diff --git a/src/xspice/icm/table/mada/eno2.c b/src/xspice/icm/table/mada/eno2.c index 1adb003e0..e8a0cc867 100644 --- a/src/xspice/icm/table/mada/eno2.c +++ b/src/xspice/icm/table/mada/eno2.c @@ -36,23 +36,74 @@ sf_eno2_init (int order, /* interpolation order */ int n1, int n2 /* data dimensions */) /*< Initialize interpolation object >*/ { - sf_eno2 pnt; - int i2; + int xrc = 0; + sf_eno2 pnt = (sf_eno2) NULL; + + if ((pnt = (sf_eno2) sf_alloc( + 1, sizeof(*pnt))) == (sf_eno2) NULL) { + cm_message_printf("Unable to allocate sf_eno2 structure " + "in sf_eno2_init"); + xrc = -1; + goto EXITPOINT; + } - pnt = (sf_eno2) sf_alloc(1, sizeof(*pnt)); pnt->order = order; pnt->n1 = n1; pnt->n2 = n2; pnt->ng = 2 * order - 2; - if (pnt->ng > pnt->n2) + if (pnt->ng > pnt->n2) { cm_message_printf("%s: ng=%d is too big", __FILE__, pnt->ng); - pnt->jnt = sf_eno_init (order, pnt->ng); - pnt->f = sf_doublealloc (pnt->ng); - pnt->f1 = sf_doublealloc (pnt->ng); - pnt->ent = (sf_eno*) sf_alloc(n2, sizeof(sf_eno)); - for (i2 = 0; i2 < n2; i2++) - pnt->ent[i2] = sf_eno_init (order, n1); + xrc = -1; + goto EXITPOINT; + } + if ((pnt->jnt = sf_eno_init(order, pnt->ng)) == (sf_eno) NULL) { + cm_message_printf("Unable to initialize field jnt " + "in sf_eno2_init"); + xrc = -1; + goto EXITPOINT; + } + + if ((pnt->f = sf_doublealloc (pnt->ng)) == (double *) NULL) { + cm_message_printf("Unable to allocate field f in sf_eno2_init()"); + xrc = -1; + goto EXITPOINT; + } + + if ((pnt->f1 = sf_doublealloc (pnt->ng)) == (double *) NULL) { + cm_message_printf("Unable to allocate field f1 in sf_eno2_init()"); + xrc = -1; + goto EXITPOINT; + } + + if ((pnt->ent = (sf_eno *) sf_alloc( + n2, sizeof(sf_eno))) == (sf_eno *) NULL) { + cm_message_printf("Unable to allocate field ent in sf_eno2_init()"); + xrc = -1; + goto EXITPOINT; + } + + { + int i2; + for (i2 = 0; i2 < n2; i2++) { + if ((pnt->ent[i2] = sf_eno_init( + order, n1)) == (sf_eno) NULL) { + cm_message_printf("Unable to initialize field ent[%d] " + "in sf_eno3_init()", + i2); + xrc = -1; + goto EXITPOINT; + } + } + } + +EXITPOINT: + if (xrc != 0) { + if (pnt != (sf_eno2) NULL) { + sf_eno2_close(pnt); + pnt = (sf_eno2) NULL; + } + } return pnt; } diff --git a/src/xspice/icm/table/mada/eno3.c b/src/xspice/icm/table/mada/eno3.c index 2942f142c..a5cb76f64 100644 --- a/src/xspice/icm/table/mada/eno3.c +++ b/src/xspice/icm/table/mada/eno3.c @@ -37,27 +37,88 @@ sf_eno3_init(int order, /* interpolation order */ int n1, int n2, int n3 /* data dimensions */) /*< Initialize interpolation object >*/ { - sf_eno3 pnt; - int i2, i3; + int xrc = 0; + sf_eno3 pnt = (sf_eno3) NULL; + + /* Allocate base structrue */ + if ((pnt = (sf_eno3) sf_alloc (1, sizeof *pnt)) == (sf_eno3) NULL) { + cm_message_printf("Unable to allocate sf_eno3 structure " + "in sf_eno3_init"); + xrc = -1; + goto EXITPOINT; + } - pnt = (sf_eno3) sf_alloc (1, sizeof(*pnt)); pnt->order = order; pnt->n1 = n1; pnt->n2 = n2; pnt->n3 = n3; pnt->ng = 2 * order - 2; - if (pnt->ng > n2 || pnt->ng > n3) + + if (pnt->ng > n2 || pnt->ng > n3) { cm_message_printf("%s: ng=%d is too big", __FILE__, pnt->ng); - pnt->jnt = sf_eno2_init (order, pnt->ng, pnt->ng); - pnt->f = sf_doublealloc2 (pnt->ng, pnt->ng); - pnt->f1 = sf_doublealloc2 (pnt->ng, pnt->ng); - pnt->ent = (sf_eno**) sf_alloc (n3, sizeof(sf_eno*)); - for (i3 = 0; i3 < n3; i3++) { - pnt->ent[i3] = (sf_eno*) sf_alloc (n2, sizeof(sf_eno)); - for (i2 = 0; i2 < n2; i2++) - pnt->ent[i3][i2] = sf_eno_init (order, n1); + xrc = -1; + goto EXITPOINT; } + if ((pnt->jnt = sf_eno2_init( + order, pnt->ng, pnt->ng)) == (sf_eno2) NULL) { + cm_message_printf("Unable to initialize field jnt " + "in sf_eno3_init"); + xrc = -1; + goto EXITPOINT; + } + + if ((pnt->f = sf_doublealloc2(pnt->ng, pnt->ng)) == (double **) NULL) { + cm_message_printf("Unable to allocate field f in sf_eno3_init()"); + xrc = -1; + goto EXITPOINT; + } + + if ((pnt->f1 = sf_doublealloc2(pnt->ng, pnt->ng)) == (double **) NULL) { + cm_message_printf("Unable to allocate field f1 in sf_eno3_init()"); + xrc = -1; + goto EXITPOINT; + } + + if ((pnt->ent = (sf_eno **) sf_alloc( + n3, sizeof(sf_eno*))) == (sf_eno **) NULL) { + cm_message_printf("Unable to allocate field ent in sf_eno3_init()"); + xrc = -1; + goto EXITPOINT; + } + + { + int i3; + for (i3 = 0; i3 < n3; i3++) { + if ((pnt->ent[i3] = (sf_eno*) sf_alloc( + n2, sizeof(sf_eno))) == (sf_eno *) NULL) { + cm_message_printf("Unable to allocate field ent[%d] " + "in sf_eno3_init()", i3); + xrc = -1; + goto EXITPOINT; + } + int i2; + for (i2 = 0; i2 < n2; i2++) { + if ((pnt->ent[i3][i2] = sf_eno_init( + order, n1)) == (sf_eno) NULL) { + cm_message_printf("Unable to initialize field " + "ent[%d][%d] in sf_eno3_init()", + i2, i3); + xrc = -1; + goto EXITPOINT; + } + } + } + } + +EXITPOINT: + if (xrc != 0) { + if (pnt != (sf_eno3) NULL) { + sf_eno3_close(pnt); + free(pnt); + pnt = (sf_eno3) NULL; + } + } return pnt; } diff --git a/src/xspice/icm/table/support/gettokens.c b/src/xspice/icm/table/support/gettokens.c index 4566ad932..4c936c017 100644 --- a/src/xspice/icm/table/support/gettokens.c +++ b/src/xspice/icm/table/support/gettokens.c @@ -12,33 +12,11 @@ is returned. The original input string is undisturbed. #include #include -/*=== CONSTANTS ========================*/ - -#define OK 0 -#define FAIL 1 - -/* Type definition for each possible token returned. */ -typedef enum token_type_s { CNV_NO_TOK, CNV_STRING_TOK } Cnv_Token_Type_t; - -extern char *CNVget_token(char **s, Cnv_Token_Type_t *type); - -/*=== MACROS ===========================*/ - -#if defined(__MINGW32__) || defined(_MSC_VER) -#define DIR_PATHSEP "\\" -#else -#define DIR_PATHSEP "/" -#endif - -#if defined(_MSC_VER) -#define strdup _strdup -#define snprintf _snprintf -#endif +#include "gettokens.h" -char * -CNVgettok(char **s) +char *CNVgettok(char **s) { char *buf; /* temporary storage to copy token into */ /*char *temp;*/ /* temporary storage to copy token into */ @@ -52,7 +30,7 @@ CNVgettok(char **s) /* skip over any white space */ - while (isspace_c(**s) || (**s == '=') || + while (isspace(**s) || (**s == '=') || (**s == '(') || (**s == ')') || (**s == ',')) (*s)++; @@ -71,7 +49,7 @@ CNVgettok(char **s) /* or a mess o' characters. */ i = 0; while ( (**s != '\0') && - (! ( isspace_c(**s) || (**s == '=') || + (! ( isspace(**s) || (**s == '=') || (**s == '(') || (**s == ')') || (**s == ',') ) ) ) { @@ -85,7 +63,7 @@ CNVgettok(char **s) /* skip over white space up to next token */ - while (isspace_c(**s) || (**s == '=') || + while (isspace(**s) || (**s == '=') || (**s == '(') || (**s == ')') || (**s == ',')) (*s)++; @@ -98,11 +76,10 @@ CNVgettok(char **s) if (buf) free(buf); return ret_str; -} +} /* end of function CNVgettok */ -/*=== Static CNVget_token ROUTINE =============*/ /* Get the next token from the input string together with its type. The input string pointer @@ -110,9 +87,7 @@ is advanced to the following token and the token from the input string is copied to malloced storage and a pointer to that storage is returned. The original input string is undisturbed. */ - -char * -CNVget_token(char **s, Cnv_Token_Type_t *type) +char * CNVget_token(char **s, Cnv_Token_Type_t *type) { char *ret_str; /* storage for returned string */ @@ -132,4 +107,126 @@ CNVget_token(char **s, Cnv_Token_Type_t *type) break; } return ret_str; -} +} /* end of function CNVget_token */ + + + +/* + Function takes as input a string token from a SPICE + deck and returns a floating point equivalent value. +*/ +int cnv_get_spice_value(char *str, /* IN - The value text e.g. 1.2K */ + double *p_value) /* OUT - The numerical value */ +{ + /* the following were "int4" devices - jpm */ + size_t len; + size_t i; + int n_matched; + + /* A SPICE size line. <= 80 characters plus '\n\0' */ + typedef char line_t[82]; + line_t val_str; + + char c = ' '; + char c1; + + double scale_factor; + double value; + + /* Scan the input string looking for an alpha character that is not */ + /* 'e' or 'E'. Such a character is assumed to be an engineering */ + /* suffix as defined in the Spice 2G.6 user's manual. */ + + len = strlen(str); + if (len > sizeof(val_str) - 1) + len = sizeof(val_str) - 1; + + for (i = 0; i < len; i++) { + c = str[i]; + if (isalpha(c) && (c != 'E') && (c != 'e')) + break; + else if (isspace(c)) + break; + else + val_str[i] = c; + } + val_str[i] = '\0'; + + /* Determine the scale factor */ + + if ((i >= len) || (! isalpha(c))) + scale_factor = 1.0; + else { + c = (char) tolower(c); + + switch (c) { + + case 't': + scale_factor = 1.0e12; + break; + + case 'g': + scale_factor = 1.0e9; + break; + + case 'k': + scale_factor = 1.0e3; + break; + + case 'u': + scale_factor = 1.0e-6; + break; + + case 'n': + scale_factor = 1.0e-9; + break; + + case 'p': + scale_factor = 1.0e-12; + break; + + case 'f': + scale_factor = 1.0e-15; + break; + + case 'm': + i++; + if (i >= len) { + scale_factor = 1.0e-3; + break; + } + c1 = str[i]; + if (!isalpha(c1)) { + scale_factor = 1.0e-3; + break; + } + c1 = (char) toupper(c1); + if (c1 == 'E') + scale_factor = 1.0e6; + else if (c1 == 'I') + scale_factor = 25.4e-6; + else + scale_factor = 1.0e-3; + break; + + default: + scale_factor = 1.0; + } + } + + /* Convert the numeric portion to a float and multiply by the */ + /* scale factor. */ + + n_matched = sscanf(val_str, "%le", &value); + + if (n_matched < 1) { + *p_value = 0.0; + return -1; + } + + *p_value = value * scale_factor; + return 0; +} /* end of function cnv_get_spice_value */ + + + diff --git a/src/xspice/icm/table/support/interp.c b/src/xspice/icm/table/support/interp.c index 3ace153b5..c3c5d2327 100644 --- a/src/xspice/icm/table/support/interp.c +++ b/src/xspice/icm/table/support/interp.c @@ -13,39 +13,33 @@ typedef struct Point3Struct { /* 3d point */ } Point3; typedef Point3 Vector3; -//FIXME -double BilinearInterpolation(double q11, double q12, double q21, double q22, double x1, double x2, double y1, double y2, double x, double y); - /* Function to find the cross over point (the point before which elements are smaller than or equal to x and after which greater than x) - http://www.geeksforgeeks.org/find-k-closest-elements-given-value/ */ -int -findCrossOver(double arr[], int low, int high, double x) + Returns the highest index of an element in arr whose value is less than + or equal to x or 0 if all elements are greater than x. It is assumed that + arr is sorted in order of increasing values. */ +int findCrossOver(double arr[], int n, double x) { - int mid; - // Base cases - if (arr[high] <= x) // x is greater than all - return high; - if (arr[low] > x) // x is smaller than all - return low; + int low = 0; + int high = n; /* 1 more than highest index */ + while (high - low > 1) { + const int mid = (low + high) / 2; + if (arr[mid] > x) { /* search lower */ + high = mid; + } + else { /* search higher */ + low = mid; + } + } /* end of bisecting loop */ - // Find the middle point - mid = (low + high)/2; /* low + (high - low)/2 */ + return low; +} /* end of function findCrossOver */ - /* If x is same as middle element, then return mid */ - if (arr[mid] <= x && arr[mid+1] > x) - return mid; - /* If x is greater than arr[mid], then either arr[mid + 1] - is ceiling of x or ceiling lies in arr[mid+1...high] */ - if (arr[mid] < x) - return findCrossOver(arr, mid+1, high, x); - - return findCrossOver(arr, low, mid - 1, x); -} +#if 0 /* https://helloacm.com/cc-function-to-compute-the-bilinear-interpolation/ */ double BilinearInterpolation(double q11, double q12, double q21, double q22, double x1, double x2, double y1, double y2, double x, double y) @@ -74,7 +68,6 @@ BilinearInterpolation(double q11, double q12, double q21, double q22, double x1, * */ -#if 0 double trilinear(Point3 *p, double *d, int xsize, int ysize, int zsize, double def) @@ -152,13 +145,31 @@ trilinear(Point3 *p, double *d, int xsize, int ysize, int zsize, double def) #endif +double BilinearInterpolation(double x, double y, + int xind, int yind, double **td) +{ + double V00, V10, V01, V11, Vxyz; + + V00 = td[yind][xind]; + V10 = td[yind][xind+1]; + V01 = td[yind+1][xind]; + V11 = td[yind+1][xind+1]; + + Vxyz = V00 * (1 - x) * (1 - y) + + V10 * x * (1 - y) + + V01 * (1 - x) * y + + V11 * x * y; + return Vxyz; +} /* end of function BilinearInterpolation */ + + + /* trilinear interpolation Paul Bourke July 1997 http://paulbourke.net/miscellaneous/interpolation/ */ - -double -TrilinearInterpolation(double x, double y, double z, int xind, int yind, int zind, double ***td) +double TrilinearInterpolation(double x, double y, double z, + int xind, int yind, int zind, double ***td) { double V000, V100, V010, V001, V101, V011, V110, V111, Vxyz; @@ -172,12 +183,18 @@ TrilinearInterpolation(double x, double y, double z, int xind, int yind, int zin V111 = td[zind+1][yind+1][xind+1]; Vxyz = V000 * (1 - x) * (1 - y) * (1 - z) + - V100 * x * (1 - y) * (1 - z) + - V010 * (1 - x) * y * (1 - z) + - V001 * (1 - x) * (1 - y) * z + - V101 * x * (1 - y) * z + - V011 * (1 - x) * y * z + - V110 * x * y * (1 - z) + - V111 * x * y * z; + V100 * x * (1 - y) * (1 - z) + + V010 * (1 - x) * y * (1 - z) + + V001 * (1 - x) * (1 - y) * z + + V101 * x * (1 - y) * z + + V011 * (1 - x) * y * z + + V110 * x * y * (1 - z) + + V111 * x * y * z; return Vxyz; } + + + + + + diff --git a/src/xspice/icm/table/table2D/cfunc.mod b/src/xspice/icm/table/table2D/cfunc.mod index df8d363a9..77760dae6 100644 --- a/src/xspice/icm/table/table2D/cfunc.mod +++ b/src/xspice/icm/table/table2D/cfunc.mod @@ -62,7 +62,7 @@ NON-STANDARD FEATURES ===============================================================================*/ /*=== INCLUDE FILES ====================*/ - +#include #include #include #include @@ -74,10 +74,21 @@ NON-STANDARD FEATURES #include "mada/eno2.h" -/*=== CONSTANTS ========================*/ +typedef struct { + int ix; /* size of array in x */ + int iy; /* size of array in y */ -#define OK 0 -#define FAIL 1 + sf_eno2 newtable; /* the table, code borrowed from madagascar project */ + + /* Input values corresponding to each index. They define the value + * in the domain at each index value */ + double *xcol; /* array of doubles in x */ + double *ycol; /* array of doubles in y */ + + double **table; /* f(xi, yj) */ +} Table2_Data_t; + +typedef Table2_Data_t Local_Data_t; /*=== MACROS ===========================*/ @@ -100,35 +111,22 @@ struct filesource_state { }; -typedef struct { - int ix; /* size of array in x */ - int iy; /* size of array in y */ - struct filesource_state *state; /* the storage array for the - filesource status. */ - int init_err; - - sf_eno2 newtable; /* the table, code borrowed from madagascar project */ - - double *xcol; /* array of floats in x */ - double *ycol; /* array of floats in y */ - - double **table; - -} Local_Data_t; - -/* Type definition for each possible token returned. */ -typedef enum token_type_s {CNV_NO_TOK, CNV_STRING_TOK} Cnv_Token_Type_t; - -typedef char line_t[82]; /* A SPICE size line. <= 80 characters plus '\n\0' */ /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ -extern int findCrossOver(double arr[], int low, int high, double x); -extern double BilinearInterpolation(double q11, double q12, double q21, double q22, double x1, double x2, double y1, double y2, double x, double y); - +double BilinearInterpolation(double x, double y, + int xind, int yind, double **td); extern char *CNVgettok(char **s); +int cnv_get_spice_value(char *str, double *p_value); +extern int findCrossOver(double arr[], int n, double x); + +static void free_local_data(Table2_Data_t *loc); +static inline double get_local_diff(int n, double *col, int ind); +static Table2_Data_t *init_local_data(const char *filename, int order); + + /*============================================================================== @@ -168,151 +166,23 @@ NON-STANDARD FEATURES ==============================================================================*/ -/*=== Static CNV_get_spice_value ROUTINE =============*/ - -/* - Function takes as input a string token from a SPICE - deck and returns a floating point equivalent value. -*/ -static int -cnv_get_spice_value(char *str, /* IN - The value text e.g. 1.2K */ - double *p_value) /* OUT - The numerical value */ -{ - /* the following were "int4" devices - jpm */ - size_t len; - size_t i; - int n_matched; - line_t val_str; - - char c = ' '; - char c1; - - double scale_factor; - double value; - - /* Scan the input string looking for an alpha character that is not */ - /* 'e' or 'E'. Such a character is assumed to be an engineering */ - /* suffix as defined in the Spice 2G.6 user's manual. */ - - len = strlen(str); - if (len > sizeof(val_str) - 1) - len = sizeof(val_str) - 1; - - for (i = 0; i < len; i++) { - c = str[i]; - if (isalpha_c(c) && (c != 'E') && (c != 'e')) - break; - else if (isspace_c(c)) - break; - else - val_str[i] = c; - } - val_str[i] = '\0'; - - /* Determine the scale factor */ - - if ((i >= len) || !isalpha_c(c)) - scale_factor = 1.0; - else { - - if (isupper_c(c)) - c = tolower_c(c); - - switch (c) { - - case 't': - scale_factor = 1.0e12; - break; - - case 'g': - scale_factor = 1.0e9; - break; - - case 'k': - scale_factor = 1.0e3; - break; - - case 'u': - scale_factor = 1.0e-6; - break; - - case 'n': - scale_factor = 1.0e-9; - break; - - case 'p': - scale_factor = 1.0e-12; - break; - - case 'f': - scale_factor = 1.0e-15; - break; - - case 'm': - i++; - if (i >= len) { - scale_factor = 1.0e-3; - break; - } - c1 = str[i]; - if (!isalpha_c(c1)) { - scale_factor = 1.0e-3; - break; - } - if (islower_c(c1)) - c1 = toupper_c(c1); - if (c1 == 'E') - scale_factor = 1.0e6; - else if (c1 == 'I') - scale_factor = 25.4e-6; - else - scale_factor = 1.0e-3; - break; - - default: - scale_factor = 1.0; - } - } - - /* Convert the numeric portion to a float and multiply by the */ - /* scale factor. */ - - n_matched = sscanf(val_str, "%le", &value); - - if (n_matched < 1) { - *p_value = 0.0; - return FAIL; - } - - *p_value = value * scale_factor; - return OK; -} - -static void -cm_table2D_callback(ARGS, Mif_Callback_Reason_t reason) +static void cm_table2D_callback(ARGS, + Mif_Callback_Reason_t reason) { switch (reason) { case MIF_CB_DESTROY: { - int i; - Local_Data_t *loc = STATIC_VAR (locdata); - if (!loc) - break; - free(loc->state); - for (i = 0; i < loc->iy; i++) - free(loc->table[i]); - free(loc->table); - free(loc->xcol); - free(loc->ycol); - sf_eno2_close (loc->newtable); - free(loc); - STATIC_VAR (locdata) = loc = NULL; + Table2_Data_t *loc = STATIC_VAR(locdata); + if (loc) { + free_local_data(loc); + STATIC_VAR(locdata) = loc = NULL; + } break; - } - } -} + } /* end of case MIF_CB_DESTROY */ + } /* end of switch over reason being called */ +} /* end of function cm_table2D_callback */ @@ -359,7 +229,7 @@ ix iy * x row independent variables x0 x1 x2 x3 ... xix-1 -y column independent variables +* y column independent variables y0 y1 y2 y3 ... yiy-1 * table x0y0 x1y0 x2y0 ... xix-1y0 @@ -374,339 +244,89 @@ x0yiy-1 x1yiy-1 x2yiy-1 ... xix-1yiy-1 /*=== CM_table2D ROUTINE ===*/ -void -cm_table2D(ARGS) /* structure holding parms, inputs, outputs, etc. */ +void cm_table2D(ARGS) /* structure holding parms, inputs, outputs, etc. */ { int size, xind, yind; double xval, yval, xoff, yoff, xdiff, ydiff; double derivval[2], outval; - double q11, q12, q21, q22, x1, x2, y1, y2; - Local_Data_t *loc; /* Pointer to local static data, not to be included + Table2_Data_t *loc; /* Pointer to local static data, not to be included in the state vector */ - Mif_Complex_t ac_gain; size = PORT_SIZE(out); - if (INIT == 1) { - - int i; - int ix = 0, /* elements in a row */ - iy = 0; /* number of rows */ - double **table_data; - double tmp; - char *cFile, *cThisPtr, *cThisLine, *cThisLinePtr; - int isNewline; /* Boolean indicating we've read a CR or LF */ - size_t lFileLen; /* Length of file */ - size_t lFileRead; /* Length of file read in */ - long lIndex; /* Index into cThisLine array */ - int lLineCount; /* Current line number */ - size_t lStartPos; /* Offset of start of current line */ - size_t lTotalChars; /* Total characters read */ - int interporder; /* order of interpolation for eno */ - + if (INIT == 1) { /* Must do initializations */ + STATIC_VAR(locdata) = init_local_data( + PARAM(file), + PARAM(order)); CALLBACK = cm_table2D_callback; - - /* allocate static storage for *loc */ - STATIC_VAR (locdata) = calloc(1, sizeof(Local_Data_t)); - loc = STATIC_VAR (locdata); - - /* Allocate storage for internal state */ - loc->state = (struct filesource_state*) malloc(sizeof(struct filesource_state)); - loc->ix = loc->iy = 0; - - /* open file */ - loc->state->fp = fopen_with_path(PARAM(file), "r"); - loc->state->pos = 0; - loc->state->atend = 0; - if (!loc->state->fp) { - char *lbuffer, *p; - lbuffer = getenv("NGSPICE_INPUT_DIR"); - if (lbuffer && *lbuffer) { - p = (char*) malloc(strlen(lbuffer) + strlen(DIR_PATHSEP) + strlen(PARAM(file)) + 1); - sprintf(p, "%s%s%s", lbuffer, DIR_PATHSEP, PARAM(file)); - loc->state->fp = fopen(p, "r"); - free(p); - } - } - struct stat st; - if (!loc->state->fp || fstat(fileno(loc->state->fp), &st)) { - cm_message_printf("cannot open file %s", PARAM(file)); - free(loc->state); - free(loc); - STATIC_VAR (locdata) = loc = NULL; - return; - } - /* get file length */ - lFileLen = (size_t) st.st_size; - - /* create string to hold the whole file */ - cFile = calloc(lFileLen + 1, sizeof(char)); - /* create another string long enough for file manipulation */ - cThisLine = calloc(lFileLen + 1, sizeof(char)); - if (cFile == NULL || cThisLine == NULL) { - cm_message_printf("Insufficient memory to read file %s", PARAM(file)); - free(loc->state); - free(loc); - STATIC_VAR (locdata) = loc = NULL; - if(cFile) free(cFile); - if(cThisLine) free(cThisLine); - return; - } - /* read whole file into cFile */ - lFileRead = fread(cFile, sizeof(char), lFileLen, loc->state->fp); - fclose(loc->state->fp); - /* Number of chars read may be less than lFileLen, because /r are skipt by 'fread' */ - cFile[lFileRead] = '\0'; - - cThisPtr = cFile; - cThisLinePtr = cThisLine; - lLineCount = 0L; - lTotalChars = 0L; - - while (*cThisPtr) { /* Read until reaching null char */ - - lIndex = 0L; /* Reset counters and flags */ - isNewline = 0; - lStartPos = lTotalChars; - - while (*cThisPtr) { - if (!isNewline) { /* Haven't read a LF yet */ - if (*cThisPtr == '\n') /* This char is LF */ - isNewline = 1; /* Set flag */ - } - else if (*cThisPtr != '\n') /* Already found LF */ - break; /* Done with line */ - - cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ - lTotalChars++; - } - - cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ - lLineCount++; /* Increment the line counter */ - /* continue if comment or empty */ - if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\n') { - lLineCount--; /* we count only real lines */ - continue; - } - - if (lLineCount == 1) { - cnv_get_spice_value(cThisLinePtr, &tmp); - loc->ix = ix = (int) tmp; - /* generate row data structure (x) */ - loc->xcol = (double*) calloc((size_t) ix, sizeof(double)); - } - else if (lLineCount == 2) { - cnv_get_spice_value(cThisLinePtr, &tmp); - loc->iy = iy = (int) tmp; - /* generate column data structure (y) */ - loc->ycol = (double*) calloc((size_t) iy, sizeof(double)); - } - else if (lLineCount == 3) { - char *token = CNVgettok(&cThisLinePtr); - i = 0; - while (token) { - if (i == ix) { - cm_message_printf("Too many numbers in x row."); - loc->init_err = 1; - return; - } - cnv_get_spice_value(token, &loc->xcol[i++]); - free(token); - token = CNVgettok(&cThisLinePtr); - } - if (i < ix) { - cm_message_printf("Not enough numbers in x row."); - loc->init_err = 1; - return; - } - } - else if (lLineCount == 4) { - char *token = CNVgettok(&cThisLinePtr); - i = 0; - while (token) { - if (i == iy) { - cm_message_printf("Too many numbers in y row."); - loc->init_err = 1; - return; - } - cnv_get_spice_value(token, &loc->ycol[i++]); - free(token); - token = CNVgettok(&cThisLinePtr); - } - if (i < iy) { - cm_message_printf("Not enough numbers in y row."); - loc->init_err = 1; - return; - } - /* jump out of while loop to read in the table */ - break; - } - } - - /* generate table core */ - interporder = PARAM(order); - /* boundary limits set to param 'order' aren't recognized, - so limit them here */ - if (interporder < 2) { - cm_message_printf("Parameter Order=%d not possible, set to minimum value 2", interporder); - interporder = 2; - } - /* int order : interpolation order, - int n1, int n2 : data dimensions */ - loc->newtable = sf_eno2_init(interporder, ix, iy); - - /* create table_data in memory */ - /* data [n2][n1] */ - table_data = calloc((size_t) iy, sizeof(double *)); - for (i = 0; i < iy; i++) - table_data[i] = calloc((size_t) ix, sizeof(double)); - - loc->table = table_data; - - /* continue reading from cFile */ - lLineCount = 0; - while (*cThisPtr) { /* Read until reaching null char */ - char *token; - - lIndex = 0L; /* Reset counters and flags */ - isNewline = 0; - lStartPos = lTotalChars; - - while (*cThisPtr) { /* Read until reaching null char */ - - if (!isNewline) { /* Haven't read a LF yet */ - if (*cThisPtr == '\n') /* This char is a LF */ - isNewline = 1; /* Set flag */ - } - - else if (*cThisPtr != '\n') /* Already found LF */ - break; /* Done with line */ - - cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ - lTotalChars++; - } - - cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ - lLineCount++; /* Increment the line counter */ - /* continue if comment or empty */ - if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\0') { - if (lTotalChars >= lFileLen) { - cm_message_printf("Not enough data in file %s", PARAM(file)); - loc->init_err = 1; - return; - } - lLineCount--; /* we count only real lines */ - continue; - } - token = CNVgettok(&cThisLinePtr); - i = 0; - while (token) { - double tmpval; - if (i == ix) { - cm_message_printf("Too many numbers in y row no. %d.", lLineCount); - loc->init_err = 1; - return; - } - - /* read table core from cFile, fill local static table structure table_data */ - cnv_get_spice_value(token, &tmpval); - table_data[lLineCount - 1][i++] = tmpval; - free(token); - token = CNVgettok(&cThisLinePtr); - } - if (i < ix) { - cm_message_printf("Not enough numbers in y row no. %d.", lLineCount); - loc->init_err = 1; - return; - } - } - - /* fill table data into eno2 structure */ - sf_eno2_set (loc->newtable, table_data /* data [n2][n1] */); - - /* free the file memory allocated */ - free(cFile); - free(cThisLine); - } /* end of initialization "if (INIT == 1)" */ - - loc = STATIC_VAR (locdata); + } /* return immediately if there was an initialization error */ - if (!loc || loc->init_err == 1) + if ((loc = STATIC_VAR(locdata)) == (Table2_Data_t *) NULL) { return; + } - /* get input x, y, - find corresponding indices, - get x and y offsets, - call interpolation function with value and derivative */ + /* get input x, y; + find corresponding indices; + get x and y offsets; + call interpolation functions with value and derivative */ xval = INPUT(inx); yval = INPUT(iny); - /* find index */ + /* check table ranges */ if (xval < loc->xcol[0] || xval > loc->xcol[loc->ix - 1]) { - if (PARAM(verbose) > 0) + if (PARAM(verbose) > 0) { cm_message_printf("x value %g exceeds table limits,\n" - " please enlarge range of your table", - xval); + " please enlarge range of your table", + xval); + } return; } if (yval < loc->ycol[0] || yval > loc->ycol[loc->iy - 1]) { - if (PARAM(verbose) > 0) + if (PARAM(verbose) > 0) { cm_message_printf("y value %g exceeds table limits,\n" - " please enlarge range of your table", - yval); + " please enlarge range of your table", + yval); + } return; } + + /*** find indices where interpolation will be done ***/ /* something like binary search to get the index */ - xind = findCrossOver(loc->xcol, 0, loc->ix - 1, xval); - /* find index with minimum distance between xval and row value */ - if (fabs(loc->xcol[xind + 1] - xval) < fabs(xval - loc->xcol[xind])) - xind++; + xind = findCrossOver(loc->xcol, loc->ix, xval); xoff = xval - loc->xcol[xind]; - yind = findCrossOver(loc->ycol, 0, loc->iy - 1, yval); - /* find index with minimum distance between yval and column value */ - if (fabs(loc->ycol[yind + 1] - yval) < fabs(yval - loc->ycol[yind])) - yind++; + yind = findCrossOver(loc->ycol, loc->iy, yval); yoff = yval - loc->ycol[yind]; - /* find local difference around index of independent row and column values */ - if (xind == loc->ix - 1) - xdiff = loc->xcol[xind] - loc->xcol[xind - 1]; - else if (xind == 0) - xdiff = loc->xcol[xind + 1] - loc->xcol[xind]; - else - xdiff = 0.5 * (loc->xcol[xind + 1] - loc->xcol[xind - 1]); - - if (yind == loc->iy - 1) - ydiff = loc->ycol[yind] - loc->ycol[yind - 1]; - else if (yind == 0) - ydiff = loc->ycol[yind + 1] - loc->ycol[yind]; - else - ydiff = 0.5 * (loc->ycol[yind + 1] - loc->ycol[yind - 1]); + /* Find local difference around index of independent row and + * column values */ + xdiff = get_local_diff(loc->ix, loc->xcol, xind); + ydiff = get_local_diff(loc->iy, loc->ycol, yind); /* Essentially non-oscillatory (ENO) interpolation to obtain the derivatives only. Using outval for now yields ngspice op non-convergence */ - sf_eno2_apply (loc->newtable, - xind, yind, /* grid location */ - xoff, yoff, /* offset from grid */ - &outval, /* output data value */ - derivval, /* output derivatives [2] */ - DER /* what to compute [FUNC, DER, BOTH] */ - ); + sf_eno2_apply(loc->newtable, + xind, yind, /* grid location */ + xoff, yoff, /* offset from grid */ + &outval, /* output data value */ + derivval, /* output derivatives [2] */ + DER /* what to compute [FUNC, DER, BOTH] */ + ); - /* bilinear interpolation to obtain the output value */ - xind = findCrossOver(loc->xcol, 0, loc->ix - 1, xval); - yind = findCrossOver(loc->ycol, 0, loc->iy - 1, yval); - x1 = loc->xcol[xind]; - x2 = loc->xcol[xind + 1]; - y1 = loc->ycol[yind]; - y2 = loc->ycol[yind + 1]; - q11 = loc->table[yind][xind]; - q12 = loc->table[yind + 1][xind]; - q21 = loc->table[yind][xind + 1]; - q22 = loc->table[yind + 1][xind + 1]; - outval = BilinearInterpolation(q11, q12, q21, q22, x1, x2, y1, y2, xval, yval); + /* xind and yind may become too large */ + if (xind == loc->ix - 1) { + --xind; + } + if (yind == loc->iy - 1) { + --yind; + } + + /* Overwrite outval from sf_eno2_apply by bilinear interpolation */ + outval = BilinearInterpolation( + xoff / (loc->xcol[xind + 1] - loc->xcol[xind]), + yoff / (loc->ycol[yind + 1] - loc->ycol[yind]), + xind, yind, loc->table); if (ANALYSIS != MIF_AC) { double xderiv, yderiv, outv; @@ -717,10 +337,14 @@ cm_table2D(ARGS) /* structure holding parms, inputs, outputs, etc. */ yderiv = PARAM(gain) * derivval[1] / ydiff; PARTIAL(out, iny) = yderiv; - if (PARAM(verbose) > 1) - cm_message_printf("\nI: %g, xval: %g, yval: %g, xderiv: %g, yderiv: %g", outv, xval, yval, xderiv, yderiv); + if (PARAM(verbose) > 1) { + cm_message_printf("\nI: %g, xval: %g, yval: %g, " + "xderiv: %g, yderiv: %g", + outv, xval, yval, xderiv, yderiv); + } } else { + Mif_Complex_t ac_gain; ac_gain.real = PARAM(gain) * derivval[0] / xdiff; ac_gain.imag= 0.0; AC_GAIN(out, inx) = ac_gain; @@ -728,5 +352,388 @@ cm_table2D(ARGS) /* structure holding parms, inputs, outputs, etc. */ ac_gain.imag= 0.0; AC_GAIN(out, iny) = ac_gain; } +} /* end of function cm_table2D */ + + + +/* This function initializes local data */ +static Table2_Data_t *init_local_data(const char *filename, int order) +{ + int xrc = 0; + int ix = 0, /* elements in a row */ + iy = 0; /* number of rows */ + + double **table_data; + double tmp; + FILE *fp = (FILE *) NULL; /* Handle to file */ + char *cFile = (char *) NULL; + char *cThisLine = (char *) NULL; + char *cThisPtr, *cThisLinePtr; + size_t lFileLen; /* Length of file */ + size_t lFileRead; /* Length of file read in */ + int lLineCount; /* Current line number */ + size_t lTotalChar; /* Total characters read */ + int interporder; /* order of interpolation for eno */ + Table2_Data_t *loc = (Table2_Data_t *) NULL; /* local data */ + + + /* Allocate static storage for *loc */ + if ((loc = (Table2_Data_t *) calloc(1, + sizeof(Table2_Data_t))) == (Table2_Data_t *) NULL) { + cm_message_printf("cannot allocate memory for lookup table."); + xrc = -1; + goto EXITPOINT; + } + + /* Init row and column counts to 0 (actually already were due + * to calloc) */ + loc->ix = loc->iy = 0; + + /* open file */ + fp = fopen_with_path(filename, "r"); + if (!fp) { /* Standard open attempt failed */ + const char * const lbuffer = getenv("NGSPICE_INPUT_DIR"); + if (lbuffer && *lbuffer) { + char * const p = (char *) malloc(strlen(lbuffer) + + strlen(DIR_PATHSEP) + + strlen(filename) + 1); + if (p == (char *) NULL) { + cm_message_printf("cannot allocate buffer to " + "attempt alternate file open."); + xrc = -1; + goto EXITPOINT; + } + (void) sprintf(p, "%s%s%s", + lbuffer, DIR_PATHSEP, filename); + fp = fopen(p, "r"); + free(p); + } + } + + /* Test for valid file pointer */ + if (!fp) { + cm_message_printf("cannot open file %s", filename); + xrc = -1; + goto EXITPOINT; + } + + /* Find the size of the data file */ + { + struct stat st; + if (fstat(fileno(fp), &st)) { + cm_message_printf("cannot get length of file %s", + filename); + xrc = -1; + goto EXITPOINT; + } + /* Copy file length */ + lFileLen = (size_t) st.st_size; + } + + /* create string to hold the whole file */ + cFile = calloc(lFileLen + 1, sizeof(char)); + /* create another string long enough for file manipulation */ + cThisLine = calloc(lFileLen + 1, sizeof(char)); + if (cFile == NULL || cThisLine == NULL) { + cm_message_printf("Insufficient memory to read file %s", + filename); + xrc = -1; + goto EXITPOINT; + } + + /* read whole file into cFile */ + { + /* Number of chars read may be less than lFileLen, because /r are + * skipped by 'fread' when file opened in text mode */ + lFileRead = fread(cFile, sizeof(char), lFileLen, fp); + const int file_error = ferror(fp); + fclose(fp); /* done with file */ + if (file_error) { + cm_message_printf("Error reading data file %s", filename); + xrc = -1; + goto EXITPOINT; + } + } + /* Number of chars read may be less than lFileLen, because /r are + * skipped by 'fread' when file opened in text mode */ + cFile[lFileRead] = '\0'; + + cThisPtr = cFile; + cThisLinePtr = cThisLine; + lLineCount = 0L; + lTotalChar = 0L; + + while (*cThisPtr) { /* Read until reaching null char */ + long lIndex = 0L; /* Index into cThisLine array */ + bool isNewline = false; /* Boolean indicating read a CR or LF */ + + while (*cThisPtr) { /* Read until reaching null char */ + if (!isNewline) { /* Haven't read a LF yet */ + if (*cThisPtr == '\n') { /* This char is a LF */ + isNewline = true; /* Set flag */ + } + } + else if (*cThisPtr != '\n') { /* Already found LF */ + break; /* Done with line */ + } + + /* Add char to output and increment */ + cThisLinePtr[lIndex++] = *cThisPtr++; + lTotalChar++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + lLineCount++; /* Increment the line counter */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\n') { + lLineCount--; /* we count only real lines */ + continue; + } + + if (lLineCount == 1) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->ix = ix = (int) tmp; + /* generate row data structure (x) */ + if ((loc->xcol = (double *) calloc((size_t) ix, + sizeof(double))) == (double *) NULL) { + cm_message_printf("Unable to allocate row structure."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 2) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->iy = iy = (int) tmp; + /* generate column data structure (y) */ + if ((loc->ycol = (double *) calloc((size_t) iy, + sizeof(double))) == (double *) NULL) { + cm_message_printf("Unable to allocate colum structure."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 3) { + char *token = CNVgettok(&cThisLinePtr); + int i = 0; + while (token) { + if (i == ix) { + cm_message_printf("Too many numbers in x row."); + xrc = -1; + goto EXITPOINT; + } + cnv_get_spice_value(token, &loc->xcol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in x row."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 4) { + char *token = CNVgettok(&cThisLinePtr); + int i = 0; + while (token) { + if (i == iy) { + cm_message_printf("Too many numbers in y row."); + xrc = -1; + goto EXITPOINT; + } + cnv_get_spice_value(token, &loc->ycol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < iy) { + cm_message_printf("Not enough numbers in y row."); + xrc = -1; + goto EXITPOINT; + + } + /* jump out of while loop to read in the table */ + break; + } + } + + /* generate table core */ + interporder = order; + /* boundary limits set to param 'order' aren't recognized, + so limit them here */ + if (interporder < 2) { + cm_message_printf("Parameter Order=%d not possible, " + "set to minimum value 2", + interporder); + interporder = 2; + } + /* int order : interpolation order, + int n1, int n2 : data dimensions */ + if ((loc->newtable = sf_eno2_init( + interporder, ix, iy)) == (sf_eno2) NULL) { + cm_message_printf("eno2 initialization failure."); + xrc = -1; + goto EXITPOINT; + + } + + /* create table_data in memory */ + /* data [n2][n1] */ + if ((loc->table = table_data = (double **) calloc((size_t) iy, + sizeof(double *))) == (double **) NULL) { + cm_message_printf("Unable to allocate data table."); + free(cFile); + free(cThisLine); + free_local_data(loc); + return (Local_Data_t *) NULL; + } + + { + int i; + for (i = 0; i < iy; i++) { + if ((table_data[i] = (double *) calloc((size_t) ix, + sizeof(double))) == (double *) NULL) { + cm_message_printf("Unable to allocate data table " + "row %d", i + 1); + free(cFile); + free(cThisLine); + free_local_data(loc); + return (Local_Data_t *) NULL; + } + } + } + + loc->table = table_data; /* give to local data structure */ + + + /* continue reading f(x,y) values from cFile */ + lLineCount = 0; + while (*cThisPtr) { /* Read until reaching null char */ + char *token; + long int lIndex = 0; /* Index into cThisLine array */ + bool isNewline = 0; + + while (*cThisPtr) { /* Read until reaching null char */ + + if (!isNewline) { /* Haven't read a LF yet */ + if (*cThisPtr == '\n') /* This char is a LF */ + isNewline = 1; /* Set flag */ + } + + else if (*cThisPtr != '\n') { /* Already found LF */ + break; /* Done with line */ + } + + /* Add char to output and increment */ + cThisLinePtr[lIndex++] = *cThisPtr++; + lTotalChar++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + lLineCount++; /* Increment the line counter */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\0') { + if (lTotalChar >= lFileLen) { + cm_message_printf("Not enough data in file %s", + filename); + free(cFile); + free(cThisLine); + free_local_data(loc); + return (Local_Data_t *) NULL; + } + lLineCount--; /* we count only real lines */ + continue; + } + token = CNVgettok(&cThisLinePtr); + { + int i = 0; + while (token) { + double tmpval; + if (i == ix) { + cm_message_printf("Too many numbers in y row no. %d.", + lLineCount); + xrc = -1; + goto EXITPOINT; + } + + /* read table core from cFile, fill local static table + * structure table_data */ + cnv_get_spice_value(token, &tmpval); + table_data[lLineCount - 1][i++] = tmpval; + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in y row no. %d.", + lLineCount); + xrc = -1; + goto EXITPOINT; + } + } + } /* end of loop over characters read from file */ + + /* fill table data into eno2 structure */ + sf_eno2_set(loc->newtable, table_data /* data [n2][n1] */); + +EXITPOINT: + /* free the file and memory allocated */ + if (cFile != (char *) NULL) { + free(cFile); + } + if (cThisLine != (char *) NULL) { + free(cThisLine); + } + if (fp != (FILE *) NULL) { + (void) fclose(fp); + } + + /* On error free any initialization that was started */ + if (xrc != 0) { + if (loc != (Table2_Data_t *) NULL) { + free_local_data(loc); + loc = (Table2_Data_t *) NULL; + } + } + return loc; +} /* end of function init_local_data */ + + + +/* Free memory allocations in Local_Data_t structure */ +static void free_local_data(Table2_Data_t *loc) +{ + if (loc == (Table2_Data_t *) NULL) { + return; + } + + /* Free data table and related values */ + if (loc->table) { + int i; + int n_y = loc->iy; + for (i = 0; i < n_y; i++) { + free(loc->table[i]); + } + + free(loc->table); + } + + free(loc->xcol); + free(loc->ycol); + sf_eno2_close(loc->newtable); + free(loc); +} /* end of function free_local_data */ + + + +/* Finds difference between column values */ +static inline double get_local_diff(int n, double *col, int ind) +{ + if (ind >= n - 1) { + return col[n - 1] - col[n - 2]; + } + if (ind <= 0) { + return col[1] - col[0]; + } + return 0.5 * (col[ind + 1] - col[ind - 1]); +} /* end of function get_local_diff */ + + -} diff --git a/src/xspice/icm/table/table3D/cfunc.mod b/src/xspice/icm/table/table3D/cfunc.mod index 9fe1cf5b1..d354cc9c3 100644 --- a/src/xspice/icm/table/table3D/cfunc.mod +++ b/src/xspice/icm/table/table3D/cfunc.mod @@ -62,7 +62,7 @@ NON-STANDARD FEATURES ===============================================================================*/ /*=== INCLUDE FILES ====================*/ - +#include #include #include #include @@ -72,13 +72,27 @@ NON-STANDARD FEATURES #include #include +#include "support/gettokens.h" #include "mada/eno2.h" #include "mada/eno3.h" -/*=== CONSTANTS ========================*/ +typedef struct { + int ix; /* size of array in x */ + int iy; /* size of array in y */ + int iz; /* size of array in z */ -#define OK 0 -#define FAIL 1 + sf_eno3 newtable; /* the table, code borrowed from madagascar project */ + + /* Input values corresponding to each index. They define the value + * in the domain at each index value */ + double *xcol; /* array of doubles in x */ + double *ycol; /* array of doubles in y */ + double *zcol; /* array of doubles in z */ + + double ***table; /* f(xi, yj, zk) */ +} Table3_Data_t; + +typedef Table3_Data_t Local_Data_t; /*=== MACROS ===========================*/ @@ -94,47 +108,21 @@ NON-STANDARD FEATURES /*=== LOCAL VARIABLES & TYPEDEFS =======*/ -struct filesource_state { - FILE *fp; - long pos; - unsigned char atend; -}; -typedef struct { - - int ix; /* size of array in x */ - int iy; /* size of array in y */ - int iz; /* size of array in z */ - - struct filesource_state *state; /* the storage array for the - filesource status. */ - - int init_err; - - sf_eno3 newtable; /* the table, code borrowed from madagascar project */ - - double *xcol; /* array of doubles in x */ - double *ycol; /* array of doubles in y */ - double *zcol; /* array of doubles in z */ - - double ***table; - -} Local_Data_t; - -/*********************/ -/* 3d geometry types */ -/*********************/ - -typedef char line_t[82]; /* A SPICE size line. <= 80 characters plus '\n\0' */ /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ -extern int findCrossOver(double arr[], int low, int high, double x); - -extern double TrilinearInterpolation(double x, double y, double z, int xind, int yind, int zind, double ***td); - extern char *CNVgettok(char **s); +extern double TrilinearInterpolation(double x, double y, double z, int xind, int yind, int zind, double ***td); +int cnv_get_spice_value(char *str, double *p_value); +extern int findCrossOver(double arr[], int n, double x); + +static void free_local_data(Table3_Data_t *loc); +static inline double get_local_diff(int n, double *col, int ind); +static Table3_Data_t *init_local_data(const char *filename, int order); + + /*============================================================================== @@ -174,156 +162,25 @@ NON-STANDARD FEATURES ==============================================================================*/ -/*=== Static CNV_get_spice_value ROUTINE =============*/ - -/* - Function takes as input a string token from a SPICE - deck and returns a floating point equivalent value. -*/ -static int -cnv_get_spice_value(char *str, /* IN - The value text e.g. 1.2K */ - double *p_value) /* OUT - The numerical value */ -{ - /* the following were "int4" devices - jpm */ - size_t len; - size_t i; - int n_matched; - line_t val_str; - char c = ' '; - char c1; - - double scale_factor; - double value; - - /* Scan the input string looking for an alpha character that is not */ - /* 'e' or 'E'. Such a character is assumed to be an engineering */ - /* suffix as defined in the Spice 2G.6 user's manual. */ - - len = strlen(str); - if (len > sizeof(val_str) - 1) - len = sizeof(val_str) - 1; - - for (i = 0; i < len; i++) { - c = str[i]; - if (isalpha_c(c) && (c != 'E') && (c != 'e')) - break; - else if (isspace_c(c)) - break; - else - val_str[i] = c; - } - val_str[i] = '\0'; - - /* Determine the scale factor */ - - if ((i >= len) || (! isalpha_c(c))) - scale_factor = 1.0; - else { - - if (isupper_c(c)) - c = tolower_c(c); - - switch (c) { - - case 't': - scale_factor = 1.0e12; - break; - - case 'g': - scale_factor = 1.0e9; - break; - - case 'k': - scale_factor = 1.0e3; - break; - - case 'u': - scale_factor = 1.0e-6; - break; - - case 'n': - scale_factor = 1.0e-9; - break; - - case 'p': - scale_factor = 1.0e-12; - break; - - case 'f': - scale_factor = 1.0e-15; - break; - - case 'm': - i++; - if (i >= len) { - scale_factor = 1.0e-3; - break; - } - c1 = str[i]; - if (!isalpha_c(c1)) { - scale_factor = 1.0e-3; - break; - } - if (islower_c(c1)) - c1 = toupper_c(c1); - if (c1 == 'E') - scale_factor = 1.0e6; - else if (c1 == 'I') - scale_factor = 25.4e-6; - else - scale_factor = 1.0e-3; - break; - - default: - scale_factor = 1.0; - } - } - - /* Convert the numeric portion to a float and multiply by the */ - /* scale factor. */ - - n_matched = sscanf(val_str, "%le", &value); - - if (n_matched < 1) { - *p_value = 0.0; - return FAIL; - } - - *p_value = value * scale_factor; - return OK; -} - -static void -cm_table3D_callback(ARGS, Mif_Callback_Reason_t reason) +static void cm_table3D_callback(ARGS, + Mif_Callback_Reason_t reason) { switch (reason) { case MIF_CB_DESTROY: { - int i, j; - Local_Data_t *loc = STATIC_VAR (locdata); - if (!loc) - break; - free(loc->state); - - for (i = 0; i < loc->iz; i++) { - for (j = 0; j < loc->iy; j++) - free(loc->table[i][j]); - free(loc->table[i]); + Table3_Data_t *loc = STATIC_VAR(locdata); + if (loc) { + free_local_data(loc); + STATIC_VAR(locdata) = loc = NULL; } - free(loc->table); - free(loc->xcol); - free(loc->ycol); - free(loc->zcol); - sf_eno3_close (loc->newtable); - free(loc); - STATIC_VAR (locdata) = loc = NULL; break; - } - } -} + } /* end of case MIF_CB_DESTROY */ + } /* end of switch over reason being called */ +} /* end of function cm_table2D_callback */ + /*============================================================================== @@ -369,8 +226,10 @@ ix iy * x row independent variables x0 x1 x2 x3 ... xix-1 -y column independent variables +* y column independent variables y0 y1 y2 y3 ... yiy-1 +* z column independent variables +z0 z1 z2 z3 ... ziz-1 * table x0y0 x1y0 x2y0 ... xix-1y0 ... @@ -384,391 +243,105 @@ x0yiy-1 x1yiy-1 x2yiy-1 ... xix-1yiy-1 /*=== CM_table3D ROUTINE ===*/ -void -cm_table3D(ARGS) /* structure holding parms, inputs, outputs, etc. */ +void cm_table3D(ARGS) /* structure holding parms, inputs, outputs, etc. */ { int size, xind, yind, zind; double xval, yval, zval, xoff, yoff, zoff, xdiff, ydiff, zdiff; double derivval[3], outval; - Local_Data_t *loc; /* Pointer to local static data, not to be included + Table3_Data_t *loc; /* Pointer to local static data, not to be included in the state vector */ - Mif_Complex_t ac_gain; size = PORT_SIZE(out); - if (INIT == 1) { - - int i, j; - int ix = 0, /* elements in a row */ - iy = 0, /* number of rows */ - iz = 0; /* number of 2D tables */ - - double ***table_data; - - double tmp; - char *cFile, *cThisPtr, *cThisLine, *cThisLinePtr; - int isNewline; /* Boolean indicating we've read a CR or LF */ - size_t lFileLen; /* Length of file */ - size_t lFileRead; /* Length of file read in */ - long lIndex; /* Index into cThisLine array */ - int lLineCount; /* Current line number */ - size_t lStartPos; /* Offset of start of current line */ - size_t lTotalChars; /* Total characters read */ - int lTableCount; /* Number of tables */ - int interporder; /* order of interpolation for eno */ - + if (INIT == 1) { /* Must do initializations */ + STATIC_VAR(locdata) = init_local_data( + PARAM(file), + PARAM(order)); CALLBACK = cm_table3D_callback; - - /* allocate static storage for *loc */ - STATIC_VAR (locdata) = calloc (1, sizeof(Local_Data_t)); - loc = STATIC_VAR (locdata); - - /* Allocate storage for internal state */ - loc->state = (struct filesource_state*) malloc(sizeof(struct filesource_state)); - loc->ix = loc->iy = loc->iz = 0; - loc->init_err = 0; - - /* open file */ - loc->state->fp = fopen_with_path(PARAM(file), "r"); - loc->state->pos = 0; - loc->state->atend = 0; - if (!loc->state->fp) { - char *lbuffer, *pp; - lbuffer = getenv("NGSPICE_INPUT_DIR"); - if (lbuffer && *lbuffer) { - pp = (char*) malloc(strlen(lbuffer) + strlen(DIR_PATHSEP) + strlen(PARAM(file)) + 1); - sprintf(pp, "%s%s%s", lbuffer, DIR_PATHSEP, PARAM(file)); - loc->state->fp = fopen(pp, "r"); - free(pp); - } - } - struct stat st; - if (!loc->state->fp || fstat(fileno(loc->state->fp), &st)) { - cm_message_printf("cannot open file %s", PARAM(file)); - free(loc->state); - free(loc); - STATIC_VAR (locdata) = loc = NULL; - return; - } - /* get file length */ - lFileLen = (size_t) st.st_size; - - /* create string to hold the whole file */ - cFile = calloc(lFileLen + 1, sizeof(char)); - /* create another string long enough for file manipulation */ - cThisLine = calloc(lFileLen + 1, sizeof(char)); - if (cFile == NULL || cThisLine == NULL) { - cm_message_printf("Insufficient memory to read file %s", PARAM(file)); - free(loc->state); - free(loc); - STATIC_VAR (locdata) = loc = NULL; - if(cFile) free(cFile); - if(cThisLine) free(cThisLine); - return; - } - /* read whole file into cFile */ - lFileRead = fread(cFile, sizeof(char), lFileLen, loc->state->fp); - fclose(loc->state->fp); - /* Number of chars read may be less than lFileLen, because /r are skipt by 'fread' */ - cFile[lFileRead] = '\0'; - - cThisPtr = cFile; - cThisLinePtr = cThisLine; - lLineCount = 0L; - lTotalChars = 0L; - - while (*cThisPtr) { /* Read until reaching null char */ - lIndex = 0L; /* Reset counters and flags */ - isNewline = 0; - lStartPos = lTotalChars; - - while (*cThisPtr) { /* Read until reaching null char */ - if (!isNewline) { /* Haven't read a LF yet */ - if (*cThisPtr == '\n') /* This char is a LF */ - isNewline = 1; /* Set flag */ - } - - else if (*cThisPtr != '\n') /* Already found LF */ - break; /* Done with line */ - - cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ - lTotalChars++; - } - - cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ - lLineCount++; /* Increment the line counter */ - /* continue if comment or empty */ - if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\n') { - lLineCount--; /* we count only real lines */ - continue; - } - if (lLineCount == 1) { - cnv_get_spice_value(cThisLinePtr, &tmp); - loc->ix = ix = (int) tmp; - /* generate row data structure (x) */ - loc->xcol = (double*) calloc((size_t) ix, sizeof(double)); - } else if (lLineCount == 2) { - cnv_get_spice_value(cThisLinePtr, &tmp); - loc->iy = iy = (int) tmp; - /* generate column data structure (y) */ - loc->ycol = (double*) calloc((size_t) iy, sizeof(double)); - } else if (lLineCount == 3) { - cnv_get_spice_value(cThisLinePtr, &tmp); - loc->iz = iz = (int) tmp; - /* generate column data structure (y) */ - loc->zcol = (double*) calloc((size_t) iz, sizeof(double)); - } else if (lLineCount == 4) { - char *token = CNVgettok(&cThisLinePtr); - i = 0; - while (token) { - if (i == ix) { - cm_message_printf("Too many numbers in x row."); - loc->init_err = 1; - return; - } - cnv_get_spice_value(token, &loc->xcol[i++]); - free(token); - token = CNVgettok(&cThisLinePtr); - } - if (i < ix) { - cm_message_printf("Not enough numbers in x row."); - loc->init_err = 1; - return; - } - } else if (lLineCount == 5) { - char *token = CNVgettok(&cThisLinePtr); - i = 0; - while (token) { - if (i == iy) { - cm_message_printf("Too many numbers in y row."); - loc->init_err = 1; - return; - } - cnv_get_spice_value(token, &loc->ycol[i++]); - free(token); - token = CNVgettok(&cThisLinePtr); - } - if (i < iy) { - cm_message_printf("Not enough numbers in y row."); - loc->init_err = 1; - return; - } - } else if (lLineCount == 6) { - char *token = CNVgettok(&cThisLinePtr); - i = 0; - while (token) { - if (i == iz) { - cm_message_printf("Too many numbers in z row."); - loc->init_err = 1; - return; - } - cnv_get_spice_value(token, &loc->zcol[i++]); - free(token); - token = CNVgettok(&cThisLinePtr); - } - if (i < iz) { - cm_message_printf("Not enough numbers in z row."); - loc->init_err = 1; - return; - } - /* jump out of while loop to read in the table */ - break; - } - } - - /* generate table core */ - interporder = PARAM(order); - /* boundary limits set to param 'order' aren't recognized, - so limit them here */ - if (interporder < 2) { - cm_message_printf("Parameter Order=%d not possible, set to minimum value 2", interporder); - interporder = 2; - } - /* int order : interpolation order, - int n1, int n2, int n3 : data dimensions */ - loc->newtable = sf_eno3_init(interporder, ix, iy, iz); - - /* create table_data in memory */ - /* data [n3][n2][n1] */ - table_data = calloc((size_t) iy, sizeof(double *)); - for (i = 0; i < iz; i++) { - table_data[i] = calloc((size_t) iy, sizeof(double *)); - for (j = 0; j < iy; j++) - table_data[i][j] = calloc((size_t) ix, sizeof(double)); - } - - loc->table = table_data; - - /* continue reading from cFile */ - for (lTableCount = 0; lTableCount < iz; lTableCount++) { - lLineCount = 0; - while (lLineCount < iy) { - char *token; - - lIndex = 0L; /* Reset counters and flags */ - isNewline = 0; - lStartPos = lTotalChars; - - /* read a line */ - while (*cThisPtr) { /* Read until reaching null char */ - if (!isNewline) { /* Haven't read a CR or LF yet */ - if (*cThisPtr == '\n') /* This char is LF */ - isNewline = 1; /* Set flag */ - } - - else if (*cThisPtr != '\n') /* Already found LF */ - break; /* Done with line */ - - cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ - lTotalChars++; - } - - cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ - /* continue if comment or empty */ - if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\0') { - if (lTotalChars >= lFileLen) { - cm_message_printf("Not enough data in file %s", PARAM(file)); - loc->init_err = 1; - return; - } - continue; - } - token = CNVgettok(&cThisLinePtr); - i = 0; - while (token) { - double tmpval; - - if (i == ix) { - cm_message_printf("Too many numbers in y row no. %d of table %d.", lLineCount, lTableCount); - loc->init_err = 1; - return; - } - - /* read table core from cFile, fill local static table structure table_data */ - cnv_get_spice_value(token, &tmpval); - - table_data[lTableCount][lLineCount][i++] = tmpval; - - free(token); - token = CNVgettok(&cThisLinePtr); - } - if (i < ix) { - cm_message_printf("Not enough numbers in y row no. %d of table %d.", lLineCount, lTableCount); - loc->init_err = 1; - return; - } - lLineCount++; - } - } - - /* fill table data into eno3 structure */ - - sf_eno3_set(loc->newtable, table_data /* data [n3][n2][n1] */); - - /* free file memory allocated */ - free(cFile); - free(cThisLine); - } /* end of initialization "if (INIT == 1)" */ - - loc = STATIC_VAR (locdata); + } /* return immediately if there was an initialization error */ - if (!loc || loc->init_err == 1) + if ((loc = STATIC_VAR(locdata)) == (Table3_Data_t *) NULL) { return; + } /* get input x, y, z; find corresponding indices; get x and y offsets; call interpolation functions with value and derivative */ - xval = INPUT(inx); yval = INPUT(iny); zval = INPUT(inz); /* check table ranges */ if (xval < loc->xcol[0] || xval > loc->xcol[loc->ix - 1]) { - if (PARAM(verbose) > 0) - cm_message_printf("x value %g exceeds table limits, \nplease enlarge range of your table", xval); + if (PARAM(verbose) > 0) { + cm_message_printf("x value %g exceeds table limits,\n" + " please enlarge range of your table", + xval); + } return; } if (yval < loc->ycol[0] || yval > loc->ycol[loc->iy - 1]) { - if (PARAM(verbose) > 0) - cm_message_printf("y value %g exceeds table limits, \nplease enlarge range of your table", yval); + if (PARAM(verbose) > 0) { + cm_message_printf("y value %g exceeds table limits,\n" + " please enlarge range of your table", + yval); + } return; } if (zval < loc->zcol[0] || zval > loc->zcol[loc->iz - 1]) { - if (PARAM(verbose) > 0) - cm_message_printf("z value %g exceeds table limits, \nplease enlarge range of your table", zval); + if (PARAM(verbose) > 0) { + cm_message_printf("z value %g exceeds table limits,\n" + " please enlarge range of your table", + zval); + } return; } - /* find index */ - /* something like binary search to get the index */ - xind = findCrossOver(loc->xcol, 0, loc->ix - 1, xval); - /* find index with minimum distance between xval and row value - if (fabs(loc->xcol[xind + 1] - xval) < fabs(xval - loc->xcol[xind])) - xind++; - */ + /*** find indices where interpolation will be done ***/ + /* something like binary search to get the index */ + xind = findCrossOver(loc->xcol, loc->ix, xval); xoff = xval - loc->xcol[xind]; - yind = findCrossOver(loc->ycol, 0, loc->iy - 1, yval); - /* find index with minimum distance between yval and column value - if (fabs(loc->ycol[yind + 1] - yval) < fabs(yval - loc->ycol[yind])) - yind++; - */ + yind = findCrossOver(loc->ycol, loc->iy, yval); yoff = yval - loc->ycol[yind]; - zind = findCrossOver(loc->zcol, 0, loc->iz - 1, zval); - /* find index with minimum distance between zval and table value - if (fabs(loc->zcol[zind + 1] - zval) < fabs(zval - loc->zcol[zind])) - zind++; - */ + zind = findCrossOver(loc->zcol, loc->iz, zval); zoff = zval - loc->zcol[zind]; - /* find local difference around index of independent row and column values */ - if (xind == loc->ix - 1) - xdiff = loc->xcol[xind] - loc->xcol[xind - 1]; - else if (xind == 0) - xdiff = loc->xcol[xind + 1] - loc->xcol[xind]; - else - xdiff = 0.5 * (loc->xcol[xind + 1] - loc->xcol[xind - 1]); - - if (yind == loc->iy - 1) - ydiff = loc->ycol[yind] - loc->ycol[yind - 1]; - else if (yind == 0) - ydiff = loc->ycol[yind + 1] - loc->ycol[yind]; - else - ydiff = 0.5 * (loc->ycol[yind + 1] - loc->ycol[yind - 1]); - - if (zind == loc->iz - 1) - zdiff = loc->zcol[zind] - loc->zcol[zind - 1]; - else if (zind == 0) - zdiff = loc->zcol[zind + 1] - loc->zcol[zind]; - else - zdiff = 0.5 * (loc->zcol[zind + 1] - loc->zcol[zind - 1]); + /* Find local difference around index of independent row and + * column values */ + xdiff = get_local_diff(loc->ix, loc->xcol, xind); + ydiff = get_local_diff(loc->iy, loc->ycol, yind); + zdiff = get_local_diff(loc->iz, loc->zcol, zind); /* Essentially non-oscillatory (ENO) interpolation to obtain the derivatives only. Using outval for now yields ngspice op non-convergence */ - sf_eno3_apply (loc->newtable, - xind, yind, zind, /* grid location */ - xoff, yoff, zoff, /* offset from grid */ - &outval, /* output data value */ - derivval, /* output derivatives [3] */ - DER /* what to compute [FUNC, DER, BOTH] */ - ); + sf_eno3_apply(loc->newtable, + xind, yind, zind, /* grid location */ + xoff, yoff, zoff, /* offset from grid */ + &outval, /* output data value */ + derivval, /* output derivatives [3] */ + DER /* what to compute [FUNC, DER, BOTH] */ + ); -/* xind yind zind may become too large */ - if (xind == loc->ix - 1) - xind--; - if (yind == loc->iy - 1) - yind--; - if (zind == loc->iz - 1) - zind--; + /* xind and yind may become too large */ + if (xind == loc->ix - 1) { + --xind; + } + if (yind == loc->iy - 1) { + --yind; + } + if (zind == loc->iz - 1) { + --zind; + } /* overwrite outval from sf_eno3_apply by trilinear interpolation */ - outval = TrilinearInterpolation(xoff / (loc->xcol[xind + 1] - loc->xcol[xind]), - yoff / (loc->ycol[yind + 1] - loc->ycol[yind]), - zoff / (loc->zcol[zind + 1] - loc->zcol[zind]), - xind, yind, zind, loc->table); + outval = TrilinearInterpolation( + xoff / (loc->xcol[xind + 1] - loc->xcol[xind]), + yoff / (loc->ycol[yind + 1] - loc->ycol[yind]), + zoff / (loc->zcol[zind + 1] - loc->zcol[zind]), + xind, yind, zind, loc->table); if (ANALYSIS != MIF_AC) { double xderiv, yderiv, zderiv, outv; @@ -781,17 +354,445 @@ cm_table3D(ARGS) /* structure holding parms, inputs, outputs, etc. */ zderiv = PARAM(gain) * derivval[2] / zdiff; PARTIAL(out, inz) = zderiv; - if (PARAM(verbose) > 1) - cm_message_printf("\nI: %g, xval: %g, yval: %g, zval: %g, xderiv: %g, yderiv: %g, zderiv: %g", outv, xval, yval, zval, xderiv, yderiv, zderiv); - } else { + if (PARAM(verbose) > 1) { + cm_message_printf("\nI: %g, xval: %g, yval: %g, zval: %g, " + "xderiv: %g, yderiv: %g, zderiv: %g", + outv, xval, yval, zval, xderiv, yderiv, zderiv); + } + } + else { + Mif_Complex_t ac_gain; ac_gain.real = PARAM(gain) * derivval[0] / xdiff; ac_gain.imag= 0.0; AC_GAIN(out, inx) = ac_gain; ac_gain.real = PARAM(gain) * derivval[1] / ydiff; ac_gain.imag= 0.0; AC_GAIN(out, iny) = ac_gain; + ac_gain.real = PARAM(gain) * derivval[2] / zdiff; + ac_gain.imag= 0.0; + AC_GAIN(out, iny) = ac_gain; } -} +} /* end of function cm_table3D */ + + + +/* This function initializes local data */ +static Table3_Data_t *init_local_data(const char *filename, int interporder) +{ + int xrc = 0; + int ix = 0, /* elements in a row */ + iy = 0, /* number of rows */ + iz = 0; /* number of 2D tables */ + double ***table_data; + double tmp; + FILE *fp = (FILE *) NULL; /* Handle to file */ + char *cFile = (char *) NULL; + char *cThisLine = (char *) NULL; + char *cThisPtr, *cThisLinePtr; + size_t lFileLen; /* Length of file */ + size_t lFileRead; /* Length of file read in */ + int lLineCount; /* Current line number */ + size_t lTotalChar; /* Total characters read */ + int lTableCount; /* Number of tables */ + Table3_Data_t *loc = (Table3_Data_t *) NULL; /* local data */ + + + /* Allocate static storage for *loc */ + if ((loc = (Table3_Data_t *) calloc(1, + sizeof(Table3_Data_t))) == (Table3_Data_t *) NULL) { + cm_message_printf("cannot allocate memory for lookup table."); + xrc = -1; + goto EXITPOINT; + } + + /* Init row and column counts to 0 (actually already were due + * to calloc) */ + loc->ix = loc->iy = loc->iz = 0; + + /* open file */ + fp = fopen_with_path(filename, "r"); + if (!fp) { /* Standard open attempt failed */ + const char * const lbuffer = getenv("NGSPICE_INPUT_DIR"); + if (lbuffer && *lbuffer) { + char * const p = (char *) malloc(strlen(lbuffer) + + strlen(DIR_PATHSEP) + + strlen(filename) + 1); + if (p == (char *) NULL) { + cm_message_printf("cannot allocate buffer to " + "attempt alternate file open."); + xrc = -1; + goto EXITPOINT; + } + (void) sprintf(p, "%s%s%s", + lbuffer, DIR_PATHSEP, filename); + fp = fopen(p, "r"); + free(p); + } + } + + /* Test for valid file pointer */ + if (!fp) { + cm_message_printf("cannot open file %s", filename); + xrc = -1; + goto EXITPOINT; + } + + /* Find the size of the data file */ + { + struct stat st; + if (fstat(fileno(fp), &st)) { + cm_message_printf("cannot get length of file %s", + filename); + xrc = -1; + goto EXITPOINT; + } + /* Copy file length */ + lFileLen = (size_t) st.st_size; + } + + /* create string to hold the whole file */ + cFile = calloc(lFileLen + 1, sizeof(char)); + /* create another string long enough for file manipulation */ + cThisLine = calloc(lFileLen + 1, sizeof(char)); + if (cFile == NULL || cThisLine == NULL) { + cm_message_printf("Insufficient memory to read file %s", + filename); + xrc = -1; + goto EXITPOINT; + } + + /* read whole file into cFile */ + { + /* Number of chars read may be less than lFileLen, because /r are + * skipped by 'fread' when file opened in text mode */ + lFileRead = fread(cFile, sizeof(char), lFileLen, fp); + const int file_error = ferror(fp); + fclose(fp); /* done with file */ + if (file_error) { + cm_message_printf("Error reading data file %s", filename); + xrc = -1; + goto EXITPOINT; + } + } + /* Number of chars read may be less than lFileLen, because /r are + * skipped by 'fread' when file opened in text mode */ + cFile[lFileRead] = '\0'; + + cThisPtr = cFile; + cThisLinePtr = cThisLine; + lLineCount = 0L; + lTotalChar = 0L; + + while (*cThisPtr) { /* Read until reaching null char */ + long lIndex = 0L; /* Index into cThisLine array */ + bool isNewline = false; /* Boolean indicating read a CR or LF */ + + while (*cThisPtr) { /* Read until reaching null char */ + if (!isNewline) { /* Haven't read a LF yet */ + if (*cThisPtr == '\n') { /* This char is a LF */ + isNewline = true; /* Set flag */ + } + } + else if (*cThisPtr != '\n') { /* Already found LF */ + break; /* Done with line */ + } + + /* Add char to output and increment */ + cThisLinePtr[lIndex++] = *cThisPtr++; + lTotalChar++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + lLineCount++; /* Increment the line counter */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\n') { + lLineCount--; /* we count only real lines */ + continue; + } + + if (lLineCount == 1) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->ix = ix = (int) tmp; + /* generate row data structure (x) */ + if ((loc->xcol = (double *) calloc((size_t) ix, + sizeof(double))) == (double *) NULL) { + cm_message_printf("Unable to allocate row structure."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 2) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->iy = iy = (int) tmp; + /* generate column data structure (y) */ + if ((loc->ycol = (double *) calloc((size_t) iy, + sizeof(double))) == (double *) NULL) { + cm_message_printf("Unable to allocate colum structure."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 3) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->iz = iz = (int) tmp; + /* generate column data structure (z) */ + if ((loc->zcol = (double *) calloc((size_t) iz, + sizeof(double))) == (double *) NULL) { + cm_message_printf("Unable to allocate \"z\" structure."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 4) { + char *token = CNVgettok(&cThisLinePtr); + int i = 0; + while (token) { + if (i == ix) { + cm_message_printf("Too many numbers in x row."); + xrc = -1; + goto EXITPOINT; + } + cnv_get_spice_value(token, &loc->xcol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in x row."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 5) { + char *token = CNVgettok(&cThisLinePtr); + int i = 0; + while (token) { + if (i == iy) { + cm_message_printf("Too many numbers in y row."); + xrc = -1; + goto EXITPOINT; + } + cnv_get_spice_value(token, &loc->ycol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < iy) { + cm_message_printf("Not enough numbers in y row."); + xrc = -1; + goto EXITPOINT; + } + } + else if (lLineCount == 6) { + char *token = CNVgettok(&cThisLinePtr); + int i = 0; + while (token) { + if (i == iz) { + cm_message_printf("Too many numbers in z row."); + xrc = -1; + goto EXITPOINT; + } + cnv_get_spice_value(token, &loc->zcol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < iz) { + cm_message_printf("Not enough numbers in z row."); + xrc = -1; + goto EXITPOINT; + } + + /* jump out of while loop to read in the table */ + break; + } + } + + /* generate table core */ + /* boundary limits set to param 'order' aren't recognized, + so limit them here */ + if (interporder < 2) { + cm_message_printf("Parameter Order=%d not possible, " + "set to minimum value 2", + interporder); + interporder = 2; + } + /* int order : interpolation order, + int n1, int n2, int n3 : data dimensions */ + if ((loc->newtable = sf_eno3_init( + interporder, ix, iy, iz)) == (sf_eno3) NULL) { + cm_message_printf("eno3 initialization failure."); + xrc = -1; + goto EXITPOINT; + } + + /* create table_data in memory */ + /* data [n3][n2][n1] */ + if ((loc->table = table_data = (double ***) calloc((size_t) iz, + sizeof(double **))) == (double ***) NULL) { + cm_message_printf("Unable to allocate data table."); + xrc = -1; + goto EXITPOINT; + } + + { + int i, j; + for (i = 0; i < iz; i++) { + if ((table_data[i] = (double **) calloc((size_t) iy, + sizeof(double *))) == (double **) NULL) { + cm_message_printf("Unable to allocate data table " + "z=%d", + i); + xrc = -1; + goto EXITPOINT; + } + for (j = 0; j < iy; j++) { + if ((table_data[i][j] = (double *) calloc((size_t) ix, + sizeof(double))) == (double *) NULL) { + cm_message_printf("Unable to allocate data table " + "z=%d y=%d", + i, j); + xrc = -1; + goto EXITPOINT; + } + } + } + } + + + /* continue reading f(x,y,z) values from cFile */ + for (lTableCount = 0; lTableCount < iz; lTableCount++) { + lLineCount = 0; + while (lLineCount < iy) { + char *token; + long int lIndex = 0; /* Index into cThisLine array */ + bool isNewline = 0; + + while (*cThisPtr) { /* Read until reaching null char */ + if (!isNewline) { /* Haven't read a CR or LF yet */ + if (*cThisPtr == '\n') /* This char is LF */ + isNewline = 1; /* Set flag */ + } + + else if (*cThisPtr != '\n') { /* Already found LF */ + break; /* Done with line */ + } + + cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ + lTotalChar++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\0') { + if (lTotalChar >= lFileLen) { + cm_message_printf("Not enough data in file %s", + filename); + xrc = -1; + goto EXITPOINT; + } + continue; + } + token = CNVgettok(&cThisLinePtr); + { + int i = 0; + while (token) { + double tmpval; + + if (i == ix) { + cm_message_printf("Too many numbers in y row " + "no. %d of table %d.", + lLineCount, lTableCount); + xrc = -1; + goto EXITPOINT; + } + + /* read table core from cFile, fill local static table structure table_data */ + cnv_get_spice_value(token, &tmpval); + + table_data[lTableCount][lLineCount][i++] = tmpval; + + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in y row " + "no. %d of table %d.", + lLineCount, lTableCount); + xrc = -1; + goto EXITPOINT; + } + } + lLineCount++; + } + } /* end of loop over characters read from file */ + + /* fill table data into eno3 structure */ + sf_eno3_set(loc->newtable, table_data /* data [n3][n2][n1] */); + +EXITPOINT: + /* free the file and memory allocated */ + if (cFile != (char *) NULL) { + free(cFile); + } + if (cThisLine != (char *) NULL) { + free(cThisLine); + } + if (fp != (FILE *) NULL) { + (void) fclose(fp); + } + + /* On error free any initialization that was started */ + if (xrc != 0) { + if (loc != (Table3_Data_t *) NULL) { + free_local_data(loc); + loc = (Table3_Data_t *) NULL; + } + } + return loc; +} /* end of function init_local_data */ + + + +/* Free memory allocations in Local_Data_t structure */ +static void free_local_data(Table3_Data_t *loc) +{ + if (loc == (Table3_Data_t *) NULL) { + return; + } + + /* Free data table and related values */ + if (loc->table) { + int i, j; + int n_y = loc->iy; + int n_z = loc->iz; + for (i = 0; i < n_z; i++) { + for (j = 0; j < n_y; j++) { + free(loc->table[i][j]); + } + free(loc->table[i]); + } + + free(loc->table); + } + + free(loc->xcol); + free(loc->ycol); + free(loc->zcol); + sf_eno3_close(loc->newtable); + free(loc); +} /* end of function free_local_data */ + + + +/* Finds difference between column values */ +static inline double get_local_diff(int n, double *col, int ind) +{ + if (ind >= n - 1) { + return col[n - 1] - col[n - 2]; + } + if (ind <= 0) { + return col[1] - col[0]; + } + return 0.5 * (col[ind + 1] - col[ind - 1]); +} /* end of function get_local_diff */ /* These includes add functions from extra source code files, diff --git a/visualc/xspice/analog.vcxproj b/visualc/xspice/analog.vcxproj index 14576b480..4bbc0fd19 100644 --- a/visualc/xspice/analog.vcxproj +++ b/visualc/xspice/analog.vcxproj @@ -203,6 +203,7 @@ + @@ -291,7 +292,10 @@ + + + - \ No newline at end of file + diff --git a/visualc/xspice/digital.vcxproj b/visualc/xspice/digital.vcxproj index f48a5e999..b97b08a73 100644 --- a/visualc/xspice/digital.vcxproj +++ b/visualc/xspice/digital.vcxproj @@ -203,6 +203,7 @@ + ..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) @@ -371,7 +372,10 @@ + + + - \ No newline at end of file + diff --git a/visualc/xspice/spice2poly.vcxproj b/visualc/xspice/spice2poly.vcxproj index d72ac9cda..a784b6016 100644 --- a/visualc/xspice/spice2poly.vcxproj +++ b/visualc/xspice/spice2poly.vcxproj @@ -203,6 +203,7 @@ + @@ -210,7 +211,10 @@ + + + - \ No newline at end of file + diff --git a/visualc/xspice/table.vcxproj b/visualc/xspice/table.vcxproj index ec972ee53..d65d404c4 100644 --- a/visualc/xspice/table.vcxproj +++ b/visualc/xspice/table.vcxproj @@ -94,7 +94,7 @@ Disabled - icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + icm\$(ProjectName);..\src\include;..\..\src\include;..\mada;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;CIDER;%(PreprocessorDefinitions) false @@ -124,7 +124,7 @@ MaxSpeed true - icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + icm\$(ProjectName);..\src\include;..\..\src\include;..\mada;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) @@ -151,7 +151,7 @@ Disabled - icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + icm\$(ProjectName);..\src\include;..\..\src\include;..\mada;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;CIDER;%(PreprocessorDefinitions) false @@ -183,7 +183,7 @@ MaxSpeed true - icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + icm\$(ProjectName);..\src\include;..\..\src\include;..\mada;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) @@ -203,6 +203,7 @@ + ..\..\src\xspice\icm\$(ProjectName);..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) @@ -219,7 +220,11 @@ + + + + - \ No newline at end of file + diff --git a/visualc/xspice/xtradev.vcxproj b/visualc/xspice/xtradev.vcxproj index 31bf6689f..3ff05ff78 100644 --- a/visualc/xspice/xtradev.vcxproj +++ b/visualc/xspice/xtradev.vcxproj @@ -203,6 +203,7 @@ + ..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) @@ -271,7 +272,10 @@ + + + - \ No newline at end of file + diff --git a/visualc/xspice/xtraevt.vcxproj b/visualc/xspice/xtraevt.vcxproj index e83a4c5c6..ddba7fde6 100644 --- a/visualc/xspice/xtraevt.vcxproj +++ b/visualc/xspice/xtraevt.vcxproj @@ -204,6 +204,7 @@ call .\aux-udnfunc.bat $(ProjectName) + @@ -226,7 +227,10 @@ call .\aux-udnfunc.bat $(ProjectName) + + + - \ No newline at end of file + From 33bb874678e5e55cbfbd2ce01a9f3a259cda1c1e Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Wed, 29 Jan 2020 21:06:22 -0500 Subject: [PATCH 18/36] Add const to some parameters, made function static --- src/frontend/arg.c | 29 +++++++++++++++-------------- src/frontend/arg.h | 15 +++++++-------- src/frontend/com_measure2.c | 8 ++++++-- src/frontend/plotting/agraf.c | 8 ++++---- src/frontend/trannoise/1-f-code.c | 8 ++++---- src/spicelib/analysis/acan.c | 2 +- src/spicelib/devices/asrc/asrcext.h | 2 +- src/spicelib/devices/asrc/asrcset.c | 4 ++-- 8 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/frontend/arg.c b/src/frontend/arg.c index deeb90a93..6a09b1c86 100644 --- a/src/frontend/arg.c +++ b/src/frontend/arg.c @@ -17,7 +17,9 @@ Author: 1987 Jeffrey M. Hsu #include "variable.h" -static void common(char *string, struct wordlist *wl, struct comm *command); +static void common(const char *string, const struct wordlist *wl, + const struct comm *command); +static int countargs(const wordlist *wl); /* returns a private copy of the string */ @@ -39,11 +41,10 @@ prompt(FILE *fp) } -int -countargs(wordlist *wl) +static int countargs(const wordlist *wl) { int number = 0; - wordlist *w; + const wordlist *w; for (w = wl; w; w = w->wl_next) number++; @@ -63,42 +64,42 @@ process(wordlist *wlist) void -arg_print(wordlist *wl, struct comm *command) +arg_print(const wordlist *wl, const struct comm *command) { common("which variable", wl, command); } void -arg_plot(wordlist *wl, struct comm *command) +arg_plot(const wordlist *wl, const struct comm *command) { common("which variable", wl, command); } void -arg_load(wordlist *wl, struct comm *command) +arg_load(wordlist *wl, const struct comm *command) { /* just call com_load */ command->co_func(wl); } -void arg_let(wordlist *wl, struct comm *command) +void arg_let(const wordlist *wl, const struct comm *command) { common("which vector", wl, command); } void -arg_set(wordlist *wl, struct comm *command) +arg_set(const wordlist *wl, const struct comm *command) { common("which variable", wl, command); } void -arg_display(wordlist *wl, struct comm *command) +arg_display(const wordlist *wl, const struct comm *command) { NG_IGNORE(wl); NG_IGNORE(command); @@ -108,8 +109,8 @@ arg_display(wordlist *wl, struct comm *command) /* a common prompt routine */ -static void -common(char *string, struct wordlist *wl, struct comm *command) +static void common(const char *string, const struct wordlist *wl, + const struct comm *command) { struct wordlist *w; char *buf; @@ -125,11 +126,11 @@ common(char *string, struct wordlist *wl, struct comm *command) /* O.K. now call fn */ command->co_func(w); } -} +} /* end of function common */ void -outmenuprompt(char *string) +outmenuprompt(const char *string) { fprintf(cp_out, "%s: ", string); fflush(cp_out); diff --git a/src/frontend/arg.h b/src/frontend/arg.h index 268594532..de9ec6f09 100644 --- a/src/frontend/arg.h +++ b/src/frontend/arg.h @@ -7,15 +7,14 @@ #define ngspice_ARG_H char *prompt(FILE *fp); -int countargs(wordlist *wl); wordlist *process(wordlist *wlist); -void arg_print(wordlist *wl, struct comm *command); -void arg_plot(wordlist *wl, struct comm *command); -void arg_load(wordlist *wl, struct comm *command); -void arg_let(wordlist *wl, struct comm *command); -void arg_set(wordlist *wl, struct comm *command); -void arg_display(wordlist *wl, struct comm *command); -void outmenuprompt(char *string); +void arg_print(const wordlist *wl, const struct comm *command); +void arg_plot(const wordlist *wl, const struct comm *command); +void arg_load(wordlist *wl, const struct comm *command); +void arg_let(const wordlist *wl, const struct comm *command); +void arg_set(const wordlist *wl, const struct comm *command); +void arg_display(const wordlist *wl, const struct comm *command); +void outmenuprompt(const char *string); #endif diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 7cc3ac0e5..83c811139 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -54,6 +54,10 @@ typedef enum AnalysisType { AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3, AT_MIN_AT, AT_MAX_AT } ANALYSIS_TYPE_T; +static void measure_errMessage(const char *mName, const char *mFunction, + const char *trigTarg, const char *errMsg, int chk_only); + + /** return precision (either 5 or value of environment variable NGSPICE_MEAS_PRECISION) */ int @@ -69,8 +73,8 @@ measure_get_precision(void) } -static void -measure_errMessage(char *mName, char *mFunction, char *trigTarg, char *errMsg, int chk_only) +static void measure_errMessage(const char *mName, const char *mFunction, + const char *trigTarg, const char *errMsg, int chk_only) { if (!chk_only) { printf("\nError: measure %s %s(%s) : ", mName, mFunction, trigTarg); diff --git a/src/frontend/plotting/agraf.c b/src/frontend/plotting/agraf.c index 5acf73ea7..de750a973 100644 --- a/src/frontend/plotting/agraf.c +++ b/src/frontend/plotting/agraf.c @@ -328,9 +328,9 @@ ft_agraf(double *xlims, double *ylims, struct dvec *xscale, struct plot *plot, s out_printf("%s\n%s\n", line1, line2); - tfree(field); - tfree(line1); - tfree(line2); + txfree(field); + txfree(line1); + txfree(line2); if (!novalue) - tfree(values); + txfree(values); } diff --git a/src/frontend/trannoise/1-f-code.c b/src/frontend/trannoise/1-f-code.c index 9b55dc671..bdbcb2ef3 100644 --- a/src/frontend/trannoise/1-f-code.c +++ b/src/frontend/trannoise/1-f-code.c @@ -104,8 +104,8 @@ f_alpha(int n_pts, int n_exp, double X[], double Q_d, double alpha) #endif - tfree(hfa); - tfree(wfa); + txfree(hfa); + txfree(wfa); /* fft tables will be freed in vsrcaccept.c and isrcaccept.c fftFree(); */ fprintf(stdout, "%d 1/f noise values in time domain created\n", n_pts); @@ -247,6 +247,6 @@ trnoise_state_free(struct trnoise_state *this) { if (!this) return; - tfree(this->oneof); - tfree(this); + txfree(this->oneof); + txfree(this); } diff --git a/src/spicelib/analysis/acan.c b/src/spicelib/analysis/acan.c index 1bef51747..da8d5bd39 100644 --- a/src/spicelib/analysis/acan.c +++ b/src/spicelib/analysis/acan.c @@ -165,7 +165,7 @@ ACan(CKTcircuit *ckt, int restart) NULL, IF_REAL, numNames, nameList, IF_REAL, &acPlot); - tfree(nameList); + txfree(nameList); ipc_send_dcop_prefix(); CKTdump(ckt, 0.0, acPlot); diff --git a/src/spicelib/devices/asrc/asrcext.h b/src/spicelib/devices/asrc/asrcext.h index 70e430b4c..05d42cca5 100644 --- a/src/spicelib/devices/asrc/asrcext.h +++ b/src/spicelib/devices/asrc/asrcext.h @@ -12,6 +12,6 @@ extern int ASRCload(GENmodel *, CKTcircuit *); extern int ASRCparam(int, IFvalue *, GENinstance *, IFvalue *); extern int ASRCpzLoad(GENmodel *, CKTcircuit *, SPcomplex *); extern int ASRCacLoad(GENmodel *, CKTcircuit *); -extern int ASRCsetup(SMPmatrix *, GENmodel *, CKTcircuit *, int *); +extern int ASRCsetup(SMPmatrix *, GENmodel *, CKTcircuit *, const int *); extern int ASRCunsetup(GENmodel *, CKTcircuit *); extern int ASRCtemp(GENmodel *, CKTcircuit *); diff --git a/src/spicelib/devices/asrc/asrcset.c b/src/spicelib/devices/asrc/asrcset.c index f97ff035c..63c67d046 100644 --- a/src/spicelib/devices/asrc/asrcset.c +++ b/src/spicelib/devices/asrc/asrcset.c @@ -21,8 +21,8 @@ Author: 1987 Kanwar Jit Singh * pointers needed later for fast matrix loading */ -int -ASRCsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) +int ASRCsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, + const int *states) { ASRCinstance *here; ASRCmodel *model = (ASRCmodel*) inModel; From 2035442a9f2a898565128d770a551552f3f62bdd Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Fri, 31 Jan 2020 00:39:27 -0500 Subject: [PATCH 19/36] fixed path created by ngdirname in Windows. Also added const to parameters whose arguments do not change and fixed some potential buffer overruns. --- src/frontend/help/help.c | 2 +- src/frontend/inpcom.c | 202 +++++++++++++++++++++------------ src/frontend/parser/glob.c | 2 +- src/include/ngspice/cpextern.h | 4 +- src/include/ngspice/fteext.h | 5 +- src/include/ngspice/ngspice.h | 4 +- src/misc/util.c | 64 ++++++----- 7 files changed, 172 insertions(+), 111 deletions(-) diff --git a/src/frontend/help/help.c b/src/frontend/help/help.c index bee81e218..a02b48980 100644 --- a/src/frontend/help/help.c +++ b/src/frontend/help/help.c @@ -13,7 +13,7 @@ Modified 1999 Emmanuel Rouat #include "ngspice/hlpdefs.h" #include "ngspice/suffix.h" -extern char *cp_tildexpand(char *string); +extern char *cp_tildexpand(const char *string); char *hlp_directory; extern char *hlp_filelist[]; diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index bd2e4d64e..d26fb674a 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -20,6 +20,7 @@ Author: 1985 Wayne A. Christopher #include "ngspice/compatmode.h" #include "ngspice/cpdefs.h" +#include "ngspice/dstring.h" #include "ngspice/dvec.h" #include "ngspice/ftedefs.h" #include "ngspice/fteext.h" @@ -119,7 +120,8 @@ static void inp_stripcomments_line(char *s, bool cs); static void inp_fix_for_numparam( struct names *subckt_w_params, struct card *deck); static void inp_remove_excess_ws(struct card *deck); -static void expand_section_references(struct card *deck, char *dir_name); +static void expand_section_references(struct card *deck, + const char *dir_name); static void inp_grab_func(struct function_env *, struct card *deck); static void inp_fix_inst_calls_for_numparam( struct names *subckt_w_params, struct card *deck); @@ -163,7 +165,7 @@ static void inp_check_syntax(struct card *deck); static char *inp_spawn_brace(char *s); static char *inp_pathresolve(const char *name); -static char *inp_pathresolve_at(char *name, char *dir); +static char *inp_pathresolve_at(const char *name, const char *dir); static char *search_plain_identifier(char *str, const char *identifier); static struct nscope *inp_add_levels(struct card *deck); @@ -184,8 +186,8 @@ struct inp_read_t { int line_number; }; -static struct inp_read_t inp_read( - FILE *fp, int call_depth, char *dir_name, bool comfile, bool intfile); +struct inp_read_t inp_read( FILE *fp, int call_depth, const char *dir_name, + bool comfile, bool intfile); #ifndef XSPICE @@ -302,8 +304,7 @@ static struct card *find_section_definition(struct card *c, char *name) return NULL; } - -static struct library *read_a_lib(char *y, char *dir_name) +static struct library *read_a_lib(const char *y, const char *dir_name) { char *yy, *y_resolved; @@ -355,7 +356,8 @@ static struct library *read_a_lib(char *y, char *dir_name) txfree(y_resolved); return lib; -} +} /* end of function read_a_lib */ + static struct names *new_names(void) @@ -587,8 +589,8 @@ static COMPATMODE_T ngspice_compat_mode(void) remove the 'level' entries from each card *-------------------------------------------------------------------------*/ -struct card *inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile, - bool *expr_w_temper_p) +struct card *inp_readall(FILE *fp, const char *dir_name, + bool comfile, bool intfile, bool *expr_w_temper_p) { struct card *cc; struct inp_read_t rv; @@ -764,8 +766,8 @@ struct card *inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile, } -struct inp_read_t inp_read( - FILE *fp, int call_depth, char *dir_name, bool comfile, bool intfile) +struct inp_read_t inp_read( FILE *fp, int call_depth, const char *dir_name, + bool comfile, bool intfile) /* fp: in, pointer to file to be read, call_depth: in, nested call to fcn dir_name: in, name of directory of file to be read @@ -1266,18 +1268,19 @@ is_plain_filename(const char *p) #endif -FILE *inp_pathopen(char *name, char *mode) +FILE *inp_pathopen(const char *name, const char *mode) { - char *path = inp_pathresolve(name); + char * const path = inp_pathresolve(name); if (path) { FILE *fp = fopen(path, mode); - tfree(path); + txfree(path); return fp; } - return NULL; -} + return (FILE *) NULL; +} /* end of function inp_pathopen */ + /*-------------------------------------------------------------------------* @@ -1287,7 +1290,6 @@ FILE *inp_pathopen(char *name, char *mode) static char *inp_pathresolve(const char *name) { - char buf[BSIZE_SP]; struct variable *v; struct stat st; @@ -1297,10 +1299,17 @@ static char *inp_pathresolve(const char *name) if (cp_getvar("mingwpath", CP_BOOL, NULL, 0) && name[0] == DIR_TERM_LINUX && isalpha_c(name[1]) && name[2] == DIR_TERM_LINUX) { - strcpy(buf, name); + DS_CREATE(ds, 100); + if (ds_cat_str(&ds, name) != 0) { + fprintf(stderr, "Unable to copy string while resolving path"); + controlled_exit(EXIT_FAILURE); + } + char *const buf = ds_get_buf(&ds); buf[0] = buf[1]; buf[1] = ':'; - return inp_pathresolve(buf); + char * const resolved_path = inp_pathresolve(buf); + ds_free(&ds); + return resolved_path; } #endif @@ -1312,55 +1321,77 @@ static char *inp_pathresolve(const char *name) /* fail if this was an absolute filename or if there is no sourcepath var */ if (is_absolute_pathname(name) || - !cp_getvar("sourcepath", CP_LIST, &v, 0)) - return NULL; - - for (; v; v = v->va_next) { - - 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_pathresolve\nAborting...\n"); - controlled_exit(EXIT_FAILURE); - break; - } - - if (stat(buf, &st) == 0) - return copy(buf); + !cp_getvar("sourcepath", CP_LIST, &v, 0)) { + return (char *) NULL; } - return (NULL); -} + { + DS_CREATE(ds, 100); + for (; v; v = v->va_next) { + int rc_ds; + ds_clear(&ds); /* empty buffer */ + + switch (v->va_type) { + case CP_STRING: + cp_wstrip(v->va_string); + rc_ds = ds_cat_printf(&ds, "%s%s%s", + v->va_string, DIR_PATHSEP, name); + break; + case CP_NUM: + rc_ds = ds_cat_printf(&ds, "%d%s%s", + v->va_num, DIR_PATHSEP, name); + break; + case CP_REAL: /* This is foolish */ + rc_ds = ds_cat_printf(&ds, "%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_pathresolve\nAborting...\n"); + controlled_exit(EXIT_FAILURE); + } + + if (rc_ds != 0) { /* unable to build string */ + (void) fprintf(cp_err, + "Unable to build path name in inp_pathresolve"); + controlled_exit(EXIT_FAILURE); + } + + /* Test if the file is found */ + { + const char * const buf = ds_get_buf(&ds); + if (stat(buf, &st) == 0) { + char * const buf_cpy = dup_string( + buf, ds_get_length(&ds)); + ds_free(&ds); + return buf_cpy; + } + /* Else contiue with next attempt */ + } + } /* end of loop over linked variables */ + ds_free(&ds); + } /* end of block trying to find a valid name */ + + return (char *) NULL; +} /* end of function inp_pathresolve */ -static char *inp_pathresolve_at(char *name, char *dir) + +static char *inp_pathresolve_at(const char *name, const char *dir) { - char buf[BSIZE_SP], *end; - /* if name is an absolute path name, * or if we haven't anything to prepend anyway */ - - if (is_absolute_pathname(name) || !dir || !dir[0]) + if (is_absolute_pathname(name) || !dir || !dir[0]) { return inp_pathresolve(name); + } if (name[0] == '~' && name[1] == '/') { - char *y = cp_tildexpand(name); + char * const y = cp_tildexpand(name); if (y) { - char *r = inp_pathresolve(y); - tfree(y); + char * const r = inp_pathresolve(y); + txfree(y); return r; } } @@ -1371,28 +1402,49 @@ static char *inp_pathresolve_at(char *name, char *dir) * sourcepath */ - strcpy(buf, "."); + { + DS_CREATE(ds, 100); + if (ds_cat_printf(&ds, ".%c%s", DIR_TERM, name) != 0) { + (void) fprintf(cp_err, + "Unable to build \".\" path name in inp_pathresolve_at"); + controlled_exit(EXIT_FAILURE); + } + char * const r = inp_pathresolve(ds_get_buf(&ds)); + ds_free(&ds); + if (r != (char *) NULL) { + return r; + } + } - end = strchr(buf, '\0'); - if (end[-1] != DIR_TERM) - *end++ = DIR_TERM; + { + DS_CREATE(ds, 100); + int rc_ds = 0; + rc_ds |= ds_cat_str(&ds, dir); /* copy the dir name */ + const size_t n = ds_get_length(&ds); /* end of copied dir name */ - strcpy(end, name); + /* Append a directory separator if not present already */ + const char ch_last = n > 0 ? dir[n - 1] : '\0'; + if (ch_last != DIR_TERM +#ifdef _WIN32 + && ch_last != DIR_TERM_LINUX +#endif + ) { + rc_ds |= ds_cat_char(&ds, DIR_TERM); + } + rc_ds |= ds_cat_str(&ds, name); /* append the file name */ - char *r = inp_pathresolve(buf); - if (r) + if (rc_ds != 0) { + (void) fprintf(cp_err, "Unable to build \"dir\" path name " + "in inp_pathresolve_at"); + controlled_exit(EXIT_FAILURE); + } + + char * const r = inp_pathresolve(ds_get_buf(&ds)); + ds_free(&ds); return r; + } +} /* end of function inp_pathresolve_at */ - strcpy(buf, dir); - - end = strchr(buf, '\0'); - if (end[-1] != DIR_TERM) - *end++ = DIR_TERM; - - strcpy(end, name); - - return inp_pathresolve(buf); -} /*-------------------------------------------------------------------------* @@ -2746,7 +2798,7 @@ static void inp_remove_excess_ws(struct card *c) } -static struct card *expand_section_ref(struct card *c, char *dir_name) +static struct card *expand_section_ref(struct card *c, const char *dir_name) { char *line = c->line; @@ -2847,7 +2899,7 @@ static struct card *expand_section_ref(struct card *c, char *dir_name) * just those references occuring in the given library section definition */ -static void expand_section_references(struct card *c, char *dir_name) +static void expand_section_references(struct card *c, const char *dir_name) { for (; c; c = c->nextcard) if (ciprefix(".lib", c->line)) diff --git a/src/frontend/parser/glob.c b/src/frontend/parser/glob.c index 4cdd8c8f0..469af46ee 100644 --- a/src/frontend/parser/glob.c +++ b/src/frontend/parser/glob.c @@ -390,7 +390,7 @@ static wordlist_l *brac2(const char *string, /* Expand tildes. */ -char *cp_tildexpand(char *string) +char *cp_tildexpand(const char *string) { /* Attempt to do the tilde expansion */ char * const result = tildexpand(string); diff --git a/src/include/ngspice/cpextern.h b/src/include/ngspice/cpextern.h index 52b88744a..9fa01e23e 100644 --- a/src/include/ngspice/cpextern.h +++ b/src/include/ngspice/cpextern.h @@ -79,8 +79,8 @@ extern void cp_pushcontrol(void); /* glob.c */ -extern bool cp_globmatch(char *p, char *s); -extern char *cp_tildexpand(char *string); +extern bool cp_globmatch(const char *p, const char *s); +extern char *cp_tildexpand(const char *string); extern char cp_cbrac; extern char cp_ccurl; extern char cp_comma; diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 2e892c811..70cea638c 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -214,8 +214,9 @@ extern void inp_source(const char *file); int inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile); extern void inp_casefix(char *string); extern void inp_list(FILE *file, struct card *deck, struct card *extras, int type); -extern struct card *inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile, bool *expr_w_temper); -extern FILE *inp_pathopen(char *name, char *mode); +struct card *inp_readall(FILE *fp, const char *dir_name, + bool comfile, bool intfile, bool *expr_w_temper_p); +extern FILE *inp_pathopen(const char *name, const char *mode); extern char *search_identifier(char *str, const char *identifier, char *str_begin); extern char *find_assignment(const char *s); extern char *find_back_assignment(const char *s, const char *start); diff --git a/src/include/ngspice/ngspice.h b/src/include/ngspice/ngspice.h index 3e1c1c1f4..801d70953 100644 --- a/src/include/ngspice/ngspice.h +++ b/src/include/ngspice/ngspice.h @@ -140,7 +140,7 @@ #ifdef HAS_WINGUI #include "ngspice/wstdio.h" #define HAS_PROGREP -extern void SetAnalyse(char *Analyse, int Percent); +extern void SetAnalyse(const char *Analyse, int Percent); #endif #if defined (__MINGW32__) || defined (__CYGWIN__) || defined (_MSC_VER) @@ -299,7 +299,7 @@ extern int sh_vfprintf(FILE *fd, const char *format, va_list args); extern int sh_fputs(const char *input, FILE *fd); extern int sh_fputc(int input, FILE *fd); extern int sh_putc(int input, FILE *fd); -extern void SetAnalyse(char *analyse, int percent); +extern void SetAnalyse(const char *analyse, int percent); #define HAS_PROGREP diff --git a/src/misc/util.c b/src/misc/util.c index e8f1e58ce..60b5f2e49 100644 --- a/src/misc/util.c +++ b/src/misc/util.c @@ -189,43 +189,51 @@ basename(const char *name) #if defined(HAS_WINGUI) || defined(_MSC_VER) || defined(__MINGW32__) - -char * -ngdirname(const char *name) +/* This function returns the path portion of name or "." if it is NULL. + * The returned string is a new allocation that must be freed by the + * caller */ +char *ngdirname(const char *name) { - char *ret; - const char *end = NULL; - int start = 0; - - if(name && ((name[0] >= 'a' && name[0] <= 'z') || - (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':') - start = 2; - - if(name) { - const char *p = name + start; - for(; *p; p++) - if(*p == '/' || *p == '\\') - end = p; + /* If name not given, return "." */ + if (name == (char *) NULL) { + return dup_string(".", 1); } - if(end && end == name + start) - end++; + /* Offset to start of path name after any drive letter present */ + const int start = (((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':') ? 2 : 0; - if(end) - ret = copy_substring(name, end); - else { - char *p = TMALLOC(char, 4); - ret = p; - if(start) { + /* Find last dir separator, if any, and return the input directory up to + * that separator or including it if it is the 1st char after any drive + *specification. */ + { + const char *p0 = name + start; /* 1st char past drive */ + const char *p; + for (p = p0 + strlen(name + start) - 1; p >= p0; --p) { + const char *ch_cur = *p; + if (ch_cur == '/' || ch_cur == '\\') { /* at last dir sep */ + /* Stop copy at last dir sep or right after if + * it is the first char after any drive spec. + * In the second case return "[drive]" */ + const char * const end = p + (p == p0); + return copy_substring(name, end); + } + } + } + + /* No directory separator found so return "[drive]." */ + { + char * const ret = TMALLOC(char, 2 + start); + char *p = ret; + if (start) { /* Add drive letter if found */ *p++ = name[0]; *p++ = name[1]; } *p++ = '.'; - *p++ = '\0'; + *p = '\0'; + return ret; } - - return ret; -} +} /* end of function ngdirname */ #else From 1d86e5a9c7550945a8bbefcb321017aac875f7ff Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Fri, 31 Jan 2020 01:01:17 -0500 Subject: [PATCH 20/36] fixed singluar/plural agreement in an error message generated by the let command --- src/frontend/com_let.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/frontend/com_let.c b/src/frontend/com_let.c index 2884840fe..150f13788 100644 --- a/src/frontend/com_let.c +++ b/src/frontend/com_let.c @@ -199,11 +199,14 @@ void com_let(wordlist *wl) /* Check # elem required vs available */ if (n_dst_elem != vec_src->v_length) { + const int v_length = vec_src->v_length; + const bool f_1 = v_length == 1; (void) fprintf(cp_err, "Data for an index vector must " "fit exactly. The indexed range required %d " - "elements to fill it, but there were %d " - "elements supplied.\n", - n_dst_elem, vec_src->v_length); + "element%s to fill it, but there %s %d " + "element%s supplied.\n", + n_dst_elem, n_dst_elem == 1 ? "" : "s", + f_1 ? "was" : "were", v_length, f_1 ? "" : "s"); goto quit; } } From ef6c8abb6c50ea314b63282d666cd1a694ee3491 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 12 Feb 2020 22:48:16 +0100 Subject: [PATCH 21/36] Fix of buffer overrun in interpolation at endpoint of interval. Made cfunc.mod for tables more modular. Prevented buffer overrun when building file name. Added error checking for allocation failures in many locations. Made binary search for interpolation more efficient. --- src/xspice/icm/table/support/gettokens.h | 10 ++++++ src/xspice/icm/table/support/table_util.h | 38 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/xspice/icm/table/support/gettokens.h create mode 100644 src/xspice/icm/table/support/table_util.h diff --git a/src/xspice/icm/table/support/gettokens.h b/src/xspice/icm/table/support/gettokens.h new file mode 100644 index 000000000..fef240af4 --- /dev/null +++ b/src/xspice/icm/table/support/gettokens.h @@ -0,0 +1,10 @@ +#ifndef gettokens_h_included +#define gettokens_h_included + +/* Type definition for each possible token returned. */ +typedef enum token_type_s { CNV_NO_TOK, CNV_STRING_TOK } Cnv_Token_Type_t; + +char * CNVget_token(char **s, Cnv_Token_Type_t *type); +char *CNVgettok(char **s); +int cnv_get_spice_value(char *str, double *p_value); +#endif /* gettokens_h_included */ diff --git a/src/xspice/icm/table/support/table_util.h b/src/xspice/icm/table/support/table_util.h new file mode 100644 index 000000000..88bf059e3 --- /dev/null +++ b/src/xspice/icm/table/support/table_util.h @@ -0,0 +1,38 @@ +#include "eno2.h" +#include "eno3.h" + +typedef struct { + int ix; /* size of array in x */ + int iy; /* size of array in y */ + int iz; /* size of array in z */ + + sf_eno3 newtable; /* the table, code borrowed from madagascar project */ + + /* Input values corresponding to each index. They define the value + * in the domain at each index value */ + double *xcol; /* array of doubles in x */ + double *ycol; /* array of doubles in y */ + double *zcol; /* array of doubles in z */ + + double ***table; /* f(xi, yj, zk) */ +} Table3_Data_t; + +void free_local_data(Table3_Data_t *loc); + + +Table3_Data_t *init_local_data(const char *filename, int order); + +/* Finds difference between column values */ +static inline double get_local_diff(int n, double *col, int ind) +{ + if (ind >= n - 1) { + return col[n - 1] - col[n - 2]; + } + if (ind <= 0) { + return col[1] - col[0]; + } + return 0.5 * (col[ind + 1] - col[ind - 1]); +} /* end of function get_local_diff */ + + + From e4c6789bc354c4193aaafbbcb1536ecd8c73926c Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Wed, 29 Jan 2020 02:24:42 -0500 Subject: [PATCH 22/36] Jim Monte's update to cmpp --- src/xspice/cmpp/Makefile.am | 4 +- src/xspice/cmpp/cmpp.h | 19 +- src/xspice/cmpp/main.c | 116 ++- src/xspice/cmpp/pp_ifs.c | 65 +- src/xspice/cmpp/pp_lst.c | 1362 +++++++++++++++++++++++++---------- src/xspice/cmpp/pp_mod.c | 126 +++- src/xspice/cmpp/read_ifs.c | 64 +- src/xspice/cmpp/util.c | 44 +- src/xspice/cmpp/writ_ifs.c | 1120 ++++++++++++++-------------- 9 files changed, 1854 insertions(+), 1066 deletions(-) diff --git a/src/xspice/cmpp/Makefile.am b/src/xspice/cmpp/Makefile.am index c5fce8cc3..c858a3348 100644 --- a/src/xspice/cmpp/Makefile.am +++ b/src/xspice/cmpp/Makefile.am @@ -11,7 +11,7 @@ bin_PROGRAMS = cmpp AM_CPPFLAGS = -I. -I$(srcdir) AM_YFLAGS = -d -cmpp_SOURCES = main.c cmpp.h \ +cmpp_SOURCES = main.c cmpp.h file_buffer.c file_buffer.h\ pp_ifs.c pp_lst.c pp_mod.c read_ifs.c writ_ifs.c util.c \ ifs_lex.l ifs_yacc.y ifs_yacc_y.h \ mod_lex.l mod_yacc.y mod_yacc_y.h @@ -42,7 +42,7 @@ if CROSS_COMPILING BUILT_SOURCES += build/cmpp$(BUILD_EXEEXT) CLEANFILES = build/cmpp$(BUILD_EXEEXT) -BUILD_CMPP_FILES = main.c \ +BUILD_CMPP_FILES = main.c file_buffer.c \ pp_ifs.c pp_lst.c pp_mod.c read_ifs.c writ_ifs.c util.c \ ifs_lex.c ifs_yacc.c \ mod_lex.c mod_yacc.c diff --git a/src/xspice/cmpp/cmpp.h b/src/xspice/cmpp/cmpp.h index e719fa850..27e713ab7 100644 --- a/src/xspice/cmpp/cmpp.h +++ b/src/xspice/cmpp/cmpp.h @@ -38,6 +38,7 @@ NON-STANDARD FEATURES ============================================================================*/ +#include #include #include @@ -49,20 +50,25 @@ NON-STANDARD FEATURES #ifdef _MSC_VER #include #include + +/* If CRT debugging is being used so that crtdbg.h is included, strdup will + * be defined to a debug version. In this case, strdup should not be + * redefined to the standard version. */ +#ifndef strdup #define strdup _strdup +#endif + #define unlink _unlink #define isatty _isatty #define fileno _fileno -#endif +#endif /* _MSC_VER */ /* *********************************************************************** */ #define GET_IFS_TABLE 0 /* Read the entire ifs table */ #define GET_IFS_NAME 1 /* Get the C function name out of the table only */ -#define MAX_PATH_LEN 1024 /* Maximum pathname length */ #define MAX_NAME_LEN 1024 /* Maximum SPICE name length */ -#define MAX_FN_LEN 31 /* Maximum filename length */ /* ******************************************************************** */ @@ -262,7 +268,9 @@ void preprocess_ifs_file(void); void preprocess_lst_files(void); -void preprocess_mod_file(char *filename); +void preprocess_mod_file(const char *filename); + +int output_paths_from_lst_file(const char *filename); void init_error (char *program_name); @@ -272,6 +280,7 @@ void print_error(const char *fmt, ...) __attribute__ ((format (__printf__, 1, 2) #else void print_error(const char *fmt, ...); #endif +void vprint_error(const char *fmt, va_list p); void str_to_lower(char *s); @@ -281,7 +290,7 @@ int read_ifs_file(const char *filename, int mode, Ifs_Table_t *ifs_table); int write_ifs_c_file(const char *filename, Ifs_Table_t *ifs_table); -FILE *fopen_cmpp(const char **path_p, const char *mode); +char *gen_filename(const char *filename, const char *mode); void rem_ifs_table(Ifs_Table_t *ifs_table); diff --git a/src/xspice/cmpp/main.c b/src/xspice/cmpp/main.c index 94ad9fff5..d49f30f77 100644 --- a/src/xspice/cmpp/main.c +++ b/src/xspice/cmpp/main.c @@ -35,25 +35,37 @@ REFERENCED FILES NON-STANDARD FEATURES None. - ============================================================================*/ +#ifdef DEBUG_CMPP +#ifdef _WIN32 +#include +#endif +#endif #include #include #include + #include "cmpp.h" -#define USAGE_MSG "Usage: cmpp [-ifs] [-mod []] [-lst]" +#define USAGE_MSG \ + "Usage: cmpp [-ifs] | [-mod []] | [-lst] | [-p fn.lst]" #define TOO_FEW_ARGS "ERROR - Too few arguments" #define TOO_MANY_ARGS "ERROR - Too many arguments" #define UNRECOGNIZED_ARGS "ERROR - Unrecognized argument" +#ifdef DEBUG_CMPP +#define PRINT_CMPP_INFO(argc, argv) print_cmpp_info(argc, argv); +static void print_cmpp_info(int argc, char **argv); +#else +#define PRINT_CMPP_INFO(argc, argv) +#endif + + /* *********************************************************************** */ - - /* main @@ -61,9 +73,11 @@ Function main checks the validity of the command-line arguments supplied when the program is invoked and calls one of the three major functions as appropriate: - preprocess_ifs_file Process Interface Specification File. - preprocess_mod_file Process Model Definition File. - preprocess_lst_file Process Pathname List Files. + preprocess_ifs_file Process Interface Specification File. + preprocess_mod_file Process Model Definition File. + preprocess_lst_file Process Pathname List Files. + output_paths_from_lst_file Write paths from a list file to stdout + to facilite building the code models depending on the argument. */ @@ -72,11 +86,11 @@ int main( int argc, /* Number of command line arguments */ char *argv[]) /* Command line argument text */ { - init_error (argv[0]); - /* Process command line arguments and vector to appropriate function */ + PRINT_CMPP_INFO(argc, argv) + /* Process command line arguments and vector to appropriate function */ if(argc < 2) { print_error(TOO_FEW_ARGS); print_error(USAGE_MSG); @@ -115,6 +129,26 @@ int main( print_error(USAGE_MSG); exit(1); } + } + else if (strcmp(argv[1],"-p") == 0) { /* Output paths from a list file */ + if (argc == 3) { + const int n_item = output_paths_from_lst_file(argv[2]); + if (n_item < 0) { + print_error("Unable to print paths to stdout"); + exit(-1); + } + exit(n_item); + } + else { /* Wrong number of arguments */ + if (argc < 3) { + print_error(TOO_FEW_ARGS); + } + else { + print_error(TOO_MANY_ARGS); + } + print_error(USAGE_MSG); + exit(1); + } } else { print_error(UNRECOGNIZED_ARGS); @@ -123,5 +157,67 @@ int main( } exit(0); -} +} /* end of function main */ + + + +#ifdef DEBUG_CMPP +/* Print some debugging information for cmpp + * + * With the use of environment variables to locate files, it is helpful + * to know some information about the program when debugging. If the + * build of a code model fails due to cmpp, the macro can be enabled to + * find the information needed to separately debug cmpp */ +static void print_cmpp_info(int argc, char **argv) +{ + /* Print the program and its arguments */ + { + int i; + for (i = 0; i < argc; ++i) { + (void) fprintf(stdout, "%s ", argv[i]); + } + (void) fprintf(stdout, "\n"); + } + +#ifdef _WIN32 + /* Print the current directory */ + { + const DWORD n_char = GetCurrentDirectoryA(0, (char *) NULL); + if (n_char > 0) { + char *p_buf = (char *) malloc(n_char); + if (p_buf != (char *) NULL) { + if (GetCurrentDirectoryA(n_char, p_buf) != 0) { + (void) fprintf(stdout, "Current Directory: \"%s\".\n", + p_buf); + } + free(p_buf); + } + } + } +#endif + + /* Print the CMPP_IDIR environment variable if defined */ + { + const char * const ev = getenv("CMPP_IDIR"); + if (ev) { + (void) fprintf(stdout, "CMPP_IDIR = \"%s\"\n", ev); + } + else { + (void) fprintf(stdout, "CMPP_IDIR is not defined\n"); + } + } + + /* Print the CMPP_ODIR environment variable if defined */ + { + const char * const ev = getenv("CMPP_ODIR"); + if (ev) { + (void) fprintf(stdout, "CMPP_ODIR = \"%s\"\n", ev); + } + else { + (void) fprintf(stdout, "CMPP_ODIR is not defined\n"); + } + } +} /* end of function print_cmpp_info */ +#endif /* #ifdef DEBUG_CMPP */ + diff --git a/src/xspice/cmpp/pp_ifs.c b/src/xspice/cmpp/pp_ifs.c index ce840b0c4..830633fef 100644 --- a/src/xspice/cmpp/pp_ifs.c +++ b/src/xspice/cmpp/pp_ifs.c @@ -42,14 +42,6 @@ NON-STANDARD FEATURES -/* *********************************************************************** */ - -static void txfree(void *ptr) -{ - if(ptr) - free(ptr); -}; - /* preprocess_ifs_file @@ -91,30 +83,51 @@ void preprocess_ifs_file(void) void rem_ifs_table(Ifs_Table_t *ifs_table) { - int i; /* Remove the ifs_table */ - txfree(ifs_table->name.c_fcn_name); - txfree(ifs_table->name.description); - txfree(ifs_table->name.model_name); + free(ifs_table->name.c_fcn_name); + free(ifs_table->name.description); + free(ifs_table->name.model_name); - for(i = 0; i < ifs_table->num_conn; i++) { - txfree(ifs_table->conn[i].name); - txfree(ifs_table->conn[i].description); - txfree(ifs_table->conn[i].default_type); + { + Conn_Info_t * const p_conn = ifs_table->conn; + const int num_conn = ifs_table->num_conn; + int i; + for (i = 0; i < num_conn; ++i) { + Conn_Info_t *p_conn_cur = p_conn + i; + free(p_conn_cur->name); + free(p_conn_cur->description); + free(p_conn_cur->default_type); + } } - for(i = 0; i < ifs_table->num_param; i++) { - txfree(ifs_table->param[i].name); - txfree(ifs_table->param[i].description); + { + Param_Info_t * const p_param = ifs_table->param; + const int num_param = ifs_table->num_param; + int i; + for (i = 0; i < num_param; ++i) { + Param_Info_t *p_param_cur = p_param + i; + free(p_param_cur->name); + free(p_param_cur->description); + } } - for(i = 0; i < ifs_table->num_inst_var; i++) { - txfree(ifs_table->inst_var[i].name); - txfree(ifs_table->inst_var[i].description); + + { + Inst_Var_Info_t * const p_inst_var = ifs_table->inst_var; + const int num_inst_var = ifs_table->num_inst_var; + int i; + for(i = 0; i < num_inst_var; ++i) { + Inst_Var_Info_t *p_inst_var_cur = p_inst_var + i; + free(p_inst_var_cur->name); + free(p_inst_var_cur->description); + } } - txfree(ifs_table->conn); - txfree(ifs_table->param); - txfree(ifs_table->inst_var); -} + + free(ifs_table->conn); + free(ifs_table->param); + free(ifs_table->inst_var); +} /* end of function rem_ifs_table */ + + diff --git a/src/xspice/cmpp/pp_lst.c b/src/xspice/cmpp/pp_lst.c index 01a624a3a..3d321a396 100644 --- a/src/xspice/cmpp/pp_lst.c +++ b/src/xspice/cmpp/pp_lst.c @@ -47,11 +47,15 @@ NON-STANDARD FEATURES ============================================================================*/ -#include "cmpp.h" #include +#include +#include +#include #include #include +#include "cmpp.h" +#include "file_buffer.h" /* *********************************************************************** */ @@ -63,34 +67,56 @@ typedef struct { char *path_name; /* Pathname read from model path file */ char *spice_name; /* Name of model from ifspec.ifs */ char *cfunc_name; /* Name of C fcn from ifspec.ifs */ - bool spice_unique; /* True if spice name unique */ - bool cfunc_unique; /* True if C fcn name unique */ + unsigned int version; /* version of the code model */ } Model_Info_t; typedef struct { char *path_name; /* Pathname read from udn path file */ char *node_name; /* Name of node type */ - bool unique; /* True if node type name unique */ + unsigned int version; /* version of the code model */ } Node_Info_t; - -/* *********************************************************************** */ +/* Structure for uniqueness testing */ +struct Key_src { + const char *key; /* value to compare */ + const char *src; /* source of value */ +}; + + + +/************************************************************************ */ + +static int cmpr_ks(const struct Key_src *ks1, const struct Key_src *ks2); +static void free_model_info(int num_models, Model_Info_t *p_model_info); +static void free_node_info(int num_nodes, Node_Info_t *p_node_info); static int read_modpath(int *num_models, Model_Info_t **model_info); static int read_udnpath(int *num_nodes, Node_Info_t **node_info); static int read_model_names(int num_models, Model_Info_t *model_info); static int read_node_names(int num_nodes, Node_Info_t *node_info); static int check_uniqueness(int num_models, Model_Info_t *model_info, - int num_nodes, Node_Info_t *node_info); + int num_nodes, Node_Info_t *node_info); +static void report_error_spice_name(const struct Key_src *p_ks1, + const struct Key_src *p_ks2); +static void report_error_function_name (const struct Key_src *p_ks1, + const struct Key_src *p_ks2); +static void report_error_udn_name(const struct Key_src *p_ks1, + const struct Key_src *p_ks2); +static bool test_for_duplicates(unsigned int n, struct Key_src *p_ks, + void (*p_error_reporter)(const struct Key_src *p_ks1, + const struct Key_src *p_ks2)); +static inline void trim_slash(size_t *p_n, char *p); static int write_CMextrn(int num_models, Model_Info_t *model_info); static int write_CMinfo(int num_models, Model_Info_t *model_info); +static int write_CMinfo2(int num_models, Model_Info_t *model_info); static int write_UDNextrn(int num_nodes, Node_Info_t *node_info); static int write_UDNinfo(int num_nodes, Node_Info_t *node_info); +static int write_UDNinfo2(int num_nodes, Node_Info_t *node_info); static int write_objects_inc(int num_models, Model_Info_t *model_info, - int num_nodes, Node_Info_t *node_info); + int num_nodes, Node_Info_t *node_info); static int read_udn_type_name(const char *path, char **node_name); @@ -101,7 +127,7 @@ static int read_udn_type_name(const char *path, char **node_name); preprocess_lst_files Function preprocess_lst_files is the top-level driver function for -preprocessing a simulator model path list file (modpath.lst). +preprocessing a simulator model path list file (modpath.lst). This function calls read_ifs_file() requesting it to read and parse the Interface Specification file (ifspec.ifs) to extract the model name and associated C function name and place this @@ -125,20 +151,18 @@ void preprocess_lst_files(void) int num_models; /* The number of models */ int num_nodes; /* The number of user-defined nodes */ - /* Get list of models from model pathname file */ status = read_modpath(&num_models, &model_info); - if(status != 0) { + if (status != 0) { exit(1); } /* Get list of node types from udn pathname file */ status = read_udnpath(&num_nodes, &node_info); - if(status != 0) { + if (status < 0) { exit(1); } - /* Get the spice and C function names from the ifspec.ifs files */ status = read_model_names(num_models, model_info); if(status != 0) { @@ -151,15 +175,12 @@ void preprocess_lst_files(void) exit(1); } - /* Check to be sure the names are unique */ - status = check_uniqueness(num_models, model_info, - num_nodes, node_info); + status = check_uniqueness(num_models, model_info, num_nodes, node_info); if(status != 0) { exit(1); } - /* Write out the CMextrn.h file used to compile SPIinit.c */ status = write_CMextrn(num_models, model_info); if(status != 0) { @@ -171,7 +192,10 @@ void preprocess_lst_files(void) if(status != 0) { exit(1); } - + status = write_CMinfo2(num_models, model_info); + if(status != 0) { + exit(1); + } /* Write out the UDNextrn.h file used to compile SPIinit.c */ status = write_UDNextrn(num_nodes, node_info); @@ -184,7 +208,10 @@ void preprocess_lst_files(void) if(status != 0) { exit(1); } - + status = write_UDNinfo2(num_nodes, node_info); + if(status != 0) { + exit(1); + } /* Write the make_include file used to link the models and */ /* user-defined node functions with the simulator */ @@ -193,17 +220,107 @@ void preprocess_lst_files(void) if(status != 0) { exit(1); } - /* remove model_info and node_info */ - if (model_info) { - if(model_info->cfunc_name) free(model_info->cfunc_name); - if(model_info->path_name) free(model_info->path_name); - if(model_info->spice_name) free(model_info->spice_name); + + /* Free allocations */ + if (model_info != (Model_Info_t *) NULL) { + free_model_info(num_models, model_info); } - if (node_info) { - if(node_info->node_name) free(node_info->node_name); - if(node_info->path_name) free(node_info->path_name); + if (node_info != (Node_Info_t *) NULL) { + free_node_info(num_nodes, node_info); } -} +} /* end of function preprocess_lst_files */ + + + +/* This function parses the supplied .lst file and outputs the paths to + * stdout */ +int output_paths_from_lst_file(const char *filename) +{ + int xrc = 0; + FILEBUF *fbp = (FILEBUF *) NULL; /* for reading MODPATH_FILENAME */ + unsigned int n_path = 0; + + /* Open the file */ + if ((fbp = fbopen(filename, 0)) == (FILEBUF *) NULL) { + print_error("ERROR - Unable to open file \"%s\" to obtain " + "paths: %s", + filename, strerror(errno)); + xrc = -1; + goto EXITPOINT; + } + + bool f_have_path = false; /* do not have a path to store */ + FBTYPE fbtype; + FBOBJ fbobj; + for ( ; ; ) { /* Read items until end of file */ + /* Get the next path if not found yet */ + if (!f_have_path) { + const int rc = fbget(fbp, 0, (FBTYPE *) NULL, &fbtype, &fbobj); + if (rc != 0) { + if (rc == -1) { /* Error */ + print_error("ERROR - Unable to read item to buffer"); + xrc = -1; + goto EXITPOINT; + } + else { /* +1 -- EOF */ + break; + } + } /* end of abnormal case */ + + /* Remove trailing slash if appended to path */ + trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz); + } + + /* Output the file that was found */ + if (fprintf(stdout, "%s\n", fbobj.str_value.sz) < 0) { + print_error("ERROR - Unable to output path name to stdout: %s", + strerror(errno)); + xrc = -1; + goto EXITPOINT; + } + ++n_path; /* 1 more path printed OK */ + + /* Try getting a version. If found, it will be discarded */ + FBTYPE type_wanted = BUF_TYPE_ULONG; + const int rc = fbget(fbp, 1, &type_wanted, &fbtype, &fbobj); + if (rc != 0) { + if (rc == -1) { /* Error */ + print_error("ERROR - Unable to read item to buffer"); + xrc = -1; + goto EXITPOINT; + } + else { /* +1 -- EOF */ + break; + } + } /* end of abnormal case */ + + if (fbtype == BUF_TYPE_ULONG) { /* found version number */ + f_have_path = false; + } + else { /* it was a string, so it is the next path */ + f_have_path = true; + + /* Remove trailing slash if appended to path */ + trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz); + } + } /* end of loop reading items into buffer */ + +EXITPOINT: + /* Close model pathname file and return data read */ + if (fbclose(fbp) != 0) { + print_error("ERROR - Unable to close file with path names: %s", + strerror(errno)); + xrc = -1; + } + + /* Return the path count if no errors */ + if (xrc == 0) { + xrc = (int) n_path; + } + + return xrc; +} /* end of function output_paths_from_lst_file */ + @@ -218,108 +335,169 @@ file, and puts them into an internal data structure for future processing. */ +/* Structure for retrieving data items from the file. These will be either + * names, such as directory names or unsigned integers that are version + * numbers */ +#define N_MODEL_INIT 10 static int read_modpath( - int *num_models, /* Number of model pathnames found */ - Model_Info_t **model_info /* Info about each model */ -) + int *p_num_model_info, /* Number of model pathnames found */ + Model_Info_t **pp_model_info) /* Info about each model */ { - FILE *fp; /* Model pathname file pointer */ - char path[MAX_PATH_LEN+2]; /* space to read pathnames into */ - Model_Info_t *model = NULL; /* temporary pointer to model info */ - - int n; - int i; - int j; - int len; - int line_num; - - const char *filename = MODPATH_FILENAME; - - - /* Initialize number of models to zero in case of error */ - *num_models = 0; + int xrc = 0; + FILEBUF *fbp = (FILEBUF *) NULL; /* for reading MODPATH_FILENAME */ + Model_Info_t *p_model_info = (Model_Info_t *) NULL; + unsigned int n_model_info = 0; + unsigned int n_model_info_alloc = 0; + char *filename = (char *) NULL; /* Open the model pathname file */ - fp = fopen_cmpp(&filename, "r"); - - if (fp == NULL) { - print_error("ERROR - File not found: %s", filename); - return -1; + if ((filename = gen_filename(MODPATH_FILENAME, "r")) == (char *) NULL) { + print_error("ERROR - Unable to build mod path file name"); + xrc = -1; + goto EXITPOINT; + } + /* Open the file using the default buffer size. For debugging, a very + * small value can be used, for example by giving the size as 1, to + * force the function do actions that otherwise would be done rarely + * if at all. */ + if ((fbp = fbopen(filename, 0)) == (FILEBUF *) NULL) { + print_error("ERROR - Unable to open mod path file \"%s\": %s", + filename, strerror(errno)); + xrc = -1; + goto EXITPOINT; } - /* Read the pathnames from the file, one line at a time until EOF */ - n = 0; - line_num = 0; - while( fgets(path, sizeof(path), fp) ) { + /* Allocate initial model info array */ + if ((p_model_info = (Model_Info_t *) malloc(N_MODEL_INIT * + sizeof(Model_Info_t))) == (Model_Info_t *) NULL) { + print_error("ERROR - Unable to allocate initial model array"); + xrc = -1; + goto EXITPOINT; + } + n_model_info_alloc = N_MODEL_INIT; - line_num++; - len = (int) strlen(path); + bool f_have_path = false; /* do not have a path to store */ + FBTYPE fbtype; + FBOBJ fbobj; + for ( ; ; ) { /* Read items until end of file */ + /* Get the next path if not found yet */ + if (!f_have_path) { + const int rc = fbget(fbp, 0, (FBTYPE *) NULL, &fbtype, &fbobj); + if (rc != 0) { + if (rc == -1) { /* Error */ + print_error("ERROR - Unable to read item to buffer"); + xrc = -1; + goto EXITPOINT; + } + else { /* +1 -- EOF */ + break; + } + } /* end of abnormal case */ - /* If line was too long for buffer, exit with error */ - if(len > MAX_PATH_LEN) { - print_error("ERROR - Line %d of %s exceeds %d characters", - line_num, filename, MAX_PATH_LEN); - return -1; + /* Remove trailing slash if appended to path */ + trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz); } - /* Strip white space including newline */ - for(i = 0, j = 0; i < len; ) { - if(isspace_c(path[i])) { - i++; - } - else { - path[j] = path[i]; - i++; - j++; + /* Enlarge model array if full */ + if (n_model_info_alloc == n_model_info) { + n_model_info_alloc *= 2; + void * const p = realloc(p_model_info, + n_model_info_alloc * sizeof(Model_Info_t)); + if (p == NULL) { + print_error("ERROR - Unable to enlarge model array"); + xrc = -1; + goto EXITPOINT; } + p_model_info = (Model_Info_t *) p; } - path[j] = '\0'; - len = j; - - /* Strip trailing '/' if any */ - if(path[len - 1] == '/') - path[--len] = '\0'; - - /* If blank line, continue */ - if(len == 0) - continue; - - /* Make sure pathname is short enough to add a filename at the end */ - if(len > (MAX_PATH_LEN - (MAX_FN_LEN + 1)) ) { - print_error("ERROR - Pathname on line %d of %s exceeds %d characters", - line_num, filename, (MAX_PATH_LEN - (MAX_FN_LEN + 1))); - return -1; - } - - /* Allocate and initialize a new model info structure */ - if(n == 0) - model = (Model_Info_t *) malloc(sizeof(Model_Info_t)); - else - model = (Model_Info_t *) realloc(model, (size_t) (n + 1) * sizeof(Model_Info_t)); - model[n].path_name = NULL; - model[n].spice_name = NULL; - model[n].cfunc_name = NULL; - model[n].spice_unique = true; - model[n].cfunc_unique = true; /* Put pathname into info structure */ - model[n].path_name = (char *) malloc((size_t) (len+1)); - strcpy(model[n].path_name, path); + Model_Info_t * const p_model_info_cur = p_model_info + + n_model_info; - /* Increment count of paths read */ - n++; + if ((p_model_info_cur->path_name = (char *) malloc( + fbobj.str_value.n_char + 1)) == (char *) NULL) { + print_error("ERROR - Unable to allocate path name"); + xrc = -1; + goto EXITPOINT; + } + + strcpy(p_model_info_cur->path_name, fbobj.str_value.sz); + p_model_info_cur->spice_name = (char *) NULL; + p_model_info_cur->cfunc_name = (char *) NULL; + + /* Must set before returning due to EOF. */ + p_model_info_cur->version = 1; + ++n_model_info; + + /* Try getting a version */ + FBTYPE type_wanted = BUF_TYPE_ULONG; + const int rc = fbget(fbp, 1, &type_wanted, &fbtype, &fbobj); + if (rc != 0) { + if (rc == -1) { /* Error */ + print_error("ERROR - Unable to read item to buffer"); + xrc = -1; + goto EXITPOINT; + } + else { /* +1 -- EOF */ + break; + } + } /* end of abnormal case */ + + if (fbtype == BUF_TYPE_ULONG) { /* found version number */ + f_have_path = false; + p_model_info_cur->version = (unsigned int) fbobj.ulong_value; + } + else { /* it was a string, so it is the next path */ + f_have_path = true; + + /* Remove trailing slash if appended to path */ + trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz); + } + } /* end of loop reading items into buffer */ + +EXITPOINT: + /* Close model pathname file and return data read */ + if (fbclose(fbp) != 0) { + print_error("ERROR - Unable to close file with model info: %s", + strerror(errno)); + xrc = -1; } + /* Free name of file being used */ + if (filename) { + free((void *) filename); + } - /* Close model pathname file and return data read */ - fclose(fp); + /* If error, free model info */ + if (xrc != 0) { + free_model_info(n_model_info, p_model_info); + n_model_info = 0; + p_model_info = (Model_Info_t *) NULL; + } - *num_models = n; - *model_info = model; + *p_num_model_info = n_model_info; + *pp_model_info = p_model_info; + + return xrc; +} /* end of function read_modpath */ + + + +/* Remove slash at end of path name if present */ +static inline void trim_slash(size_t *p_n, char *p) +{ + size_t n = *p_n; + if (n > 1) { + char * const p_last = p + n - 1; + if (*p_last == '/') { + *p_last = '\0'; + --*p_n; + } + } +} /* end of function trim_slash */ - return 0; -} /* *********************************************************************** */ @@ -334,106 +512,153 @@ processing. */ +#define N_NODE_INIT 5 + static int read_udnpath( - int *num_nodes, /* Number of node pathnames found */ - Node_Info_t **node_info /* Info about each node */ + int *p_num_node_info, /* Addr to receive # node pathnames */ + Node_Info_t **pp_node_info /* Addr to receive node info */ ) { - FILE *fp; /* Udn pathname file pointer */ - char path[MAX_PATH_LEN+2]; /* space to read pathnames into */ - Node_Info_t *node = NULL; /* temporary pointer to node info */ + int xrc = 0; + FILEBUF *fbp = (FILEBUF *) NULL; /* For reading Udn pathname */ + Node_Info_t *p_node_info = (Node_Info_t *) NULL; + /* array of node info */ + unsigned int n_node_info = 0; + unsigned int n_node_info_alloc = 0; + char *filename = (char *) NULL; - int n; - int i; - int j; - int len; - int line_num; - - const char *filename = UDNPATH_FILENAME; - - - /* Initialize number of nodes to zero in case of error */ - *num_nodes = 0; /* Open the node pathname file */ - fp = fopen_cmpp(&filename, "r"); - - /* For backward compatibility, return with WARNING only if file not found */ - if(fp == NULL) { - print_error("WARNING - File not found: %s", filename); - return 0; + if ((filename = gen_filename(UDNPATH_FILENAME, "r")) == (char *) NULL) { + print_error("ERROR - Unable to build udn path file name"); + xrc = -1; + goto EXITPOINT; } - /* Read the pathnames from the file, one line at a time until EOF */ - n = 0; - line_num = 0; - while( fgets(path, sizeof(path), fp) ) { + /* For backward compatibility, return with WARNING only if file + * not found */ + if ((fbp = fbopen(filename, 0)) == (FILEBUF *) NULL) { + print_error("WARNING - File not found: %s", filename); + xrc = +1; + goto EXITPOINT; + } - line_num++; - len = (int) strlen(path); + /* Allocate initial node info array */ + if ((p_node_info = (Node_Info_t *) malloc(N_NODE_INIT * + sizeof(Node_Info_t))) == (Node_Info_t *) NULL) { + print_error("ERROR - Unable to allocate initial node array"); + xrc = -1; + goto EXITPOINT; + } + n_node_info_alloc = N_NODE_INIT; - /* If line was too long for buffer, exit with error */ - if(len > MAX_PATH_LEN) { - print_error("ERROR - Line %d of %s exceeds %d characters", - line_num, filename, MAX_PATH_LEN); - return -1; + bool f_have_path = false; /* do not have a path to store */ + FBTYPE fbtype; + FBOBJ fbobj; + + for ( ; ; ) { /* Read items until end of file */ + /* Get the next path if not found yet */ + if (!f_have_path) { + const int rc = fbget(fbp, 0, (FBTYPE *) NULL, &fbtype, &fbobj); + if (rc != 0) { + if (rc == -1) { /* Error */ + print_error("ERROR - Unable to read item to buffer"); + xrc = -1; + goto EXITPOINT; + } + else { /* +1 -- EOF */ + break; + } + } /* end of abnormal case */ + + /* Remove trailing slash if appended to path */ + trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz); } - /* Strip white space including newline */ - for(i = 0, j = 0; i < len; ) { - if(isspace_c(path[i])) { - i++; - } - else { - path[j] = path[i]; - i++; - j++; + + /* Enlarge node array if full */ + if (n_node_info_alloc == n_node_info) { + n_node_info_alloc *= 2; + void * const p = realloc(p_node_info, + n_node_info_alloc * sizeof(Node_Info_t)); + if (p == NULL) { + print_error("ERROR - Unable to enlarge node array"); + xrc = -1; + goto EXITPOINT; } + p_node_info = (Node_Info_t *) p; } - path[j] = '\0'; - len = j; - - /* Strip trailing '/' if any */ - if(path[len - 1] == '/') - path[--len] = '\0'; - - /* If blank line, continue */ - if(len == 0) - continue; - - /* Make sure pathname is short enough to add a filename at the end */ - if(len > (MAX_PATH_LEN - (MAX_FN_LEN + 1)) ) { - print_error("ERROR - Pathname on line %d of %s exceeds %d characters", - line_num, filename, (MAX_PATH_LEN - (MAX_FN_LEN + 1))); - return -1; - } - - /* Allocate and initialize a new node info structure */ - if(n == 0) - node = (Node_Info_t *) malloc(sizeof(Node_Info_t)); - else - node = (Node_Info_t *) realloc(node, (size_t) (n + 1) * sizeof(Node_Info_t)); - node[n].path_name = NULL; - node[n].node_name = NULL; - node[n].unique = true; /* Put pathname into info structure */ - node[n].path_name = (char *) malloc((size_t) (len+1)); - strcpy(node[n].path_name, path); + Node_Info_t * const p_node_info_cur = p_node_info + + n_node_info; - /* Increment count of paths read */ - n++; + if ((p_node_info_cur->path_name = (char *) malloc( + fbobj.str_value.n_char + 1)) == (char *) NULL) { + print_error("ERROR - Unable to allocate path name"); + xrc = -1; + goto EXITPOINT; + } + + strcpy(p_node_info_cur->path_name, fbobj.str_value.sz); + p_node_info_cur->node_name = NULL; + + /* Must set before returning due to EOF. */ + p_node_info_cur->version = 1; + ++n_node_info; + + /* Try getting a version */ + FBTYPE type_wanted = BUF_TYPE_ULONG; + const int rc = fbget(fbp, 1, &type_wanted, &fbtype, &fbobj); + if (rc != 0) { + if (rc == -1) { /* Error */ + print_error("ERROR - Unable to read item to buffer"); + xrc = -1; + goto EXITPOINT; + } + else { /* +1 -- EOF */ + break; + } + } /* end of abnormal case */ + + if (fbtype == BUF_TYPE_ULONG) { /* found version number */ + f_have_path = false; + p_node_info_cur->version = (unsigned int) fbobj.ulong_value; + } + else { /* it was a string, so it is the next path */ + f_have_path = true; + + /* Remove trailing slash if appended to path */ + trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz); + } + + } /* end of loop reading items into buffer */ + +EXITPOINT: + /* Close model pathname file and return data read */ + if (fbclose(fbp) != 0) { + print_error("ERROR - Unable to close file with node info: %s", + strerror(errno)); + xrc = -1; } + /* Free name of file being used */ + if (filename) { + free((void *) filename); + } - /* Close node pathname file and return data read */ - fclose(fp); + /* If error, free node info */ + if (xrc != 0) { + free_node_info(n_node_info, p_node_info); + n_node_info = 0; + p_node_info = (Node_Info_t *) NULL; + } - *num_nodes = n; - *node_info = node; + *p_num_node_info = n_node_info; + *pp_node_info = p_node_info; - return 0; -} + return xrc; +} /* end of function read_udnpath */ @@ -452,47 +677,109 @@ static int read_model_names( Model_Info_t *model_info /* Info about each model */ ) { - bool all_found; /* True if all ifspec files read */ - int i; /* A temporary counter */ - char path[MAX_PATH_LEN+1]; /* full pathname to ifspec file */ - int status; /* Return status */ - Ifs_Table_t ifs_table; /* Repository for info read from ifspec file */ + bool all_found = true; /* True if all ifspec files read */ + int i; /* A temporary counter */ + char path_stack[100]; /* full pathname to ifspec file if from stack */ + char *path = path_stack; /* actual path buffer */ + int status; /* Return status */ + + /* Repository for info read from ifspec file.*/ + Ifs_Table_t ifs_table; + + /* Find the required buffer size and allocate if the default buffer + * on the stack is too small */ + { + int j; + size_t n_byte_needed = 0; + for (j = 0; j < num_models; j++) { /* max(model path lengths) */ + const size_t n = strlen(model_info[j].path_name); + if (n_byte_needed < n) { + n_byte_needed = n; + } + } + n_byte_needed += 1 + strlen(IFSPEC_FILENAME) + 1; + if (n_byte_needed > sizeof path_stack) { + if ((path = (char *) malloc(n_byte_needed)) == (char *) NULL) { + print_error("ERROR - Unable to allocate a buffer " + "for model paths"); + return -1; + } + } + } /* For each model found in model pathname file, read the interface */ /* spec file to get the SPICE and C function names into model_info */ + for(i = 0; i < num_models; i++) { + Model_Info_t *p_model_info_cur = model_info + i; - for(i = 0, all_found = true; i < num_models; i++) { + /* 0 for error recovery */ + (void) memset(&ifs_table, 0, sizeof ifs_table); - /* Form the full pathname to the interface spec file */ - strcpy(path, model_info[i].path_name); - strcat(path, "/"); - strcat(path, IFSPEC_FILENAME); + /* Form the full pathname to the interface spec file. Size has + * been checked to ensure that all strings will fit. */ + { + char *p_dst = path; + + /* Copy path name */ + const char *p_src = model_info[i].path_name; + for ( ; ; ) { + const char ch_cur = *p_src; + if (ch_cur == '\0') { + break; + } + *p_dst++ = ch_cur; + ++p_src; + } + *p_dst++ = '/'; /* add directory separator */ + strcpy(p_dst, IFSPEC_FILENAME); + } /* Read the SPICE and C function names from the interface spec file */ status = read_ifs_file(path, GET_IFS_NAME, &ifs_table); /* Transfer the names into the model_info structure */ - if(status == 0) { - model_info[i].spice_name = ifs_table.name.model_name; - model_info[i].cfunc_name = ifs_table.name.c_fcn_name; + if (status == 0) { + if ((p_model_info_cur->spice_name = strdup( + ifs_table.name.model_name)) == (char *) NULL) { + print_error("ERROR - Unable to copy code model name"); + all_found = false; + break; + } + if ((p_model_info_cur->cfunc_name = strdup( + ifs_table.name.c_fcn_name)) == (char *) NULL) { + print_error("ERROR - Unable to copy code model function name"); + all_found = false; + break; + } } else { + print_error( + "ERROR - Problems reading \"%s\" in directory \"%s\"", + IFSPEC_FILENAME, p_model_info_cur->path_name); all_found = false; - print_error("ERROR - Problems reading %s in directory %s", - IFSPEC_FILENAME, model_info[i].path_name); + break; } /* Remove the ifs_table */ rem_ifs_table(&ifs_table); + } /* end of loop over models */ + + /* Free buffer if allocated */ + if (path != path_stack) { + free(path); } - if(all_found) + if (all_found) { return 0; - else + } + else { + /* Free allocations of model when failure occurred */ + rem_ifs_table(&ifs_table); return -1; + } +} /* end of function read_model_names */ -} /* *********************************************************************** */ @@ -511,21 +798,57 @@ static int read_node_names( Node_Info_t *node_info /* Info about each node */ ) { - bool all_found; /* True if all files read OK */ - int i; /* A temporary counter */ - char path[MAX_PATH_LEN+1]; /* full pathname to file */ - int status; /* Return status */ + bool all_found = true; /* True if all ifspec files read */ + int i; /* A temporary counter */ + char path_stack[100]; /* full pathname to ifspec file if from stack */ + char *path = path_stack; /* actual path buffer */ + int status; /* Return status */ char *node_name; /* Name of node type read from file */ + /* Find the required buffer size and allocate if the default buffer + * on the stack is too small */ + { + int j; + size_t n_byte_needed = 0; + for (j = 0; j < num_nodes; j++) { /* max(model path lengths) */ + const size_t n = strlen(node_info[j].path_name); + if (n_byte_needed < n) { + n_byte_needed = n; + } + } + n_byte_needed += 1 + strlen(UDNFUNC_FILENAME) + 1; + if (n_byte_needed > sizeof path_stack) { + if ((path = (char *) malloc(n_byte_needed)) == (char *) NULL) { + print_error("ERROR - Unable to allocate a buffer " + "for user types"); + return -1; + } + } + } + + /* For each node found in node pathname file, read the udnfunc.c */ /* file to get the node type names into node_info */ for(i = 0, all_found = true; i < num_nodes; i++) { + /* Form the full pathname to the user-defined type file. Size has + * been checked to ensure that all strings will fit. */ + { + char *p_dst = path; - /* Form the full pathname to the interface spec file */ - strcpy(path, node_info[i].path_name); - strcat(path, "/"); - strcat(path, UDNFUNC_FILENAME); + /* Copy path name */ + const char *p_src = node_info[i].path_name; + for ( ; ; ) { + const char ch_cur = *p_src; + if (ch_cur == '\0') { + break; + } + *p_dst++ = ch_cur; + ++p_src; + } + *p_dst++ = '/'; /* add directory separator */ + strcpy(p_dst, UDNFUNC_FILENAME); + } /* Read the udn node type name from the file */ status = read_udn_type_name(path, &node_name); @@ -545,8 +868,7 @@ static int read_node_names( return 0; else return -1; - -} +} /* end of function read_node_names */ @@ -568,14 +890,11 @@ static int check_uniqueness( Node_Info_t *node_info /* Info about each node type */ ) { - int i; /* A temporary counter */ - int j; /* A temporary counter */ - bool all_unique; /* true if names are unique */ - /* Define a list of model names used internally by XSPICE */ /* These names (except 'poly') are defined in src/sim/INP/INPdomodel.c and */ /* are case insensitive */ - static char *SPICEmodel[] = { "npn", + static const char *SPICEmodel[] = { + "npn", "pnp", "d", "njf", @@ -590,13 +909,14 @@ static int check_uniqueness( "sw", "csw", "poly" }; - static int numSPICEmodels = sizeof(SPICEmodel) / sizeof(char *); + static const int numSPICEmodels = sizeof(SPICEmodel) / sizeof(char *); /* Define a list of node type names used internally by the simulator */ /* These names are defined in src/sim/include/MIFtypes.h and are case */ /* insensitive */ - static char *UDNidentifier[] = { "v", + static const char *UDNidentifier[] = { + "v", "vd", "i", "id", @@ -606,138 +926,220 @@ static int check_uniqueness( "h", "hd", "d" }; - static int numUDNidentifiers = sizeof(UDNidentifier) / sizeof(char *); - + static const int numUDNidentifiers = sizeof(UDNidentifier) / sizeof(char *); + bool f_have_duplicate = false; /* no duplicates found yet */ /* First, normalize case of all model and node names to lower since */ /* SPICE is case insensitive in parsing decks */ - for(i = 0; i < num_models; i++) - str_to_lower(model_info[i].spice_name); - for(i = 0; i < num_nodes; i++) - str_to_lower(node_info[i].node_name); - - /* Then, loop through all model names and report errors if same as SPICE */ - /* model name or same as another model name in list */ - for(i = 0, all_unique = true; i < num_models; i++) { - - /* First check against list of SPICE internal names */ - for(j = 0; j < numSPICEmodels; j++) { - if(strcmp(model_info[i].spice_name, SPICEmodel[j]) == 0) { - all_unique = false; - print_error("ERROR - Model name '%s' is same as internal SPICE model name\n", - model_info[i].spice_name); - } + { + int i; + for(i = 0; i < num_models; i++) { + str_to_lower(model_info[i].spice_name); } - - /* Skip if already seen once */ - if(model_info[i].spice_unique == false) - continue; - - /* Then check against other names in list */ - for(j = 0; j < num_models; j++) { - - /* Skip checking against itself */ - if(i == j) - continue; - - /* Compare the names */ - if(strcmp(model_info[i].spice_name, model_info[j].spice_name) == 0) { - all_unique = false; - model_info[i].spice_unique = false; - model_info[j].spice_unique = false; - print_error("ERROR - Model name '%s' in directory: %s", - model_info[i].spice_name, - model_info[i].path_name); - print_error(" is same as"); - print_error(" model name '%s' in directory: %s\n", - model_info[j].spice_name, - model_info[j].path_name); - } - } - } - - /* Loop through all C function names and report errors if duplicates found */ - for(i = 0; i < num_models; i++) { - - /* Skip if already seen once */ - if(model_info[i].cfunc_unique == false) - continue; - - /* Check against other names in list only, not against SPICE identifiers */ - /* Let linker catch collisions with SPICE identifiers for now */ - for(j = 0; j < num_models; j++) { - - /* Skip checking against itself */ - if(i == j) - continue; - - /* Compare the names */ - if(strcmp(model_info[i].cfunc_name, model_info[j].cfunc_name) == 0) { - all_unique = false; - model_info[i].cfunc_unique = false; - model_info[j].cfunc_unique = false; - print_error("ERROR - C function name '%s' in directory: %s", - model_info[i].cfunc_name, - model_info[i].path_name); - print_error(" is same as"); - print_error(" C function name '%s' in directory: %s\n", - model_info[j].cfunc_name, - model_info[j].path_name); - } - } - - } - - /* Loop through all node type names and report errors if same as internal */ - /* name or same as another name in list */ - for(i = 0; i < num_nodes; i++) { - - /* First check against list of internal names */ - for(j = 0; j < numUDNidentifiers; j++) { - if(strcmp(node_info[i].node_name, UDNidentifier[j]) == 0) { - all_unique = false; - print_error("ERROR - Node type '%s' is same as internal node type\n", - node_info[i].node_name); - } - } - - /* Skip if already seen once */ - if(node_info[i].unique == false) - continue; - - /* Then check against other names in list */ - for(j = 0; j < num_nodes; j++) { - - /* Skip checking against itself */ - if(i == j) - continue; - - /* Compare the names */ - if(strcmp(node_info[i].node_name, node_info[j].node_name) == 0) { - all_unique = false; - node_info[i].unique = false; - node_info[j].unique = false; - print_error("ERROR - Node type '%s' in directory: %s", - node_info[i].node_name, - node_info[i].path_name); - print_error(" is same as"); - print_error(" node type '%s' in directory: %s\n", - node_info[j].node_name, - node_info[j].path_name); - } + { + int i; + for(i = 0; i < num_nodes; i++) { + str_to_lower(node_info[i].node_name); } } + /* Sizes of models and nodes */ + const unsigned int n_model = (unsigned int) numSPICEmodels + num_models; + const unsigned int n_node = (unsigned int) numUDNidentifiers + num_nodes; + const unsigned int n_ks = n_model > n_node ? n_model : n_node; + + /* Allocate structure to compare */ + struct Key_src * const p_ks = (struct Key_src *) malloc( + n_ks * sizeof *p_ks); + if (p_ks == (struct Key_src *) NULL) { + print_error("ERROR - Unable to allocate array to check uniqueness."); + return -1; + } + + /* Set up for test of SPICE name of models and test */ + if (num_models > 0) { /* Have user-defined models */ + { + int i, j; + + /* Fill up with SPICE models */ + for (i = 0; i < numSPICEmodels; ++i) { + struct Key_src *p_ks_cur = p_ks + i; + p_ks_cur->key = SPICEmodel[i]; + p_ks_cur->src = (char *) NULL; /* denotes internal SPICE */ + } + /* Add SPICE model names for code models */ + for (j = 0; j < num_models; ++i, ++j) { + struct Key_src *p_ks_cur = p_ks + i; + Model_Info_t *p_mi_cur = model_info + j; + p_ks_cur->key = p_mi_cur->spice_name; + p_ks_cur->src = p_mi_cur->path_name; + } + + /* Test for duplicates */ + f_have_duplicate |= test_for_duplicates(n_model, p_ks, + &report_error_spice_name); + } + + /* Set up for test of function names */ + { + int i; + + /* Fill up with C function names from code models */ + for (i = 0; i < num_models; ++i) { + struct Key_src *p_ks_cur = p_ks + i; + Model_Info_t *p_mi_cur = model_info + i; + p_ks_cur->key = p_mi_cur->cfunc_name; + p_ks_cur->src = p_mi_cur->path_name; + } + + /* Test for duplicates */ + f_have_duplicate |= test_for_duplicates(num_models, p_ks, + &report_error_function_name); + } + } + + /* Set up for test of node types and test */ + if (num_nodes > 0) { /* Have user-defined types */ + int i, j; + + /* Fill up with SPICE node types */ + for (i = 0; i < numUDNidentifiers; ++i) { + struct Key_src *p_ks_cur = p_ks + i; + p_ks_cur->key = UDNidentifier[i]; + p_ks_cur->src = (char *) NULL; /* denotes internal SPICE */ + } + /* Add user-defined nodes */ + for (j = 0; j < num_nodes; ++i, ++j) { + struct Key_src *p_ks_cur = p_ks + i; + Node_Info_t *p_ni_cur = node_info + j; + p_ks_cur->key = p_ni_cur->node_name; + p_ks_cur->src = p_ni_cur->path_name; + } + + /* Test for duplicates */ + f_have_duplicate |= test_for_duplicates(n_node, p_ks, + &report_error_udn_name); + } + + /* Free allocation for compares */ + free(p_ks); /* Return error status */ - if(all_unique) - return 0; - else - return -1; + return f_have_duplicate ? -1 : 0; +} /* end of function check_uniqueness */ + + + +/* Test for duplicate key values and report using the supplied function + * if found */ +static bool test_for_duplicates(unsigned int n, struct Key_src *p_ks, + void (*p_error_reporter)(const struct Key_src *p_ks1, + const struct Key_src *p_ks2)) +{ + bool f_have_duplicate = false; + + /* Sort to put duplicates together */ + qsort(p_ks, n, sizeof(struct Key_src), + (int (*)(const void *, const void *)) &cmpr_ks); + + unsigned int i; + for (i = 0; i != n; ) { + const struct Key_src * const p_ks_i = p_ks + i; + const char * const p_key_i_val = p_ks_i->key; + unsigned int j; + for (j = i + 1; j != n; ++j) { + const struct Key_src * const p_ks_j = p_ks + j; + const char * const p_key_j_val = p_ks_j->key; + if (strcmp(p_key_i_val, p_key_j_val) != 0) { + break; + } + + /* Duplicate found. Indicate a duplicate was found and report + * the error */ + f_have_duplicate = true; + (*p_error_reporter)(p_ks_i, p_ks_j); + } /* end of loop testing for duplicates */ + i = j; /* advance to next unique value or end of list */ + } /* end of loop over items to test */ + return f_have_duplicate; +} /* end of function test_for_duplicates */ + + + +/* Compare function for struct Key_src. + * + * Remarks + * the src field may be NULL to indicate internal values. These should + * be ordered before values that are not NULL for nicer error messages. + * Note that for a given key, only one src field can be NULL. */ +static int cmpr_ks(const struct Key_src *ks1, const struct Key_src *ks2) +{ + /* First order by the value of the key */ + const int rc = strcmp(ks1->key, ks2->key); + if (rc != 0) { + return rc; + } + + /* Test for NULL src fields. Only one can be NULL for the same key */ + if (ks1->src == (char *) NULL) { + return -1; + } + if (ks2->src == (char *) NULL) { + return +1; + } + + /* Both keys not NULL, so compare */ + return strcmp(ks1->src, ks2->src); +} /* end of function cmpr_ks */ + + + +static void report_error_spice_name(const struct Key_src *p_ks1, + const struct Key_src *p_ks2) +{ + const char * const p_ks1_src = p_ks1->src; + if (p_ks1_src == (char *) NULL) { /* internal SPICE name */ + print_error("ERROR: Model name \"%s\" from directory \"%s\" " + "is the name of an internal SPICE model", + p_ks1->key, p_ks2->src); + } + else { + print_error("ERROR: Model name \"%s\" in directory \"%s\" " + "is also in directory \"%s\".", + p_ks1->key, p_ks1_src, p_ks2->src); + } +} /* end of function report_error_spice_name */ + + + +static void report_error_function_name (const struct Key_src *p_ks1, + const struct Key_src *p_ks2) +{ + print_error("ERROR: C function name \"%s\" in directory \"%s\" " + "is also in directory \"%s\".", + p_ks1->key, p_ks1->src, p_ks2->src); +} /* end of function report_error_spice_name */ + + + +static void report_error_udn_name(const struct Key_src *p_ks1, + const struct Key_src *p_ks2) +{ + const char * const p_ks1_src = p_ks1->src; + if (p_ks1_src == (char *) NULL) { /* internal SPICE name */ + print_error("ERROR: Node type \"%s\" from directory \"%s\" " + "is the name of an internal SPICE node type", + p_ks1->key, p_ks2->src); + } + else { + print_error("ERROR: Node type \"%s\" in directory \"%s\" " + "is also in directory \"%s\".", + p_ks1->key, p_ks1_src, p_ks2->src); + } +} /* end of function report_error_udn_name */ -} /* *********************************************************************** */ @@ -761,12 +1163,17 @@ static int write_CMextrn( int i; /* A temporary counter */ FILE *fp; /* File pointer for writing CMextrn.h */ - const char *filename = "cmextrn.h"; + char *filename = (char *) NULL; /* Open the file to be written */ - fp = fopen_cmpp(&filename, "w"); + if ((filename = gen_filename("cmextrn.h", "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to cmextrn.h"); + return -1; + } + fp = fopen(filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); + free(filename); return -1; } @@ -776,9 +1183,14 @@ static int write_CMextrn( } /* Close the file and return */ - fclose(fp); + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing %s", filename); + free(filename); + return -1; + } + free(filename); return 0; -} +} /* end of function write_CMextrn */ /* *********************************************************************** */ @@ -802,24 +1214,81 @@ static int write_CMinfo( int i; /* A temporary counter */ FILE *fp; /* File pointer for writing CMinfo.h */ - const char *filename = "cminfo.h"; + char *filename = (char *) NULL; /* Open the file to be written */ - fp = fopen_cmpp(&filename, "w"); + if ((filename = gen_filename("cminfo.h", "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to cminfo.h"); + return -1; + } + fp = fopen(filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); + free(filename); return -1; } /* Write out the data */ for(i = 0; i < num_models; i++) { - fprintf(fp, "&%s_info,\n", model_info[i].cfunc_name); + Model_Info_t *p_mi_cur = model_info + i; + if (p_mi_cur->version == 1) { + fprintf(fp, "&%s_info,\n", model_info[i].cfunc_name); + } } /* Close the file and return */ - fclose(fp); + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing %s", filename); + free(filename); + return -1; + } + + free(filename); return 0; -} +} /* end of function write_CMinfo */ + + + +static int write_CMinfo2( + int num_models, /* Number of model pathnames */ + Model_Info_t *model_info /* Info about each model */ +) +{ + int i; /* A temporary counter */ + FILE *fp; /* File pointer for writing CMinfo.h */ + + char *filename = (char *) NULL; + + /* Open the file to be written */ + if ((filename = gen_filename("cminfo2.h", "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to cminfo2.h"); + return -1; + } + fp = fopen(filename, "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening %s for write", filename); + free(filename); + return -1; + } + + /* Write out the data */ + for (i = 0; i < num_models; i++) { + Model_Info_t *p_mi_cur = model_info + i; + if (p_mi_cur->version <= 2) { + fprintf(fp, "&%s_info,\n", model_info[i].cfunc_name); + } + } + + /* Close the file and return */ + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing %s", filename); + free(filename); + return -1; + } + + free(filename); + return 0; +} /* end of function write_CMinfo2 */ @@ -847,10 +1316,14 @@ static int write_UDNextrn( int i; /* A temporary counter */ FILE *fp; /* File pointer for writing UDNextrn.h */ - const char *filename = "udnextrn.h"; + char *filename = (char *) NULL; /* Open the file to be written */ - fp = fopen_cmpp(&filename, "w"); + if ((filename = gen_filename("udnextrn.h", "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to udnextrn.h"); + return -1; + } + fp = fopen(filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); return -1; @@ -862,9 +1335,16 @@ static int write_UDNextrn( } /* Close the file and return */ - fclose(fp); + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing %s", filename); + free(filename); + return -1; + } + + free(filename); return 0; -} +} /* end of function write_UDNextrn */ + /* *********************************************************************** */ @@ -879,9 +1359,6 @@ and user-defined nodes. This SPICE source file uses the structures mentioned in the include file to define the node types known to the simulator. */ - - - static int write_UDNinfo( int num_nodes, /* Number of node pathnames */ Node_Info_t *node_info /* Info about each node */ @@ -890,10 +1367,14 @@ static int write_UDNinfo( int i; /* A temporary counter */ FILE *fp; /* File pointer for writing UDNinfo.h */ - const char *filename = "udninfo.h"; + char *filename = (char *) NULL; /* Open the file to be written */ - fp = fopen_cmpp(&filename, "w"); + if ((filename = gen_filename("udninfo.h", "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to udninfo.h"); + return -1; + } + fp = fopen(filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); return -1; @@ -901,13 +1382,65 @@ static int write_UDNinfo( /* Write out the data */ for(i = 0; i < num_nodes; i++) { - fprintf(fp, "&udn_%s_info,\n", node_info[i].node_name); + Node_Info_t *p_ni_cur = node_info + i; + if (p_ni_cur->version == 1) { + fprintf(fp, "&udn_%s_info,\n", p_ni_cur->node_name); + } } /* Close the file and return */ - fclose(fp); + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing %s", filename); + free(filename); + return -1; + } + + free(filename); return 0; -} +} /* end of function write_UDNinfo */ + + + +static int write_UDNinfo2( + int num_nodes, /* Number of node pathnames */ + Node_Info_t *node_info /* Info about each node */ +) +{ + int i; /* A temporary counter */ + FILE *fp; /* File pointer for writing UDNinfo.h */ + + char *filename = (char *) NULL; + + /* Open the file to be written */ + if ((filename = gen_filename("udninfo2.h", "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to udninfo2.h"); + return -1; + } + fp = fopen(filename, "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening %s for write", filename); + return -1; + } + + /* Write out the data */ + for(i = 0; i < num_nodes; i++) { + Node_Info_t *p_ni_cur = node_info + i; + if (p_ni_cur->version <= 2) { + fprintf(fp, "&udn_%s_info,\n", p_ni_cur->node_name); + } + } + + /* Close the file and return */ + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing %s", filename); + free(filename); + return -1; + } + + free(filename); + return 0; +} /* end of function write_UDNinfo */ + /* *********************************************************************** */ @@ -930,10 +1463,14 @@ static int write_objects_inc( int i; /* A temporary counter */ FILE *fp; /* File pointer for writing make_include */ - const char *filename = "objects.inc"; + char *filename = (char *) NULL; /* Open the file to be written */ - fp = fopen_cmpp(&filename, "w"); + if ((filename = gen_filename("objects.inc", "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to objects.inc"); + return -1; + } + fp = fopen(filename, "w"); if(fp == NULL) { print_error("ERROR - Problems opening %s for write", filename); return -1; @@ -956,9 +1493,16 @@ static int write_objects_inc( } /* Close the file and return */ - fclose(fp); + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing %s", filename); + free(filename); + return -1; + } + + free(filename); return 0; -} +} /* end of function write_objects_inc */ + /* @@ -983,12 +1527,18 @@ static int read_udn_type_name( int i; /* a counter */ static char *struct_type = "Evt_Udn_Info_t"; + char *filename = (char *) NULL; /* Open the file from which the node type name will be read */ - fp = fopen_cmpp(&path, "r"); - free((char*)path); - if(fp == NULL) + if ((filename = gen_filename(path, "r")) == (char *) NULL) { + print_error("ERROR - Unable to build path to Evt_Udn_Info_t"); return -1; + } + fp = fopen(filename, "r"); + if(fp == NULL) { + print_error("ERROR - Problems opening %s for reading", filename); + return -1; + } /* Read the file until the definition of the Evt_Udn_Info_t struct */ /* is found, then get the name of the node type from the first */ @@ -1039,10 +1589,19 @@ static int read_udn_type_name( c = fgetc(fp); if(c == '"') { found = true; + if (i >= sizeof name) { + print_error("name too long"); + exit(1); + } name[i] = '\0'; } - else if(c != EOF) + else if(c != EOF) { + if (i > sizeof name) { + print_error("name too long"); + exit(1); + } name[i++] = (char) c; + } } while((c != EOF) && (! found)); } } while((c != EOF) && (! found)); @@ -1054,7 +1613,11 @@ static int read_udn_type_name( fclose(fp); if(found) { - *node_name = (char *) malloc(strlen(name) + 1); + if ((*node_name = (char *) malloc( + strlen(name) + 1)) == (char *) NULL) { + print_error("ERROR - Unable to allocate node name"); + return -1; + } strcpy(*node_name, name); return 0; } @@ -1064,3 +1627,58 @@ static int read_udn_type_name( } } + + +/* Free allocations in p_model_info array */ +static void free_model_info(int num_models, Model_Info_t *p_model_info) +{ + /* Return if no structure */ + if (p_model_info == (Model_Info_t *) NULL) { + return; + } + + int i; + for (i = 0; i < num_models; ++i) { + Model_Info_t *p_cur = p_model_info + i; + void *p; + if ((p = p_cur->cfunc_name) != NULL) { + free(p); + } + if ((p = p_cur->path_name) != NULL) { + free(p); + } + if ((p = p_cur->spice_name) != NULL) { + free(p); + } + } + + free(p_model_info); +} /* end of function free_model_info */ + + + +/* Free allocations in p_nod_info array */ +static void free_node_info(int num_nodes, Node_Info_t *p_node_info) +{ + /* Return if no structure */ + if (p_node_info == (Node_Info_t *) NULL) { + return; + } + + int i; + for (i = 0; i < num_nodes; ++i) { + Node_Info_t *p_cur = p_node_info + i; + void *p; + if ((p = p_cur->node_name) != NULL) { + free(p); + } + if ((p = p_cur->path_name) != NULL) { + free(p); + } + } + + free(p_node_info); +} /* end of function free_node_info */ + + + diff --git a/src/xspice/cmpp/pp_mod.c b/src/xspice/cmpp/pp_mod.c index fe31be4f0..c31bce1a8 100644 --- a/src/xspice/cmpp/pp_mod.c +++ b/src/xspice/cmpp/pp_mod.c @@ -54,6 +54,7 @@ NON-STANDARD FEATURES ============================================================================*/ +#include #include #include #include @@ -74,21 +75,33 @@ extern int mod_num_errors; extern Ifs_Table_t *mod_ifs_table; -extern const char *current_filename; +extern char *current_filename; extern char *prog_name; /*---------------------------------------------------------------------------*/ -static char *change_extension (char *filename, char *ext) +/* Allocate and build a file name from the input filename by changing its + * extension (text after the last '.') in filename to ext or append .ext if + * the filename has no extension */ +static char *change_extension(const char *filename, const char *ext) { - char *p = strrchr(filename, '.'); - size_t prefix_len = p ? (size_t) (p-filename+1) : strlen(filename); - char *new_filename = malloc(prefix_len + strlen(ext) + 1); + const char * const p = strrchr(filename, '.'); + const size_t prefix_len = p ? (size_t) (p - filename) : strlen(filename); + const size_t ext_len = strlen(ext); + char * const new_filename = malloc(prefix_len + ext_len + 2); + /* +1 for '.' +1 for '\0' */ + if (new_filename == (char *) NULL) { + return (char *) NULL; + } - strncpy(new_filename, filename, prefix_len); - strcpy(new_filename+prefix_len, ext); + { + char *p_cur = (char *) memcpy(new_filename, filename, prefix_len) + + prefix_len; + *p_cur++ = '.'; + (void) memcpy(p_cur, ext, ext_len + 1); + } return new_filename; -} +} /* end of function change_extension */ /*---------------------------------------------------------------------------*/ @@ -108,14 +121,12 @@ utilities. void preprocess_mod_file ( - char *filename) /* The file to read */ + const char *filename) /* The file to read */ { - - - Ifs_Table_t ifs_table; /* info read from ifspec.ifs file */ - int status; /* Return status */ - const char *output_filename; - + Ifs_Table_t ifs_table; /* info read from ifspec.ifs file */ + int status; /* Return status */ + char *output_filename = (char *) NULL; /* .mod file being written */ + /* * Read the entire ifspec.ifs file and load the data into ifs_table */ @@ -125,45 +136,80 @@ void preprocess_mod_file ( if (status != 0) { exit(1); } - - current_filename = filename; - mod_yyin = fopen_cmpp (¤t_filename, "r"); - if (mod_yyin == NULL) { - print_error("ERROR - Could not open input .mod file: %s", current_filename); - exit(1); - } - - output_filename = change_extension (filename, "c"); - mod_yyout = fopen_cmpp (&output_filename, "w"); + /* Open the cfunc.mod file defining the code model function */ + if ((current_filename = gen_filename(filename, "r")) == (char *) NULL) { + print_error("ERROR - Unable to build mod file name"); + exit(1); + } + if ((mod_yyin = fopen(current_filename, "r")) == (FILE *) NULL) { + print_error("ERROR - Unable to open mod file \"%s\": %s", + current_filename, strerror(errno)); + exit(1); + } + + { + char *output_filename_base = (char *) NULL; + if ((output_filename_base = change_extension( + filename, "c")) == (char *) NULL) { + print_error("ERROR - Could not change extension of " + "\"%s\".", filename); + exit(1); + } + + if ((output_filename = gen_filename( + output_filename_base, "w")) == (char *) NULL) { + print_error("ERROR - Unable to build output file name"); + exit(1); + } + + free(output_filename_base); + } + + if ((mod_yyout = fopen(output_filename, "w")) == (FILE *) NULL) { + /* .c file could not be opened */ + print_error("ERROR - Could not open output .c file\"%s\": %s", + output_filename, strerror(errno)); + exit(1); + } - if (mod_yyout == NULL) { - print_error("ERROR - Could not open output .c file: %s", output_filename); - exit(1); - } - mod_ifs_table = &ifs_table; mod_num_errors = 0; +/* Define DEBUG_WITH_MOD_FILE to have the compiler use the cfunc.mod file for + * deugging instead of the cfunc.c file. */ +#ifdef DEBUG_WITH_MOD_FILE fprintf (mod_yyout, "#line 1 \"%s\"\n", current_filename); +#endif fprintf (mod_yyout, "#include \"ngspice/cm.h\"\n"); fprintf (mod_yyout, "extern void %s(Mif_Private_t *);\n", - ifs_table.name.c_fcn_name); + ifs_table.name.c_fcn_name); +#ifdef DEBUG_WITH_MOD_FILE fprintf (mod_yyout, "#line 1 \"%s\"\n", current_filename); +#endif mod_yylineno = 1; - if (mod_yyparse() || (mod_num_errors > 0)) { - print_error("Error parsing .mod file: \"%s\"", current_filename); - unlink (output_filename); - exit (1); - } - fclose (mod_yyout); - if(output_filename) - free((char*)output_filename); + if (mod_yyparse() || (mod_num_errors > 0)) { + print_error("Error parsing .mod file: \"%s\"", current_filename); + unlink(output_filename); + exit(1); + } + + if (fclose(mod_yyout) != 0) { + print_error("Error closing output file \"%s\": %s", + current_filename, strerror(errno)); + unlink(output_filename); + exit(1); + } + rem_ifs_table(&ifs_table); mod_yyrestart(NULL); -} + free(output_filename); + free(current_filename); +} /* end of function preprocess_mod_file */ + + /*---------------------------------------------------------------------------*/ void diff --git a/src/xspice/cmpp/read_ifs.c b/src/xspice/cmpp/read_ifs.c index 51b72184d..ce439a8a5 100644 --- a/src/xspice/cmpp/read_ifs.c +++ b/src/xspice/cmpp/read_ifs.c @@ -47,7 +47,11 @@ NON-STANDARD FEATURES ============================================================================*/ #include +#include #include +#include +#include + #include "ifs_yacc_y.h" extern char *prog_name; @@ -65,7 +69,7 @@ extern int ifs_num_errors; static int read_ifs_table(FILE *fp, int mode, Ifs_Table_t *ifs_table); -const char *current_filename; +char *current_filename; /* *********************************************************************** */ @@ -94,35 +98,42 @@ int read_ifs_file( int mode, /* Get names only or get everything? */ Ifs_Table_t *ifs_table) /* Table to put info in */ { - - FILE *fp; /* Ifs file pointer */ - - int status; /* returned status from function */ - - + FILE *fp = (FILE *) NULL; /* Ifs file pointer */ + int status = 0; /* returned status from function */ + + /* Open the ifs file for read access */ - fp = fopen_cmpp(&filename, "r"); - - if(fp == NULL) { - perror (prog_name); - print_error("ERROR - File not found: %s", filename); - return -1; + /* Open the model pathname file */ + if ((current_filename = gen_filename(filename, "r")) == (char *) NULL) { + print_error("ERROR - Unable to build full file name"); + return -1; + } + if ((fp = fopen(current_filename, "r")) == (FILE *) NULL) { + print_error("ERROR - Unable to open \"%s\": %s", + current_filename, strerror(errno)); + status = -1; + goto EXITPOINT; + } + + /* Get the stuff from the file into the ifs_table struct. Here mode + * defines the data that will be added to the structure */ + status = read_ifs_table(fp, mode, ifs_table); + + EXITPOINT: + /* Close file and return */ + if (fp != (FILE *) NULL) { + if (fclose(fp) != 0) { + print_error("ERROR - Unable to close \"%s\": %s", + current_filename, strerror(errno)); + status = -1; + } } - current_filename = filename; - - /* Get the stuff from the file into the ifs_table struct */ - - status = read_ifs_table(fp, mode, ifs_table); - - /* Close file and return */ - - fclose(fp); - - return(status); - -} + free(current_filename); + current_filename = (char *) NULL; + return status; +} /* end of function read_ifs_file */ @@ -146,7 +157,6 @@ static int read_ifs_table( int mode, /* Get names only or get everything? */ Ifs_Table_t *ifs_table) /* Table to put info in */ { - assert (ifs_table); assert (fp); diff --git a/src/xspice/cmpp/util.c b/src/xspice/cmpp/util.c index da6a27163..255812e4d 100644 --- a/src/xspice/cmpp/util.c +++ b/src/xspice/cmpp/util.c @@ -84,16 +84,21 @@ void print_error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - - fprintf(stderr, "%s: ", prog_name); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - + vprint_error(fmt, ap); va_end(ap); } /* end of function print_error */ +void vprint_error(const char *fmt, va_list p_arg) +{ + fprintf(stderr, "%s: ", prog_name); + vfprintf(stderr, fmt, p_arg); + fprintf(stderr, "\n"); +} /* end of function vprint_error */ + + + /* Convert a string to all lower case */ void str_to_lower(char *s) { @@ -110,24 +115,22 @@ void str_to_lower(char *s) /* If *path_p is relative, prefix with the value of the CMPP output or * input environment variable. Open the file and return the path that * was used to open it. */ -FILE *fopen_cmpp(const char **path_p, const char *mode) +char *gen_filename(const char *filename, const char *mode) { - const char *path = *path_p; char *buf = (char *) NULL; /* If absoulte path, prefix with CMPP_ODIR/CMPP_IDIR env value */ - if (!is_absolute_pathname(path)) { /* relative path */ + if (!is_absolute_pathname(filename)) { /* relative path */ const char *e = getenv((*mode == 'w' || *mode == 'a') ? "CMPP_ODIR" : "CMPP_IDIR"); if (e) { /* have env var */ const size_t len_prefix = strlen(e); - const size_t len_path = strlen(path); - const size_t n_char = len_prefix + len_path + 1; + const size_t len_filename = strlen(filename); + const size_t n_char = len_prefix + len_filename + 1; /* Allocate buffer to build full file name */ if ((buf = (char *) malloc(n_char + 1)) == (char *) NULL) { - *path_p = (char *) NULL; - return (FILE *) NULL; + return (char *) NULL; } /* Build the full file name */ @@ -136,24 +139,21 @@ FILE *fopen_cmpp(const char **path_p, const char *mode) (void) memcpy(p_cur, e, len_prefix); p_cur += len_prefix; *p_cur++ = DIR_TERM_UNIX; - (void) memcpy(p_cur, path, len_path + 1); + (void) memcpy(p_cur, filename, len_filename + 1); } } /* end of case that env variable found */ } /* end of case that path is absolute */ - /* If did not build full file name yet, copy the original - * name of the file */ + /* If did not build full file name yet, make the original + * name of the file the full file name */ if (buf == (char *) NULL) { - if ((buf = strdup(path)) == (char *) NULL) { /* failed */ - *path_p = (char *) NULL; - return (FILE *) NULL; + if ((buf = strdup(filename)) == (char *) NULL) { /* failed */ + return (char *) NULL; } } - /* Return copy of file name and opened file */ - *path_p = buf; - return fopen(buf, mode); -} /* end of function fopen_cmpp */ + return buf; +} /* end of function gen_filename */ diff --git a/src/xspice/cmpp/writ_ifs.c b/src/xspice/cmpp/writ_ifs.c index 9e9129fa7..e1ab2d5e6 100644 --- a/src/xspice/cmpp/writ_ifs.c +++ b/src/xspice/cmpp/writ_ifs.c @@ -40,45 +40,31 @@ NON-STANDARD FEATURES #include +#include #include #include #include "cmpp.h" /* Local function prototypes */ - -static void write_comment(FILE *fp, Ifs_Table_t *ifs_table); - -static void write_includes(FILE *fp); - -static void write_mPTable(FILE *fp, Ifs_Table_t *ifs_table); - -static void write_pTable(FILE *fp, Ifs_Table_t *ifs_table); - -static void write_conn_info(FILE *fp, Ifs_Table_t *ifs_table); - -static void write_param_info(FILE *fp, Ifs_Table_t *ifs_table); - -static void write_inst_var_info(FILE *fp, Ifs_Table_t *ifs_table); - -static void write_SPICEdev(FILE *fp, Ifs_Table_t *ifs_table); +static int write_comment(FILE *fp, Ifs_Table_t *ifs_table); +static int write_includes(FILE *fp); +static int write_mPTable(FILE *fp, Ifs_Table_t *ifs_table); +static int write_pTable(FILE *fp, Ifs_Table_t *ifs_table); +static int write_conn_info(FILE *fp, Ifs_Table_t *ifs_table); +static int write_param_info(FILE *fp, Ifs_Table_t *ifs_table); +static int write_inst_var_info(FILE *fp, Ifs_Table_t *ifs_table); +static int write_SPICEdev(FILE *fp, Ifs_Table_t *ifs_table); -static char *data_type_to_str(Data_Type_t type); - -static char *port_type_to_str(Port_Type_t port); - -static char *dir_to_str(Dir_t dir); - +static const char *data_type_to_str(Data_Type_t type); +static const char *port_type_to_str(Port_Type_t port); +static const char *dir_to_str(Dir_t dir); static char *value_to_str(Data_Type_t type, Value_t value); - -static char *no_value_to_str(void); - -static char *boolean_to_str(bool value); - +static const char *no_value_to_str(void); +static const char *boolean_to_str(bool value); static char *integer_to_str(int value); - -static char *gen_port_type_str(Port_Type_t port); +static const char *gen_port_type_str(Port_Type_t port); @@ -110,59 +96,102 @@ The output file is then closed. int write_ifs_c_file( - const char *filename, /* File to write to */ + const char *filename_in, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - FILE *fp; /* File pointer */ - int int_status; /* returned status from fclose */ + FILE *fp = (FILE *) NULL; /* File pointer */ + char *filename = (char *) NULL; + int xrc = 0; /* Open the ifspec.c file for write access */ - - fp = fopen_cmpp(&filename, "w"); - - if(fp == NULL) { - print_error("ERROR - Can't create file: %s", filename); - return -1; + if ((filename = gen_filename(filename_in, "w")) == (char *) NULL) { + print_error("ERROR - Unable to build path to \"%s\".", filename); + xrc = -1; + goto EXITPOINT; + } + fp = fopen(filename, "w"); + if(fp == NULL) { + print_error("ERROR - Problems opening \"%s\" for write", filename); + xrc = -1; + goto EXITPOINT; } - /* Write out a comment section at the top of the file */ - write_comment(fp, ifs_table); + if (write_comment(fp, ifs_table) != 0) { + print_error("ERROR - Problems writing comment to \"%s\"", filename); + xrc = -1; + goto EXITPOINT; + } /* Put in the # includes */ - write_includes(fp); + if (write_includes(fp) != 0) { + print_error("ERROR - Problems writing includes to \"%s\"", filename); + xrc = -1; + goto EXITPOINT; + } /* Write the SPICE3 required XXXmPTable structure */ - write_mPTable(fp, ifs_table); + if (write_mPTable(fp, ifs_table) != 0) { + print_error("ERROR - Problems writing mPTable to \"%s\"", filename); + xrc = -1; + goto EXITPOINT; + } /* Write the SPICE3 required XXXpTable structure */ - write_pTable(fp, ifs_table); + if (write_pTable(fp, ifs_table) != 0) { + print_error("ERROR - Problems writing pTable to \"%s\"", filename); + xrc = -1; + goto EXITPOINT; + } /* Write out the connector table required for the code model element parser */ - write_conn_info(fp, ifs_table); + if (write_conn_info(fp, ifs_table) != 0) { + print_error("ERROR - Problems writing includes to \"%s\"", filename); + xrc = -1; + goto EXITPOINT; + } /* Write out the parameter table required for the code model element parser */ - write_param_info(fp, ifs_table); + if (write_param_info(fp, ifs_table) != 0) { + print_error("ERROR - Problems writing params to \"%s\"", filename); + xrc = -1; + goto EXITPOINT; + } /* Write out the instance variable table required for the code model element parser */ - write_inst_var_info(fp, ifs_table); + if (write_inst_var_info(fp, ifs_table) != 0) { + print_error("ERROR - Problems writing instaice variables to \"%s\"", + filename); + xrc = -1; + goto EXITPOINT; + } /* Write out the externally visible structure for this model */ - write_SPICEdev(fp, ifs_table); - - - /* Close the ifspec.c file and return */ - - int_status = fclose(fp); - - if (int_status == 0) { - return 0; + if (write_SPICEdev(fp, ifs_table) != 0) { + print_error("ERROR - Problems writing model structureto \"%s\"", + filename); + xrc = -1; + goto EXITPOINT; } - else { - return -1; + + +EXITPOINT: + /* Close the ifspec.c file, free allocation, and return */ + if (fp != (FILE *) NULL) { + if (fclose(fp) != 0) { + print_error("ERROR - Problems closing \"%s\": %s.", + filename, strerror(errno)); + xrc = -1; + } } -} + + if (filename != (char *) NULL) { + free(filename); + } + + return xrc; +} /* end of function write_ifs_c_file */ @@ -178,21 +207,29 @@ generated and should not be edited. */ -static void write_comment( +static int write_comment( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - fprintf(fp, "\n"); - fprintf(fp, "/*\n"); - fprintf(fp, " * Structures for model: %s\n", ifs_table->name.model_name); - fprintf(fp, " *\n"); - fprintf(fp, " * Automatically generated by cmpp preprocessor\n"); - fprintf(fp, " *\n"); - fprintf(fp, " * !!! DO NOT EDIT !!!\n"); - fprintf(fp, " *\n"); - fprintf(fp, " */\n"); - fprintf(fp, "\n"); -} + const int rc = fprintf(fp, + "\n" + "/*\n" + " * Structures for model: %s\n" + " *\n" + " * Automatically generated by cmpp preprocessor\n" + " *\n" + " * !!! DO NOT EDIT !!!\n" + " *\n" + " */\n" + "\n", + ifs_table->name.model_name); + if (rc < 0) { + print_error("Comment writing failed."); + return -1; + } + return 0; +} /* end of function write_comment */ + /* *********************************************************************** */ @@ -205,21 +242,28 @@ ifspec.c. */ -static void write_includes( +static int write_includes( FILE *fp) /* File to write to */ { - fprintf(fp, "\n"); - fprintf(fp, "#include \"ngspice/ngspice.h\"\n"); -/* fprintf(fp, "#include \"ngspice/prefix.h\"\n");*/ - fprintf(fp, "#include \n"); - fprintf(fp, "#include \"ngspice/devdefs.h\"\n"); - fprintf(fp, "#include \"ngspice/ifsim.h\"\n"); - fprintf(fp, "#include \"ngspice/mifdefs.h\"\n"); - fprintf(fp, "#include \"ngspice/mifproto.h\"\n"); - fprintf(fp, "#include \"ngspice/mifparse.h\"\n"); -/* fprintf(fp, "#include \"ngspice/suffix.h\"\n");*/ - fprintf(fp, "\n"); -} + const int rc = fprintf(fp, + "\n" + "#include \"ngspice/ngspice.h\"\n" +/* "#include \"ngspice/prefix.h\"\n"*/ + "#include \n" + "#include \"ngspice/devdefs.h\"\n" + "#include \"ngspice/ifsim.h\"\n" + "#include \"ngspice/mifdefs.h\"\n" + "#include \"ngspice/mifproto.h\"\n" + "#include \"ngspice/mifparse.h\"\n" +/* "#include \"ngspice/suffix.h\"\n"*/ + "\n"); + if (rc < 0) { + print_error("Include writing failed."); + return -1; + } + return 0; +} /* end of function write_includes */ + /* *********************************************************************** */ @@ -238,28 +282,28 @@ that can be queried using the SPICE 3C1 .save feature. */ -static void write_pTable( +static int write_pTable( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - + int xrc = 0; int i; - char str[80]; bool is_array; Data_Type_t type; /* Only write the pTable if there is something to put in it. */ /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ + if (ifs_table->num_inst_var == 0) { + return 0; + } - if(ifs_table->num_inst_var == 0) - return; - + int rc = 0; /* Write the structure beginning */ - - fprintf(fp, "\n"); - fprintf(fp, "static IFparm MIFpTable[] = {\n"); + rc |= fprintf(fp, + "\n" + "static IFparm MIFpTable[] = {\n"); /* Write out an entry for each instance variable in the table */ @@ -267,68 +311,71 @@ static void write_pTable( /* Use the index of the element in the instance variable info array */ /* ADDED TO the number of parameters as the SPICE3 integer tag. */ - for(i = 0; i < ifs_table->num_inst_var; i++) { + for (i = 0; i < ifs_table->num_inst_var; i++) { /* Use the SPICE3 OP macro since instance vars are output-only */ - fprintf(fp, " OP("); + rc |= fprintf(fp, " OP("); /* Put in the name of the parameter and the integer tag */ - fprintf(fp, "\"%s\", ", ifs_table->inst_var[i].name); - fprintf(fp, "%d, ", i + ifs_table->num_param); + rc |= fprintf(fp, "\"%s\", ", ifs_table->inst_var[i].name); + rc |= fprintf(fp, "%d, ", i + ifs_table->num_param); /* Format SPICE3 type according to parameter type field */ type = ifs_table->inst_var[i].type; is_array = ifs_table->inst_var[i].is_array; - strcpy(str,""); - if(is_array == true) { - strcat(str,"("); + rc |= fprintf(fp, "("); } if(type == CMPP_BOOLEAN) { - strcat(str,"IF_FLAG"); /* There is no BOOLEAN in SPICE3 */ + rc |= fprintf(fp, "IF_FLAG"); /* no BOOLEAN in SPICE3 */ } else if(type == CMPP_INTEGER) { - strcat(str,"IF_INTEGER"); + rc |= fprintf(fp, "IF_INTEGER"); } else if(type == CMPP_REAL) { - strcat(str,"IF_REAL"); + rc |= fprintf(fp, "IF_REAL"); } else if(type == CMPP_COMPLEX) { - strcat(str,"IF_COMPLEX"); + rc |= fprintf(fp, "IF_COMPLEX"); } else if(type == CMPP_STRING) { - strcat(str,"IF_STRING"); + rc |= fprintf(fp, "IF_STRING"); } else if(type == CMPP_POINTER) { - strcat(str,"IF_STRING"); + rc |= fprintf(fp, "IF_STRING"); } else { print_error("INTERNAL ERROR - write_pTable() - Impossible data type."); + xrc = -1; + rc |= fprintf(fp, "INVALID DATA TYPE"); } if(is_array == true) { - strcat(str,"|IF_VECTOR)"); + rc |= fprintf(fp, "|IF_VECTOR)"); } - fprintf(fp, "%s, ", str); /* Put in the description string and finish this line off */ - - fprintf(fp, "\"%s\"", ifs_table->inst_var[i].description); - fprintf(fp, "),\n"); - - } + rc |= fprintf(fp, ", \"%s\"),\n", ifs_table->inst_var[i].description); + } /* end of loop over instance variables */ /* Finish off the structure */ + rc |= fprintf(fp, "};\n\n"); + + /* Check outputs */ + if (rc < 0) { + print_error("pTable writing failed."); + xrc = -1; + } + + return xrc; +} /* end of function write_pTable */ - fprintf(fp, "};\n"); - fprintf(fp, "\n"); -} /* *********************************************************************** */ @@ -345,95 +392,95 @@ model parameters are derived from the Interface Specification's PARAMETER table. */ -static void write_mPTable( +static int write_mPTable( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - + int xrc = 0; int i; - char str[80]; - bool is_array; - Data_Type_t type; /* Only write the mPTable if there is something to put in it. */ /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ - if(ifs_table->num_param == 0) - return; + if (ifs_table->num_param == 0) { + return 0; + } + int rc = 0; /* Write the structure beginning */ - - fprintf(fp, "\n"); - fprintf(fp, "static IFparm MIFmPTable[] = {\n"); + rc |= fprintf(fp, + "\n" + "static IFparm MIFmPTable[] = {\n"); /* Write out an entry for each parameter in the table */ /* Use the index of the element in the parameter info array */ /* as the SPICE3 integer tag. */ - + Param_Info_t *param = ifs_table->param; for(i = 0; i < ifs_table->num_param; i++) { + Param_Info_t *param_cur = param + i; /* Use the SPICE3 IOP macro since model parameters are input/output */ - fprintf(fp, " IOP("); + rc |= fprintf(fp, " IOP("); /* Put in the name of the parameter and the integer tag */ - - fprintf(fp, "\"%s\", ", ifs_table->param[i].name); - fprintf(fp, "%d, ", i); + rc |= fprintf(fp, "\"%s\", ", param_cur->name); + rc |= fprintf(fp, "%d, ", i); /* Format SPICE3 type according to parameter type field */ - type = ifs_table->param[i].type; - is_array = ifs_table->param[i].is_array; + const bool is_array = param_cur->is_array; + const Data_Type_t type = param_cur->type; - strcpy(str,""); - - if(is_array == true) { - strcat(str,"("); + if (is_array) { + rc |= fprintf(fp, "("); } - if(type == CMPP_BOOLEAN) { - strcat(str,"IF_FLAG"); /* There is no BOOLEAN in SPICE3 */ + if (type == CMPP_BOOLEAN) { + rc |= fprintf(fp, "IF_FLAG"); /* no BOOLEAN in SPICE3 */ } - else if(type == CMPP_INTEGER) { - strcat(str,"IF_INTEGER"); + else if (type == CMPP_INTEGER) { + rc |= fprintf(fp, "IF_INTEGER"); } - else if(type == CMPP_REAL) { - strcat(str,"IF_REAL"); + else if (type == CMPP_REAL) { + rc |= fprintf(fp, "IF_REAL"); } - else if(type == CMPP_COMPLEX) { - strcat(str,"IF_COMPLEX"); + else if (type == CMPP_COMPLEX) { + rc |= fprintf(fp, "IF_COMPLEX"); } - else if(type == CMPP_STRING) { - strcat(str,"IF_STRING"); + else if (type == CMPP_STRING) { + rc |= fprintf(fp, "IF_STRING"); } else { print_error("INTERNAL ERROR - write_mPTable() - Impossible data type."); + xrc = -1; } - if(is_array == true) { - strcat(str,"|IF_VECTOR)"); + if (is_array) { + rc |= fprintf(fp, "|IF_VECTOR)"); } - fprintf(fp, "%s, ", str); /* Put in the description string and finish this line off */ - - fprintf(fp, "\"%s\"", ifs_table->param[i].description); - fprintf(fp, "),\n"); - - } + rc |= fprintf(fp, ", \"%s\"),\n", ifs_table->param[i].description); + } /* end of loop over parameters */ /* Finish off the structure */ + rc |= fprintf(fp, "};\n\n"); - fprintf(fp, "};\n"); - fprintf(fp, "\n"); + /* Check outputs */ + if (rc < 0) { + print_error("mPTable writing failed."); + xrc = -1; + } + + return xrc; +} /* end of function write_mPTable */ -} /* *********************************************************************** */ @@ -450,147 +497,164 @@ derived from the Interface Specification file's PORT table. -static void write_conn_info( +static int write_conn_info( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - + int xrc = 0; int i; int j; - char *str; + const char *str; + int rc = 0; /* Only write the connTable if there is something to put in it. */ /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ - if(ifs_table->num_conn == 0) /* An unlikely condition for sure ... */ - return; + if (ifs_table->num_conn == 0) { /* An unlikely condition for sure ... */ + return 0; + } /* First, we must define arrays of port types */ /* Note that there should be always at least one allowed port type */ /* so we don't have to worry about arrays with no elements */ - for(i = 0; i < ifs_table->num_conn; i++) { + const Conn_Info_t * const conn = ifs_table->conn; + const int num_conn = ifs_table->num_conn; + for (i = 0; i < num_conn; i++) { + const Conn_Info_t * const p_conn_cur = conn + i; + rc |= fprintf(fp, + "\n" + "static Mif_Port_Type_t MIFportEnum%d[] = {\n", i); - fprintf(fp, "\n"); - fprintf(fp, "static Mif_Port_Type_t MIFportEnum%d[] = {\n", i); - - if(ifs_table->conn[i].num_allowed_types < 1) - print_error("ERROR - write_conn_info() - Number of allowed types cannot be zero"); - - for(j = 0; j < ifs_table->conn[i].num_allowed_types; j++) { - - str = port_type_to_str(ifs_table->conn[i].allowed_port_type[j]); - fprintf(fp, "\t%s,\n", str); + if (p_conn_cur->num_allowed_types < 1) { + print_error("ERROR - write_conn_info() - " + "Number of allowed types cannot be zero"); + xrc = -1; + } + const int num_allowed_types = p_conn_cur->num_allowed_types; + for (j = 0; j < num_allowed_types; j++) { + rc |= fprintf(fp, " %s,\n", + port_type_to_str(p_conn_cur->allowed_port_type[j])); } /* for number of allowed types */ - fprintf(fp, "};\n"); - fprintf(fp, "\n"); + rc |= fprintf(fp, + "};\n" + "\n" + "\n" + "static char *MIFportStr%d[] = {\n", i); - - fprintf(fp, "\n"); - fprintf(fp, "static char *MIFportStr%d[] = {\n", i); - - for(j = 0; j < ifs_table->conn[i].num_allowed_types; j++) { - if(ifs_table->conn[i].allowed_port_type[j] == USER_DEFINED) - fprintf(fp, "\t\"%s\",\n", ifs_table->conn[i].allowed_type[j]); + for (j = 0; j < num_allowed_types; j++) { + if (p_conn_cur->allowed_port_type[j] == USER_DEFINED) { + rc |= fprintf(fp, " \"%s\",\n", + p_conn_cur->allowed_type[j]); + } else { - str = gen_port_type_str(ifs_table->conn[i].allowed_port_type[j]); - fprintf(fp, "\t\"%s\",\n", str); + str = gen_port_type_str(p_conn_cur->allowed_port_type[j]); + rc |= fprintf(fp, " \"%s\",\n", str); } } /* for number of allowed types */ - fprintf(fp, "};\n"); - fprintf(fp, "\n"); - + rc |= fprintf(fp, + "};\n" + "\n"); } /* for number of connections */ /* Now write the structure */ - - fprintf(fp, "\n"); - fprintf(fp, "static Mif_Conn_Info_t MIFconnTable[] = {\n"); + rc |= fprintf(fp, + "\n" + "static Mif_Conn_Info_t MIFconnTable[] = {\n"); /* Write out an entry for each parameter in the table */ - for(i = 0; i < ifs_table->num_conn; i++) { + for (i = 0; i < num_conn; i++) { + const Conn_Info_t * const p_conn_cur = conn + i; - fprintf(fp, " {\n"); - fprintf(fp, " \"%s\",\n",ifs_table->conn[i].name); - fprintf(fp, " \"%s\",\n",ifs_table->conn[i].description); + rc |= fprintf(fp, " {\n"); + rc |= fprintf(fp, " \"%s\",\n", p_conn_cur->name); + rc |= fprintf(fp, " \"%s\",\n", p_conn_cur->description); - str = dir_to_str(ifs_table->conn[i].direction); - fprintf(fp, " %s,\n", str); + str = dir_to_str(p_conn_cur->direction); + rc |= fprintf(fp, " %s,\n", str); - str = port_type_to_str(ifs_table->conn[i].default_port_type); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", + port_type_to_str(p_conn_cur->default_port_type)); - fprintf(fp, " \"%s\",\n", - (ifs_table->conn[i].default_port_type == USER_DEFINED) - ? ifs_table->conn[i].default_type - : gen_port_type_str (ifs_table->conn[i].default_port_type)); + rc |= fprintf(fp, " \"%s\",\n", + (p_conn_cur->default_port_type == USER_DEFINED) + ? p_conn_cur->default_type + : gen_port_type_str(p_conn_cur->default_port_type)); - fprintf(fp," %d,\n",ifs_table->conn[i].num_allowed_types); - - fprintf(fp, " MIFportEnum%d,\n", i); - fprintf(fp, " MIFportStr%d,\n", i); + rc |= fprintf(fp," %d,\n", p_conn_cur->num_allowed_types); + rc |= fprintf(fp, " MIFportEnum%d,\n", i); + rc |= fprintf(fp, " MIFportStr%d,\n", i); - str = boolean_to_str(ifs_table->conn[i].is_array); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_conn_cur->is_array); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->conn[i].is_array == false) { + if (p_conn_cur->is_array == false) { str = boolean_to_str(false); /* has_lower_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* lower_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = boolean_to_str(false); /* has_upper_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* upper_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); } else { /* is_array == true */ - str = boolean_to_str(ifs_table->conn[i].has_lower_bound); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_conn_cur->has_lower_bound); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->conn[i].has_lower_bound == true) - str = integer_to_str(ifs_table->conn[i].lower_bound); + if (p_conn_cur->has_lower_bound == true) + str = integer_to_str(p_conn_cur->lower_bound); else str = integer_to_str(0); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); - str = boolean_to_str(ifs_table->conn[i].has_upper_bound); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_conn_cur->has_upper_bound); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->conn[i].has_upper_bound == true) - str = integer_to_str(ifs_table->conn[i].upper_bound); + if (p_conn_cur->has_upper_bound == true) + str = integer_to_str(p_conn_cur->upper_bound); else str = integer_to_str(0); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); } /* if is_array */ - str = boolean_to_str(ifs_table->conn[i].null_allowed); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_conn_cur->null_allowed); + rc |= fprintf(fp, " %s,\n", str); - fprintf(fp, " },\n"); + rc |= fprintf(fp, " },\n"); } /* for number of parameters */ /* Finish off the structure */ + rc |= fprintf(fp, + "};\n" + "\n"); + + /* Check outputs */ + if (rc < 0) { + print_error("Writing of connection information failed."); + xrc = -1; + } + + return xrc; +} /* end of function write_conn_info */ - fprintf(fp, "};\n"); - fprintf(fp, "\n"); -} /* *********************************************************************** */ @@ -613,152 +677,162 @@ input deck. -static void write_param_info( +static int write_param_info( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - + int xrc = 0; int i; - char *str; + const char *str; /* Only write the paramTable if there is something to put in it. */ /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ - if(ifs_table->num_param == 0) - return; + if (ifs_table->num_param == 0) { + return 0; + } /* Write the structure beginning */ - - fprintf(fp, "\n"); - fprintf(fp, "static Mif_Param_Info_t MIFparamTable[] = {\n"); + int rc = 0; + rc |= fprintf(fp, + "\n" + "static Mif_Param_Info_t MIFparamTable[] = {\n"); /* Write out an entry for each parameter in the table */ + const Param_Info_t * const param = ifs_table->param; + const int num_param = ifs_table->num_param; + for (i = 0; i < num_param; i++) { + const Param_Info_t * const p_param_cur = param + i; - for(i = 0; i < ifs_table->num_param; i++) { + rc |= fprintf(fp, " {\n"); + rc |= fprintf(fp, " \"%s\",\n", p_param_cur->name); + rc |= fprintf(fp, " \"%s\",\n", p_param_cur->description); - fprintf(fp, " {\n"); - fprintf(fp, " \"%s\",\n",ifs_table->param[i].name); - fprintf(fp, " \"%s\",\n",ifs_table->param[i].description); + rc |= fprintf(fp, " %s,\n", + data_type_to_str(p_param_cur->type)); - str = data_type_to_str(ifs_table->param[i].type); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->has_default); + rc |= fprintf(fp, " %s,\n", str); - str = boolean_to_str(ifs_table->param[i].has_default); - fprintf(fp, " %s,\n", str); - - if(ifs_table->param[i].has_default == true) - str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].default_value); + if (p_param_cur->has_default == true) + str = value_to_str(p_param_cur->type, p_param_cur->default_value); else str = no_value_to_str(); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); - str = boolean_to_str(ifs_table->param[i].has_lower_limit); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->has_lower_limit); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_lower_limit == true) - str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].lower_limit); + if (p_param_cur->has_lower_limit == true) + str = value_to_str(p_param_cur->type, p_param_cur->lower_limit); else str = no_value_to_str(); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); - str = boolean_to_str(ifs_table->param[i].has_upper_limit); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->has_upper_limit); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_upper_limit == true) - str = value_to_str(ifs_table->param[i].type, ifs_table->param[i].upper_limit); + if (p_param_cur->has_upper_limit == true) + str = value_to_str(p_param_cur->type, p_param_cur->upper_limit); else str = no_value_to_str(); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); - str = boolean_to_str(ifs_table->param[i].is_array); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->is_array); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].is_array == false) { + if (!p_param_cur->is_array) { str = boolean_to_str(false); /* has_conn_ref */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* conn_ref */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = boolean_to_str(false); /* has_lower_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* lower_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = boolean_to_str(false); /* has_upper_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* upper_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); } else { /* is_array == true */ - str = boolean_to_str(ifs_table->param[i].has_conn_ref); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->has_conn_ref); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_conn_ref == true) { + if (p_param_cur->has_conn_ref) { - str = integer_to_str(ifs_table->param[i].conn_ref); - fprintf(fp, " %s,\n", str); + str = integer_to_str(p_param_cur->conn_ref); + rc |= fprintf(fp, " %s,\n", str); str = boolean_to_str(false); /* has_lower_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* lower_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = boolean_to_str(false); /* has_upper_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); str = integer_to_str(0); /* upper_bound */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); } else { /* has_conn_ref == false */ str = integer_to_str(0); /* conn_ref */ - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); - str = boolean_to_str(ifs_table->param[i].has_lower_bound); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->has_lower_bound); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_lower_bound == true) - str = integer_to_str(ifs_table->param[i].lower_bound); + if (p_param_cur->has_lower_bound) + str = integer_to_str(p_param_cur->lower_bound); else str = integer_to_str(0); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); - str = boolean_to_str(ifs_table->param[i].has_upper_bound); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->has_upper_bound); + rc |= fprintf(fp, " %s,\n", str); - if(ifs_table->param[i].has_upper_bound == true) - str = integer_to_str(ifs_table->param[i].upper_bound); + if (p_param_cur->has_upper_bound) + str = integer_to_str(p_param_cur->upper_bound); else str = integer_to_str(0); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); } /* if has_conn_ref */ } /* if is_array */ - str = boolean_to_str(ifs_table->param[i].null_allowed); - fprintf(fp, " %s,\n", str); + str = boolean_to_str(p_param_cur->null_allowed); + rc |= fprintf(fp, " %s,\n", str); - fprintf(fp, " },\n"); + rc |= fprintf(fp, " },\n"); } /* for number of parameters */ /* Finish off the structure */ - fprintf(fp, "};\n"); - fprintf(fp, "\n"); + rc |= fprintf(fp, "};\n\n"); -} + /* Check outputs */ + if (rc < 0) { + print_error("Writing of param information failed."); + xrc = -1; + } + + return xrc; +} /* end of function write_param_info */ @@ -780,53 +854,59 @@ written by write_inst_var_info is more extensive. -static void write_inst_var_info( +static int write_inst_var_info( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - + int xrc = 0; int i; - char *str; + const char *str; /* Only write the inst_varTable if there is something to put in it. */ /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ - if(ifs_table->num_inst_var == 0) - return; + if (ifs_table->num_inst_var == 0) + return 0; /* Write the structure beginning */ - - fprintf(fp, "\n"); - fprintf(fp, "static Mif_Inst_Var_Info_t MIFinst_varTable[] = {\n"); + int rc = 0; + rc |= fprintf(fp, + "\n" + "static Mif_Inst_Var_Info_t MIFinst_varTable[] = {\n"); /* Write out an entry for each parameter in the table */ for(i = 0; i < ifs_table->num_inst_var; i++) { - fprintf(fp, " {\n"); - fprintf(fp, " \"%s\",\n",ifs_table->inst_var[i].name); - fprintf(fp, " \"%s\",\n",ifs_table->inst_var[i].description); + rc |= fprintf(fp, " {\n"); + rc |= fprintf(fp, " \"%s\",\n",ifs_table->inst_var[i].name); + rc |= fprintf(fp, " \"%s\",\n",ifs_table->inst_var[i].description); - str = data_type_to_str(ifs_table->inst_var[i].type); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", + data_type_to_str(ifs_table->inst_var[i].type)); str = boolean_to_str(ifs_table->inst_var[i].is_array); - fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " %s,\n", str); - fprintf(fp, " },\n"); + rc |= fprintf(fp, " },\n"); } /* for number of parameters */ /* Finish off the structure */ - fprintf(fp, "};\n"); - fprintf(fp, "\n"); + rc |= fprintf(fp, "};\n\n"); -} + /* Check outputs */ + if (rc < 0) { + print_error("Writing of instance variable information failed."); + xrc = -1; + } + return xrc; +} /* end of function write_inst_var_info */ @@ -845,118 +925,133 @@ pointers to all of the above data structures. -static void write_SPICEdev( +static int write_SPICEdev( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - - /* Extern the code model function name */ - fprintf(fp, "\n"); - fprintf(fp, "extern void %s(Mif_Private_t *);\n", - ifs_table->name.c_fcn_name); + int rc = 0; /* init print rc to nonnegative (no error) */ + int xrc = 0; - /* SPICE now needs these static integers */ - fprintf(fp, "\n"); - fprintf(fp, "static int val_terms = 0;\n"); - fprintf(fp, "static int val_numNames = 0;\n"); - fprintf(fp, "static int val_numInstanceParms = %d;\n",ifs_table->num_inst_var); - fprintf(fp, "static int val_numModelParms = %d;\n",ifs_table->num_param); - fprintf(fp, "static int val_sizeofMIFinstance = sizeof(MIFinstance);\n"); - fprintf(fp, "static int val_sizeofMIFmodel = sizeof(MIFmodel);\n"); + /* Extern the code model function name */ + rc |= fprintf(fp, + "\n" + "extern void %s(Mif_Private_t *);\n", + ifs_table->name.c_fcn_name); + + /* SPICE now needs these static integers */ + rc |= fprintf(fp, + "\n" + "static int val_terms = 0;\n" + "static int val_numNames = 0;\n" + "static int val_numInstanceParms = %d;\n" + "static int val_numModelParms = %d;\n" + "static int val_sizeofMIFinstance = sizeof(MIFinstance);\n" + "static int val_sizeofMIFmodel = sizeof(MIFmodel);\n", + ifs_table->num_inst_var, ifs_table->num_param); /* Write out the structure beginning */ /* Use the c function external identifier appended with _info as the */ /* external identifier for the structure. */ - fprintf(fp, "\n"); - fprintf(fp, "SPICEdev %s_info = {\n", ifs_table->name.c_fcn_name); + rc |= fprintf(fp, + "\n" + "SPICEdev %s_info = {\n", ifs_table->name.c_fcn_name); /* Write the IFdevice structure */ - fprintf(fp, " .DEVpublic = {\n"); - fprintf(fp, " .name = \"%s\",\n", ifs_table->name.model_name); - fprintf(fp, " .description = \"%s\",\n", ifs_table->name.description); - fprintf(fp, " .terms = &val_terms,\n"); - fprintf(fp, " .numNames = &val_numNames,\n"); - fprintf(fp, " .termNames = NULL,\n"); + rc |= fprintf(fp, " .DEVpublic = {\n"); + rc |= fprintf(fp, " .name = \"%s\",\n", ifs_table->name.model_name); + rc |= fprintf(fp, " .description = \"%s\",\n", ifs_table->name.description); + rc |= fprintf(fp, + " .terms = &val_terms,\n" + " .numNames = &val_numNames,\n" + " .termNames = NULL,\n" + " .numInstanceParms = &val_numInstanceParms,\n"); - fprintf(fp, " .numInstanceParms = &val_numInstanceParms,\n"); if(ifs_table->num_inst_var > 0) - fprintf(fp, " .instanceParms = MIFpTable,\n"); + rc |= fprintf(fp, " .instanceParms = MIFpTable,\n"); else - fprintf(fp, " .instanceParms = NULL,\n"); + rc |= fprintf(fp, " .instanceParms = NULL,\n"); - fprintf(fp, " .numModelParms = &val_numModelParms,\n"); + rc |= fprintf(fp, " .numModelParms = &val_numModelParms,\n"); if(ifs_table->num_param > 0) - fprintf(fp, " .modelParms = MIFmPTable,\n"); + rc |= fprintf(fp, " .modelParms = MIFmPTable,\n"); else - fprintf(fp, " .modelParms = NULL,\n"); - fprintf(fp, " .flags = 0,\n\n"); + rc |= fprintf(fp, " .modelParms = NULL,\n"); + rc |= fprintf(fp, " .flags = 0,\n\n"); - fprintf(fp, " .cm_func = %s,\n", ifs_table->name.c_fcn_name); + rc |= fprintf(fp, " .cm_func = %s,\n", ifs_table->name.c_fcn_name); - fprintf(fp, " .num_conn = %d,\n", ifs_table->num_conn); + rc |= fprintf(fp, " .num_conn = %d,\n", ifs_table->num_conn); if(ifs_table->num_conn > 0) - fprintf(fp, " .conn = MIFconnTable,\n"); + rc |= fprintf(fp, " .conn = MIFconnTable,\n"); else - fprintf(fp, " .conn = NULL,\n"); + rc |= fprintf(fp, " .conn = NULL,\n"); - fprintf(fp, " .num_param = %d,\n", ifs_table->num_param); + rc |= fprintf(fp, " .num_param = %d,\n", ifs_table->num_param); if(ifs_table->num_param > 0) - fprintf(fp, " .param = MIFparamTable,\n"); + rc |= fprintf(fp, " .param = MIFparamTable,\n"); else - fprintf(fp, " .param = NULL,\n"); + rc |= fprintf(fp, " .param = NULL,\n"); - fprintf(fp, " .num_inst_var = %d,\n", ifs_table->num_inst_var); + rc |= fprintf(fp, " .num_inst_var = %d,\n", ifs_table->num_inst_var); if(ifs_table->num_inst_var > 0) - fprintf(fp, " .inst_var = MIFinst_varTable,\n"); + rc |= fprintf(fp, " .inst_var = MIFinst_varTable,\n"); else - fprintf(fp, " .inst_var = NULL,\n"); + rc |= fprintf(fp, " .inst_var = NULL,\n"); - fprintf(fp, " },\n\n"); + rc |= fprintf(fp, " },\n\n"); /* Write the names of the generic code model functions */ - fprintf(fp, " .DEVparam = NULL,\n"); - fprintf(fp, " .DEVmodParam = MIFmParam,\n"); - fprintf(fp, " .DEVload = MIFload,\n"); - fprintf(fp, " .DEVsetup = MIFsetup,\n"); - fprintf(fp, " .DEVunsetup = MIFunsetup,\n"); - fprintf(fp, " .DEVpzSetup = NULL,\n"); - fprintf(fp, " .DEVtemperature = NULL,\n"); - fprintf(fp, " .DEVtrunc = MIFtrunc,\n"); - fprintf(fp, " .DEVfindBranch = NULL,\n"); - fprintf(fp, " .DEVacLoad = MIFload,\n"); - fprintf(fp, " .DEVaccept = NULL,\n"); - fprintf(fp, " .DEVdestroy = MIFdestroy,\n"); - fprintf(fp, " .DEVmodDelete = MIFmDelete,\n"); - fprintf(fp, " .DEVdelete = MIFdelete,\n"); - fprintf(fp, " .DEVsetic = NULL,\n"); - fprintf(fp, " .DEVask = MIFask,\n"); - fprintf(fp, " .DEVmodAsk = MIFmAsk,\n"); - fprintf(fp, " .DEVpzLoad = NULL,\n"); - fprintf(fp, " .DEVconvTest = MIFconvTest,\n"); - fprintf(fp, " .DEVsenSetup = NULL,\n"); - fprintf(fp, " .DEVsenLoad = NULL,\n"); - fprintf(fp, " .DEVsenUpdate = NULL,\n"); - fprintf(fp, " .DEVsenAcLoad = NULL,\n"); - fprintf(fp, " .DEVsenPrint = NULL,\n"); - fprintf(fp, " .DEVsenTrunc = NULL,\n"); - fprintf(fp, " .DEVdisto = NULL,\n"); - fprintf(fp, " .DEVnoise = NULL,\n"); - fprintf(fp, " .DEVsoaCheck = NULL,\n"); - fprintf(fp, " .DEVinstSize = &val_sizeofMIFinstance,\n"); - fprintf(fp, " .DEVmodSize = &val_sizeofMIFmodel,\n"); - fprintf(fp, "\n"); - fprintf(fp, "#ifdef CIDER\n"); - fprintf(fp, " .DEVdump = NULL,\n"); - fprintf(fp, " .DEVacct = NULL,\n"); - fprintf(fp, "#endif\n"); - fprintf(fp, "};\n"); - fprintf(fp, "\n"); -} + rc |= fprintf(fp, + " .DEVparam = NULL,\n" + " .DEVmodParam = MIFmParam,\n" + " .DEVload = MIFload,\n" + " .DEVsetup = MIFsetup,\n" + " .DEVunsetup = MIFunsetup,\n" + " .DEVpzSetup = NULL,\n" + " .DEVtemperature = NULL,\n" + " .DEVtrunc = MIFtrunc,\n" + " .DEVfindBranch = NULL,\n" + " .DEVacLoad = MIFload,\n" + " .DEVaccept = NULL,\n" + " .DEVdestroy = MIFdestroy,\n" + " .DEVmodDelete = MIFmDelete,\n" + " .DEVdelete = MIFdelete,\n" + " .DEVsetic = NULL,\n" + " .DEVask = MIFask,\n" + " .DEVmodAsk = MIFmAsk,\n" + " .DEVpzLoad = NULL,\n" + " .DEVconvTest = MIFconvTest,\n" + " .DEVsenSetup = NULL,\n" + " .DEVsenLoad = NULL,\n" + " .DEVsenUpdate = NULL,\n" + " .DEVsenAcLoad = NULL,\n" + " .DEVsenPrint = NULL,\n" + " .DEVsenTrunc = NULL,\n" + " .DEVdisto = NULL,\n" + " .DEVnoise = NULL,\n" + " .DEVsoaCheck = NULL,\n" + " .DEVinstSize = &val_sizeofMIFinstance,\n" + " .DEVmodSize = &val_sizeofMIFmodel,\n" + "\n" + "#ifdef CIDER\n" + " .DEVdump = NULL,\n" + " .DEVacct = NULL,\n" + "#endif\n" + "};\n\n" + ); + /* Check outputs */ + if (rc < 0) { + print_error("Writing of SPICE device information failed."); + xrc = -1; + } + + return xrc; +} /* end of function write_SPICEdev */ @@ -973,202 +1068,111 @@ being created. #define BASE_STR_LEN 80 -static char *data_type_to_str(Data_Type_t type) +static const char *data_type_to_str(Data_Type_t type) { - static char *str = NULL; - - if(str == NULL) - str = (char *) malloc(BASE_STR_LEN+1); - - switch(type) { - + switch (type) { case CMPP_BOOLEAN: - strcpy(str,"MIF_BOOLEAN"); - break; - + return "MIF_BOOLEAN"; case CMPP_INTEGER: - strcpy(str,"MIF_INTEGER"); - break; - + return "MIF_INTEGER"; case CMPP_REAL: - strcpy(str,"MIF_REAL"); - break; - + return "MIF_REAL"; case CMPP_COMPLEX: - strcpy(str,"MIF_COMPLEX"); - break; - + return "MIF_COMPLEX"; case CMPP_STRING: - strcpy(str,"MIF_STRING"); - break; - - case CMPP_POINTER: - strcpy(str,"MIF_STRING"); - break; - + case CMPP_POINTER: + return "MIF_STRING"; default: print_error("INTERNAL ERROR - data_type_to_str() - Impossible data type."); + return "INVALID DATA TYPE"; } - - return(str); } /* *********************************************************************** */ -static char *port_type_to_str(Port_Type_t port) +static const char *port_type_to_str(Port_Type_t port) { - static char *str = NULL; - - if(str == NULL) - str = (char *) malloc(BASE_STR_LEN+1); - - switch(port) { - + switch (port) { case VOLTAGE: - strcpy(str,"MIF_VOLTAGE"); - break; - + return "MIF_VOLTAGE"; case DIFF_VOLTAGE: - strcpy(str,"MIF_DIFF_VOLTAGE"); - break; - + return "MIF_DIFF_VOLTAGE"; case CURRENT: - strcpy(str,"MIF_CURRENT"); - break; - + return "MIF_CURRENT"; case DIFF_CURRENT: - strcpy(str,"MIF_DIFF_CURRENT"); - break; - + return "MIF_DIFF_CURRENT"; case VSOURCE_CURRENT: - strcpy(str,"MIF_VSOURCE_CURRENT"); - break; - + return "MIF_VSOURCE_CURRENT"; case CONDUCTANCE: - strcpy(str,"MIF_CONDUCTANCE"); - break; - + return "MIF_CONDUCTANCE"; case DIFF_CONDUCTANCE: - strcpy(str,"MIF_DIFF_CONDUCTANCE"); - break; - + return "MIF_DIFF_CONDUCTANCE"; case RESISTANCE: - strcpy(str,"MIF_RESISTANCE"); - break; - + return "MIF_RESISTANCE"; case DIFF_RESISTANCE: - strcpy(str,"MIF_DIFF_RESISTANCE"); - break; - + return "MIF_DIFF_RESISTANCE"; case DIGITAL: - strcpy(str,"MIF_DIGITAL"); - break; - + return "MIF_DIGITAL"; case USER_DEFINED: - strcpy(str,"MIF_USER_DEFINED"); - break; - + return "MIF_USER_DEFINED"; default: print_error("INTERNAL ERROR - port_type_to_str() - Impossible port type."); + return "INVALID PORT TYPE"; } - - return(str); - } /* *********************************************************************** */ -static char *gen_port_type_str(Port_Type_t port) +static const char *gen_port_type_str(Port_Type_t port) { - static char *str = NULL; - - if(str == NULL) - str = (char *) malloc(BASE_STR_LEN+1); - - switch(port) { - + switch (port) { case VOLTAGE: - strcpy(str,"v"); - break; - + return "v"; case DIFF_VOLTAGE: - strcpy(str,"vd"); - break; - + return "vd"; case CURRENT: - strcpy(str,"i"); - break; - + return "i"; case DIFF_CURRENT: - strcpy(str,"id"); - break; - + return "id"; case VSOURCE_CURRENT: - strcpy(str,"vnam"); - break; - + return "vnam"; case CONDUCTANCE: - strcpy(str,"g"); - break; - + return "g"; case DIFF_CONDUCTANCE: - strcpy(str,"gd"); - break; - + return "gd"; case RESISTANCE: - strcpy(str,"h"); - break; - + return "h"; case DIFF_RESISTANCE: - strcpy(str,"hd"); - break; - + return "hd"; case DIGITAL: - strcpy(str,"d"); - break; - + return "d"; case USER_DEFINED: - strcpy(str,""); - break; - + return ""; default: - print_error("INTERNAL ERROR - gen_port_type_str() - Impossible port type."); + print_error("INTERNAL ERROR - gen_port_type_str() - " + "Impossible port type."); + return "INVALID PORT TYPE"; } +} /* end of function gen_port_type_str */ - return(str); - -} /* *********************************************************************** */ -static char *dir_to_str(Dir_t dir) +static const char *dir_to_str(Dir_t dir) { - static char *str = NULL; - - if(str == NULL) - str = (char *) malloc(BASE_STR_LEN+1); - switch(dir) { - case CMPP_IN: - strcpy(str,"MIF_IN"); - break; - + return "MIF_IN"; case CMPP_OUT: - strcpy(str,"MIF_OUT"); - break; - + return "MIF_OUT"; case CMPP_INOUT: - strcpy(str,"MIF_INOUT"); - break; - + return "MIF_INOUT"; default: print_error("INTERNAL ERROR - dir_to_str() - Impossible direction type."); + return "MIF_DIRECTION_INVALID"; } - - return(str); } @@ -1180,12 +1184,15 @@ static char *value_to_str(Data_Type_t type, Value_t value) static char *str = NULL; static int max_len = 0; - char *bool_str; + const char *bool_str; int str_len; if(str == NULL) { - str = (char *) malloc(2 * BASE_STR_LEN + 1); + if ((str = (char *) malloc(2 * BASE_STR_LEN + 1)) == (char *) NULL) { + (void) fprintf(stderr, "Unable to allocate string buffer.\n"); + return (char *) NULL; + } max_len = 2 * BASE_STR_LEN; } @@ -1212,35 +1219,38 @@ static char *value_to_str(Data_Type_t type, Value_t value) case CMPP_STRING: /* be careful, the string could conceivably be very long... */ str_len = (int) strlen(value.svalue); - if((str_len + BASE_STR_LEN) > max_len) { - str = (char *) realloc(str, (size_t) (max_len + str_len + 1)); + if ((str_len + BASE_STR_LEN) > max_len) { + size_t n_byte_alloc = max_len + str_len + 1; + void * const p = realloc(str, n_byte_alloc); + if (p == NULL) { + (void) fprintf(stderr, "Unable to resize string " + "buffer to size %zu.\n", + n_byte_alloc); + free(str); + return (char *) NULL; + } + str = (char *) p; max_len += str_len; - } + } /* end of resize */ + sprintf(str, "{MIF_FALSE, 0, 0.0, {0.0, 0.0}, \"%s\"}", value.svalue); break; default: print_error("INTERNAL ERROR - value_to_str() - Impossible data type."); - } + } /* end of switch */ + + return str; +} /* end of function value_to_string */ - return(str); -} /* *********************************************************************** */ -static char *boolean_to_str(bool value) +static const char *boolean_to_str(bool value) { - static char *str = NULL; - - if (str == NULL) { - str = (char *) malloc(BASE_STR_LEN+1); - } - - strcpy(str, value ? "MIF_TRUE" : "MIF_FALSE"); - - return str; + return value ? "MIF_TRUE" : "MIF_FALSE"; } @@ -1248,31 +1258,17 @@ static char *boolean_to_str(bool value) static char *integer_to_str(int value) { - static char *str = NULL; - - if(str == NULL) { - str = (char *) malloc(BASE_STR_LEN + 1); - } - + static char str[3 * sizeof(int) + 1]; sprintf(str, "%d", value); - - return(str); + return str; } /* *********************************************************************** */ -static char *no_value_to_str(void) +static const char *no_value_to_str(void) { - static char *str = NULL; - - if(str == NULL) { - str = (char *) malloc(BASE_STR_LEN + 1); - } - - sprintf(str, "{MIF_FALSE, 0, 0.0, {0.0, 0.0}, NULL}"); - - return(str); + return "{MIF_FALSE, 0, 0.0, {0.0, 0.0}, NULL}"; } From 6ce9003d3d8849cacf938bcdbe0e30a415e6299c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 12 Feb 2020 23:13:08 +0100 Subject: [PATCH 23/36] update to cmpp by J. Monte --- src/xspice/cmpp/file_buffer.c | 698 +++++++++++++++++++++++++++++++ src/xspice/cmpp/file_buffer.h | 58 +++ src/xspice/icm/dlmain.h | 10 + visualc/xspice/cmpp/cmpp.vcxproj | 10 +- 4 files changed, 772 insertions(+), 4 deletions(-) create mode 100644 src/xspice/cmpp/file_buffer.c create mode 100644 src/xspice/cmpp/file_buffer.h create mode 100644 src/xspice/icm/dlmain.h diff --git a/src/xspice/cmpp/file_buffer.c b/src/xspice/cmpp/file_buffer.c new file mode 100644 index 000000000..27a9d10ff --- /dev/null +++ b/src/xspice/cmpp/file_buffer.c @@ -0,0 +1,698 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "file_buffer.h" +#include "cmpp.h" + +/* Default buffer size */ +#define N_BYTE_FILEBUF_INIT_DFLT 16384 + + +static int fb_fill(FILEBUF *p_fb); +static int fbget_quoted_unescaped_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj); +static size_t fb_make_space_at_end(FILEBUF *p_fb); +static int fbget_quoted_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj); +static int fbget_quoted_escaped_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj); +static int fbget_unquoted_string(FILEBUF *p_fb, + unsigned int n_type_wanted, FBTYPE *p_type_wanted, + FBTYPE *p_type_found, FBOBJ *p_fbobj); +static int fb_return_obj(FILEBUF *p_fb, + unsigned int n_type_wanted, FBTYPE *p_type_wanted, + FBTYPE *p_type_found, FBOBJ *p_fbobj); +static int fb_return_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj); +static int fb_skip_to_eol(FILEBUF *p_fb); +static int fb_skip_whitespace(FILEBUF *p_fb); + + +/* This function initializes a file-buffer read access to the named file. + * + * Parameters + * filename: Name of file to be opened for reading + * n_byte_buf_init: Intial buffer size. May be 0 for default size + * + * Return values + * NULL: Error occurred. The value of errno will provide more details + * Otherwise an initialized structure + */ +FILEBUF *fbopen(const char *filename, size_t n_byte_buf_init) +{ + int xrc = 0; + FILEBUF *p_fb = (FILEBUF *) NULL; + + /* Set default buffer size if requested */ + if (n_byte_buf_init == 0) { + n_byte_buf_init = N_BYTE_FILEBUF_INIT_DFLT; + } + + /* Allocate structure to return */ + if ((p_fb = (FILEBUF *) malloc(sizeof *p_fb)) == (FILEBUF *) NULL) { + xrc = -1; + goto EXITPOINT; + } + + p_fb->is_eof = false; + p_fb->f_skip_to_eol = false; + + /* Init resources for error recovery */ + p_fb->fp = (FILE *) NULL; + p_fb->p_buf = (char *) NULL; + + /* Allocate data buffer */ + if ((p_fb->p_buf = (char *) malloc(n_byte_buf_init)) == (char *) NULL) { + xrc = -1; + goto EXITPOINT; + } + p_fb->n_byte_buf_alloc = n_byte_buf_init; + p_fb->p_data_end = p_fb->p_data_cur = p_fb->p_buf; + p_fb->p_buf_end = p_fb->p_buf + n_byte_buf_init; + + /* p_fb->p_obj_undefined since no object yet */ + + /* Open file. It is opened in binary mode because the scanning will + * handle all EOL chars, so any translations by the OS are almost + * pure overhead. Also, not converting ensures that if fread returns + * fewer than the requested number of chars, that read was to the + * end of the file (if not an error). Otherwise an additional read + * getting a size of 0 would be required. */ + if ((p_fb->fp = fopen(filename, "rb")) == (FILE *) NULL) { + xrc = -1; + goto EXITPOINT; + } + +EXITPOINT: + /* Free resources on error */ + if (xrc != 0) { + if (p_fb != (FILEBUF *) NULL) { + const int errno_save = errno; /* save errno in case fbclose() + * changes it */ + (void) fbclose(p_fb); + errno = errno_save; + p_fb = (FILEBUF *) NULL; + } + } /* end of case of error */ + + return p_fb; +} /* end of function fbopen */ + + + +/* This function frees resources used by a FILEBUF. + * + * Parameter + * p_fb: The address of the FILEBUF to free. This argument may be NULL. + * + * Return values + * 0: OK + * EOF: Error closing file. Details can be found using errno. + */ +int fbclose(FILEBUF *p_fb) +{ + if (p_fb == (FILEBUF *) NULL) { + return 0; + } + + int xrc = 0; + + { + void *p; + if ((p = p_fb->p_buf) != NULL) { + free(p); + } + } + + { + FILE *fp; + if ((fp = p_fb->fp) != (FILE *) NULL) { + xrc = fclose(fp); + } + } + + free(p_fb); + return xrc; +} /* end of function fbclose */ + + + +/* This function gets the next object converting it to the most desired + * type. + * + * Parameters + * p_fb: FILEBUF pointer initialized using fbopen() + * n_type_wanted: number of desired type conversions for data from highest + * priority to lowest. + * p_type_wanted: Desired type conversions for data from highest priority + * to lowest. + * p_type_found: Address to receive the type of the data obtained + * p_fbobj: Address of an FBOBJ structure to receive the data + * + * Return codes + * +1: EOF reached + * 0: Normal return + * -1: Error. Use errno for further details. + * + * Remarks + * Type BUF_TYPE_STRING is always implicitly added to the list of wanted + * types as the final choice, which any data will satisfy + * + * A string may be double-quoted. In this case the quotes are not supplied + * to the caller as part of the data. Double-quoting ensures that a string + * will not be converted to any other type. Within double quotes, a double + * qoute and a backslash are escaped by a backslash, and a final unescaped + * double quote is impilcitly added if EOF is reached when scanning for a + * closing quote. + * + * A "*" or a "#" not within a quoted expression begins a comment that + * extends to the end of the line. + * + * When called p_fb has data from the last get or it is the first call. + * + * Return Codes + * +1: EOF + * 0: Normal + * -1: Error + */ +int fbget(FILEBUF *p_fb, + unsigned int n_type_wanted, FBTYPE *p_type_wanted, + FBTYPE *p_type_found, FBOBJ *p_fbobj) +{ + /* Test for existing EOF */ + if (p_fb->is_eof && p_fb->p_data_cur == p_fb->p_data_end) { /* no data */ + return +1; + } + + /* Init to no object */ + p_fb->p_obj_start = (char *) NULL; + + /* Skip the comment if the initiating character was processed during + * the last call to fbget */ + if (p_fb->f_skip_to_eol) { + const int rc = fb_skip_to_eol(p_fb); + if (rc != 0) { /* EOF or error */ + return rc; + } + } + + { + const int rc = fb_skip_whitespace(p_fb); + if (rc != 0) { /* EOF or error */ + return rc; + } + } + + /* Current char exists and starts the item */ + if (*p_fb->p_data_cur == '"') { /* quoted string */ + return fbget_quoted_string(p_fb, p_type_found, p_fbobj); + } + + /* Else unquoted string */ + return fbget_unquoted_string(p_fb, n_type_wanted, p_type_wanted, + p_type_found, p_fbobj); +} /* end of function fbget */ + + + +/* Get a quoted string given at a quote. On entry p_fb->p_data_cur points + * to the quote starting the quoted string. On return it points to the first + * character after the current item or equals p_fb->p_data_end if the + * current item extens to the end of the current data string. */ +static int fbget_quoted_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj) +{ + /* Advance past the opening quote to the true start of the string */ + if (++p_fb->p_data_cur == p_fb->p_data_end) { + /* The leading quote ended the current data */ + const int rc = fb_fill(p_fb); /* Try to refill buffer */ + if (rc != 0) { /* EOF or error */ + if (rc < 0) { /* error */ + return -1; + } + /* Else EOF. This item is an empty string that ended without the + * closing quote, so add an implicit closing quote, i.e., end + * the string to form "". + * + * Since the object was started at the beginning of the buffer + * and the buffer has at leat 1 byte a NULL to create the + * string "" can be written here */ + *(p_fb->p_obj_end = p_fb->p_obj_start = p_fb->p_buf) = '\0'; + return fb_return_string(p_fb, p_type_found, p_fbobj); + } + /* Else data is now available at p_fb->p_data_cur */ + } /* end of case that at end of data from file */ + + /* Save the start of the string as the current position */ + p_fb->p_obj_start = p_fb->p_data_cur; + + /* Continue processing as an unescaped string, unless the contrary + * is found to be true */ + return fbget_quoted_unescaped_string(p_fb, p_type_found, p_fbobj); +} /* end of function fbget_quoted_string */ + + + +/* Get a quoted string with no escape. The start has already been set on + * entry. If an escape is found, processing continues as an escaped string */ +int fbget_quoted_unescaped_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj) +{ + /* Step through characters until end or escape */ + char *p_data_cur = p_fb->p_data_cur; + char *p_data_end = p_fb->p_data_end; + for ( ; ; ) { /* continue until done */ + for ( ; p_data_cur != p_data_end; ++p_data_cur) { /* current data */ + const char ch_cur = *p_data_cur; + if (ch_cur == '"') { /* Closing quote, so done */ + *(p_fb->p_obj_end = p_data_cur) = '\0'; + p_fb->p_data_cur = p_data_cur + 1; + return fb_return_string(p_fb, p_type_found, p_fbobj); + } + if (ch_cur == '\\') { /* Escape */ + /* After an escape, data must be moved to fill in the gap + * left by the escape character */ + p_fb->p_data_cur = p_data_cur; /* Reprocess the escape */ + return fbget_quoted_escaped_string(p_fb, + p_type_found, p_fbobj); + } + /* Else the character is part of the quoted string */ + } /* end of loop over current text */ + + p_fb->p_data_cur = p_data_cur; /* update current position */ + const int rc = fb_fill(p_fb); /* Try to refill buffer */ + if (rc != 0) { /* EOF or error */ + if (rc < 0) { /* error */ + return -1; + } + /* Else EOF. Ended without closing quote, so add an implicit + * closing quote, i.e., end the string. Since fb_fill() + * did not return -1, there is at least 1 byte at the end of + * the buffer where the read would have gone. */ + *(p_fb->p_obj_end = p_fb->p_data_cur) = '\0'; + return fb_return_string(p_fb, p_type_found, p_fbobj); + } + p_data_cur = p_fb->p_data_cur; /* Update after fill */ + p_data_end = p_fb->p_data_end; + } /* end of loop processing until done or escape */ +} /* end of function fbget_quoted_unescaped_string */ + + + +/* Get a quoted string with an escape. The start has already been set on + * entry */ +static int fbget_quoted_escaped_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj) +{ + /* Step through characters until end */ + char *p_data_src = p_fb->p_data_cur; /* at current char */ + char *p_data_dst = p_data_src; /* at current char */ + char *p_data_end = p_fb->p_data_end; + bool f_escape_in_progress = false; + for ( ; ; ) { /* continue until done */ + for ( ; p_data_src != p_data_end; ++p_data_src) { /* current data */ + const char ch_cur = *p_data_src; + if (f_escape_in_progress) { /* Always copy the char */ + f_escape_in_progress = false; + *p_data_dst++ = ch_cur; + } + else { /* Not an escaped character */ + if (ch_cur == '"') { /* Closing quote, so done */ + p_fb->p_data_cur = p_data_src + 1; + *(p_fb->p_obj_end = p_data_dst) = '\0'; + return fb_return_string(p_fb, p_type_found, p_fbobj); + } + if (ch_cur == '\\') { /* Escape */ + f_escape_in_progress = true; + /* Do not copy the escape or advancd p_data_dst */ + } + else { /* ordinary character */ + *p_data_dst++ = ch_cur; + } + } /* end of case of not an escaped character */ + /* Else the character is part of the quoted string */ + } /* end of loop over current text */ + + /* Indicate that there is no more unprocessed data */ + p_fb->p_data_end = p_fb->p_data_cur = p_data_dst; + + /* If no pending escape, can switch back to unescaped version and + * avoid the moves */ + if (!f_escape_in_progress) { + return fbget_quoted_unescaped_string(p_fb, p_type_found, + p_fbobj); + } + + /* Else escape must be processed, so continue with escaped version */ + const int rc = fb_fill(p_fb); /* Try to refill buffer */ + if (rc != 0) { /* EOF or error */ + if (rc < 0) { /* error */ + return -1; + } + /* Else EOF. Ended without closing quote, so add an implicit + * closing quote, i.e., end the string. Since fb_fill() + * did not return -1, there is at least 1 byte at the end of + * the buffer where the read would have gone. */ + *(p_fb->p_obj_end = p_fb->p_data_cur) = '\0'; + return fb_return_string(p_fb, p_type_found, p_fbobj); + } + p_data_dst = p_data_src = p_fb->p_data_cur; /* Update after fill */ + p_data_end = p_fb->p_data_end; + } /* end of loop processing until done or escape */ +} /* end of function fbget_quoted_escaped_string */ + + + +/* Get an unquoted string starting at the current position */ +static int fbget_unquoted_string(FILEBUF *p_fb, + unsigned int n_type_wanted, FBTYPE *p_type_wanted, + FBTYPE *p_type_found, FBOBJ *p_fbobj) +{ + /* Save the start of the string as the current position */ + p_fb->p_obj_start = p_fb->p_data_cur; + + static const signed char p_map[1 << CHAR_BIT] = { + [(unsigned char ) ' '] = (signed char) +1, + [(unsigned char ) '\t'] = (signed char) +1, + [(unsigned char ) '\n'] = (signed char) +1, + [(unsigned char ) '\r'] = (signed char) +1, + [(unsigned char ) '\v'] = (signed char) +1, + [(unsigned char ) '\f'] = (signed char) +1, + [(unsigned char ) '*'] = (signed char) -1, + [(unsigned char ) '#'] = (signed char) -1 + }; + /* Step through characters until whitespace or comment */ + char *p_data_cur = p_fb->p_data_cur; + char *p_data_end = p_fb->p_data_end; + for ( ; ; ) { /* continue until done */ + for ( ; p_data_cur != p_data_end; ++p_data_cur) { /* current data */ + const char ch_cur = *p_data_cur; + const signed char map_cur = p_map[(unsigned char) ch_cur]; + if (map_cur != 0) { /* ws or comment start, so done */ + *(p_fb->p_obj_end = p_data_cur) = '\0'; + p_fb->p_data_cur = p_data_cur + 1; /* 1st char past string */ + p_fb->f_skip_to_eol = map_cur < 0; + return fb_return_obj(p_fb, n_type_wanted, p_type_wanted, + p_type_found, p_fbobj); + } + /* Else more of the string */ + } /* end of loop over current text */ + + p_fb->p_data_cur = p_data_cur; /* update current position */ + const int rc = fb_fill(p_fb); /* Try to refill buffer */ + if (rc != 0) { /* EOF or error */ + if (rc < 0) { /* error */ + return -1; + } + /* Else EOF. Ended without closing quote, so add an implicit + * closing quote, i.e., end the string. Since fb_fill() + * did not return -1, there is at least 1 byte at the end of + * the buffer where the read would have gone. */ + *(p_fb->p_obj_end = p_fb->p_data_cur) = '\0'; + return fb_return_obj(p_fb, n_type_wanted, p_type_wanted, + p_type_found, p_fbobj); + } + p_data_cur = p_fb->p_data_cur; /* Update after fill */ + p_data_end = p_fb->p_data_end; + } /* end of loop processing until done or escape */ +} /* end of function fbget_unquoted_string */ + + + +/* This function fills the buffer. First it moves all data in the interval + * [start current object, current position) to the beginning of the buffer. + * + * If there is no space left at the end of the buffer after the move (so + * that the move did not occur and data extends to the end), the buffer is + * doubled in size. In either case, the end of the buffer is filled with + * data read from the file. */ +static int fb_fill(FILEBUF *p_fb) +{ + /* Exit if EOF already */ + if (p_fb->is_eof) { + return +1; + } + + /* Move the data in use to the front of the buffer if not already and + * enlarge the buffer if still no space. Returned value is bytes + * available at the end of the buffer at p_data_end */ + const size_t n_byte_read = fb_make_space_at_end(p_fb); + if (n_byte_read == 0) { + return -1; + } + + const size_t n_got = fread(p_fb->p_data_end, 1, n_byte_read, p_fb->fp); + if (n_got < n_byte_read) { /* EOF or error */ + if (ferror(p_fb->fp)) { + return -1; + } + /* Else mark as EOF for subsequent calls */ + p_fb->is_eof = true; + + if (n_got == 0) { /* Nothing to return for this call */ + return +1; + } + /* Else partial buffer to return */ + } + + /* Extend the end of the data by the bytes obtained */ + p_fb->p_data_end += n_got; + return 0; +} /* end of function fb_fill */ + + + +/* Make space at the end of the buffer by moving data of current object + * to the front of the buffer and enlarging if there is still no room + * + * Return value: Number of spaces that are free at the end of p_buf on + * return. If 0, more space could not be obtained. + */ +static size_t fb_make_space_at_end(FILEBUF *p_fb) +{ + const char * const p_obj_start = p_fb->p_obj_start; + const char * const p_src = p_obj_start == (char *) NULL ? + p_fb->p_data_cur : p_obj_start; + char * const p_dst = p_fb->p_buf; + + /* Shift data in use to the front of the buffer if not already */ + if (p_dst != p_src) { /* object is not at start of buffer */ + const size_t n = p_fb->p_data_end - p_src; + if (n > 0) { /* Will be 0 if skipping whitespace and comments */ + (void) memmove(p_dst, p_src, n); + } + + /* Adjust pointers after the move */ + ptrdiff_t delta = p_src - p_dst; + p_fb->p_data_cur -= delta; + p_fb->p_data_end -= delta; + + if (p_obj_start != (char *) NULL) { + p_fb->p_obj_start -= delta; + } + /* never called when p_obj_end is valid */ + } + else { /* already at front */ + if (p_fb->p_buf_end - p_fb->p_data_end == 0) { + const size_t n_alloc_orig = p_fb->n_byte_buf_alloc; + + /* For debugging, this added size can be made very small to + * force many reallocs and to have strings end at "hard" + * locations such as right before where a terminating null + * should be added to a string */ + //const size_t n_added = 1; + const size_t n_added = n_alloc_orig; + + const size_t n_byte_buf_alloc_new = n_alloc_orig + n_added; + void * const p = realloc(p_fb->p_buf, n_byte_buf_alloc_new); + if (p == NULL) { + return 0; + } + /* Else allocation OK, so update buffer and internal pointers */ + ptrdiff_t delta = (char *) p - p_fb->p_buf; + p_fb->p_buf = (char *) p; + p_fb->p_buf_end = (char *) p + n_byte_buf_alloc_new; + p_fb->n_byte_buf_alloc = n_byte_buf_alloc_new; + p_fb->p_data_cur += delta; + p_fb->p_data_end += delta; + + if (p_obj_start != (char *) NULL) { + p_fb->p_obj_start += delta; + } + /* never called when p_obj_end is valid */ + } + } + + return p_fb->p_buf_end - p_fb->p_data_end; +} /* end of function fb_make_space_at_end */ + + + +/* Skip whitespace, including comments starting at the current position */ +static int fb_skip_whitespace(FILEBUF *p_fb) +{ + static const signed char p_map[1 << CHAR_BIT] = { + [(unsigned char ) ' '] = (signed char) +1, + [(unsigned char ) '\t'] = (signed char) +1, + [(unsigned char ) '\n'] = (signed char) +1, + [(unsigned char ) '\r'] = (signed char) +1, + [(unsigned char ) '\v'] = (signed char) +1, + [(unsigned char ) '\f'] = (signed char) +1, + [(unsigned char ) '*'] = (signed char) -1, + [(unsigned char ) '#'] = (signed char) -1 + }; + /* Step through characters until not whitespace (including comments) */ + char *p_data_cur = p_fb->p_data_cur; + char *p_data_end = p_fb->p_data_end; + for ( ; ; ) { /* continue until done */ + for ( ; p_data_cur != p_data_end; ++p_data_cur) { /* current data */ + const char ch_cur = *p_data_cur; + const signed char map_cur = p_map[(unsigned char) ch_cur]; + if (map_cur == 0) { /* not in ws or at comment start, so done */ + p_fb->p_data_cur = p_data_cur; + return 0; + } + if (map_cur == -1) { /* a comment has started */ + p_fb->p_data_cur = p_data_cur + 1; /* after comment start */ + const int rc = fb_skip_to_eol(p_fb); + if (rc != 0) { /* EOF or error */ + return rc; + } + + /* Update local variables. Note that p_fb->p_data_cur is at + * the character after the comment, which is a \n or \r. + * These characters are whitespace that will be skipped, + * so incrementing past it in the ++p_data_cur of the for() + * only skips a character that will be skipped anyhow. + * (A long comment to say that + * p_data_cur = p_fb->p_data_cur - 1 is not necessary.) */ + p_data_cur = p_fb->p_data_cur; + p_data_end = p_fb->p_data_end; + } /* end of comment processing */ + /* Else whitespace, which is skipped */ + } /* end of loop over current text */ + + p_fb->p_data_cur = p_data_cur; /* update current position */ + const int rc = fb_fill(p_fb); /* Try to refill buffer */ + if (rc != 0) { /* EOF or error */ + return rc; + } + /* Else got more text to process */ + p_data_cur = p_fb->p_data_cur; /* Update after fill */ + p_data_end = p_fb->p_data_end; + } /* end of loop over text pieces */ +} /* end of function fb_skip_whitespace */ + + + +/* Skip text to EOL char, starting at the current position */ +static int fb_skip_to_eol(FILEBUF *p_fb) +{ + /* Step through characters until not whitespace (including comments) */ + char *p_data_cur = p_fb->p_data_cur; + char *p_data_end = p_fb->p_data_end; + for ( ; ; ) { /* continue until done */ + for ( ; p_data_cur != p_data_end; ++p_data_cur) { /* current data */ + const char ch_cur = *p_data_cur; + if (ch_cur == '\n' || ch_cur == '\r') { + p_fb->p_data_cur = p_data_cur; + return 0; + } + /* Else not EOL, which is skipped */ + } /* end of loop over current text */ + + p_fb->p_data_cur = p_data_cur; /* update current position */ + const int rc = fb_fill(p_fb); /* Try to refill buffer */ + if (rc != 0) { /* EOF or error */ + return rc; + } + /* Else got more text to process */ + p_data_cur = p_fb->p_data_cur; /* Update after fill */ + p_data_end = p_fb->p_data_end; + } /* end of loop over text pieces */ +} /* end of function fb_skip_to_eol */ + + + +/* Return the data found in the most preferred format possible */ +static int fb_return_obj(FILEBUF *p_fb, + unsigned int n_type_wanted, FBTYPE *p_type_wanted, + FBTYPE *p_type_found, FBOBJ *p_fbobj) +{ + const char * const p_obj_start = p_fb->p_obj_start; /* data to convert */ + const char * const p_obj_end = p_fb->p_obj_end; + + /* Must test for null string separately since strto* does not set + * errno in this case. Aside from that, it can only be returned + * as a string anyhow. */ + if (p_obj_start != p_obj_end) { /* have a string besides "" */ + unsigned int i; + for (i = 0; i < n_type_wanted; ++i) { + FBTYPE type_cur = p_type_wanted[i]; + errno = 0; + if (type_cur == BUF_TYPE_ULONG) { + char *p_end; + unsigned long val = strtoul(p_obj_start, &p_end, 10); + /* Test for processing of full string. Note that checking + * for the end of the string rather than a NULL handles the + * case of an embedded NULL which the latter test would + * not */ + if (errno == 0 && p_end == p_obj_end) { + *p_type_found = BUF_TYPE_ULONG; + p_fbobj->ulong_value = val; + return 0; + } + } + else if (type_cur == BUF_TYPE_LONG) { + char *p_end; + long val = strtol(p_obj_start, &p_end, 10); + if (errno == 0 && p_end == p_obj_end) { + *p_type_found = BUF_TYPE_LONG; + p_fbobj->long_value = val; + return 0; + } + } + else if (type_cur == BUF_TYPE_DOUBLE) { + char *p_end; + double val = strtod(p_obj_start, &p_end); + if (errno == 0 && p_end == p_obj_end) { + *p_type_found = BUF_TYPE_DOUBLE; + p_fbobj->dbl_value = val; + return 0; + } + } + else if (type_cur == BUF_TYPE_STRING) { + break; /* exit loop and use default return of string */ + } + else { /* unknown type */ + print_error("Unknown output data type %d is ignored.", + (int) type_cur); + } + } /* end of loop trying types */ + } /* end of case that string is not "" */ + + /* If no rquested type was converted OK or string requested, return as + * a string */ + return fb_return_string(p_fb, p_type_found, p_fbobj); +} /* end of function fb_return_obj */ + + + +/* Return string */ +static int fb_return_string(FILEBUF *p_fb, + FBTYPE *p_type_found, FBOBJ *p_fbobj) +{ + const char *p_data_start = + p_fbobj->str_value.sz = p_fb->p_obj_start; + p_fbobj->str_value.n_char = p_fb->p_obj_end - p_data_start; + *p_type_found = BUF_TYPE_STRING; + return 0; +} /* end of function fb_return_string */ + + + diff --git a/src/xspice/cmpp/file_buffer.h b/src/xspice/cmpp/file_buffer.h new file mode 100644 index 000000000..bee1f76fc --- /dev/null +++ b/src/xspice/cmpp/file_buffer.h @@ -0,0 +1,58 @@ +#ifndef file_buffer_h_included +#define file_buffer_h_included + +#include + + +/* Null-terminated string prefixed by length excluding null */ +typedef struct Filebuf_len_str { + size_t n_char; /* length of string excluding null termination */ + char *sz; /* Start of string */ +} FBSTRING; + +/* Union for returned value */ +typedef union Filebuf_obj { + FBSTRING str_value; + unsigned long ulong_value; + long long_value; + double dbl_value; +} FBOBJ; + +/* Structure for getting file data */ +typedef struct Filebuf { + FILE *fp; /* handle to file */ + bool is_eof; /* flag that EOF reached */ + bool f_skip_to_eol; + /* Flag that text until the next EOL character should be + * skipped before getting the next item from the buffer. + * This flag is set when a comment terminates an item, + * such as "abc# This is a comment." */ + size_t n_byte_buf_alloc; /* Allocated buffer size */ + char *p_buf; /* buffer to receive data from file */ + char *p_obj_start; /* start of object being returned */ + char *p_obj_end; /* byte past object being returned */ + char *p_data_cur; /* current position in buffer. Depending on + * circumstances, it points to either the character + * being processed or the next character to process */ + char *p_data_end; /* byte past end of data in buffer */ + char *p_buf_end; /* byte past end of allocated buffer size, equal to + * p_buf + n_byte_buf_alloc, so it is redundant, but + * convenient to have available */ +} FILEBUF; + +/* Types of data */ +typedef enum FBtype { + BUF_TYPE_STRING, /* value type string (always possible) */ + BUF_TYPE_ULONG, /* value type an unsigned int */ + BUF_TYPE_LONG, /* value type an int */ + BUF_TYPE_DOUBLE /* value type double */ +} FBTYPE; + + +FILEBUF *fbopen(const char *filename, size_t n_byte_buf_init); +int fbget(FILEBUF *p_fb, unsigned int n_type_wanted, FBTYPE *p_type_wanted, + FBTYPE *p_type_found, FBOBJ *p_fbobj); +int fbclose(FILEBUF *fbp); + + +#endif /* include guard */ diff --git a/src/xspice/icm/dlmain.h b/src/xspice/icm/dlmain.h new file mode 100644 index 000000000..c442f1a14 --- /dev/null +++ b/src/xspice/icm/dlmain.h @@ -0,0 +1,10 @@ +#ifndef dlmain_h_included +#define dlmain_h_included + +#include "ngspice/cmproto.h" +#include "ngspice/mifproto.h" +#include "ngspice/dllitf.h" + +struct coreInfo_t *coreitf; + +#endif /* dlmain.h */ diff --git a/visualc/xspice/cmpp/cmpp.vcxproj b/visualc/xspice/cmpp/cmpp.vcxproj index 45cecc0ec..f14055b33 100644 --- a/visualc/xspice/cmpp/cmpp.vcxproj +++ b/visualc/xspice/cmpp/cmpp.vcxproj @@ -87,7 +87,7 @@ _CRT_SECURE_NO_WARNINGS;YY_NO_UNISTD_H;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) false MultiThreadedDebug - ..\..\..\src\xspice\cmpp + $(ProjectDir)..\..\..\src\xspice\cmpp; true @@ -106,7 +106,7 @@ false MultiThreaded ProgramDatabase - ..\..\..\src\xspice\cmpp + $(ProjectDir)..\..\..\src\xspice\cmpp; true @@ -128,7 +128,7 @@ false Default MultiThreadedDebug - ..\..\..\src\xspice\cmpp;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\src\xspice\cmpp;%(AdditionalIncludeDirectories) true @@ -145,7 +145,7 @@ _CRT_SECURE_NO_WARNINGS;YY_NO_UNISTD_H;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) false CompileAsC - ..\..\..\src\xspice\cmpp;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\src\xspice\cmpp;%(AdditionalIncludeDirectories) true @@ -169,11 +169,13 @@ + + From bb61c0ba1ecd14042d68f1027ebdb96fc3ec2ee5 Mon Sep 17 00:00:00 2001 From: Vogt Date: Thu, 13 Feb 2020 16:56:13 +0100 Subject: [PATCH 24/36] just use strcmp instead of wrapper function --- src/frontend/device.c | 2 +- src/frontend/parser/glob.c | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/frontend/device.c b/src/frontend/device.c index 37c806b6f..809d9f24a 100644 --- a/src/frontend/device.c +++ b/src/frontend/device.c @@ -1332,7 +1332,7 @@ devexpand(char *name) if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) { devices = cp_cctowl(ft_curckt->ci_devices); for (wl = NULL; devices; devices = devices->wl_next) - if (cp_globmatch(name, devices->wl_word)) + if (!strcmp(name, devices->wl_word)) wl = wl_cons(devices->wl_word, wl); } else if (cieq(name, "all")) { wl = cp_cctowl(ft_curckt->ci_devices); diff --git a/src/frontend/parser/glob.c b/src/frontend/parser/glob.c index 469af46ee..caddc6784 100644 --- a/src/frontend/parser/glob.c +++ b/src/frontend/parser/glob.c @@ -407,18 +407,6 @@ char *cp_tildexpand(const char *string) } /* end of function cp_tildexpand */ - -/* Say whether the pattern p can match the string s. */ - -/* MW. Now simply compare strings */ - -bool cp_globmatch(char *p, char *s) -{ - return !(strcmp(p, s)); -} /* end of function cp_globmatch */ - - - /* This function expands the leading ~ of wl_node. */ static void tilde_expand_word(wordlist *wl_node) { From 0c693748769ff44b876ec139392e51b99e15dd5f Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 13 Feb 2020 18:21:34 +0100 Subject: [PATCH 25/36] no wrapper cp_globmatch needed --- src/include/ngspice/cpextern.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/include/ngspice/cpextern.h b/src/include/ngspice/cpextern.h index 9fa01e23e..8d18caf34 100644 --- a/src/include/ngspice/cpextern.h +++ b/src/include/ngspice/cpextern.h @@ -79,7 +79,6 @@ extern void cp_pushcontrol(void); /* glob.c */ -extern bool cp_globmatch(const char *p, const char *s); extern char *cp_tildexpand(const char *string); extern char cp_cbrac; extern char cp_ccurl; From 28002be1501a97fd222e36f6615aadef8c915264 Mon Sep 17 00:00:00 2001 From: dwarning Date: Thu, 13 Feb 2020 18:43:04 +0100 Subject: [PATCH 26/36] correct the path to dstring.c --- src/xspice/icm/GNUmakefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index 1958103fe..744d316a1 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -43,7 +43,7 @@ clean: #----------------------------------------------------------------------------- -NGSRCDIR = $(CURDIR)/../../../../src +NGSRCDIR = $(CURDIR)/../../../src dstring.o : $(NGSRCDIR)/misc/dstring.c $(NGSRCDIR)/include/ngspice/dstring.h $(COMPILE) -I $(NGSRCDIR)/include/ngspice -o $@ -c $< From 94960da2070799aecf38883275076d31ddcdf838 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Thu, 13 Feb 2020 21:32:02 +0100 Subject: [PATCH 27/36] prevent false freeing of vector --- src/frontend/parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/parse.c b/src/frontend/parse.c index a1ac39fa4..cc86903d0 100644 --- a/src/frontend/parse.c +++ b/src/frontend/parse.c @@ -471,7 +471,7 @@ void free_pnode_x(struct pnode *t) free_pnode(t->pn_right); free_pnode(t->pn_next); tfree(t->pn_name); /* va: it is a copy() of original string, can be free'd */ - if (t->pn_value && !(t->pn_value->v_flags & VF_PERMANENT)) { + if (t->pn_use == 1 && t->pn_value && !(t->pn_value->v_flags & VF_PERMANENT)) { vec_free(t->pn_value); /* patch by Stefan Jones */ } txfree(t); From ed95f462598fc52e0ed121b419343d601283aaa9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 14 Feb 2020 19:35:30 +0100 Subject: [PATCH 28/36] Revert "correct the path to dstring.c" This reverts commit 28002be1501a97fd222e36f6615aadef8c915264. --- src/xspice/icm/GNUmakefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index 744d316a1..1958103fe 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -43,7 +43,7 @@ clean: #----------------------------------------------------------------------------- -NGSRCDIR = $(CURDIR)/../../../src +NGSRCDIR = $(CURDIR)/../../../../src dstring.o : $(NGSRCDIR)/misc/dstring.c $(NGSRCDIR)/include/ngspice/dstring.h $(COMPILE) -I $(NGSRCDIR)/include/ngspice -o $@ -c $< From 9b4944df332c17bbf4bf5ee395869c163a86f72c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 14 Feb 2020 19:37:19 +0100 Subject: [PATCH 29/36] make path to dstring.c independent from build directory --- src/xspice/icm/GNUmakefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index 1958103fe..29eb60d94 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -43,7 +43,7 @@ clean: #----------------------------------------------------------------------------- -NGSRCDIR = $(CURDIR)/../../../../src +NGSRCDIR = $(srcdir)/../../ dstring.o : $(NGSRCDIR)/misc/dstring.c $(NGSRCDIR)/include/ngspice/dstring.h $(COMPILE) -I $(NGSRCDIR)/include/ngspice -o $@ -c $< From 38fb2e205f56dffced054979696a466830c816a2 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Fri, 14 Feb 2020 13:23:48 -0500 Subject: [PATCH 30/36] Fixed incorrect type of variable ch_cur. It was from const char * but should have been const char. --- src/misc/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc/util.c b/src/misc/util.c index 60b5f2e49..6801eb860 100644 --- a/src/misc/util.c +++ b/src/misc/util.c @@ -210,7 +210,7 @@ char *ngdirname(const char *name) const char *p0 = name + start; /* 1st char past drive */ const char *p; for (p = p0 + strlen(name + start) - 1; p >= p0; --p) { - const char *ch_cur = *p; + const char ch_cur = *p; if (ch_cur == '/' || ch_cur == '\\') { /* at last dir sep */ /* Stop copy at last dir sep or right after if * it is the first char after any drive spec. From 871677e809bfe7a7c7ded0749e8f2981e6c0e9f2 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 14 Feb 2020 22:52:09 +0100 Subject: [PATCH 31/36] Fixed compiler warnings related to const, unreachable code, and an empty translation unit. --- src/winmain.c | 10 ++++++++++ src/xspice/mif/mifutil.c | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/winmain.c b/src/winmain.c index d22bde1a3..c1498dee7 100644 --- a/src/winmain.c +++ b/src/winmain.c @@ -1641,4 +1641,14 @@ winmessage(char *new_msg) } + +#else /* HAS_WINGUI not defined */ +/* Prevent warning regarding empty translation unit */ +static void dummy(void) +{ + return; +} /* end of function dummy */ + + + #endif /* HAS_WINGUI */ diff --git a/src/xspice/mif/mifutil.c b/src/xspice/mif/mifutil.c index b1243afb9..6a98f1004 100644 --- a/src/xspice/mif/mifutil.c +++ b/src/xspice/mif/mifutil.c @@ -142,7 +142,6 @@ char *MIFgettok(char **s) } break; } - return NULL; /* should not happen */ } #if 0 From f5b8de12b8b54435f8f960d0911f10f816faee5d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 14 Feb 2020 23:01:35 +0100 Subject: [PATCH 32/36] remove unreachable code warning, add const --- src/sharedspice.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sharedspice.c b/src/sharedspice.c index cabfd9928..eea42015f 100644 --- a/src/sharedspice.c +++ b/src/sharedspice.c @@ -1628,7 +1628,7 @@ char* outstorage(char* wordin, bool write) An update occurs only every DELTATIME milliseconds. */ #define DELTATIME 150 void SetAnalyse( - char * Analyse, /*in: analysis type */ + const char * Analyse, /*in: analysis type */ int DecaPercent /*in: 10 times the progress [%]*/ /*HWND hwAnalyse, in: global handle to analysis window */ ) { @@ -1995,7 +1995,6 @@ getvsrcval(double time, char *vname) if (!wantvdat) { fprintf(stderr, "Error: No callback supplied for source %s\n", vname); shared_exit(EXIT_BAD); - return(EXIT_BAD); } else { /* callback fcn */ @@ -2013,7 +2012,6 @@ getisrcval(double time, char *iname) if (!wantidat) { fprintf(stderr, "Error: No callback supplied for source %s\n", iname); shared_exit(EXIT_BAD); - return(EXIT_BAD); } else { /* callback fcn */ From d61af96eb471b86c9db0d812339749a672bd7fa6 Mon Sep 17 00:00:00 2001 From: dwarning Date: Mon, 17 Feb 2020 09:20:09 +0100 Subject: [PATCH 33/36] more meaningful warning if vector can't interpolate --- src/frontend/interp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/frontend/interp.c b/src/frontend/interp.c index dada350b4..82bb2dd32 100644 --- a/src/frontend/interp.c +++ b/src/frontend/interp.c @@ -21,12 +21,17 @@ lincopy(struct dvec *ov, double *newscale, int newlen, struct dvec *oldscale) double *nd; if (!isreal(ov)) { - fprintf(cp_err, "Warning: %s is not real\n", ov->v_name); + fprintf(cp_err, "Warning: vector %s is not real - no interpolation\n", ov->v_name); + return; + } + + if (ov->v_length == 1) { + fprintf(cp_err, "Warning: %s is not a vector - no interpolation\n", ov->v_name); return; } if (ov->v_length < oldscale->v_length) { - fprintf(cp_err, "Warning: %s is too short\n", ov->v_name); + fprintf(cp_err, "Warning: vector %s is too short - no interpolation\n", ov->v_name); return; } From 9c89e480a6f8911f594a7b70042d027b46e16f84 Mon Sep 17 00:00:00 2001 From: dwarning Date: Mon, 17 Feb 2020 09:56:05 +0100 Subject: [PATCH 34/36] partially revert commit b4bbcb149 for spec analysis functionality --- src/frontend/spec.c | 62 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/src/frontend/spec.c b/src/frontend/spec.c index 73cd11e84..9f18130a1 100644 --- a/src/frontend/spec.c +++ b/src/frontend/spec.c @@ -24,7 +24,7 @@ com_spec(wordlist *wl) { ngcomplex_t **fdvec = NULL; double **tdvec = NULL; - double *win = NULL, *time, *dc = NULL; + double *freq, *win = NULL, *time, *dc = NULL; double startf, stopf, stepf, span; int fpts, i, j, k, tlen, ngood; bool trace; @@ -209,6 +209,7 @@ com_spec(wordlist *wl) VF_REAL | VF_PERMANENT | VF_PRINT, fpts, NULL); vec_new(f); + freq = f->v_realdata; tdvec = TMALLOC(double *, ngood); fdvec = TMALLOC(ngcomplex_t *, ngood); @@ -235,41 +236,38 @@ com_spec(wordlist *wl) } trace = cp_getvar("spectrace", CP_BOOL, NULL, 0); - { - double * const freq = f->v_realdata; - for (j = (startf == 0 ? 1 : 0); j < fpts; j++) { - freq[j] = startf + j*stepf; - if (trace) { - fprintf(cp_err, "spec: %e Hz: \r", freq[j]); - } - for (i = 0; i < ngood; i++) { - fdvec[i][j].cx_real = 0; - fdvec[i][j].cx_imag = 0; - } - for (k = 1; k < tlen; k++) { - double - amp = 2*win[k]/(tlen-1), - rad = 2*M_PI*time[k]*freq[j], - cosa = amp*cos(rad), - sina = amp*sin(rad); - for (i = 0; i < ngood; i++) { - double value = tdvec[i][k]-dc[i]; - fdvec[i][j].cx_real += value*cosa; - fdvec[i][j].cx_imag += value*sina; - } - } -#ifdef HAS_PROGREP - SetAnalyse("spec", (int)(j * 1000./ fpts)); -#endif + for (j = (startf == 0 ? 1 : 0); j < fpts; j++) { + freq[j] = startf + j*stepf; + if (trace) { + fprintf(cp_err, "spec: %e Hz: \r", freq[j]); } - - if (startf == 0) { - freq[0] = 0; + for (i = 0; i < ngood; i++) { + fdvec[i][j].cx_real = 0; + fdvec[i][j].cx_imag = 0; + } + for (k = 1; k < tlen; k++) { + double + amp = 2*win[k]/(tlen-1), + rad = 2*M_PI*time[k]*freq[j], + cosa = amp*cos(rad), + sina = amp*sin(rad); for (i = 0; i < ngood; i++) { - fdvec[i][0].cx_real = dc[i]; - fdvec[i][0].cx_imag = 0; + double value = tdvec[i][k]-dc[i]; + fdvec[i][j].cx_real += value*cosa; + fdvec[i][j].cx_imag += value*sina; } } +#ifdef HAS_PROGREP + SetAnalyse("spec", (int)(j * 1000./ fpts)); +#endif + } + + if (startf == 0) { + freq[0] = 0; + for (i = 0; i < ngood; i++) { + fdvec[i][0].cx_real = dc[i]; + fdvec[i][0].cx_imag = 0; + } } if (trace) From d3150377b0eff85e0eb20366e4fdcc3502896c70 Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Mon, 17 Feb 2020 10:51:10 -0500 Subject: [PATCH 35/36] Made descriptions of invalid interpolation cases more descriptive and fixed a memory leak --- src/frontend/interp.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/frontend/interp.c b/src/frontend/interp.c index 82bb2dd32..f54fd4c32 100644 --- a/src/frontend/interp.c +++ b/src/frontend/interp.c @@ -17,37 +17,45 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group void lincopy(struct dvec *ov, double *newscale, int newlen, struct dvec *oldscale) { - struct dvec *v; - double *nd; - if (!isreal(ov)) { - fprintf(cp_err, "Warning: vector %s is not real - no interpolation\n", ov->v_name); + fprintf(cp_err, "Warning: vector %s is a complex vector - " + "complex vectors cannot be interpolated\n", + ov->v_name); return; } if (ov->v_length == 1) { - fprintf(cp_err, "Warning: %s is not a vector - no interpolation\n", ov->v_name); + fprintf(cp_err, "Warning: %s is a scalar - " + "interpolation is not possible\n", + ov->v_name); return; } if (ov->v_length < oldscale->v_length) { - fprintf(cp_err, "Warning: vector %s is too short - no interpolation\n", ov->v_name); + fprintf(cp_err, "Warning: %s only contains %d points - " + "interpolation is not performed unless there are " + "at least as many points as the scale vector (%d)\n", + ov->v_name, ov->v_length, oldscale->v_length); return; } - v = dvec_alloc(copy(ov->v_name), + /* Allocate the vector to receive the linearized data */ + struct dvec * const v = dvec_alloc(copy(ov->v_name), ov->v_type, ov->v_flags | VF_PERMANENT, newlen, NULL); - nd = v->v_realdata; - if (!ft_interpolate(ov->v_realdata, nd, oldscale->v_realdata, - oldscale->v_length, newscale, newlen, 1)) - { + /* Do interpolation and then add the vector to the current plot. If + * interpolation fails, the vector must be freed. */ + if (!ft_interpolate(ov->v_realdata, v->v_realdata, oldscale->v_realdata, + oldscale->v_length, newscale, newlen, 1)) { fprintf(cp_err, "Error: can't interpolate %s\n", ov->v_name); + dvec_free(v); return; } vec_new(v); -} +} /* end of function lincopy */ + + From c094b12d3d03e3067cf3efdd180f86372681c066 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 19 Feb 2020 23:43:23 +0100 Subject: [PATCH 36/36] Zero fp, this fixes bug no #475 --- src/xspice/icm/table/table2D/cfunc.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xspice/icm/table/table2D/cfunc.mod b/src/xspice/icm/table/table2D/cfunc.mod index 77760dae6..ef636404a 100644 --- a/src/xspice/icm/table/table2D/cfunc.mod +++ b/src/xspice/icm/table/table2D/cfunc.mod @@ -448,6 +448,7 @@ static Table2_Data_t *init_local_data(const char *filename, int order) lFileRead = fread(cFile, sizeof(char), lFileLen, fp); const int file_error = ferror(fp); fclose(fp); /* done with file */ + fp = (FILE *) NULL; if (file_error) { cm_message_printf("Error reading data file %s", filename); xrc = -1;