1 /*
2 * SpiceStream - simple, incremental reader for analog data files,
3 * such as those produced by spice-type simulators.
4 *
5 * Copyright (C) 1998,1999 Stephen G. Tell
6 *
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.
11 *
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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23 #include "ssintern.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <float.h>
29 #include <stdarg.h>
30 #include <errno.h>
31 #include <config.h>
32 #include <glib.h>
33
34 #include "spicestream.h"
35
36 extern SpiceStream *sf_rdhdr_hspice(char *name, FILE *fp);
37 extern SpiceStream *sf_rdhdr_hsascii(char *name, FILE *fp);
38 extern SpiceStream *sf_rdhdr_hsbin(char *name, FILE *fp);
39 extern SpiceStream *sf_rdhdr_cazm(char *name, FILE *fp);
40 extern SpiceStream *sf_rdhdr_s3raw(char *name, FILE *fp);
41 extern SpiceStream *sf_rdhdr_s2raw(char *name, FILE *fp);
42 extern SpiceStream *sf_rdhdr_ascii(char *name, FILE *fp);
43 extern SpiceStream *sf_rdhdr_nsout(char *name, FILE *fp);
44 static int ss_readrow_none(SpiceStream *, double *ivar, double *dvars);
45
46 SSMsgLevel spicestream_msg_level = WARN;
47
48 typedef SpiceStream* (*PFD)(char *name, FILE *fp);
49
50 typedef struct {
51 char *name;
52 PFD rdfunc;
53 } DFormat;
54
55 static DFormat format_tab[] = {
56 {"hspice", sf_rdhdr_hspice },
57 {"hsascii", sf_rdhdr_hsascii },
58 {"hsbinary", sf_rdhdr_hsbin },
59 {"cazm", sf_rdhdr_cazm },
60 {"spice3raw", sf_rdhdr_s3raw },
61 {"spice2raw", sf_rdhdr_s2raw },
62 {"ascii", sf_rdhdr_ascii },
63 {"nsout", sf_rdhdr_nsout },
64 };
65 static const int NFormats = sizeof(format_tab)/sizeof(DFormat);
66
67 /*
68 * Open spice waveform file for reading.
69 * Reads in header with signal names (and sometimes signal types).
70 * TODO: simple strategies for trying to deduce file type from
71 * name or contents.
72 */
73
74 SpiceStream *
ss_open_internal(FILE * fp,char * filename,char * format)75 ss_open_internal(FILE *fp, char *filename, char *format)
76 {
77 SpiceStream *ss;
78 int i;
79
80 for(i = 0; i < NFormats; i++) {
81 if(0==strcmp(format, format_tab[i].name)) {
82 ss = (format_tab[i].rdfunc)(filename, fp);
83 if(ss) {
84 ss->filetype = i;
85 return ss;
86 } else {
87 ss_msg(DBG, "ss_open", "failed to open %s using format %s", filename, format_tab[i].name);
88 return NULL;
89 }
90 }
91 }
92 ss_msg(ERR, "ss_open", "Format \"%s\" unknown", format);
93 return NULL;
94 }
95
96 SpiceStream *
ss_open(char * filename,char * format)97 ss_open(char *filename, char *format)
98 {
99 FILE *fp;
100
101 fp = fopen64(filename, "r");
102 if(fp == NULL) {
103 fprintf(stderr, "fopen(\"%s\"): %s\n", filename, strerror(errno));
104 return NULL;
105 }
106
107 return ss_open_internal(fp, filename, format);
108 }
109
110 SpiceStream *
ss_open_fp(FILE * fp,char * format)111 ss_open_fp(FILE *fp, char *format)
112 {
113 return ss_open_internal(fp, "<spicestream>", format);
114 }
115
116 /*
117 * Allocate SpiceStream structure and fill in some portions.
118 * To be called only from format-specific header-reading functions,
119 * usually after they read and verify the header.
120 * Caller must still set types and names of ivar and dvars,
121 * and must set readrow and linebuf items.
122 */
123 SpiceStream *
ss_new(FILE * fp,char * filename,int ndv,int nspar)124 ss_new(FILE *fp, char *filename, int ndv, int nspar)
125 {
126 SpiceStream *ss;
127
128 ss = g_new0(SpiceStream, 1);
129 ss->filename = g_strdup(filename);
130 ss->fp = fp;
131 ss->ivar = g_new0(SpiceVar, 1);
132 ss->ndv = ndv;
133 if(ndv)
134 ss->dvar = g_new0(SpiceVar, ndv);
135 ss->nsweepparam = nspar;
136 if(nspar)
137 ss->spar = g_new0(SpiceVar, nspar);
138
139 return ss;
140 }
141
142 /*
143 * Close the file assocated with a SpiceStream.
144 * No more data can be read, but the header information can still
145 * be accessed.
146 */
ss_close(SpiceStream * ss)147 void ss_close(SpiceStream *ss)
148 {
149 fclose(ss->fp);
150 ss->fp = NULL;
151 ss->readrow = ss_readrow_none;
152 }
153
154 /*
155 * Free all resources associated with a SpiceStream.
156 */
ss_delete(SpiceStream * ss)157 void ss_delete(SpiceStream *ss)
158 {
159 if(ss->fp)
160 fclose(ss->fp);
161 if(ss->filename)
162 g_free(ss->filename);
163 if(ss->ivar)
164 g_free(ss->ivar);
165 if(ss->dvar)
166 g_free(ss->dvar);
167 if(ss->linebuf)
168 g_free(ss->linebuf);
169 g_free(ss);
170 }
171
172 /*
173 * row-reading function that always returns EOF.
174 */
175 static int
ss_readrow_none(SpiceStream * ss,double * ivar,double * dvars)176 ss_readrow_none(SpiceStream *ss, double *ivar, double *dvars)
177 {
178 return 0;
179 }
180
181
182 static char *vartype_names[] = {
183 "Unknown", "Time", "Voltage", "Current", "Frequency"
184 };
185 const int nvartype_names = sizeof(vartype_names)/sizeof(char *);
186
187 /*
188 * return a string corresponding to a SpiceStream VarType.
189 * the pointer returned is in static or readonly storage,
190 * and is overwritten with each call.
191 */
vartype_name_str(VarType type)192 char *vartype_name_str(VarType type)
193 {
194 static char buf[32];
195 if(type < nvartype_names)
196 return vartype_names[type];
197 else {
198 sprintf(buf, "type-%d", type);
199 return buf;
200 }
201 }
202
203 /*
204 * return pointer to string with printable name for a variable
205 * or one of the columns of a variable.
206 * buf is a pointer to a buffer to use. If NULL, one will be allocated.
207 * n is the maximum number of characters to put in the buffer.
208 */
ss_var_name(SpiceVar * sv,int col,char * buf,int n)209 char *ss_var_name(SpiceVar *sv, int col, char *buf, int n)
210 {
211 int idx;
212
213 if(buf == NULL) {
214 int l;
215 l = strlen(sv->name + 3);
216 buf = g_new(char, l);
217 n = l;
218 }
219 strncpy(buf, sv->name, n-1);
220 n -= strlen(buf)+1;
221 if(sv->ncols == 1 || col < 0)
222 return buf;
223 if(n>1) {
224 idx = strlen(buf);
225 buf[idx++] = '.';
226 buf[idx++] = '0'+col;
227 buf[idx] = 0;
228 }
229
230 return(buf);
231 }
232
233 /*
234 * given a filetype number, return a pointer to a string containing the
235 * name of the Spicestream file format.
236 * Valid file type numbers start at 0.
237 */
ss_filetype_name(int n)238 char *ss_filetype_name(int n)
239 {
240 if(n >= 0 && n < NFormats)
241 return format_tab[n].name;
242 else
243 return NULL;
244 }
245
246 /*
247 * utility function to read whole line into buffer, expanding buffer if needed.
248 * line buffer must be allocated with g_malloc/g_new, or NULL in which case
249 * we allocate an initial, buffer.
250 * returns 0 or EOF.
251 */
252 int
fread_line(FILE * fp,char ** bufp,int * bufsize)253 fread_line(FILE *fp, char **bufp, int *bufsize)
254 {
255 int c;
256 int n = 0;
257 if(*bufp == NULL) {
258 if(*bufsize == 0)
259 *bufsize = 1024;
260 *bufp = g_new(char, *bufsize);
261 }
262 while(((c = getc(fp)) != EOF) && c != '\n') {
263 (*bufp)[n++] = c;
264 if(n >= *bufsize) {
265 *bufsize *= 2;
266 *bufp = g_realloc(*bufp, *bufsize);
267 }
268 }
269 (*bufp)[n] = 0;
270 if(c == EOF)
271 return EOF;
272 else
273 return 0;
274 }
275
276 FILE *ss_error_file;
277 SSMsgHook ss_error_hook;
278
279 /*
280 * ss_msg: emit an error message from anything in the spicestream subsystem,
281 * or anything else that wants to use our routines.
282 *
283 * If ss_error_hook is non-NULL, it is a pointer to a function that
284 * will be called with the error string.
285 * if ss_error_file is non-NULL, it is a FILE* to write the message to.
286 * If neither of these are non-null, the message is written to stderr.
287 *
288 * args:
289 * type is one of:
290 * DBG - Debug, ERR - ERROR, INFO - infomration, WARN - warning
291 * id is the name of the function, or other identifier
292 * remaining arguments are printf-like.
293 */
294 void
ss_msg(SSMsgLevel type,const char * id,const char * msg,...)295 ss_msg(SSMsgLevel type, const char *id, const char *msg, ...)
296 {
297 char *typestr;
298 va_list args;
299 int blen = 1024;
300 char buf[1024];
301
302 if(type < spicestream_msg_level)
303 return;
304
305 switch (type) {
306 case DBG:
307 typestr = "<<DEBUG>>";
308 break;
309 case ERR:
310 typestr = "<<ERROR>>";
311 break;
312 case WARN:
313 typestr = "<<WARNING>>";
314 break;
315 case INFO:
316 default:
317 typestr = "";
318 break;
319 }
320
321 va_start(args, msg);
322
323 #ifdef HAVE_SNPRINTF
324 blen = snprintf(buf, 1024, "[%s]: %s ", id, typestr);
325 if(blen>0)
326 blen += vsnprintf(&buf[blen-1], 1024-blen, msg, args);
327 if(blen>0)
328 blen += snprintf(&buf[blen-1], 1024-blen, "\n");
329 #else
330 sprintf(buf, "[%s]: %s ", id, typestr);
331 blen = strlen(buf);
332 vsprintf(&buf[blen], msg, args);
333 strcat(buf, "\n");
334 #endif
335
336 if(ss_error_hook)
337 (ss_error_hook)(buf);
338 if(ss_error_file)
339 fputs(buf, ss_error_file);
340 if(ss_error_hook == NULL && ss_error_file == NULL)
341 fputs(buf, stderr);
342
343 va_end(args);
344 }
345