Enable spice notations like 2n or 5m in filesource inputs

Tests that spaces or tabs are o.k.
This commit is contained in:
Holger Vogt 2026-08-02 16:00:36 +02:00
parent 53564f2b98
commit 4ed89173f2
2 changed files with 231 additions and 21 deletions

View File

@ -1,12 +1,12 @@
* input test
0 0 1
10e-6 0.1 0.9
20e-6 0.2 0.8
30e-6 0.3 0.7
40e-6 0.4 0.6
50e-6 0.5 0.5
60e-6 0.6 0.4
70e-6 0.7 0.3
80e-6 0.8 0.2
90e-6 0.9 0.1
100e-6 1 0
0 0 1m
10u 0.1m 0.9m
20u 0.2m 0.8m
30u 0.3m 0.7m
40u 0.4m 0.6m
50u 0.5m 0.5m
60u 0.6m 0.4m
70u 0.7m 0.3m
80u 0.8m 0.2m
90u 0.9m 0.1m
100u 1m 0

View File

@ -15,6 +15,7 @@ AUTHORS
27 Feb 2017 Marcel Hendrix
23 JUL 2018 Holger Vogt
11 Aug 2025 Holger Vogt
01 Aug 2026 Holger Vogt
MODIFICATIONS
@ -55,8 +56,8 @@ NON-STANDARD FEATURES
/*=== CONSTANTS ========================*/
#define OK 0
#define FAIL 1
/*=== MACROS ===========================*/
@ -104,13 +105,220 @@ typedef struct {
} Local_Data_t;
typedef char line_t[82]; /* A SPICE size line. <= 80 characters plus '\n\0' */
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
/*=== 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 *suffix;*/
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 'a':
scale_factor = 1.0e-18;
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 CNVgettok ROUTINE ================*/
/*
Get the next token from the input string. The input string pointer
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.
*/
#include <stdlib.h>
static char *CNVgettok(char **s)
{
char *buf; /* temporary storage to copy token into */
/*char *temp;*/ /* temporary storage to copy token into */
char *ret_str; /* storage for returned string */
int i;
/* allocate space big enough for the whole string */
buf = (char *) malloc(strlen(*s) + 1);
/* skip over any white space */
while(isspace_c(**s) || (**s == '=') ||
(**s == '(') || (**s == ')') || (**s == ','))
(*s)++;
/* isolate the next token */
switch(**s) {
case '\0': /* End of string found */
if(buf) free(buf);
return(NULL);
default: /* Otherwise, we are dealing with a */
/* string representation of a number */
/* or a mess o' characters. */
i = 0;
while( (**s != '\0') &&
(! ( isspace_c(**s) || (**s == '=') ||
(**s == '(') || (**s == ')') ||
(**s == ',')
) ) ) {
buf[i] = **s;
i++;
(*s)++;
}
buf[i] = '\0';
break;
}
/* skip over white space up to next token */
while(isspace_c(**s) || (**s == '=') ||
(**s == '(') || (**s == ')') || (**s == ','))
(*s)++;
/* make a copy using only the space needed by the string length */
ret_str = (char *) malloc(strlen(buf) + 1);
ret_str = strcpy(ret_str,buf);
if(buf) free(buf);
return(ret_str);
}
/*==============================================================================
FUNCTION void cm_filesource()
@ -277,13 +485,14 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc.
free(cpdel);
continue;
}
t = strtod(cp, &cp2);
if (cp2 == cp) {
char *ncp = CNVgettok(&cp);
int ret = cnv_get_spice_value(ncp, &t);
free(ncp);
if (ret == FAIL) {
free(cpdel);
terr = MIF_TRUE;
continue;
}
cp = cp2;
if (!PARAM_NULL(timescale))
t *= PARAM(timescale);
if (!PARAM_NULL(timerelative) && PARAM(timerelative) == MIF_TRUE)
@ -295,7 +504,7 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc.
/* before storing, check if vector size is large enough.
If not, add another 1000*size doubles */
if (count > (int) loc->indata->vecallocated - size) {
if (count > (int) loc->indata->vecallocated - stepsize) {
loc->indata->vecallocated += (size_t) (size * 1000);
void * const p = realloc(loc->indata->datavec,
sizeof(double) * loc->indata->vecallocated);
@ -311,12 +520,13 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc.
for (i = 0; i < size; ++i) {
while (*cp && (isspace_c(*cp) || *cp == ','))
++cp;
d = strtod(cp, &cp2);
if (cp2 == cp) {
char *ncp = CNVgettok(&cp);
int ret = cnv_get_spice_value(ncp, &d);
free(ncp);
if (ret == FAIL) {
derr = MIF_TRUE;
break;
}
cp = cp2;
if (i < amplscalesize)
d *= PARAM(amplscale[i]);
if (i < amploffssize)