2 * ss_spice3.c: routines for SpiceStream that handle the file formats
3 * known as Berkeley Spice3 Rawfile
5 * Copyright (C) 1998,1999 Stephen G. Tell
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 #include "spicestream.h"
35 static int sf_readrow_s3raw(SpiceStream
*sf
, double *ivar
, double *dvars
);
36 char *msgid
= "s3raw";
37 static int sf_readrow_s3bin(SpiceStream
*sf
, double *ivar
, double *dvars
);
39 /* convert variable type string from spice3 raw file to
43 sf_str2type_s3raw(char *s
)
45 if(strcasecmp(s
, "voltage") == 0)
47 else if(strcasecmp(s
, "current") == 0)
49 else if(strcasecmp(s
, "frequency") == 0)
51 else if(strcasecmp(s
, "time") == 0)
57 /* Read spice-type file header - Berkeley Spice3 "raw" format */
59 sf_rdhdr_s3raw(char *name
, FILE *fp
)
61 SpiceStream
*sf
= NULL
;
69 int dtype_complex
= 0;
71 char *vnum
, *vname
, *vtypestr
;
74 while(fread_line(fp
, &line
, &linesize
) != EOF
) {
76 if(lineno
== 1 && strncmp(line
, "Title: ", 7)) {
77 /* not a spice3raw file; bail out */
78 ss_msg(DBG
, msgid
, "%s:%d: Doesn't look like a spice3raw file; \"Title:\" expected\n", name
, lineno
);
83 key
= strtok(line
, ":");
85 ss_msg(ERR
, msgid
, "%s:%d: syntax error, expected \"keyword:\"", name
, lineno
);
89 if(strcmp(key
, "Flags") == 0) {
90 while(val
= strtok(NULL
, " ,\t\n")) {
91 if(strcmp(val
, "real") == 0) {
94 if(strcmp(val
, "complex") == 0) {
98 } else if(strcmp(key
, "No. Variables") == 0) {
99 val
= strtok(NULL
, " \t\n");
101 ss_msg(ERR
, msgid
, "%s:%d: syntax error, expected integer", name
, lineno
);
107 } else if(strcmp(key
, "No. Points") == 0) {
108 val
= strtok(NULL
, " \t\n");
110 ss_msg(ERR
, msgid
, "%s:%d: syntax error, expected integer", name
, lineno
);
115 } else if(strcmp(key
, "Variables") == 0) {
117 ss_msg(ERR
, msgid
, "%s:%d: \"Variables:\" before \"No. Variables:\"", name
, lineno
, i
);
121 sf
= ss_new(fp
, name
, nvars
-1, 0);
124 /* first variable may be described on the same line
125 * as "Variables:" keyword
127 vnum
= strtok(NULL
, " \t\n");
129 for(i
= 0; i
< nvars
; i
++) {
131 if(fread_line(fp
, &line
, &linesize
) == EOF
) {
132 ss_msg(ERR
, msgid
, "%s:%d: Unexpected EOF in \"Variables:\" at var %d", name
, lineno
, i
);
136 vnum
= strtok(line
, " \t\n");
138 vname
= strtok(NULL
, " \t\n");
139 vtypestr
= strtok(NULL
, " \t\n");
140 if(!vnum
|| !vname
|| !vtypestr
) {
141 ss_msg(ERR
, msgid
, "%s:%d: expected number name type", name
, lineno
);
144 if(i
== 0) { /* assume Ind.Var. first */
145 sf
->ivar
->name
= g_strdup(vname
);
146 sf
->ivar
->type
= sf_str2type_s3raw(vtypestr
);
148 /* ivar can't really be two-column,
149 this is a flag that says to
157 sf
->dvar
[i
-1].name
= g_strdup(vname
);
158 sf
->dvar
[i
-1].type
= sf_str2type_s3raw(vtypestr
);
159 sf
->dvar
[i
-1].col
= sf
->ncols
;
161 sf
->dvar
[i
-1].ncols
= 2;
163 sf
->dvar
[i
-1].ncols
= 1;
165 sf
->ncols
+= sf
->dvar
[i
-1].ncols
;
168 } else if(strcmp(key
, "Values") == 0) {
171 } else if(strcmp(key
, "Binary") == 0) {
180 ss_msg(ERR
, msgid
, "%s:%d: no \"Variables:\" section in header", name
, lineno
);
184 ss_msg(ERR
, msgid
, "%s:%d: EOF without \"Values:\" in header", name
, lineno
);
189 sf
->readrow
= sf_readrow_s3bin
;
191 sf
->readrow
= sf_readrow_s3raw
;
194 sf
->expected_vals
= npoints
* (sf
->ncols
+ (dtype_complex
? 1 : 0));
195 ss_msg(DBG
, msgid
, "expecting %d values\n", sf
->expected_vals
);
198 sf
->lbufsize
= linesize
;
199 ss_msg(DBG
, msgid
, "Done with header at offset 0x%lx\n", (long) ftello64(sf
->fp
));
207 /* prevent ss_delete from cleaning up FILE*; ss_open callers
208 may rewind and try another format on failure. */
215 /* return pointer to the next whitespace-seperated token in the file
216 * advances to the next lines of the file as needed.
217 * pointer points into the line buffer linebuf.
218 * token will not be nul-terminated; whole line remains available.
220 * upon return, sf->linep points to the char after the end of the token,
221 * which might be the trailing nul or might be whitespace.
223 static char *sf_nexttoken(SpiceStream
*sf
)
231 if(fread_line(sf
->fp
, &sf
->linebuf
, &sf
->lbufsize
) == EOF
) {
232 return 0; /* normal EOF */
238 // search for start of token
242 if(fread_line(sf
->fp
, &sf
->linebuf
, &sf
->lbufsize
) == EOF
) {
243 return 0; /* normal EOF */
247 } while (*cp
== 0); // skip multiple blank lines
254 // tok now points to start of the token; search for the end
255 while(*cp
&& !isspace(*cp
))
263 * Read row of values from an ascii spice3 raw file
266 sf_readrow_s3raw(SpiceStream
*sf
, double *ivar
, double *dvars
)
273 if((sf
->flags
& SSF_PUSHBACK
) == 0) {
274 tok
= sf_nexttoken(sf
);
277 // ss_msg(ERR, msgid, "%s:%d: expected row number",
278 // sf->filename, sf->lineno);
282 ss_msg(WARN
, msgid
, "%s:%d: expected row number, got \"%s\". Note: only one dataset per file is supported, extra garbage ignored",
283 sf
->filename
, sf
->lineno
, tok
);
287 /* todo: check for expected and maximum row number */
289 tok
= sf_nexttoken(sf
);
291 ss_msg(WARN
, msgid
, "%s:%d: expected ivar value",
292 sf
->filename
, sf
->lineno
);
297 /* independent-variable value decreased, this must
298 * be the start of another sweep. hold the value and
299 * return flag to caller.
302 sf
->flags
|= SSF_PUSHBACK
;
309 /* iv value for start of new sweep was read last time */
310 sf
->flags
&= ~SSF_PUSHBACK
;
314 for(i
= 0; i
< sf
->ndv
; i
++) {
318 tok
= sf_nexttoken(sf
);
320 ss_msg(ERR
, msgid
, "%s:%d: expected value",
321 sf
->filename
, sf
->lineno
);
324 dvars
[dv
->col
-1] = atof(tok
);
327 tok
= strchr(tok
, ',');
328 if(!tok
|| !*(tok
+1)) {
329 ss_msg(ERR
, msgid
, "%s:%d: expected second value",
330 sf
->filename
, sf
->lineno
);
334 dvars
[dv
->col
] = atof(tok
);
342 * Read a single value from binary spice3 rawfile, and do
343 * the related error-checking.
347 sf_getval_s3bin(SpiceStream
*sf
, double *dval
)
352 if(sf
->read_vals
>= sf
->expected_vals
) {
353 pos
= ftello64(sf
->fp
);
354 ss_msg(DBG
, "sf_getval_s3bin", "past last expected value offset 0x%lx", (long) pos
);
357 if(fread(&val
, sizeof(double), 1, sf
->fp
) != 1) {
358 pos
= ftello64(sf
->fp
);
359 ss_msg(ERR
, "sf_getval_s3bin", "unexepected EOF in data at offset 0x%lx", (long) pos
);
370 * Read row of values from a binay spice3 raw file
373 sf_readrow_s3bin(SpiceStream
*sf
, double *ivar
, double *dvars
)
379 if((sf
->flags
& SSF_PUSHBACK
) == 0) {
380 rc
= sf_getval_s3bin(sf
, &v
);
381 if(rc
== 0) /* file EOF */
385 if(sf
->ivar
->ncols
== 2) {
386 rc
= sf_getval_s3bin(sf
, &dummy
);
387 if(rc
== 0) /* file EOF */
393 /* independent-variable value decreased, this must
394 * be the start of another sweep. hold the value and
395 * return flag to caller.
398 sf
->flags
|= SSF_PUSHBACK
;
405 /* iv value for start of new sweep was read last time */
406 sf
->flags
&= ~SSF_PUSHBACK
;
410 for(i
= 0; i
< sf
->ncols
-1; i
++) {
411 if(sf_getval_s3bin(sf
, &dvars
[i
]) != 1) {
412 ss_msg(WARN
, "sf_readrow_s3bin", "%s: EOF or error reading data field %d in row %d; file is incomplete.", sf
->filename
, i
, sf
->read_rows
);