finish wf_add_var()
[gwave-svn.git] / spicefile / sp2sp.c
blob9831392568dd5ece13ebf44930e7882972c1d43a
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 SpiceVar *dvar;
193 dvar = ss_dvar(sf, i);
194 printf(" dv[%d] \"%s\" ", i, dvar->name);
195 printf(" (type=%s col=%d ncols=%d)\n",
196 vartype_name_str(dvar->type),
197 dvar->col,
198 dvar->ncols);
202 if(fieldnamelist == NULL && fieldnumlist == NULL) {
203 out_indices = g_new0(int, sf->ndv+1);
204 nsel = 0;
205 idx = 0;
206 for(i = 0; i < sf->ndv+1; i++) {
207 SpiceVar *dvar;
208 dvar = ss_dvar(sf, i-1);
210 if(i == 0 ||
211 (vartype == UNKNOWN
212 || dvar->type == vartype)) {
213 out_indices[idx++] = i;
214 nsel++;
218 if(fieldnumlist)
219 if(parse_field_numbers(&out_indices, &outi_size, &nsel,
220 fieldnumlist, sf->ndv+1) < 0)
221 exit(1);
222 if(fieldnamelist)
223 if(parse_field_names(&out_indices, &outi_size, &nsel,
224 fieldnamelist, sf) < 0)
225 exit(1);
226 if(nsel == 0) {
227 fprintf(stderr, "No fields selected for output\n");
228 exit(0);
231 if(strcmp(outfiletype, "cazm") == 0) {
232 printf("* CAZM-format output converted with sp2sp\n");
233 printf("\n");
234 printf("TRANSIENT ANALYSIS\n");
235 ascii_header_output(sf, out_indices, nsel);
236 ascii_data_output(sf, out_indices, nsel, begin_val, end_val, ndigits);
237 } else if(strcmp(outfiletype, "ascii") == 0) {
238 ascii_header_output(sf, out_indices, nsel);
239 ascii_data_output(sf, out_indices, nsel, begin_val, end_val, ndigits);
240 } else if(strcmp(outfiletype, "nohead") == 0) {
241 ascii_data_output(sf, out_indices, nsel, begin_val, end_val, ndigits);
242 } else if(strcmp(outfiletype, "none") == 0) {
243 /* do nothing */
244 } else {
245 fprintf(stderr, "%s: invalid output type name: %s\n",
246 progname, outfiletype);
249 ss_close(sf);
251 exit(0);
255 * print all column headers.
256 * For multicolumn variables, ss_var_name will generate a column name
257 * consisting of the variable name plus a suffix.
259 static void
260 ascii_header_output(SpiceStream *sf, int *indices, int nidx)
262 int i, j;
263 char buf[1024];
265 if((sf->nsweepparam > 0) && (sweep_mode == SWEEP_PREPEND)) {
266 for(i = 0; i < sf->nsweepparam; i++) {
267 printf("%s ", sf->spar[i].name);
270 for(i = 0; i < nidx; i++) {
271 if(i > 0)
272 putchar(' ');
273 if(indices[i] == 0) {
274 ss_var_name(sf->ivar, 0, buf, 1024);
275 printf("%s", buf);
276 } else {
277 int varno = indices[i]-1;
278 SpiceVar *dvar;
279 dvar = ss_dvar(sf, varno);
280 for(j = 0; j < dvar->ncols; j++) {
281 if(j > 0)
282 putchar(' ');
283 ss_var_name(dvar, j, buf, 1024);
284 printf("%s", buf);
288 putchar('\n');
292 * print data as space-seperated columns.
294 static void
295 ascii_data_output(SpiceStream *sf, int *indices, int nidx,
296 double begin_val, double end_val, int ndigits)
298 int i, j, tab;
299 int rc;
300 double ival;
301 double *dvals;
302 double *spar = NULL;
303 int done;
305 dvals = g_new(double, sf->ncols);
306 if(sf->nsweepparam > 0)
307 spar = g_new(double, sf->nsweepparam);
309 done = 0;
310 tab = 0;
311 while(!done) {
312 if(sf->nsweepparam > 0) {
313 if(ss_readsweep(sf, spar) <= 0)
314 break;
316 if(tab > 0 && sweep_mode == SWEEP_HEAD) {
317 printf("# sweep %d;", tab);
318 for(i = 0; i < sf->nsweepparam; i++) {
319 printf(" %s=%g", sf->spar[i].name, spar[i]);
321 putchar('\n');
323 while((rc = ss_readrow(sf, &ival, dvals)) > 0) {
324 if(ival < begin_val)
325 continue;
326 if(ival > end_val) {
327 /* past end_val, but can only stop reading
328 early if if there is only one sweep-table
329 in the file. */
330 if(sf->ntables == 1)
331 break;
332 else
333 continue;
336 if((sf->nsweepparam > 0) && (sweep_mode == SWEEP_PREPEND)) {
337 for(i = 0; i < sf->nsweepparam; i++) {
338 printf("%.*g ", ndigits, spar[i]);
341 for(i = 0; i < nidx; i++) {
342 if(i > 0)
343 putchar(' ');
344 if(indices[i] == 0)
345 printf("%.*g", ndigits, ival);
346 else {
347 int varno = indices[i]-1;
348 SpiceVar *dvar = ss_dvar(sf, varno);
349 int dcolno = dvar->col - 1;
350 for(j = 0; j < dvar->ncols; j++) {
351 if(j > 0)
352 putchar(' ');
353 printf("%.*g", ndigits,
354 dvals[dcolno+j]);
358 putchar('\n');
360 if(rc == -2) { /* end of sweep, more follow */
361 if(sf->nsweepparam == 0)
362 sweep_mode = SWEEP_HEAD;
363 tab++;
364 } else { /* EOF or error */
365 done = 1;
368 g_free(dvals);
369 if(spar)
370 g_free(spar);
373 static int parse_field_numbers(int **indices, int *idxsize, int *nidx,
374 char *list, int nfields)
376 int n, i;
377 char *fnum;
378 int err = 0;
379 int *idx;
380 if(!*indices || idxsize == 0) {
381 *idxsize = nfields*2;
382 idx = g_new0(int, *idxsize);
383 *indices = idx;
384 *nidx = 0;
387 fnum = strtok(list, ", \t");
388 i = 0;
389 while(fnum) {
390 if(*nidx >= *idxsize) {
391 *idxsize *= 2;
392 idx = g_realloc(idx, (*idxsize) * sizeof(int));
393 *indices = idx;
395 n = atoi(fnum);
396 if(n < 0 || n >= nfields) {
397 fprintf(stderr, "bad field number in -n option: %s\n", fnum);
398 err = -1;
399 } else {
400 idx[i++] = n;
401 (*nidx)++;
403 fnum = strtok(NULL, ", \t");
405 return err;
410 * Try looking for named dependent variable. Try twice,
411 * first as-is, then with "v(" prepended the way hspice mangles things.
413 static int find_dv_by_name(char *name, SpiceStream *sf)
415 int i;
416 SpiceVar *dvar;
418 for(i = 0; i < sf->ndv; i++) {
419 dvar = ss_dvar(sf, i);
420 if(strcasecmp(name, dvar->name) == 0)
421 return i;
423 for(i = 0; i < sf->ndv; i++) {
424 dvar = ss_dvar(sf, i);
425 if(strncasecmp("v(", dvar->name, 2) == 0
426 && strcasecmp(name, &dvar->name[2]) == 0)
427 return i;
429 return -1;
433 * parse comma-seperated list of field names. Turn on the output-enables
434 * for the listed fields.
436 static int parse_field_names(int **indices, int *idxsize, int *nidx,
437 char *list, SpiceStream *sf)
439 int err = 0;
440 int n;
441 char *fld;
442 int i;
443 int *idx;
445 if(!*indices || idxsize == 0) {
446 *idxsize = (sf->ndv+1)*2;
447 idx = g_new0(int, *idxsize);
448 *indices = idx;
449 *nidx = 0;
452 fld = strtok(list, ", \t");
453 i = 0;
454 while(fld) {
455 if(*nidx >= *idxsize) {
456 *idxsize *= 2;
457 idx = g_realloc(idx, (*idxsize) * sizeof(int));
458 *indices = idx;
460 if(strcasecmp(fld, sf->ivar->name)==0) {
461 idx[i++] = 0;
462 (*nidx)++;
463 } else if((n = find_dv_by_name(fld, sf)) >= 0) {
464 idx[i++] = n+1;
465 (*nidx)++;
466 } else {
467 fprintf(stderr, "field name in -f option not found in file: %s\n", fld);
468 err = -1;
470 fld = strtok(NULL, ", \t");
472 return err;
476 struct vtlistel {
477 VarType t;
478 char *s;
480 static struct vtlistel vtlist[] = {
481 {TIME, "time"},
482 {VOLTAGE, "volt"},
483 {VOLTAGE, "volts"},
484 {VOLTAGE, "voltage"},
485 {CURRENT, "current"},
486 {CURRENT, "amps"},
487 {FREQUENCY, "freq"},
488 {FREQUENCY, "frequency"},
489 {FREQUENCY, "hertz"},
490 {UNKNOWN, NULL},
494 * Given a variable type name, return a numeric VarType.
495 * Returns 0 (UNKNOWN) if no match.
497 static VarType get_vartype_code(char *vartype)
499 int i;
500 for(i = 0; vtlist[i].s; i++) {
501 if(strcasecmp(vartype, vtlist[i].s) == 0)
502 return vtlist[i].t;
504 return UNKNOWN;