waveview/lib/ss_cazm.c

296 lines
6.6 KiB
C
Raw Permalink Normal View History

2022-09-24 17:47:18 -04:00
/*
* ss_cazm.c - CAZM- and ASCII- format routines for SpiceStream
*
* include LICENSE
*/
/*
* CAzM and "ascii" format are closely related, so they are both handled
* in this file.
*
* CAzM format is intended to handles files written by MCNC's CAzM simulator,
* used by a number of universities, and its commercial decendant,
* the TSPICE product from Tanner Research.
*
* CAzM-format files contain a multiline header. The second to last line
* of the header identifies the analysis type, for example TRANSIENT or AC.
* The last line of the header contains the names of the variables, seperated
* by whitespace.
*
* Ascii-format files have a one-line header, containing a space- or
* tab-speperated list of the variable names. To avoid treating a file
* containing random binary garbage as an ascii-format file, we require the
* header line to contain space, tab, and USASCII printable characters only.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
// #include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <float.h>
#include <spicestream.h>
#include <wavevar.h>
2024-06-15 12:49:25 -04:00
2022-09-24 17:47:18 -04:00
#ifdef TRACE_MEM
#include <tracemem.h>
#endif
2024-06-15 12:49:25 -04:00
2022-09-24 17:47:18 -04:00
static int
ascii_process_header(SpiceStream *ss, char *line, VarType ivtype );
/*
* return 1 ok
* 0 EOF
* -1 Error
*/
/*
* Read spice-type file header - cazm format
*/
int sf_rdhdr_cazm( SpiceStream *ss )
{
2024-06-15 12:49:25 -04:00
int done = 0;
VarType ivtype;
char *line;
int ret;
while( ! done) {
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL ||
fdbuf_get_lineno(ss->linebuf) > 30) {
return 0;
}
/* "section header" line */
if(strncmp (line, "TRANSIENT", 9) == 0) {
ivtype = TIME;
done = 1;
} else if (strncmp(line, "AC ANALYSIS", 11) == 0) {
ivtype = FREQUENCY;
done = 1;
} else if (strncmp(line, "TRANSFER", 8) == 0) {
/* DC transfer function - ivar might also be current,
* but we can't tell */
ivtype = VOLTAGE;
done = 1;
}
}
/*
* line after header contains signal names
* first one is assumed to be the independent variable.
*/
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL ) {
return 0;
}
ret = ascii_process_header(ss, line, ivtype );
msg_dbg("%s : 'cazm' file format with %d columns", ss->filename, ss->ncols);
return ret;
2022-09-24 17:47:18 -04:00
}
/*
* Read spice-type file header - ascii format
*/
int sf_rdhdr_ascii( SpiceStream *ss )
{
2024-06-15 12:49:25 -04:00
char *cp;
char *line;
int ret;
/*
* first line is expected to contain space-seperated
* variable names.
* first one is assumed to be the independent variable.
*/
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL) {
return 0;
}
/*
* Check for non-ascii characters in header, to reject
* binary files.
*/
for (cp = line; *cp; cp++) {
if ( ! isgraph(*cp) && *cp != ' ' && *cp != '\t') {
return -1;
}
}
/*
* Remove some characters at beginning of the line
*/
cp = line + strspn( line, "#! " ) ; /* skip characters in arg 2 */
if ( cp > line ) {
dbuf_strcpy( (DBuf *) ss->linebuf, cp);
}
ret = ascii_process_header(ss, ((DBuf *) ss->linebuf)->s, UNKNOWN );
msg_dbg("%s : 'ascii' file format with %d columns", ss->filename, ss->ncols);
return ret;
2022-09-24 17:47:18 -04:00
}
/*
* Process a header line from an ascii or cazm format file.
* Returns a filled-in SpiceStream* with variable information.
*/
2024-06-15 12:49:25 -04:00
static int
2022-09-24 17:47:18 -04:00
ascii_process_header(SpiceStream *ss, char *line, VarType ivtype )
{
2024-06-15 12:49:25 -04:00
char *signam;
signam = strtok(line, " \t\n");
if ( ! signam) {
msg_error(_("line %d: syntax error in header"), fdbuf_get_lineno(ss->linebuf));
return -1;
}
if (app_strcasestr(signam, "index") ) {
ss->idxcol = 0;
// Skip to next token in header
signam = strtok(NULL, " \t\n");
if ( ! signam) {
msg_error(_("line %d: syntax error in header"), fdbuf_get_lineno(ss->linebuf));
return -1;
}
}
if ( ivtype == UNKNOWN) {
if (app_strcasestr(signam, "time") ) {
ivtype = TIME;
}
}
spicestream_var_add( ss, signam, ivtype, 1 );
ss->ntables = 1;
ss->ncols = 1;
while ((signam = strtok(NULL, " \t\n")) != NULL) {
spicestream_var_add( ss, signam, UNKNOWN, 1 );
ss->ncols++;
}
/* give a name to the set from filename */
if ( (signam = strrchr( ss->filename, '/')) ) {
signam++;
} else {
signam = ss->filename;
}
dataset_dup_setname(ss->wds, signam );
ss->flags = SSF_PUSHBACK | SSF_NORDHDR | SSF_CPVARS;
return 1;
2022-09-24 17:47:18 -04:00
}
/*
* Read row of values from ascii- or cazm- format file.
* Possibly reusable for other future formats with lines of
* whitespace-seperated values.
* Returns:
* 1 on success. also fills in *ivar scalar and *dvars vector
* 0 on EOF
* -1 on error (may change some ivar/dvar values)
*/
int sf_readrow_ascii(SpiceStream *ss)
{
2024-06-15 12:49:25 -04:00
int i;
char *tok;
char *line;
if ( (line = fdbuf_get_line(ss->linebuf)) == NULL) {
return 0; /* EOF */
}
tok = strtok(line, " \t\n");
if ( ! tok) {
return -2; /* blank line can indicate end of data */
}
// skip index column
if (ss->idxcol >= 0) {
tok = strtok(NULL, " \t\n");
if ( ! tok) {
return -2; /* blank line can indicate end of data */
}
}
/*
* check to see if it is numeric: ascii format is so loosly defined
* that we might read a load of garbage otherwise.
*/
if (strspn(tok, "0123456789eE+-.") != strlen(tok)) {
msg_error(_("%s:\nline %d: expected number; maybe this isn't an ascii data file at all?"),
ss->filename, ss->linebuf->lineno );
return -1;
}
double val = g_ascii_strtod(tok, NULL);
spicestream_val_add( ss, val);
for (i = 0; i < ss->ncols - 1; i++) {
tok = strtok(NULL, " \t\n");
if ( ! tok) {
msg_error(_("%s:%d: data field %d missing"),
ss->linebuf->filename, ss->linebuf->lineno );
return -1;
}
val = g_ascii_strtod(tok, NULL);
spicestream_val_add( ss, val);
}
return 1;
2022-09-24 17:47:18 -04:00
}
void sf_write_file_ascii( FILE *fd, WaveTable *wt, char *fmt)
{
2024-06-15 12:49:25 -04:00
int i;
int j;
int k = 0;
char *c = "";
char format[64];
WDataSet *wds = wavetable_get_dataset( wt, k);
WaveVar *var = g_ptr_array_index( wds->vars, 0);
// double min = wavevar_val_get_min(var);
// double max = wavevar_val_get_max(var);
// fprintf( stdout, "min %f, max %f\n", min, max);
for ( i = 0 ; i < wds->ncols ; i++ ){
var = g_ptr_array_index( wds->vars, i);
fprintf( fd, "%s%s", c, var->varName);
c = " ";
}
fprintf( fd, "\n");
if ( ! fmt ) {
fmt = "%.10g";
}
sprintf( format, "%%s%s", fmt );
while ( (wds = wavetable_get_dataset( wt, k )) ){
if ( k > 0 ) {
fprintf( fd, "\n");
}
for ( i = 0 ; i < wds->nrows ; i++ ){
c = "";
for ( j = 0 ; j < wds->ncols ; j++ ){
double val = dataset_val_get( wds, i, j );
if ( j == 0 ){
fprintf( fd, fmt, val);
} else {
fprintf( fd, format, c, val);
}
c = " ";
}
fprintf( fd, "\n");
}
k++;
}
2022-09-24 17:47:18 -04:00
}