yet another hspice file format variant
[gwave-svn.git] / spicefile / sp2sp.c
blobdc5fa2eea8a85a8d0b783ea905f478e831f0ffff
1 /*
2 * sp2sp - test program for spicestream library and
3 * rudimentary spicefile format converter.
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 General Public
18 * License along with this program; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <float.h>
27 #include <errno.h>
28 #include <glib.h>
29 #include "spicestream.h"
31 #define SWEEP_NONE 0
32 #define SWEEP_PREPEND 1
33 #define SWEEP_HEAD 2
35 int g_verbose = 0;
36 int sweep_mode = SWEEP_PREPEND;
37 char *progname = "sp2sp";
39 static void ascii_header_output(SpiceStream *sf, int *enab, int nidx);
40 static void ascii_data_output(SpiceStream *sf, int *enab, int nidx,
41 double begin_val, double end_val, int ndigits);
42 static int parse_field_numbers(int **index, int *idxsize, int *nsel,
43 char *list, int nfields);
44 static int parse_field_names(int **index, int *idxsize, int *nsel,
45 char *list, SpiceStream *sf);
46 static VarType get_vartype_code(char *vartype);
48 static void usage()
50 int i;
51 char *s;
53 fprintf(stderr, "usage: %s [options] file\n", progname);
54 fprintf(stderr, " options:\n");
55 fprintf(stderr, " -b V begin output after independent-variable value V is reached\n");
56 fprintf(stderr, " instead of start of input\n");
57 fprintf(stderr, " -c T Convert output to type T\n");
58 fprintf(stderr, " -d N use N significant digits in output\n");
59 fprintf(stderr, " -e V stop after independent-variable value V is reached\n");
60 fprintf(stderr, " instead of end of input.\n");
62 fprintf(stderr, " -f f1,f2,... Output only fields named f1, f2, etc.\n");
63 fprintf(stderr, " -n n1,n2,... Output only fields n1, n2, etc;\n");
64 fprintf(stderr, " independent variable is field number 0\n");
65 fprintf(stderr, " -u U Output only variables with units of type; U\n");
66 fprintf(stderr, " U = volts, amps, etc.\n");
67 fprintf(stderr, " -s S Handle sweep parameters as S:\n");
68 fprintf(stderr, " -s head add header-like comment line\n");
69 fprintf(stderr, " -s prepend prepend columns to all output lines\n");
70 fprintf(stderr, " -s none ignore sweep info\n");
71 fprintf(stderr, " -t T Assume that input is of type T\n");
72 fprintf(stderr, " -v Verbose - print detailed signal information\n");
73 fprintf(stderr, " output format types:\n");
74 fprintf(stderr, " none - no data output\n");
75 fprintf(stderr, " ascii - lines of space-seperated numbers, with header\n");
76 fprintf(stderr, " nohead - lines of space-seperated numbers, no headers\n");
77 fprintf(stderr, " cazm - CAzM format\n");
78 fprintf(stderr, " input format types:\n");
80 i = 0;
81 while(s = ss_filetype_name(i++)) {
82 fprintf(stderr, " %s\n", s);
86 int
87 main(int argc, char **argv)
89 SpiceStream *sf;
91 int i;
92 int idx;
93 extern int optind;
94 extern char *optarg;
95 int x_flag = 0;
96 int errflg = 0;
97 char *infiletype = "hspice";
98 char *outfiletype = "ascii";
99 char *fieldnamelist = NULL;
100 char *fieldnumlist = NULL;
101 int *out_indices = NULL;
102 int outi_size = 0;
103 int nsel;
104 VarType vartype = UNKNOWN;
105 int c;
106 int ndigits = 7;
107 double begin_val = -DBL_MAX;
108 double end_val = DBL_MAX;
110 while ((c = getopt (argc, argv, "b:c:d:e:f:n:s:t:u:vx")) != EOF) {
111 switch(c) {
112 case 'v':
113 spicestream_msg_level = DBG;
114 g_verbose = 1;
115 break;
116 case 'b':
117 begin_val = atof(optarg);
118 break;
119 case 'c':
120 outfiletype = optarg;
121 break;
122 case 'd':
123 ndigits = atoi(optarg);
124 if(ndigits < 5)
125 ndigits = 5;
126 break;
127 case 'e':
128 end_val = atof(optarg);
129 break;
130 case 'f':
131 fieldnamelist = optarg;
132 break;
133 case 'n':
134 fieldnumlist = optarg;
135 break;
136 case 's':
137 if(strcmp(optarg, "none") == 0)
138 sweep_mode = SWEEP_NONE;
139 else if(strcmp(optarg, "prepend") == 0)
140 sweep_mode = SWEEP_PREPEND;
141 else if(strcmp(optarg, "head") == 0)
142 sweep_mode = SWEEP_HEAD;
143 else {
144 fprintf(stderr, "unknown sweep-data style %s\n", optarg);
145 exit(1);
147 break;
148 case 't':
149 infiletype = optarg;
150 break;
151 case 'u':
152 vartype = get_vartype_code(optarg);
153 break;
154 case 'x':
155 spicestream_msg_level = DBG;
156 x_flag = 1;
157 break;
158 default:
159 errflg = 1;
160 break;
164 if(errflg || optind >= argc) {
165 usage();
166 exit(1);
169 sf = ss_open(argv[optind], infiletype);
170 if(!sf) {
171 if(errno)
172 perror(argv[optind]);
173 fprintf(stderr, "unable to read file\n");
174 exit(1);
176 if(g_verbose) {
177 printf("filename: \"%s\"\n", sf->filename);
178 printf(" columns: %d\n", sf->ncols);
179 printf(" tables: %d\n", sf->ntables);
180 printf("independent variable:\n");
181 printf(" name: \"%s\"\n", sf->ivar->name);
182 printf(" type: %s\n", vartype_name_str(sf->ivar->type));
183 printf(" col: %d\n", sf->ivar->col);
184 printf(" ncols: %d\n", sf->ivar->ncols);
185 printf("sweep parameters: %d\n", sf->nsweepparam);
186 for(i = 0; i < sf->nsweepparam; i++) {
187 printf(" name: \"%s\"\n", sf->spar[i].name);
188 printf(" type: %s\n", vartype_name_str(sf->spar[i].type));
190 printf("dependent variables: %d\n", sf->ndv);
191 for(i = 0; i < sf->ndv; i++) {
192 printf(" dv[%d] \"%s\" ", i, sf->dvar[i].name);
193 printf(" (type=%s col=%d ncols=%d)\n",
194 vartype_name_str(sf->dvar[i].type),
195 sf->dvar[i].col,
196 sf->dvar[i].ncols);
200 if(fieldnamelist == NULL && fieldnumlist == NULL) {
201 out_indices = g_new0(int, sf->ndv+1);
202 nsel = 0;
203 idx = 0;
204 for(i = 0; i < sf->ndv+1; i++) {
205 if(i == 0 ||
206 (vartype == UNKNOWN
207 || sf->dvar[i-1].type == vartype)) {
208 out_indices[idx++] = i;
209 nsel++;
213 if(fieldnumlist)
214 if(parse_field_numbers(&out_indices, &outi_size, &nsel,
215 fieldnumlist, sf->ndv+1) < 0)
216 exit(1);
217 if(fieldnamelist)
218 if(parse_field_names(&out_indices, &outi_size, &nsel,
219 fieldnamelist, sf) < 0)
220 exit(1);
221 if(nsel == 0) {
222 fprintf(stderr, "No fields selected for output\n");
223 exit(0);
226 if(strcmp(outfiletype, "cazm") == 0) {
227 printf("* CAZM-format output converted with sp2sp\n");
228 printf("\n");
229 printf("TRANSIENT ANALYSIS\n");
230 ascii_header_output(sf, out_indices, nsel);
231 ascii_data_output(sf, out_indices, nsel, begin_val, end_val, ndigits);
232 } else if(strcmp(outfiletype, "ascii") == 0) {
233 ascii_header_output(sf, out_indices, nsel);
234 ascii_data_output(sf, out_indices, nsel, begin_val, end_val, ndigits);
235 } else if(strcmp(outfiletype, "nohead") == 0) {
236 ascii_data_output(sf, out_indices, nsel, begin_val, end_val, ndigits);
237 } else if(strcmp(outfiletype, "none") == 0) {
238 /* do nothing */
239 } else {
240 fprintf(stderr, "%s: invalid output type name: %s\n",
241 progname, outfiletype);
244 ss_close(sf);
246 exit(0);
250 * print all column headers.
251 * For multicolumn variables, ss_var_name will generate a column name
252 * consisting of the variable name plus a suffix.
254 static void
255 ascii_header_output(SpiceStream *sf, int *indices, int nidx)
257 int i, j;
258 char buf[1024];
260 if((sf->nsweepparam > 0) && (sweep_mode == SWEEP_PREPEND)) {
261 for(i = 0; i < sf->nsweepparam; i++) {
262 printf("%s ", sf->spar[i].name);
265 for(i = 0; i < nidx; i++) {
266 if(i > 0)
267 putchar(' ');
268 if(indices[i] == 0) {
269 ss_var_name(sf->ivar, 0, buf, 1024);
270 printf("%s", buf);
271 } else {
272 int varno = indices[i]-1;
273 for(j = 0; j < sf->dvar[varno].ncols; j++) {
274 if(j > 0)
275 putchar(' ');
276 ss_var_name(&sf->dvar[varno], j, buf, 1024);
277 printf("%s", buf);
281 putchar('\n');
285 * print data as space-seperated columns.
287 static void
288 ascii_data_output(SpiceStream *sf, int *indices, int nidx,
289 double begin_val, double end_val, int ndigits)
291 int i, j, tab;
292 int rc;
293 double ival;
294 double *dvals;
295 double *spar = NULL;
296 int done;
298 dvals = g_new(double, sf->ncols);
299 if(sf->nsweepparam > 0)
300 spar = g_new(double, sf->nsweepparam);
302 done = 0;
303 tab = 0;
304 while(!done) {
305 if(sf->nsweepparam > 0) {
306 if(ss_readsweep(sf, spar) <= 0)
307 break;
309 if(tab > 0 && sweep_mode == SWEEP_HEAD) {
310 printf("# sweep %d;", tab);
311 for(i = 0; i < sf->nsweepparam; i++) {
312 printf(" %s=%g", sf->spar[i].name, spar[i]);
314 putchar('\n');
316 while((rc = ss_readrow(sf, &ival, dvals)) > 0) {
317 if(ival < begin_val)
318 continue;
319 if(ival > end_val) {
320 /* past end_val, but can only stop reading
321 early if if there is only one sweep-table
322 in the file. */
323 if(sf->ntables == 1)
324 break;
325 else
326 continue;
329 if((sf->nsweepparam > 0) && (sweep_mode == SWEEP_PREPEND)) {
330 for(i = 0; i < sf->nsweepparam; i++) {
331 printf("%.*g ", ndigits, spar[i]);
334 for(i = 0; i < nidx; i++) {
335 if(i > 0)
336 putchar(' ');
337 if(indices[i] == 0)
338 printf("%.*g", ndigits, ival);
339 else {
340 int varno = indices[i]-1;
341 int dcolno = sf->dvar[varno].col - 1;
342 for(j = 0; j < sf->dvar[varno].ncols; j++) {
343 if(j > 0)
344 putchar(' ');
345 printf("%.*g", ndigits,
346 dvals[dcolno+j]);
350 putchar('\n');
352 if(rc == -2) { /* end of sweep, more follow */
353 if(sf->nsweepparam == 0)
354 sweep_mode = SWEEP_HEAD;
355 tab++;
356 } else { /* EOF or error */
357 done = 1;
360 g_free(dvals);
361 if(spar)
362 g_free(spar);
365 static int parse_field_numbers(int **indices, int *idxsize, int *nidx,
366 char *list, int nfields)
368 int n, i;
369 char *fnum;
370 int err = 0;
371 int *idx;
372 if(!*indices || idxsize == 0) {
373 *idxsize = nfields*2;
374 idx = g_new0(int, *idxsize);
375 *indices = idx;
376 *nidx = 0;
379 fnum = strtok(list, ", \t");
380 i = 0;
381 while(fnum) {
382 if(*nidx >= *idxsize) {
383 *idxsize *= 2;
384 idx = g_realloc(idx, (*idxsize) * sizeof(int));
385 *indices = idx;
387 n = atoi(fnum);
388 if(n < 0 || n >= nfields) {
389 fprintf(stderr, "bad field number in -n option: %s\n", fnum);
390 err = -1;
391 } else {
392 idx[i++] = n;
393 (*nidx)++;
395 fnum = strtok(NULL, ", \t");
397 return err;
402 * Try looking for named dependent variable. Try twice,
403 * first as-is, then with "v(" prepended the way hspice mangles things.
405 static int find_dv_by_name(char *name, SpiceStream *sf)
407 int i;
408 for(i = 0; i < sf->ndv; i++) {
409 if(strcasecmp(name, sf->dvar[i].name) == 0)
410 return i;
412 for(i = 0; i < sf->ndv; i++) {
413 if(strncasecmp("v(", sf->dvar[i].name, 2) == 0
414 && strcasecmp(name, &sf->dvar[i].name[2]) == 0)
415 return i;
417 return -1;
421 * parse comma-seperated list of field names. Turn on the output-enables
422 * for the listed fields.
424 static int parse_field_names(int **indices, int *idxsize, int *nidx,
425 char *list, SpiceStream *sf)
427 int err = 0;
428 int n;
429 char *fld;
430 int i;
431 int *idx;
433 if(!*indices || idxsize == 0) {
434 *idxsize = (sf->ndv+1)*2;
435 idx = g_new0(int, *idxsize);
436 *indices = idx;
437 *nidx = 0;
440 fld = strtok(list, ", \t");
441 i = 0;
442 while(fld) {
443 if(*nidx >= *idxsize) {
444 *idxsize *= 2;
445 idx = g_realloc(idx, (*idxsize) * sizeof(int));
446 *indices = idx;
448 if(strcasecmp(fld, sf->ivar->name)==0) {
449 idx[i++] = 0;
450 (*nidx)++;
451 } else if((n = find_dv_by_name(fld, sf)) >= 0) {
452 idx[i++] = n+1;
453 (*nidx)++;
454 } else {
455 fprintf(stderr, "field name in -f option not found in file: %s\n", fld);
456 err = -1;
458 fld = strtok(NULL, ", \t");
460 return err;
464 struct vtlistel {
465 VarType t;
466 char *s;
468 static struct vtlistel vtlist[] = {
469 {TIME, "time"},
470 {VOLTAGE, "volt"},
471 {VOLTAGE, "volts"},
472 {VOLTAGE, "voltage"},
473 {CURRENT, "current"},
474 {CURRENT, "amps"},
475 {FREQUENCY, "freq"},
476 {FREQUENCY, "frequency"},
477 {FREQUENCY, "hertz"},
478 {UNKNOWN, NULL},
482 * Given a variable type name, return a numeric VarType.
483 * Returns 0 (UNKNOWN) if no match.
485 static VarType get_vartype_code(char *vartype)
487 int i;
488 for(i = 0; vtlist[i].s; i++) {
489 if(strcasecmp(vartype, vtlist[i].s) == 0)
490 return vtlist[i].t;
492 return UNKNOWN;