Merge Dan White's contributed additions to spicefile/sp2sp:
[gwave-svn.git] / spicefile / ss_hspice.c
blobe568b937aa8e278d04c384253ba70de4a2d82e28
1 /*
2 * ss_hspice.c: HSPICE routines for SpiceStream
4 * Copyright (C) 1998-2009 Stephen G. Tell
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.
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.
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.
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>
31 #include <config.h>
32 #include <glib.h>
33 #include "spicestream.h"
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);
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);
47 struct hsblock_header { /* structure of binary tr0 block headers */
48 gint32 h1;
49 gint32 h2;
50 gint32 h3;
51 gint32 block_nbytes;
54 union gint32bytes {
55 gint32 i;
56 gchar b[4];
59 static void swap_gint32(gint32 *pi, size_t n);
61 /* Read spice-type file header - autosense hspice binary or ascii */
62 SpiceStream *
63 sf_rdhdr_hspice(char *name, FILE *fp)
65 int c;
66 if((c = getc(fp)) == EOF)
67 return NULL;
68 ungetc(c, fp);
70 if((c & 0xff) < ' ')
71 return sf_rdhdr_hsbin(name, fp);
72 else
73 return sf_rdhdr_hsascii(name, fp);
75 return NULL;
78 /* Read spice-type file header - hspice ascii */
79 SpiceStream *
80 sf_rdhdr_hsascii(char *name, FILE *fp)
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;
93 if(fgets(lbuf, sizeof(lbuf), fp) == NULL)
94 return NULL;
95 lineno++;
97 /* version of post format */
98 if(strncmp(&lbuf[16], "9007", 4) != 0
99 && strncmp(&lbuf[16], "9601", 4) != 0
100 && strncmp(&lbuf[16], "2001", 4) != 0 )
101 return NULL;
102 strncpy(nbuf, &lbuf[0], 4);
103 nbuf[4] = 0;
104 nauto = atoi(nbuf);
106 strncpy(nbuf, &lbuf[4], 4);
107 nbuf[4] = 0;
108 nprobe = atoi(nbuf);
110 strncpy(nbuf, &lbuf[8], 4);
111 nbuf[4] = 0;
112 nsweepparam = atoi(nbuf);
114 if(fgets(lbuf, sizeof(lbuf), fp) == NULL) /* date, time etc. */
115 return NULL;
116 lineno++;
117 /* number of sweeps, possibly with cruft at the start of the line */
118 if(fgets(lbuf, sizeof(lbuf), fp) == NULL)
119 return NULL;
120 cp = strchr(lbuf, ' ');
121 if(!cp)
122 cp = lbuf;
123 ntables = atoi(cp);
124 if(ntables == 0)
125 ntables = 1;
126 lineno++;
128 maxlines = nauto + nprobe + nsweepparam + 100;
129 /* lines making up a fixed-field structure with variable-types and
130 * variable names.
131 * variable names can get split across lines! so we remove newlines,
132 * paste all of the lines together, and then deal with the
133 * whole header at once.
134 * A variable name of "$&%#" indicates the end!
136 line = g_new0(char, linesize);
137 lineused = 0;
138 do {
139 int len;
140 if(fgets(lbuf, sizeof(lbuf), fp) == NULL)
141 return NULL;
142 lineno++;
143 if((cp = strchr(lbuf, '\n')) != NULL)
144 *cp = 0;
145 len = strlen(lbuf);
146 if(lineused + len + 1 > linesize) {
147 linesize *= 2;
148 if(linesize > 1050000) {
149 ss_msg(ERR, "rdhdr_ascii", "internal error - failed to find end of header\n; linesize=%d line=\n%.200s\n", linesize, line);
150 exit(4);
153 line = g_realloc(line, linesize);
155 strcat(line, lbuf);
156 lineused += len;
158 } while(!strstr(line, "$&%#") && lineno < maxlines);
159 if(lineno == maxlines) {
160 ss_msg(DBG, "rdhdr_hsascii", "%s:%d: end of hspice header not found", name,lineno);
161 goto fail;
164 sf = hs_process_header(nauto, nprobe, nsweepparam, line, name);
165 if(!sf)
166 goto fail;
167 sf->fp = fp;
168 sf->readrow = sf_readrow_hsascii;
169 sf->linebuf = line;
170 sf->linep = NULL;
171 sf->lbufsize = linesize;
172 sf->ntables = ntables;
173 sf->read_tables = 0;
174 sf->read_rows = 0;
175 sf->read_sweepparam = 0;
176 sf->readsweep = sf_readsweep_hsascii;
177 sf->lineno = lineno;
179 ss_msg(DBG, "rdhdr_hsascii", "ntables=%d; expect %d columns",
180 sf->ntables, sf->ncols);
182 return sf;
184 fail:
185 if(line)
186 g_free(line);
187 return NULL;
191 /* Read spice-type file header - hspice binary */
192 SpiceStream *
193 sf_rdhdr_hsbin(char *name, FILE *fp)
196 SpiceStream *sf = NULL;
197 char *ahdr = NULL;
198 int ahdrsize = 0;
199 int ahdrend = 0;
200 int n;
201 int datasize;
202 int nauto, nprobe, nsweepparam, ntables;
203 char nbuf[16];
204 int ntable_offset;
205 struct hsblock_header hh;
207 do {
208 n = sf_readblock_hsbin(fp, &ahdr, &ahdrsize, ahdrend);
209 if(n <= 0)
210 goto fail;
211 ahdrend += n;
212 ahdr[ahdrend] = '\0';
214 } while(!strstr(ahdr, "$&%#"));
216 /* ahdr is an ascii header that describes the variables in
217 * much the same way that the first lines of the ascii format do,
218 * except that there are no newlines
221 if(strncmp(&ahdr[16], "9007", 4) != 0 /* version of post format */
222 && strncmp(&ahdr[16], "9601", 4) != 0
223 && strncmp(&ahdr[20], "2001", 4) != 0 )
224 goto fail;
226 if(strncmp(&ahdr[20], "2001", 4) == 0)
227 ntable_offset = 187;
228 else
229 ntable_offset = 176;
231 strncpy(nbuf, &ahdr[0], 4);
232 nbuf[4] = 0;
233 nauto = atoi(nbuf); /* number of automaticly-included variables,
234 first one is independent variable */
235 strncpy(nbuf, &ahdr[4], 4);
236 nbuf[4] = 0;
237 nprobe = atoi(nbuf); /* number of user-requested columns */
239 strncpy(nbuf, &ahdr[8], 4);
240 nbuf[4] = 0;
241 nsweepparam = atoi(nbuf); /* number of sweep parameters */
243 ntables = atoi(&ahdr[ntable_offset]);
244 if(ntables == 0)
245 ntables = 1;
247 sf = hs_process_header(nauto, nprobe, nsweepparam, &ahdr[256], name);
248 if(!sf)
249 goto fail;
251 if(fread(&hh, sizeof(hh), 1, fp) != 1) {
252 ss_msg(DBG, "sf_rdhdr_hsbin", "EOF reading block header");
253 goto fail;
255 if(hh.h1 == 0x04000000 && hh.h3 == 0x04000000) {
256 /* detected endian swap */
257 sf->flags |= SSF_ESWAP;
258 swap_gint32((gint32*)&hh, sizeof(hh)/sizeof(gint32));
260 if(hh.h1 != 4 || hh.h3 != 4) {
261 ss_msg(DBG, "sf_rdhdr_hsbin", "unexepected values in data block header");
262 goto fail;
265 datasize = hh.block_nbytes;
266 sf->expected_vals = datasize / sizeof(float);
267 sf->read_vals = 0;
269 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));
272 sf->fp = fp;
273 sf->readrow = sf_readrow_hsbin;
274 sf->readsweep = sf_readsweep_hsbin;
276 sf->ntables = ntables;
277 sf->read_tables = 0;
278 sf->read_rows = 0;
279 sf->read_sweepparam = 0;
281 return sf;
282 fail:
283 if(ahdr)
284 g_free(ahdr);
285 if(sf) {
286 if(sf->dvarp)
287 g_ptr_array_free(sf->dvarp, 1);
288 g_free(sf);
291 return NULL;
294 /* common code for reading ascii or binary hspice headers.
295 * Given a string of ascii header information, set up the
296 * SpiceStream structure appropriately.
297 * Returns NULL on failure.
299 static SpiceStream *
300 hs_process_header(int nauto, int nprobe, int nsweepparam, char *line, char *name)
302 char *cp;
303 char *signam;
304 SpiceStream *sf;
305 int i;
306 int hstype;
308 /* type of independent variable */
309 cp = strtok(line, " \t\n");
310 if(!cp) {
311 ss_msg(DBG, "hs_process_header", "%s: initial vartype not found on header line.", name);
312 return NULL;
314 sf = ss_new(NULL, name, nauto-1 + nprobe, nsweepparam);
315 hstype = atoi(cp);
316 switch(hstype) {
317 case 1:
318 sf->ivar->type = TIME;
319 break;
320 case 2:
321 sf->ivar->type = FREQUENCY;
322 break;
323 case 3:
324 sf->ivar->type = VOLTAGE;
325 break;
326 default:
327 sf->ivar->type = UNKNOWN;
328 break;
330 sf->ivar->col = 0;
331 sf->ivar->ncols = 1;
332 sf->ncols = 1;
334 /* dependent variable types */
335 for(i = 0; i < sf->ndv; i++) {
336 int ncols;
337 VarType vtype;
338 SpiceVar *dvar;
340 cp = strtok(NULL, " \t\n");
341 if(!cp) {
342 ss_msg(DBG, "hs_process_header", "%s: not enough vartypes on header line", name);
343 return NULL;
345 if(!isdigit(cp[0])) {
346 ss_msg(DBG, "hs_process_header", "%s: bad vartype %d [%s] on header line", name, i, cp);
347 return NULL;
349 hstype = atoi(cp);
350 switch(hstype) {
351 case 1:
352 case 2:
353 vtype = VOLTAGE;
354 break;
355 case 8:
356 case 15:
357 case 22:
358 vtype = CURRENT;
359 break;
360 default:
361 vtype = UNKNOWN;
362 break;
365 if(i < nauto-1 && sf->ivar->type == FREQUENCY) {
366 ncols = 2;
367 } else {
368 ncols = 1;
370 dvar = ss_spicevar_new(NULL, vtype, sf->ncols, ncols);
371 g_ptr_array_add(sf->dvarp, dvar);
372 sf->ncols += ncols;
375 /* independent variable name */
376 signam = strtok(NULL, " \t\n");
377 if(!signam) {
378 ss_msg(DBG, "hs_process_header", "%s: no IV name found on header line", name);
379 goto fail;
381 sf->ivar->name = g_strdup(signam);
383 /* dependent variable names */
384 for(i = 0; i < sf->ndv; i++) {
385 SpiceVar *dvar;
386 if((signam = strtok(NULL, " \t\n")) == NULL) {
387 ss_msg(DBG, "hs_process_header", "%s: not enough DV names found on header line", name);
388 goto fail;
390 dvar = ss_dvar(sf, i);
391 dvar->name = g_strdup(signam);
393 /* sweep parameter names */
394 for(i = 0; i < sf->nsweepparam; i++) {
395 if((signam = strtok(NULL, " \t\n")) == NULL) {
396 ss_msg(DBG, "hs_process_header", "%s: not enough sweep parameter names found on header line", name);
397 goto fail;
399 sf->spar[i].name = g_strdup(signam);
402 return sf;
404 fail:
405 ss_delete(sf);
406 return NULL;
410 * Read a "block" from an HSPICE binary file.
411 * Returns number of bytes read, 0 for EOF, negative for error.
412 * The body of the block is copied into the buffer pointed to by the
413 * buffer-pointer pointed to by bufp, at offset offset.
414 * The buffer is expanded with g_realloc if necessary.
415 * If bufp is NULL, a new buffer is allocated. The buffer
416 * size is maintained in the int pointed to by bufsize.
419 static int
420 sf_readblock_hsbin(FILE *fp, char **bufp, int *bufsize, int offset)
422 struct hsblock_header hh;
423 gint32 trailer;
424 int eswap = 0;
426 if(fread(&hh, sizeof(hh), 1, fp) != 1) {
427 ss_msg(DBG, "sf_readblock_hsbin", "EOF reading block header");
428 return 0;
430 if(hh.h1 == 0x04000000 && hh.h3 == 0x04000000) {
431 /* detected endian swap */
432 eswap = 1;
433 swap_gint32((gint32*)&hh, sizeof(hh)/sizeof(gint32));
435 if(hh.h1 != 0x00000004 || hh.h3 != 0x00000004) {
436 ss_msg(DBG, "sf_readblock_hsbin", "unexepected values in block header");
437 return -1;
439 if(bufp == NULL) { /* new buffer: exact fit */
440 *bufsize = hh.block_nbytes;
441 *bufp = g_new(char, *bufsize);
444 /* need to expand: double buffer size or make room for two blocks
445 * this size, whichever is larger. Better to realloc more now and
446 * cut down on the number of future reallocs.
448 if(*bufsize < offset + hh.block_nbytes) {
449 if(2 * *bufsize > (*bufsize + 2 * hh.block_nbytes))
450 *bufsize *= 2;
451 else
452 *bufsize += 2 * hh.block_nbytes;
453 *bufp = g_realloc(*bufp, *bufsize);
455 if(fread(*bufp + offset, sizeof(char), hh.block_nbytes, fp) != hh.block_nbytes) {
456 ss_msg(DBG, "sf_readblock_hsbin", "EOF reading block body");
457 return 0;
459 if(fread(&trailer, sizeof(gint32), 1, fp) != 1) {
460 ss_msg(DBG, "sf_readblock_hsbin", "EOF reading block trailer");
461 return 0;
463 if(eswap) {
464 swap_gint32(&trailer, 1);
466 if(trailer != hh.block_nbytes) {
467 ss_msg(DBG, "sf_readblock_hsbin", "block trailer mismatch");
468 return -2;
470 return hh.block_nbytes;
474 * helper routine: get next floating-point value from data part of binary
475 * hspice file. Handles the block-structure of hspice files; all blocks
476 * encountered are assumed to be data blocks. We don't use readblock_hsbin because
477 * some versions of hspice write very large blocks, which would require a
478 * very large buffer.
480 * Returns 0 on EOF, 1 on success, negative on error.
482 static int
483 sf_getval_hsbin(SpiceStream *sf, double *dval)
485 off64_t pos;
486 float val;
487 struct hsblock_header hh;
488 gint32 trailer;
490 if(sf->read_vals >= sf->expected_vals) {
491 pos = ftello64(sf->fp);
492 if(fread(&trailer, sizeof(gint32), 1, sf->fp) != 1) {
493 ss_msg(DBG, "sf_getval_hsbin", "EOF reading block trailer at offset 0x%lx", (long) pos);
494 return 0;
496 if(sf->flags & SSF_ESWAP) {
497 swap_gint32(&trailer, 1);
499 if(trailer != sf->expected_vals * sizeof(float)) {
500 ss_msg(DBG, "sf_getval_hsbin", "block trailer mismatch at offset 0x%lx", (long) pos);
501 return -2;
504 pos = ftello64(sf->fp);
505 if(fread(&hh, sizeof(hh), 1, sf->fp) != 1) {
506 ss_msg(DBG, "sf_getval_hsbin", "EOF reading block header at offset 0x%lx", (long) pos);
507 return 0;
509 if(hh.h1 == 0x04000000 && hh.h3 == 0x04000000) {
510 /* detected endian swap */
511 sf->flags |= SSF_ESWAP;
512 swap_gint32((gint32*)&hh, sizeof(hh)/sizeof(gint32));
513 } else {
514 sf->flags &= ~SSF_ESWAP;
516 if(hh.h1 != 0x00000004 || hh.h3 != 0x00000004) {
517 ss_msg(ERR, "sf_getval_hsbin", "unexepected values in block header at offset 0x%lx", pos);
518 return -1;
520 sf->expected_vals = hh.block_nbytes / sizeof(float);
521 sf->read_vals = 0;
523 if(fread(&val, sizeof(float), 1, sf->fp) != 1) {
524 pos = ftello64(sf->fp);
525 ss_msg(ERR, "sf_getval_hsbin", "unexepected EOF in data at offset 0x%lx", (long) pos);
526 return 0;
528 sf->read_vals++;
530 if(sf->flags & SSF_ESWAP) {
531 swap_gint32((gint32 *)&val, 1);
533 *dval = val;
534 return 1;
538 * helper routine: get next value from ascii hspice file.
539 * the file is line-oriented, with fixed-width fields on each line.
540 * Lines may look like either of these two examples:
541 0.66687E-090.21426E+010.00000E+000.00000E+000.25000E+010.71063E-090.17877E+01
542 .00000E+00 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30000E+01 .30092E-05
543 * There may be whitespace at the end of the line before the newline.
545 * Returns 0 on EOF, 1 on success.
547 static int
548 sf_getval_hsascii(SpiceStream *sf, double *val)
550 char vbuf[16];
551 char *vp;
552 char *cp;
553 int l;
555 if(!sf->linep || (*sf->linep==0) || *sf->linep == '\n') {
556 if(fgets(sf->linebuf, sf->lbufsize, sf->fp) == NULL)
557 return 0;
559 l = strlen(sf->linebuf);
560 if(l) { /* delete whitespace at end of line */
561 cp = sf->linebuf + l - 1;
562 while(cp > sf->linebuf && *cp && isspace(*cp))
563 *cp-- = '\0';
565 sf->linep = sf->linebuf;
566 sf->line_length = strlen(sf->linep);
567 /* fprintf(stderr, "#line: \"%s\"\n", sf->linebuf); */
569 if(sf->linep > sf->linebuf + sf->line_length) {
570 ss_msg(WARN, "sf_getval_hsascii",
571 "%s: internal error or bad line in file", sf->filename);
572 return 0;
575 strncpy(vbuf, sf->linep, 11);
576 sf->linep += 11;
577 vbuf[11] = 0;
578 if(strlen(vbuf) != 11) {
579 /* incomplete float value - probably truncated or
580 partialy-written file */
581 return 0;
583 vp = vbuf;
584 while(isspace(*vp)) /* atof doesn't like spaces */
585 vp++;
586 *val = atof(vp);
587 /* fprintf(stderr, "#vp=\"%s\" val=%f\n", vp, *val); */
588 return 1;
591 /* Read row of values from ascii hspice-format file.
592 * Returns:
593 * 1 on success. also fills in *ivar scalar and *dvars vector
594 * 0 on EOF
595 * -1 on error (may change some ivar/dvar values)
596 * -2 on end of table, with more tables supposedly still to be read.
599 static int
600 sf_readrow_hsascii(SpiceStream *sf, double *ivar, double *dvars)
602 int i;
604 if(!sf->read_sweepparam) { /* first row of table */
605 if(sf_readsweep_hsascii(sf, NULL) <= 0) /* discard sweep parameters, if any */
606 return -1;
608 if(sf_getval_hsascii(sf, ivar) == 0)
609 return 0;
610 if(*ivar >= 1.0e29) { /* "infinity" at end of data table */
611 sf->read_tables++;
612 if(sf->read_tables == sf->ntables)
613 return 0; /* EOF */
614 else
615 sf->read_sweepparam = 0;
616 sf->read_rows = 0;
617 return -2; /* end of table, more tables follow */
620 sf->read_rows++;
621 for(i = 0; i < sf->ncols-1; i++) {
622 if(sf_getval_hsascii(sf, &dvars[i]) == 0) {
623 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);
624 return 0;
627 return 1;
630 /* Read row of values from binary hspice-format file.
631 * Returns:
632 * 1 on success. also fills in *ivar scalar and *dvars vector
633 * 0 on EOF
634 * -1 on error (may change some ivar/dvar values)
636 static int
637 sf_readrow_hsbin(SpiceStream *sf, double *ivar, double *dvars)
639 int i;
640 int rc;
642 if(!sf->read_sweepparam) { /* first row of table */
643 if(sf_readsweep_hsbin(sf, NULL) <= 0) /* discard sweep parameters, if any */
644 return -1;
647 rc = sf_getval_hsbin(sf, ivar);
648 if(rc == 0) /* file EOF */
649 return 0;
650 if(rc < 0)
651 return -1;
652 if(*ivar >= 1.0e29) { /* "infinity" at end of data table */
653 sf->read_tables++;
654 if(sf->read_tables == sf->ntables)
655 return 0; /* end of data, should also be EOF but we don't check */
656 else {
657 sf->read_sweepparam = 0;
658 sf->read_rows = 0;
659 return -2; /* end of table, more tables follow */
662 sf->read_rows++;
663 for(i = 0; i < sf->ncols-1; i++) {
664 if(sf_getval_hsbin(sf, &dvars[i]) != 1) {
665 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);
666 return 0;
669 return 1;
673 * Read the sweep parameters from an HSPICE ascii or binary file
674 * This routine must be called before the first sf_readrow_hsascii call in each data
675 * table. If it has not been called before the first readrow call, it will be called
676 * with a NULL svar pointer to read and discard the sweep data.
678 * returns:
679 * 1 on success
680 * -1 on error
682 static int
683 sf_readsweep_hsascii(SpiceStream *sf, double *svar)
685 int i;
686 double val;
687 for(i = 0; i < sf->nsweepparam; i++) {
688 if(sf_getval_hsascii(sf, &val) == 0) {
689 ss_msg(ERR, "sf_readsweep_hsascii", "unexpected EOF reading sweep parameters\n");
690 return -1;
692 if(svar)
693 svar[i] = val;
696 sf->read_sweepparam = 1;
697 return 1;
700 static int
701 sf_readsweep_hsbin(SpiceStream *sf, double *svar)
703 int i;
704 double val;
705 for(i = 0; i < sf->nsweepparam; i++) {
706 if(sf_getval_hsbin(sf, &val) != 1) {
707 ss_msg(ERR, "sf_readsweep_hsbin", "EOF or error reading sweep parameter\n");
708 return -1;
710 if(svar)
711 svar[i] = val;
714 sf->read_sweepparam = 1;
715 return 1;
720 * Estimate how many rows are in the file associated with sf.
721 * We base our estimate on the size of the file.
722 * This can be useful to aid in memory-use planning by programs planning to
723 * read the entire file.
725 * If the file descriptor is not associated with an ordinary file, we return 0
726 * to indicate that the length cannot be estimated.
727 * If an error occurs, -1 is returned.
729 static long
730 sf_guessrows_hsbin(SpiceStream *sf)
732 int rc;
733 struct stat st;
735 rc = fstat(fileno(sf->fp), &st);
736 if(rc < 0)
737 return -1;
738 if((st.st_mode & S_IFMT) != S_IFREG)
739 return 0;
741 return st.st_size / (sizeof(float) * sf->ncols);
745 static void
746 swap_gint32(gint32 *pi, size_t n)
748 union gint32bytes *p = (union gint32bytes *)pi;
749 size_t i;
750 gchar temp;
751 for(i = 0; i < n; i++) {
752 temp = p[i].b[3] ;
753 p[i].b[3] = p[i].b[0];
754 p[i].b[0] = temp;
756 temp = p[i].b[2] ;
757 p[i].b[2] = p[i].b[1];
758 p[i].b[1] = temp;