516 lines
13 KiB
C
516 lines
13 KiB
C
/**********
|
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
|
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|
**********/
|
|
|
|
/*
|
|
* Main routine for sconvert.
|
|
*/
|
|
|
|
#include "ngspice/ngspice.h"
|
|
#include <stdio.h>
|
|
|
|
#include "ngspice/fteinput.h"
|
|
#include "ngspice/cpdefs.h"
|
|
#include "ngspice/ftedefs.h"
|
|
#include "ngspice/sim.h"
|
|
#include "ngspice/suffix.h"
|
|
#include "ngspice/compatmode.h"
|
|
#include "frontend/display.h"
|
|
#include "../misc/mktemp.h"
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
FILE *cp_in = NULL;
|
|
FILE *cp_out = NULL;
|
|
FILE *cp_err = NULL;
|
|
FILE *cp_curin = NULL;
|
|
FILE *cp_curout = NULL;
|
|
FILE *cp_curerr = NULL;
|
|
bool cp_debug = FALSE;
|
|
char cp_chars[128];
|
|
bool cp_nocc = TRUE;
|
|
bool ft_stricterror = FALSE;
|
|
bool ft_parsedb = FALSE;
|
|
struct circ *ft_curckt = NULL;
|
|
struct plot *plot_cur = NULL;
|
|
int cp_maxhistlength = 0;
|
|
bool cp_no_histsubst = FALSE;
|
|
struct compat newcompat;
|
|
|
|
char *cp_program = "sconvert";
|
|
|
|
|
|
#define tfread(ptr, siz, nit, fp) if (fread((ptr), (siz), \
|
|
(nit), (fp)) != (nit)) { \
|
|
fprintf(cp_err, "Error: unexpected EOF\n"); \
|
|
return (NULL); }
|
|
|
|
#define tfwrite(ptr, siz, nit, fp) if (fwrite((ptr), (siz), \
|
|
(nit), (fp)) != (nit)) { \
|
|
fprintf(cp_err, "Write error\n"); \
|
|
return; }
|
|
|
|
#define TMALLOC(t, n) (t*) tmalloc(sizeof(t) * (size_t)(n))
|
|
#define TREALLOC(t, p, n) (t*) trealloc(p, sizeof(t) * (size_t)(n))
|
|
|
|
|
|
char *
|
|
smktemp(char *id)
|
|
{
|
|
if (!id)
|
|
id = "sp";
|
|
const char* const home = getenv("HOME");
|
|
if (home) {
|
|
return tprintf("%s/"TEMPFORMAT, home, id, getpid());
|
|
}
|
|
const char* const usr = getenv("USERPROFILE");
|
|
if (usr) {
|
|
return tprintf("%s\\"TEMPFORMAT, usr, id, getpid());
|
|
}
|
|
return tprintf(TEMPFORMAT, id, getpid());
|
|
}
|
|
|
|
int
|
|
inchar(FILE *fp)
|
|
{
|
|
|
|
#if !defined(__MINGW32__)
|
|
char c;
|
|
ssize_t i;
|
|
|
|
do
|
|
i = read(fileno(fp), &c, 1);
|
|
while (i == -1 && errno == EINTR);
|
|
|
|
if (i == 0 || c == '\004')
|
|
return EOF;
|
|
|
|
if (i == -1) {
|
|
perror("read");
|
|
return EOF;
|
|
}
|
|
|
|
return (int) c;
|
|
#elif
|
|
|
|
return getc(fp);
|
|
#endif
|
|
}
|
|
|
|
int
|
|
input(FILE *fp)
|
|
{
|
|
REQUEST request;
|
|
RESPONSE response;
|
|
|
|
request.option = char_option;
|
|
request.fp = fp;
|
|
|
|
Input(&request, &response);
|
|
|
|
return (inchar(fp));
|
|
}
|
|
|
|
|
|
void
|
|
Input(REQUEST *request, RESPONSE *response)
|
|
{
|
|
switch (request->option) {
|
|
case char_option:
|
|
response->reply.ch = inchar(request->fp);
|
|
response->option = request->option;
|
|
break;
|
|
default:
|
|
/* just ignore, since we don't want a million error messages */
|
|
response->option = error_option;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static char *
|
|
fixdate(char *date)
|
|
{
|
|
char buf[20];
|
|
int i;
|
|
|
|
(void) strcpy(buf, date);
|
|
for (i = 17; i > 8; i--)
|
|
buf[i] = buf[i - 1];
|
|
buf[8] = ' ';
|
|
buf[18] = '\0';
|
|
return (strdup(buf));
|
|
}
|
|
|
|
|
|
static struct plot *
|
|
oldread(char *name)
|
|
{
|
|
struct plot *pl;
|
|
char buf[BSIZE_SP];
|
|
struct dvec *v, *end = NULL;
|
|
short nv; /* # vars */
|
|
long np; /* # points/var. */
|
|
long i, j;
|
|
short a; /* The magic number. */
|
|
float f1, f2;
|
|
FILE *fp;
|
|
|
|
if (!(fp = fopen(name, "r"))) {
|
|
perror(name);
|
|
return (NULL);
|
|
}
|
|
pl = TMALLOC(struct plot, 1);
|
|
tfread(buf, 1, 80, fp);
|
|
buf[80] = '\0';
|
|
for (i = (int) strlen(buf) - 1; (i > 1) && (buf[i] == ' '); i--)
|
|
;
|
|
buf[i + 1] = '\0';
|
|
pl->pl_title = strdup(buf);
|
|
|
|
tfread(buf, 1, 16, fp);
|
|
buf[16] = '\0';
|
|
pl->pl_date = strdup(fixdate(buf));
|
|
|
|
tfread(&nv, sizeof (short), 1, fp);
|
|
|
|
tfread(&a, sizeof (short), 1, fp);
|
|
if (a != 4)
|
|
fprintf(cp_err, "Warning: magic number 4 is wrong...\n");
|
|
|
|
for (i = 0; i < nv; i++) {
|
|
v = dvec_alloc(NULL,
|
|
SV_NOTYPE, 0,
|
|
0, NULL);
|
|
if (end)
|
|
end->v_next = v;
|
|
else
|
|
pl->pl_scale = pl->pl_dvecs = v;
|
|
end = v;
|
|
tfread(buf, 1, 8, fp);
|
|
buf[8] = '\0';
|
|
v->v_name = strdup(buf);
|
|
}
|
|
for (v = pl->pl_dvecs; v; v = v->v_next) {
|
|
tfread(&a, sizeof (short), 1, fp);
|
|
v->v_type = a;
|
|
}
|
|
|
|
/* If the first output variable is type FREQ then there is complex
|
|
* data, otherwise the data is real.
|
|
*/
|
|
i = pl->pl_dvecs->v_type;
|
|
if ((i == SV_FREQUENCY) || (i == SV_POLE) || (i == SV_ZERO))
|
|
for (v = pl->pl_dvecs; v; v = v->v_next)
|
|
v->v_flags |= VF_COMPLEX;
|
|
else
|
|
for (v = pl->pl_dvecs; v; v = v->v_next)
|
|
v->v_flags |= VF_REAL;
|
|
|
|
/* Check the node indices -- this shouldn't be a problem ever. */
|
|
for (i = 0; i < nv; i++) {
|
|
tfread(&a, sizeof(short), 1, fp);
|
|
if (a != i + 1)
|
|
fprintf(cp_err, "Warning: output %d should be %ld\n",
|
|
a, i);
|
|
}
|
|
tfread(buf, 1, 24, fp);
|
|
buf[24] = '\0';
|
|
pl->pl_name = strdup(buf);
|
|
/* Now to figure out how many points of data there are left in
|
|
* the file.
|
|
*/
|
|
i = ftell(fp);
|
|
(void) fseek(fp, 0L, SEEK_END);
|
|
j = ftell(fp);
|
|
(void) fseek(fp, i, SEEK_SET);
|
|
i = j - i;
|
|
if (i % 8) { /* Data points are always 8 bytes... */
|
|
fprintf(cp_err, "Error: alignment error in data\n");
|
|
(void) fclose(fp);
|
|
return (NULL);
|
|
}
|
|
i = i / 8;
|
|
if (i % nv) {
|
|
fprintf(cp_err, "Error: alignment error in data\n");
|
|
(void) fclose(fp);
|
|
return (NULL);
|
|
}
|
|
np = i / nv;
|
|
|
|
for (v = pl->pl_dvecs; v; v = v->v_next) {
|
|
dvec_realloc(v, (int) np, NULL);
|
|
}
|
|
for (i = 0; i < np; i++) {
|
|
/* Read in the output vector for point i. If the type is
|
|
* complex it will be float and we want double.
|
|
*/
|
|
for (v = pl->pl_dvecs; v; v = v->v_next) {
|
|
if (v->v_flags & VF_REAL) {
|
|
tfread(&v->v_realdata[i], sizeof (double),
|
|
1, fp);
|
|
} else {
|
|
tfread(&f1, sizeof (float), 1, fp);
|
|
tfread(&f2, sizeof (float), 1, fp);
|
|
realpart(v->v_compdata[i]) = f1;
|
|
imagpart(v->v_compdata[i]) = f2;
|
|
}
|
|
}
|
|
}
|
|
(void) fclose(fp);
|
|
return (pl);
|
|
}
|
|
|
|
|
|
static void
|
|
oldwrite(char *name, bool app, struct plot *pl)
|
|
{
|
|
short four = 4, k;
|
|
struct dvec *v;
|
|
float f1, f2, zero = 0.0;
|
|
char buf[80];
|
|
int i, j, tp = VF_REAL, numpts = 0, numvecs = 0;
|
|
FILE *fp;
|
|
|
|
if (!(fp = fopen(name, app ? "a" : "w"))) {
|
|
perror(name);
|
|
return;
|
|
}
|
|
|
|
for (v = pl->pl_dvecs; v; v = v->v_next) {
|
|
if (v->v_length > numpts)
|
|
numpts = v->v_length;
|
|
numvecs++;
|
|
if (iscomplex(v))
|
|
tp = VF_COMPLEX;
|
|
}
|
|
|
|
/* This may not be a good idea... */
|
|
if (tp == VF_COMPLEX)
|
|
pl->pl_scale->v_type = SV_FREQUENCY;
|
|
|
|
for (i = 0; i < 80; i++)
|
|
buf[i] = ' ';
|
|
for (i = 0; i < 80; i++)
|
|
if (pl->pl_title[i] == '\0')
|
|
break;
|
|
else
|
|
buf[i] = pl->pl_title[i];
|
|
tfwrite(buf, 1, 80, fp);
|
|
|
|
for (i = 0; i < 80; i++)
|
|
buf[i] = ' ';
|
|
for (i = 0; i < 16; i++)
|
|
if (pl->pl_date[i] == '\0')
|
|
break;
|
|
else
|
|
buf[i] = pl->pl_date[i];
|
|
tfwrite(buf, 1, 16, fp);
|
|
|
|
tfwrite(&numvecs, sizeof (short), 1, fp);
|
|
tfwrite(&four, sizeof (short), 1, fp);
|
|
|
|
for (v = pl->pl_dvecs; v; v = v->v_next) {
|
|
for (j = 0; j < 80; j++)
|
|
buf[j] = ' ';
|
|
for (j = 0; j < 8; j++)
|
|
if (v->v_name[j] == '\0')
|
|
break;
|
|
else
|
|
buf[j] = v->v_name[j];
|
|
tfwrite(buf, 1, 8, fp);
|
|
}
|
|
|
|
for (v = pl->pl_dvecs; v; v = v->v_next) {
|
|
j = (short) v->v_type;
|
|
tfwrite(&j, sizeof (short), 1, fp);
|
|
}
|
|
|
|
for (k = 1; k < numvecs + 1; k++)
|
|
tfwrite(&k, sizeof (short), 1, fp);
|
|
for (j = 0; j < 80; j++)
|
|
buf[j] = ' ';
|
|
for (j = 0; j < 24; j++)
|
|
if (pl->pl_name[j] == '\0')
|
|
break;
|
|
else
|
|
buf[j] = pl->pl_name[j];
|
|
tfwrite(buf, 1, 24, fp);
|
|
for (i = 0; i < numpts; i++) {
|
|
for (v = pl->pl_dvecs; v; v = v->v_next) {
|
|
if ((tp == VF_REAL) && isreal(v)) {
|
|
if (i < v->v_length) {
|
|
tfwrite(&v->v_realdata[i], sizeof (double), 1, fp);
|
|
} else {
|
|
tfwrite(&v->v_realdata[v->v_length - 1], sizeof (double), 1, fp);
|
|
}
|
|
} else if ((tp == VF_REAL) && iscomplex(v)) {
|
|
fprintf(cp_err, "internal error, everything real, yet complex ...\n");
|
|
exit(1);
|
|
} else if ((tp == VF_COMPLEX) && isreal(v)) {
|
|
if (i < v->v_length)
|
|
f1 = (float) v->v_realdata[i];
|
|
else
|
|
f1 = (float) v->v_realdata[v->v_length - 1];
|
|
tfwrite(&f1, sizeof (float), 1, fp);
|
|
tfwrite(&zero, sizeof (float), 1, fp);
|
|
} else if ((tp == VF_COMPLEX) && iscomplex(v)) {
|
|
if (i < v->v_length) {
|
|
f1 = (float) realpart(v->v_compdata[i]);
|
|
f2 = (float) imagpart(v->v_compdata[i]);
|
|
} else {
|
|
f1 = (float) realpart(v->v_compdata[v-> v_length - 1]);
|
|
f2 = (float) imagpart(v->v_compdata[v-> v_length - 1]);
|
|
}
|
|
tfwrite(&f1, sizeof (float), 1, fp);
|
|
tfwrite(&f2, sizeof (float), 1, fp);
|
|
}
|
|
}
|
|
}
|
|
|
|
(void) fclose(fp);
|
|
return;
|
|
}
|
|
|
|
|
|
int
|
|
main(int ac, char **av)
|
|
{
|
|
char *sf, *af;
|
|
char buf[BSIZE_SP];
|
|
char t, f;
|
|
struct plot *pl;
|
|
size_t n;
|
|
char *infile = NULL;
|
|
char *outfile = NULL;
|
|
FILE *fp;
|
|
|
|
switch (ac) {
|
|
case 5:
|
|
sf = av[2];
|
|
af = av[4];
|
|
f = *av[1];
|
|
t = *av[3];
|
|
break;
|
|
|
|
case 3:
|
|
f = *av[1];
|
|
t = *av[2];
|
|
/* This is a pain, but there is no choice */
|
|
sf = infile = smktemp("scin");
|
|
af = outfile = smktemp("scout");
|
|
if (!(fp = fopen(infile, "w"))) {
|
|
perror(infile);
|
|
exit(EXIT_BAD);
|
|
}
|
|
while ((n = fread(buf, 1, sizeof(buf), stdin)) != 0)
|
|
(void) fwrite(buf, 1, n, fp);
|
|
(void) fclose(fp);
|
|
break;
|
|
|
|
case 1: printf("Input file: ");
|
|
(void) fflush(stdout);
|
|
(void) fgets(buf, BSIZE_SP, stdin);
|
|
sf = strdup(buf);
|
|
printf("Input type: ");
|
|
(void) fflush(stdout);
|
|
(void) fgets(buf, BSIZE_SP, stdin);
|
|
f = buf[0];
|
|
printf("Output file: ");
|
|
(void) fflush(stdout);
|
|
(void) fgets(buf, BSIZE_SP, stdin);
|
|
af = strdup(buf);
|
|
printf("Output type: ");
|
|
(void) fflush(stdout);
|
|
(void) fgets(buf, BSIZE_SP, stdin);
|
|
t = buf[0];
|
|
break;
|
|
default:
|
|
fprintf(cp_err,
|
|
"Usage: %s fromtype fromfile totype tofile,\n",
|
|
cp_program);
|
|
fprintf(cp_err, "\twhere types are o, b, or a\n");
|
|
fprintf(cp_err,
|
|
"\tor, %s fromtype totype, used as a filter.\n",
|
|
cp_program);
|
|
exit(EXIT_BAD);
|
|
}
|
|
switch(f) {
|
|
case 'o' :
|
|
pl = oldread(sf);
|
|
break;
|
|
|
|
case 'b' :
|
|
case 'a' :
|
|
pl = raw_read(sf);
|
|
break;
|
|
|
|
default:
|
|
fprintf(cp_err, "Types are o, a, or b\n");
|
|
exit(EXIT_BAD);
|
|
}
|
|
if (!pl)
|
|
exit(EXIT_BAD);
|
|
|
|
switch(t) {
|
|
case 'o' :
|
|
oldwrite(af, FALSE, pl);
|
|
break;
|
|
|
|
case 'b' :
|
|
raw_write(af, pl, FALSE, TRUE);
|
|
break;
|
|
|
|
case 'a' :
|
|
raw_write(af, pl, FALSE, FALSE);
|
|
break;
|
|
|
|
default:
|
|
fprintf(cp_err, "Types are o, a, or b\n");
|
|
exit(EXIT_BAD);
|
|
}
|
|
if (ac == 3) {
|
|
/* Gotta finish this stuff up */
|
|
if (!(fp = fopen(outfile, "r"))) {
|
|
perror(outfile);
|
|
exit(EXIT_BAD);
|
|
}
|
|
while ((n = fread(buf, 1, sizeof(buf), fp)) != 0)
|
|
(void) fwrite(buf, 1, n, stdout);
|
|
(void) fclose(fp);
|
|
(void) unlink(infile);
|
|
(void) unlink(outfile);
|
|
}
|
|
exit(EXIT_NORMAL);
|
|
}
|
|
|
|
|
|
void cp_pushcontrol(void) { }
|
|
void cp_popcontrol(void) { }
|
|
void out_init(void) { }
|
|
void cp_doquit(void) { exit(0); }
|
|
struct variable *cp_usrvars(void) { return NULL; }
|
|
int cp_evloop(char *s) { NG_IGNORE(s); return (0); }
|
|
void cp_ccon(bool o) { NG_IGNORE(o); }
|
|
char*if_errstring(int c) { NG_IGNORE(c); return strdup("error"); }
|
|
void out_printf(char *fmt, ...) { NG_IGNORE(fmt); }
|
|
void out_send(char *string) { NG_IGNORE(string); }
|
|
struct variable * cp_enqvar(const char *word, int *tbfreed) { NG_IGNORE(word); NG_IGNORE(*tbfreed); return (NULL); }
|
|
struct dvec *vec_get(const char *word) { NG_IGNORE(word); return (NULL); }
|
|
void cp_ccom(wordlist *w, char *b, bool e) {
|
|
NG_IGNORE(e);
|
|
NG_IGNORE(b);
|
|
NG_IGNORE(w); return; }
|
|
int cp_usrset(struct variable *v, bool i) {
|
|
NG_IGNORE(i);
|
|
NG_IGNORE(v); return(US_OK); }
|
|
wordlist * cp_doalias(wordlist *wlist) {NG_IGNORE(wlist); return NULL;}
|
|
|
|
void controlled_exit(int no){exit(no);}
|
|
|
|
int disptype;
|
|
|