336 lines
8.2 KiB
C
336 lines
8.2 KiB
C
|
/*
|
||
|
* ss_spice3.c: routines for SpiceStream that handle the file formats
|
||
|
* known as Berkeley Spice3 Rawfile
|
||
|
*
|
||
|
* include LICENSE
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
// #include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include <float.h>
|
||
|
|
||
|
// #include <glib.h>
|
||
|
#include <spicestream.h>
|
||
|
|
||
|
#ifdef TRACE_MEM
|
||
|
#include <tracemem.h>
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static int sf_getval_s3ascii(SpiceStream *ss, double *val);
|
||
|
static int sf_getval_s3bin(SpiceStream *ss, double *dval);
|
||
|
|
||
|
/*
|
||
|
* return 1 ok
|
||
|
* 0 EOF
|
||
|
* -1 Error
|
||
|
*/
|
||
|
/* Read spice-type file header - Berkeley Spice3 "raw" format */
|
||
|
int sf_rdhdr_s3raw( SpiceStream *ss )
|
||
|
{
|
||
|
char *line;
|
||
|
int lineno ;
|
||
|
char *key, *val;
|
||
|
int nvars = 0;
|
||
|
int npoints = 0;
|
||
|
int got_nvars = 0;
|
||
|
int got_values = 0;
|
||
|
int dtype_complex = 0;
|
||
|
int binary = 0;
|
||
|
char *vnum, *vname, *vtypestr;
|
||
|
int i;
|
||
|
int ncols = 1;
|
||
|
|
||
|
dtype_complex = dtype_complex; /* silent the compiler ; this var is not used for the moment */
|
||
|
while ( (line = fdbuf_get_line(ss->linebuf)) != NULL ) {
|
||
|
lineno = fdbuf_get_lineno(ss->linebuf);
|
||
|
if (lineno == 1 && strncmp(line, "Title: ", 7)) {
|
||
|
/* not a spice3raw file; bail out */
|
||
|
msg_dbg("%d: Doesn't look like a spice3raw file; \"Title:\" expected\n",
|
||
|
lineno);
|
||
|
return -1;
|
||
|
}
|
||
|
/* skip empty lines */
|
||
|
char *p = line;
|
||
|
while ( *p && isspace(*p) ){
|
||
|
p++;
|
||
|
}
|
||
|
if ( ! *p ){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
key = strtok(line, ":");
|
||
|
if ( ! key) {
|
||
|
msg_error(_("%d: syntax error, expected \"keyword:\""), lineno);
|
||
|
return -1;
|
||
|
}
|
||
|
if (strcmp(key, "Flags") == 0) {
|
||
|
while ((val = strtok(NULL, " ,\t\n"))) {
|
||
|
if (strcmp(val, "real") == 0) {
|
||
|
dtype_complex = 0;
|
||
|
}
|
||
|
if (strcmp(val, "complex") == 0) {
|
||
|
dtype_complex = 1;
|
||
|
ncols = 2;
|
||
|
}
|
||
|
}
|
||
|
} else if (strcmp(key, "Plotname") == 0) {
|
||
|
val = strtok(NULL, "\n");
|
||
|
dataset_dup_setname(ss->wds, val);
|
||
|
} else if (strcmp(key, "No. Variables") == 0) {
|
||
|
val = strtok(NULL, " \t\n");
|
||
|
if ( ! val) {
|
||
|
msg_error(_("%d: syntax error, expected integer"), lineno);
|
||
|
return -1;
|
||
|
}
|
||
|
nvars = atoi(val);
|
||
|
got_nvars = 1;
|
||
|
} else if (strcmp(key, "No. Points") == 0) {
|
||
|
val = strtok(NULL, " \t\n");
|
||
|
if ( ! val) {
|
||
|
msg_error(_("%d: syntax error, expected integer"), lineno);
|
||
|
return -1;
|
||
|
}
|
||
|
npoints = atoi(val);
|
||
|
} else if(strcmp(key, "Variables") == 0) {
|
||
|
if ( ! got_nvars) {
|
||
|
msg_error(_("%d: \"Variables:\" before \"No. Variables:\""), lineno );
|
||
|
return -1;
|
||
|
}
|
||
|
ss->ncols = 0;
|
||
|
ss->ntables = 1;
|
||
|
/* first variable may be described on the same line
|
||
|
* as "Variables:" keyword
|
||
|
*/
|
||
|
vnum = strtok(NULL, " \t\n");
|
||
|
|
||
|
for (i = 0; i < nvars; i++) {
|
||
|
if (i || ! vnum) {
|
||
|
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL ) {
|
||
|
lineno = fdbuf_get_lineno(ss->linebuf);
|
||
|
msg_error(_("%d: Unexpected EOF in \"Variables:\" at var %d"),
|
||
|
lineno, i);
|
||
|
return 0;
|
||
|
}
|
||
|
vnum = strtok(line, " \t\n");
|
||
|
}
|
||
|
vname = strtok(NULL, " \t\n");
|
||
|
vtypestr = strtok(NULL, " \t\n");
|
||
|
if ( ! vnum || ! vname || ! vtypestr) {
|
||
|
msg_error(_("%d: expected number name type"), lineno);
|
||
|
return -1;
|
||
|
}
|
||
|
spicestream_var_add( ss, vname, wavevar_str2type(vtypestr), ncols);
|
||
|
ss->ncols += ncols;
|
||
|
}
|
||
|
} else if (strcmp(key, "Values") == 0) {
|
||
|
got_values = 1;
|
||
|
break;
|
||
|
} else if (strcmp(key, "Binary") == 0) {
|
||
|
binary = 1;
|
||
|
got_values = 1;
|
||
|
break;
|
||
|
}
|
||
|
if (got_values)
|
||
|
break;
|
||
|
}
|
||
|
if ( ! line ) { /* EOF */
|
||
|
return 0;
|
||
|
}
|
||
|
if ( ! got_values) {
|
||
|
msg_error(_("%s: line %d:\nEOF without \"Values:\" in header"),
|
||
|
ss->filename, lineno);
|
||
|
}
|
||
|
|
||
|
if (binary) {
|
||
|
ss->rdValFunc = sf_getval_s3bin ;
|
||
|
} else {
|
||
|
ss->rdValFunc = sf_getval_s3ascii ;
|
||
|
}
|
||
|
ss->nrows = npoints;
|
||
|
ss->expected_vals = npoints * ss->ncols ;
|
||
|
msg_dbg("expecting %d rows %d cols %d values", npoints, ss->ncols, ss->expected_vals);
|
||
|
msg_dbg("Done with header at offset 0x%lx\n", (long) fdbuf_tello(ss->linebuf) );
|
||
|
dbuf_clear((DBuf *) ss->linebuf);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int sf_getval_s3ascii(SpiceStream *ss, double *val)
|
||
|
{
|
||
|
int done = 0;
|
||
|
int i = 0;
|
||
|
int rownum = 0;
|
||
|
int c;
|
||
|
DBuf *dbuf = ss->dbuf;
|
||
|
|
||
|
dbuf_clear(dbuf);
|
||
|
while ( ! done ) {
|
||
|
while ( 1 ) {
|
||
|
c = dbuf_get_char( (DBuf *) ss->linebuf) ;
|
||
|
if ( i == 0 && c < 0 ) {
|
||
|
if ( fdbuf_get_line(ss->linebuf) == NULL) {
|
||
|
return 0; /* EOF */
|
||
|
}
|
||
|
rownum = 1; /* Could be a rownumber comming. */
|
||
|
continue;
|
||
|
}
|
||
|
/* We skip leading whitespaces. Once the first tab has been seen, we
|
||
|
* can no longer be dealing with the first field, the row field.
|
||
|
*/
|
||
|
if ( isspace(c) && i == 0 ) {
|
||
|
if ( c == '\t' ) {
|
||
|
rownum = 0;
|
||
|
}
|
||
|
continue ;
|
||
|
}
|
||
|
/* If we see a whitespace (isspace() == t) or the ned of the buffer
|
||
|
* we process whatever we read in. We also have to consider the
|
||
|
* comma character, as complex numbers are comma separated.
|
||
|
*/
|
||
|
if ( isspace(c) || c == ',' || c <= 0 ) {
|
||
|
if ( rownum ) {
|
||
|
ss->currow = atoi(dbuf->s);
|
||
|
dbuf_clear(dbuf);
|
||
|
rownum = i = 0;
|
||
|
continue;
|
||
|
}
|
||
|
done = 1;
|
||
|
break;
|
||
|
}
|
||
|
/* If we reach here we are looking at part of a number so we simpl
|
||
|
* grab it.
|
||
|
*/
|
||
|
i++;
|
||
|
dbuf_put_char( dbuf, c);
|
||
|
}
|
||
|
}
|
||
|
*val = g_ascii_strtod( dbuf->s, NULL);
|
||
|
|
||
|
// fprintf(stderr, "#buf=\"%s\" val=%g\n", dbuf->s, *val);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Read a single value from binary spice3 rawfile, and do
|
||
|
* the related error-checking.
|
||
|
*/
|
||
|
|
||
|
static int sf_getval_s3bin(SpiceStream *ss, double *dval)
|
||
|
{
|
||
|
off_t pos; /* off64_t */
|
||
|
double *val;
|
||
|
|
||
|
if (ss->read_vals >= ss->expected_vals) {
|
||
|
pos = fdbuf_tello(ss->linebuf);
|
||
|
msg_dbg("past last expected value offset 0x%lx", (long) pos);
|
||
|
return 0;
|
||
|
}
|
||
|
if ( fdbuf_read(ss->linebuf, sizeof(double) ) <= 0 ) {
|
||
|
pos = fdbuf_tello(ss->linebuf);
|
||
|
msg_error(_("unexepected EOF in data at offset 0x%lx"), (long) pos);
|
||
|
return 0;
|
||
|
}
|
||
|
val = (double *) ((DBuf *) ss->linebuf)->s;
|
||
|
*dval = *val;
|
||
|
ss->read_vals++;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Read row of values from a binay/ascii spice3 raw file
|
||
|
*/
|
||
|
int sf_readrow_s3raw(SpiceStream *ss )
|
||
|
{
|
||
|
int i;
|
||
|
int ret;
|
||
|
double val;
|
||
|
|
||
|
for (i = 0; i < ss->ncols ; i++) {
|
||
|
ret = ss->rdValFunc ( ss, &val );
|
||
|
if ( i == 0 && ret != 1 ) {
|
||
|
return ret;
|
||
|
} else if ( ret != 1) {
|
||
|
msg_warning(_("%s:\nEOF or error reading data field %d in row %d; file is incomplete."),
|
||
|
ss->filename, i, ss->read_rows );
|
||
|
return 0;
|
||
|
}
|
||
|
dataset_val_add( ss->wds, val);
|
||
|
}
|
||
|
|
||
|
ss->read_rows++;
|
||
|
if ( ss->read_rows >= ss->nrows ) {
|
||
|
return -2;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void sf_write_file_s3ascii( FILE *fd, WaveTable *wt, char *fmt)
|
||
|
{
|
||
|
int i;
|
||
|
int j;
|
||
|
int k = 0;
|
||
|
time_t now;
|
||
|
char format[32];
|
||
|
int dtype_complex;
|
||
|
WDataSet *wds = wavetable_get_dataset( wt, k);
|
||
|
WaveVar *var = g_ptr_array_index( wds->vars, 0);
|
||
|
char *title = "Data written by Gaw";
|
||
|
char *plotname;
|
||
|
|
||
|
|
||
|
if ( ! fmt ) {
|
||
|
fmt = "%0.15e";
|
||
|
}
|
||
|
fprintf( fd, "Title: %s\n", title );
|
||
|
time(&now) ;
|
||
|
fprintf( fd, "Date: %s", ctime(&now) );
|
||
|
|
||
|
while ( (wds = wavetable_get_dataset( wt, k++)) ){
|
||
|
|
||
|
var = g_ptr_array_index( wds->vars, 1);
|
||
|
dtype_complex = 0;
|
||
|
if ( var->ncols == 2 ){
|
||
|
dtype_complex = 1;
|
||
|
}
|
||
|
plotname = dataset_get_setname(wds);
|
||
|
if ( ! plotname ){
|
||
|
plotname = title;
|
||
|
}
|
||
|
fprintf( fd, "Plotname: %s\n", plotname );
|
||
|
fprintf( fd, "Flags: %s\n", dtype_complex ? "complex" : "real" );
|
||
|
fprintf( fd, "No. Variables: %d\n", wds->numVars );
|
||
|
fprintf( fd, "No. Points: %d\n", wds->nrows );
|
||
|
|
||
|
fprintf( fd, "Variables:\n" );
|
||
|
for ( i = 0 ; i < wds->numVars ; i++ ){
|
||
|
var = g_ptr_array_index( wds->vars, i);
|
||
|
fprintf( fd, "\t%d\t%s\t%s\n", i, var->varName,
|
||
|
wavevar_type2str( var->type) );
|
||
|
}
|
||
|
|
||
|
fprintf( fd, "Values:\n" );
|
||
|
|
||
|
for ( i = 0 ; i < wds->nrows ; i++ ){
|
||
|
for ( j = 0 ; j < wds->ncols ; j++ ){
|
||
|
double val = dataset_val_get( wds, i, j );
|
||
|
if ( j == 0 ){
|
||
|
sprintf( format, "%%d\t\t%s\n", fmt );
|
||
|
fprintf( fd, format, i, val);
|
||
|
sprintf( format, "\t%s\n", fmt );
|
||
|
} else {
|
||
|
fprintf( fd, format, val);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|