1 /*
2  * ss_hspice.c: HSPICE routines for SpiceStream
3  *
4  * Copyright (C) 1998-2002  Stephen G. Tell
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21 
22 #include "ssintern.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <float.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 
31 #include <config.h>
32 #include <glib.h>
33 #include "spicestream.h"
34 
35 SpiceStream *sf_rdhdr_hspice(char *name, FILE *fp);
36 SpiceStream *sf_rdhdr_hsascii(char *name, FILE *fp);
37 SpiceStream *sf_rdhdr_hsbin(char *name, FILE *fp);
38 
39 static int sf_readrow_hsascii(SpiceStream *sf, double *ivar, double *dvars);
40 static int sf_readrow_hsbin(SpiceStream *sf, double *ivar, double *dvars);
41 static SpiceStream *hs_process_header(int nauto, int nprobe,
42 				      int nsweepparam, char *line, char *name);
43 static int sf_readsweep_hsascii(SpiceStream *sf, double *svar);
44 static int sf_readsweep_hsbin(SpiceStream *sf, double *svar);
45 static int sf_readblock_hsbin(FILE *fp, char **bufp, int *bufsize, int offset);
46 
47 struct hsblock_header {  /* structure of binary tr0 block headers */
48 	gint32 h1;
49 	gint32 h2;
50 	gint32 h3;
51 	gint32 block_nbytes;
52 };
53 
54 union gint32bytes {
55 	gint32 i;
56 	gchar b[4];
57 };
58 
59 static void swap_gint32(gint32 *pi, size_t n);
60 
61 /* Read spice-type file header - autosense hspice binary or ascii */
62 SpiceStream *
sf_rdhdr_hspice(char * name,FILE * fp)63 sf_rdhdr_hspice(char *name, FILE *fp)
64 {
65 	int c;
66 	if((c = getc(fp)) == EOF)
67 		return NULL;
68 	ungetc(c, fp);
69 
70 	if((c & 0xff) < ' ')
71 		return sf_rdhdr_hsbin(name, fp);
72 	else
73 		return sf_rdhdr_hsascii(name, fp);
74 
75 	return NULL;
76 }
77 
78 /* Read spice-type file header - hspice ascii */
79 SpiceStream *
sf_rdhdr_hsascii(char * name,FILE * fp)80 sf_rdhdr_hsascii(char *name, FILE *fp)
81 {
82 	SpiceStream *sf = NULL;
83 	char *line = NULL;
84 	int nauto, nprobe, nsweepparam, ntables;
85 	int lineno = 0;
86 	int linesize = 1024;
87 	int lineused;
88 	char lbuf[256];
89 	char nbuf[16];
90 	char *cp;
91 	int maxlines;
92 
93 	if(fgets(lbuf, sizeof(lbuf), fp) == NULL)
94 		return NULL;
95 	lineno++;
96 
97 	/* version of post format */
98 	if(strncmp(&lbuf[16], "9007", 4) != 0
99 	   && strncmp(&lbuf[16], "9601", 4) != 0)
100 		return NULL;
101 	strncpy(nbuf, &lbuf[0], 4);
102 	nbuf[4] = 0;
103 	nauto = atoi(nbuf);
104 
105 	strncpy(nbuf, &lbuf[4], 4);
106 	nbuf[4] = 0;
107 	nprobe = atoi(nbuf);
108 
109 	strncpy(nbuf, &lbuf[8], 4);
110 	nbuf[4] = 0;
111 	nsweepparam = atoi(nbuf);
112 
113 	if(fgets(lbuf, sizeof(lbuf), fp) == NULL) /* date, time etc. */
114 		return NULL;
115 	lineno++;
116 	/* number of sweeps, possibly with cruft at the start of the line */
117 	if(fgets(lbuf, sizeof(lbuf), fp) == NULL)
118 		return NULL;
119 	cp = strchr(lbuf, ' ');
120 	if(!cp)
121 		cp = lbuf;
122 	ntables = atoi(cp);
123 	if(ntables == 0)
124 		ntables = 1;
125 	lineno++;
126 
127 	maxlines = nauto + nprobe + nsweepparam + 100;
128 	/* lines making up a fixed-field structure with variable-types and
129 	 * variable names.
130 	 * variable names can get split across lines! so we remove newlines,
131 	 * paste all of the lines together, and then deal with the
132 	 * whole header at once.
133 	 * A variable name of "$&%#" indicates the end!
134 	 */
135 	line = g_new0(char, linesize);
136 	lineused = 0;
137 	do {
138 		int len;
139 		if(fgets(lbuf, sizeof(lbuf), fp) == NULL)
140 			return NULL;
141 		lineno++;
142 		if((cp = strchr(lbuf, '\n')) != NULL)
143 			*cp = 0;
144 		len = strlen(lbuf);
145 		if(lineused + len + 1 > linesize) {
146 			linesize *= 2;
147 			if(linesize > 1050000) {
148 				ss_msg(ERR, "rdhdr_ascii", "internal error - failed to find end of header\n; linesize=%d line=\n%.200s\n", linesize, line);
149 				exit(4);
150 			}
151 
152 			line = g_realloc(line, linesize);
153 		}
154 		strcat(line, lbuf);
155 		lineused += len;
156 
157 	} while(!strstr(line, "$&%#") && lineno < maxlines);
158 	if(lineno == maxlines) {
159 		ss_msg(DBG, "rdhdr_hsascii", "%s:%d: end of hspice header not found", name,lineno);
160 		goto fail;
161 	}
162 
163 	sf = hs_process_header(nauto, nprobe, nsweepparam, line, name);
164 	if(!sf)
165 		goto fail;
166 	sf->fp = fp;
167 	sf->readrow = sf_readrow_hsascii;
168 	sf->linebuf = line;
169 	sf->linep = NULL;
170 	sf->lbufsize = linesize;
171 	sf->ntables = ntables;
172 	sf->read_tables = 0;
173 	sf->read_rows = 0;
174 	sf->read_sweepparam = 0;
175 	sf->readsweep = sf_readsweep_hsascii;
176 	sf->lineno = lineno;
177 
178 	ss_msg(DBG, "rdhdr_hsascii", "ntables=%d; expect %d columns",
179 	       sf->ntables, sf->ncols);
180 
181 	return sf;
182 
183  fail:
184 	if(line)
185 		g_free(line);
186 	return NULL;
187 
188 }
189 
190 /* Read spice-type file header - hspice binary */
191 SpiceStream *
sf_rdhdr_hsbin(char * name,FILE * fp)192 sf_rdhdr_hsbin(char *name, FILE *fp)
193 {
194 
195 	SpiceStream *sf = NULL;
196 	char *ahdr = NULL;
197 	int ahdrsize = 0;
198 	int ahdrend = 0;
199 	int n;
200 	int datasize;
201 	int nauto, nprobe, nsweepparam, ntables;
202 	char nbuf[16];
203 	struct hsblock_header hh;
204 
205 	do {
206 		n = sf_readblock_hsbin(fp, &ahdr, &ahdrsize, ahdrend);
207 		if(n <= 0)
208 			goto fail;
209 		ahdrend += n;
210 		ahdr[ahdrend] = '\0';
211 
212 	} while(!strstr(ahdr, "$&%#"));
213 
214 	/* ahdr is an ascii header that describes the variables in
215 	 * much the same way that the first lines of the ascii format do,
216 	 * except that there are no newlines
217 	 */
218 
219 	if(strncmp(&ahdr[16], "9007", 4) != 0 	/* version of post format */
220 	   && strncmp(&ahdr[16], "9601", 4) != 0)
221 		goto fail;
222 	strncpy(nbuf, &ahdr[0], 4);
223 	nbuf[4] = 0;
224 	nauto = atoi(nbuf);	/* number of automaticly-included variables,
225 				   first one is independent variable */
226 	strncpy(nbuf, &ahdr[4], 4);
227 	nbuf[4] = 0;
228 	nprobe = atoi(nbuf);	/* number of user-requested columns */
229 
230 	strncpy(nbuf, &ahdr[8], 4);
231 	nbuf[4] = 0;
232 	nsweepparam = atoi(nbuf);	/* number of sweep parameters */
233 
234 	ntables = atoi(&ahdr[176]);
235 	if(ntables == 0)
236 		ntables = 1;
237 
238 	sf = hs_process_header(nauto, nprobe, nsweepparam, &ahdr[256], name);
239 	if(!sf)
240 		goto fail;
241 
242 	if(fread(&hh, sizeof(hh), 1, fp) != 1) {
243 		ss_msg(DBG, "sf_rdhdr_hsbin", "EOF reading block header");
244 		goto fail;
245 	}
246 	if(hh.h1 == 0x04000000 && hh.h3 == 0x04000000) {
247 		/* detected endian swap */
248 		sf->flags |= SSF_ESWAP;
249 		swap_gint32((gint32*)&hh, sizeof(hh)/sizeof(gint32));
250 	}
251 	if(hh.h1 != 4 || hh.h3 != 4) {
252 		ss_msg(DBG, "sf_rdhdr_hsbin", "unexepected values in data block header");
253 		goto fail;
254 	}
255 
256 	datasize = hh.block_nbytes;
257 	sf->expected_vals = datasize / sizeof(float);
258 	sf->read_vals = 0;
259 
260 	ss_msg(DBG, "sf_rdhdr_hsbin", "datasize=%d expect %d columns, %d values;\n  reading first data block at 0x%lx", datasize, sf->ncols, sf->expected_vals, (long)ftello64(fp));
261 
262 
263 	sf->fp = fp;
264 	sf->readrow = sf_readrow_hsbin;
265 	sf->readsweep = sf_readsweep_hsbin;
266 
267 	sf->ntables = ntables;
268 	sf->read_tables = 0;
269 	sf->read_rows = 0;
270 	sf->read_sweepparam = 0;
271 
272 	return sf;
273  fail:
274 	if(ahdr)
275 		g_free(ahdr);
276 	if(sf) {
277 		if(sf->dvar)
278 			g_free(sf->dvar);
279 		g_free(sf);
280 	}
281 
282 	return NULL;
283 }
284 
285 /* common code for reading ascii or binary hspice headers.
286  * Given a string of ascii header information, set up the
287  * SpiceStream structure appropriately.
288  * Returns NULL on failure.
289  */
290 static SpiceStream *
hs_process_header(int nauto,int nprobe,int nsweepparam,char * line,char * name)291 hs_process_header(int nauto, int nprobe, int nsweepparam, char *line, char *name)
292 {
293 	char *cp;
294 	char *signam;
295 	SpiceStream *sf;
296 	int i;
297 	int hstype;
298 
299 /* type of independent variable */
300 	cp = strtok(line, " \t\n");
301 	if(!cp) {
302 		ss_msg(DBG, "hs_process_header", "%s: initial vartype not found on header line.", name);
303 		return NULL;
304 	}
305 	sf = ss_new(NULL, name, nauto-1 + nprobe, nsweepparam);
306 	hstype = atoi(cp);
307 	switch(hstype) {
308 	case 1:
309 		sf->ivar->type = TIME;
310 		break;
311 	case 2:
312 		sf->ivar->type = FREQUENCY;
313 		break;
314 	case 3:
315 		sf->ivar->type = VOLTAGE;
316 		break;
317 	default:
318 		sf->ivar->type = UNKNOWN;
319 		break;
320 	}
321 	sf->ivar->col = 0;
322 	sf->ivar->ncols = 1;
323 	sf->ncols = 1;
324 
325 /* dependent variable types */
326 	for(i = 0; i < sf->ndv; i++) {
327 		cp = strtok(NULL, " \t\n");
328 		if(!cp) {
329 			ss_msg(DBG, "hs_process_header", "%s: not enough vartypes on header line", name);
330 			return NULL;
331 		}
332 		if(!isdigit(cp[0])) {
333 			ss_msg(DBG, "hs_process_header", "%s: bad vartype %d [%s] on header line", name, i, cp);
334 			return NULL;
335 		}
336 		hstype = atoi(cp);
337 		switch(hstype) {
338 		case 1:
339 		case 2:
340 			sf->dvar[i].type = VOLTAGE;
341 			break;
342 		case 8:
343 		case 15:
344 		case 22:
345 			sf->dvar[i].type = CURRENT;
346 			break;
347 		default:
348 			sf->dvar[i].type = UNKNOWN;
349 			break;
350 		}
351 
352 		/* how many columns comprise this variable? */
353 		sf->dvar[i].col = sf->ncols;
354 		if(i < nauto-1 && sf->ivar->type == FREQUENCY) {
355 			sf->dvar[i].ncols = 2;
356 		} else {
357 			sf->dvar[i].ncols = 1;
358 		}
359 		sf->ncols += sf->dvar[i].ncols;
360 	}
361 
362 /* independent variable name */
363 	signam = strtok(NULL, " \t\n");
364 	if(!signam) {
365 		ss_msg(DBG, "hs_process_header", "%s: no IV name found on header line", name);
366 		goto fail;
367 	}
368 	sf->ivar->name = g_strdup(signam);
369 
370  /* dependent variable names */
371 	for(i = 0; i < sf->ndv; i++) {
372 		if((signam = strtok(NULL, " \t\n")) == NULL) {
373 			ss_msg(DBG, "hs_process_header", "%s: not enough DV names found on header line", name);
374 			goto fail;
375 		}
376 		sf->dvar[i].name = g_strdup(signam);
377 	}
378 /* sweep parameter names */
379 	for(i = 0; i < sf->nsweepparam; i++) {
380 		if((signam = strtok(NULL, " \t\n")) == NULL) {
381 			ss_msg(DBG, "hs_process_header", "%s: not enough sweep parameter names found on header line", name);
382 			goto fail;
383 		}
384 		sf->spar[i].name = g_strdup(signam);
385 	}
386 
387 	return sf;
388 
389  fail:
390 	ss_delete(sf);
391 	return NULL;
392 }
393 
394 /*
395  * Read a "block" from an HSPICE binary file.
396  * Returns number of bytes read, 0 for EOF, negative for error.
397  * The body of the block is copied into the buffer pointed to by the
398  * buffer-pointer pointed to by bufp, at offset offset.
399  * The buffer is expanded with g_realloc if necessary.
400  * If bufp is NULL, a new buffer  is allocated.   The buffer
401  * size is maintained in the int pointed to by bufsize.
402  *
403  */
404 static int
sf_readblock_hsbin(FILE * fp,char ** bufp,int * bufsize,int offset)405 sf_readblock_hsbin(FILE *fp, char **bufp, int *bufsize, int offset)
406 {
407 	struct hsblock_header hh;
408 	gint32 trailer;
409 	int eswap = 0;
410 
411 	if(fread(&hh, sizeof(hh), 1, fp) != 1) {
412 		ss_msg(DBG, "sf_readblock_hsbin", "EOF reading block header");
413 		return 0;
414 	}
415 	if(hh.h1 == 0x04000000 && hh.h3 == 0x04000000) {
416 		/* detected endian swap */
417 		eswap = 1;
418 		swap_gint32((gint32*)&hh, sizeof(hh)/sizeof(gint32));
419 	}
420 	if(hh.h1 != 0x00000004 || hh.h3 != 0x00000004) {
421 		ss_msg(DBG, "sf_readblock_hsbin", "unexepected values in block header");
422 		return -1;
423 	}
424 	if(bufp == NULL) {   /* new buffer: exact fit */
425 		*bufsize = hh.block_nbytes;
426 		*bufp = g_new(char, *bufsize);
427 	}
428 
429 	/* need to expand: double buffer size or make room for two blocks
430 	 * this size, whichever is larger.  Better to realloc more now and
431 	 * cut down on the number of future reallocs.
432 	 */
433 	if(*bufsize < offset + hh.block_nbytes) {
434 		if(2 * *bufsize > (*bufsize + 2 * hh.block_nbytes))
435 			*bufsize *= 2;
436 		else
437 			*bufsize += 2 * hh.block_nbytes;
438 		*bufp = g_realloc(*bufp, *bufsize);
439 	}
440 	if(fread(*bufp + offset, sizeof(char), hh.block_nbytes, fp) != hh.block_nbytes) {
441 		ss_msg(DBG, "sf_readblock_hsbin", "EOF reading block body");
442 		return 0;
443 	}
444 	if(fread(&trailer, sizeof(gint32), 1, fp) != 1) {
445 		ss_msg(DBG, "sf_readblock_hsbin", "EOF reading block trailer");
446 		return 0;
447 	}
448 	if(eswap) {
449 		swap_gint32(&trailer, 1);
450 	}
451 	if(trailer != hh.block_nbytes) {
452 		ss_msg(DBG, "sf_readblock_hsbin", "block trailer mismatch");
453 		return -2;
454 	}
455 	return hh.block_nbytes;
456 }
457 
458 /*
459  * helper routine: get next floating-point value from data part of binary
460  * hspice file.   Handles the block-structure of hspice files; all blocks
461  * encountered are assumed to be data blocks.  We don't use readblock_hsbin because
462  * some versions of hspice write very large blocks, which would require a
463  * very large buffer.
464  *
465  * Returns 0 on EOF, 1 on success, negative on error.
466  */
467 static int
sf_getval_hsbin(SpiceStream * sf,double * dval)468 sf_getval_hsbin(SpiceStream *sf, double *dval)
469 {
470 	off64_t pos;
471 	float val;
472 	struct hsblock_header hh;
473 	gint32 trailer;
474 
475 	if(sf->read_vals >= sf->expected_vals) {
476 		pos = ftello64(sf->fp);
477 		if(fread(&trailer, sizeof(gint32), 1, sf->fp) != 1) {
478 			ss_msg(DBG, "sf_getval_hsbin", "EOF reading block trailer at offset 0x%lx", (long) pos);
479 			return 0;
480 		}
481 		if(sf->flags & SSF_ESWAP) {
482 			swap_gint32(&trailer, 1);
483 		}
484 		if(trailer != sf->expected_vals * sizeof(float)) {
485 			ss_msg(DBG, "sf_getval_hsbin", "block trailer mismatch at offset 0x%lx", (long) pos);
486 			return -2;
487 		}
488 
489 		pos = ftello64(sf->fp);
490 		if(fread(&hh, sizeof(hh), 1, sf->fp) != 1) {
491 			ss_msg(DBG, "sf_getval_hsbin", "EOF reading block header at offset 0x%lx", (long) pos);
492 			return 0;
493 		}
494 		if(hh.h1 == 0x04000000 && hh.h3 == 0x04000000) {
495 			/* detected endian swap */
496 			sf->flags |= SSF_ESWAP;
497 			swap_gint32((gint32*)&hh, sizeof(hh)/sizeof(gint32));
498 		} else {
499 			sf->flags &= ~SSF_ESWAP;
500 		}
501 		if(hh.h1 != 0x00000004 || hh.h3 != 0x00000004) {
502 			ss_msg(ERR, "sf_getval_hsbin", "unexepected values in block header at offset 0x%lx", pos);
503 			return -1;
504 		}
505 		sf->expected_vals = hh.block_nbytes / sizeof(float);
506 		sf->read_vals = 0;
507 	}
508 	if(fread(&val, sizeof(float), 1, sf->fp) != 1) {
509 		pos = ftello64(sf->fp);
510 		ss_msg(ERR, "sf_getval_hsbin", "unexepected EOF in data at offset 0x%lx", (long) pos);
511 		return 0;
512 	}
513 	sf->read_vals++;
514 
515 	if(sf->flags & SSF_ESWAP) {
516 		swap_gint32((gint32 *)&val, 1);
517 	}
518 	*dval = val;
519 	return 1;
520 }
521 
522 /*
523  * helper routine: get next value from ascii hspice file.
524  * the file is line-oriented, with fixed-width fields on each line.
525  * Lines may look like either of these two examples:
526 0.66687E-090.21426E+010.00000E+000.00000E+000.25000E+010.71063E-090.17877E+01
527  .00000E+00 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30092E-05
528  * There may be whitespace at the end of the line before the newline.
529  *
530  * Returns 0 on EOF, 1 on success.
531  */
532 static int
sf_getval_hsascii(SpiceStream * sf,double * val)533 sf_getval_hsascii(SpiceStream *sf, double *val)
534 {
535 	char vbuf[16];
536 	char *vp;
537 	char *cp;
538 	int l;
539 
540 	if(!sf->linep || (*sf->linep==0) || *sf->linep == '\n') {
541 		if(fgets(sf->linebuf, sf->lbufsize, sf->fp) == NULL)
542 			return 0;
543 
544 		l = strlen(sf->linebuf);
545 		if(l) {  /* delete whitespace at end of line */
546 			cp = sf->linebuf + l - 1;
547 			while(cp > sf->linebuf && *cp && isspace(*cp))
548 				*cp-- = '\0';
549 		}
550 		sf->linep = sf->linebuf;
551 		sf->line_length = strlen(sf->linep);
552 		/* fprintf(stderr, "#line: \"%s\"\n", sf->linebuf); */
553 	}
554 	if(sf->linep > sf->linebuf + sf->line_length) {
555 		ss_msg(WARN, "sf_getval_hsascii",
556 		       "%s: internal error or bad line in file", sf->filename);
557 		return 0;
558 	}
559 
560 	strncpy(vbuf, sf->linep, 11);
561 	sf->linep += 11;
562 	vbuf[11] = 0;
563 	if(strlen(vbuf) != 11) {
564 		/* incomplete float value - probably truncated or
565 		   partialy-written file */
566 		return 0;
567 	}
568 	vp = vbuf;
569 	while(isspace(*vp)) /* atof doesn't like spaces */
570 		vp++;
571 	*val = atof(vp);
572 	/* fprintf(stderr, "#vp=\"%s\" val=%f\n", vp, *val); */
573 	return 1;
574 }
575 
576 /* Read row of values from ascii hspice-format file.
577  * Returns:
578  *	1 on success.  also fills in *ivar scalar and *dvars vector
579  *	0 on EOF
580  *	-1 on error  (may change some ivar/dvar values)
581  *	-2 on end of table, with more tables supposedly still to be read.
582  */
583 
584 static int
sf_readrow_hsascii(SpiceStream * sf,double * ivar,double * dvars)585 sf_readrow_hsascii(SpiceStream *sf, double *ivar, double *dvars)
586 {
587 	int i;
588 
589 	if(!sf->read_sweepparam) { /* first row of table */
590 		if(sf_readsweep_hsascii(sf, NULL) <= 0) /* discard sweep parameters, if any */
591 			return -1;
592 	}
593 	if(sf_getval_hsascii(sf, ivar) == 0)
594 		return 0;
595 	if(*ivar >= 1.0e29) { /* "infinity" at end of data table */
596 		sf->read_tables++;
597 		if(sf->read_tables == sf->ntables)
598 			return 0; /* EOF */
599 		else
600 			sf->read_sweepparam = 0;
601 			sf->read_rows = 0;
602 			return -2;  /* end of table, more tables follow */
603 	}
604 
605 	sf->read_rows++;
606 	for(i = 0; i < sf->ncols-1; i++) {
607 		if(sf_getval_hsascii(sf, &dvars[i]) == 0) {
608 			ss_msg(WARN, "sf_readrow_hsascii", "%s: EOF or error reading data field %d in row %d of table %d; file is incomplete.", sf->filename, i, sf->read_rows, sf->read_tables);
609 			return 0;
610 		}
611 	}
612 	return 1;
613 }
614 
615 /* Read row of values from binary hspice-format file.
616  * Returns:
617  *	1 on success.  also fills in *ivar scalar and *dvars vector
618  *	0 on EOF
619  *	-1 on error  (may change some ivar/dvar values)
620  */
621 static int
sf_readrow_hsbin(SpiceStream * sf,double * ivar,double * dvars)622 sf_readrow_hsbin(SpiceStream *sf, double *ivar, double *dvars)
623 {
624 	int i;
625 	int rc;
626 
627 	if(!sf->read_sweepparam) { /* first row of table */
628 		if(sf_readsweep_hsbin(sf, NULL) <= 0) /* discard sweep parameters, if any */
629 			return -1;
630 	}
631 
632 	rc = sf_getval_hsbin(sf, ivar);
633 	if(rc == 0)		/* file EOF */
634 		return 0;
635 	if(rc < 0)
636 		return -1;
637 	if(*ivar >= 1.0e29) { /* "infinity" at end of data table */
638 		sf->read_tables++;
639 		if(sf->read_tables == sf->ntables)
640 			return 0; /* end of data, should also be EOF but we don't check */
641 		else {
642 			sf->read_sweepparam = 0;
643 			sf->read_rows = 0;
644 			return -2;  /* end of table, more tables follow */
645 		}
646 	}
647 	sf->read_rows++;
648 	for(i = 0; i < sf->ncols-1; i++) {
649 		if(sf_getval_hsbin(sf, &dvars[i]) != 1) {
650 			ss_msg(WARN, "sf_readrow_hsbin", "%s: EOF or error reading data field %d in row %d of table %d; file is incomplete.", sf->filename, i, sf->read_rows, sf->read_tables);
651 			return 0;
652 		}
653 	}
654 	return 1;
655 }
656 
657 /*
658  * Read the sweep parameters from an HSPICE ascii or binary file
659  * This routine must be called before the first sf_readrow_hsascii call in each data
660  * table.  If it has not been called before the first readrow call, it will be called
661  * with a NULL svar pointer to read and discard the sweep data.
662  *
663  * returns:
664  *	1 on success
665  * 	-1 on error
666  */
667 static int
sf_readsweep_hsascii(SpiceStream * sf,double * svar)668 sf_readsweep_hsascii(SpiceStream *sf, double *svar)
669 {
670 	int i;
671 	double val;
672 	for(i = 0; i < sf->nsweepparam; i++) {
673 		if(sf_getval_hsascii(sf, &val) == 0) {
674 			ss_msg(ERR, "sf_readsweep_hsascii", "unexpected EOF reading sweep parameters\n");
675 			return -1;
676 		}
677 		if(svar)
678 			svar[i] = val;
679 	}
680 
681 	sf->read_sweepparam = 1;
682 	return 1;
683 }
684 
685 static int
sf_readsweep_hsbin(SpiceStream * sf,double * svar)686 sf_readsweep_hsbin(SpiceStream *sf, double *svar)
687 {
688 	int i;
689 	double val;
690 	for(i = 0; i < sf->nsweepparam; i++) {
691 		if(sf_getval_hsbin(sf, &val) != 1) {
692 			ss_msg(ERR, "sf_readsweep_hsbin", "EOF or error reading sweep parameter\n");
693 			return -1;
694 		}
695 		if(svar)
696 			svar[i] = val;
697 	}
698 
699 	sf->read_sweepparam = 1;
700 	return 1;
701 }
702 
703 
704 /*
705  * Estimate how many rows are in the file associated with sf.
706  * We base our estimate on the size of the file.
707  * This can be useful to aid in memory-use planning by programs planning to
708  * read the entire file.
709  *
710  * If the file descriptor is not associated with an ordinary file, we return 0
711  * to indicate that the length cannot be estimated.
712  * If an error occurs, -1 is returned.
713  */
714 static long
sf_guessrows_hsbin(SpiceStream * sf)715 sf_guessrows_hsbin(SpiceStream *sf)
716 {
717 	int rc;
718 	struct stat st;
719 
720 	rc = fstat(fileno(sf->fp), &st);
721 	if(rc < 0)
722 		return -1;
723 	if((st.st_mode & S_IFMT) != S_IFREG)
724 		return 0;
725 
726 	return st.st_size / (sizeof(float)  * sf->ncols);
727 }
728 
729 
730 static void
swap_gint32(gint32 * pi,size_t n)731 swap_gint32(gint32 *pi, size_t n)
732 {
733 	union gint32bytes *p = (union gint32bytes *)pi;
734 	size_t i;
735 	gchar temp;
736 	for(i = 0; i < n; i++) {
737 		temp = p[i].b[3] ;
738 		p[i].b[3] = p[i].b[0];
739 		p[i].b[0] = temp;
740 
741 		temp = p[i].b[2] ;
742 		p[i].b[2] = p[i].b[1];
743 		p[i].b[1] = temp;
744 	}
745 }
746