2020-08-08 15:47:34 +02:00
|
|
|
/* File: save.c
|
2020-10-12 13:13:31 +02:00
|
|
|
*
|
2020-08-08 15:47:34 +02:00
|
|
|
* This file is part of XSCHEM,
|
2020-10-12 13:13:31 +02:00
|
|
|
* a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
2020-08-08 15:47:34 +02:00
|
|
|
* simulation.
|
2022-06-24 00:36:12 +02:00
|
|
|
* Copyright (C) 1998-2022 Stefan Frederik Schippers
|
2020-08-08 15:47:34 +02:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "xschem.h"
|
|
|
|
|
#ifdef __unix__
|
|
|
|
|
#include <sys/wait.h> /* waitpid */
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-01-23 01:21:36 +01:00
|
|
|
/* get an input databuffer (din[ilen]), and a shell command (cmd) that reads stdin
|
|
|
|
|
* and writes stdout, return the result in dout[olen].
|
|
|
|
|
* Caller must free the returned buffer.
|
|
|
|
|
*/
|
2022-01-27 20:47:27 +01:00
|
|
|
#ifdef __unix__
|
2022-01-23 01:21:36 +01:00
|
|
|
int filter_data(const char *din, const size_t ilen,
|
|
|
|
|
char **dout, size_t *olen,
|
|
|
|
|
const char *cmd)
|
|
|
|
|
{
|
|
|
|
|
int p1[2]; /* parent -> child, 0: read, 1: write */
|
|
|
|
|
int p2[2]; /* child -> parent, 0: read, 1: write */
|
|
|
|
|
int ret = 0;
|
|
|
|
|
pid_t pid;
|
2022-01-24 22:58:30 +01:00
|
|
|
size_t bufsize = 32768, oalloc = 0, n = 0;
|
2022-01-23 04:51:41 +01:00
|
|
|
|
|
|
|
|
if(!din || !ilen || !cmd) { /* basic check */
|
|
|
|
|
*dout = NULL;
|
|
|
|
|
*olen = 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-01-24 22:58:30 +01:00
|
|
|
|
|
|
|
|
dbg(1, "filter_data(): ilen=%ld, cmd=%s\n", ilen, cmd);
|
2022-01-23 01:21:36 +01:00
|
|
|
pipe(p1);
|
|
|
|
|
pipe(p2);
|
|
|
|
|
signal(SIGPIPE, SIG_IGN); /* so attempting write/read a broken pipe won't kill program */
|
|
|
|
|
if( (pid = fork()) == 0) {
|
|
|
|
|
/* child */
|
|
|
|
|
close(p1[1]); /* only read from p1 */
|
|
|
|
|
close(p2[0]); /* only write to p2 */
|
|
|
|
|
close(0); /* dup2(p1[0],0); */ /* connect read side of read pipe to stdin */
|
|
|
|
|
dup(p1[0]);
|
|
|
|
|
close(1); /* dup2(p2[1],1); */ /* connect write side of write pipe to stdout */
|
|
|
|
|
dup(p2[1]);
|
|
|
|
|
/* execlp("gm", "gm", "convert", "-", "-quality", "50", "jpg:-", NULL); */
|
|
|
|
|
if(system(cmd)) {
|
|
|
|
|
fprintf(stderr, "error: conversion failed\n");
|
|
|
|
|
ret = 1;
|
|
|
|
|
}
|
|
|
|
|
close(p1[0]);
|
|
|
|
|
close(p2[1]);
|
|
|
|
|
exit(ret);
|
|
|
|
|
}
|
|
|
|
|
/* parent */
|
|
|
|
|
close(p1[0]); /*only write to p1 */
|
|
|
|
|
close(p2[1]); /* only read from p2 */
|
|
|
|
|
if(write(p1[1], din, ilen) != ilen) { /* write input data to pipe */
|
|
|
|
|
fprintf(stderr, "filter_data() write to pipe failed or not completed\n");
|
|
|
|
|
ret = 1;
|
|
|
|
|
}
|
|
|
|
|
close(p1[1]);
|
|
|
|
|
if(!ret) {
|
2022-01-24 22:58:30 +01:00
|
|
|
oalloc = bufsize + 1; /* add extra space for final '\0' */
|
|
|
|
|
*dout = my_malloc(1480, oalloc);
|
|
|
|
|
*olen = 0;
|
|
|
|
|
while( (n = read(p2[0], *dout + *olen, bufsize)) > 0) {
|
|
|
|
|
*olen += n;
|
|
|
|
|
if(*olen + bufsize + 1 >= oalloc) { /* allocate for next read */
|
|
|
|
|
oalloc = *olen + bufsize + 1; /* add extra space for final '\0' */
|
|
|
|
|
oalloc = ((oalloc << 2) + oalloc) >> 2; /* size up 1.25x */
|
|
|
|
|
dbg(1, "filter_data() read %ld bytes, reallocate dout to %ld bytes, bufsize=%ld\n", n, oalloc, bufsize);
|
|
|
|
|
my_realloc(1482, dout, oalloc);
|
2022-01-23 01:21:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-01-24 22:58:30 +01:00
|
|
|
if(*olen) (*dout)[*olen] = '\0'; /* so (if ascii) it can be used as a string */
|
2022-01-23 01:21:36 +01:00
|
|
|
}
|
|
|
|
|
close(p2[0]);
|
|
|
|
|
if(n < 0 || !*olen) {
|
|
|
|
|
if(oalloc) {
|
2022-01-23 04:51:41 +01:00
|
|
|
my_free(1483, dout);
|
2022-01-23 01:21:36 +01:00
|
|
|
*olen = 0;
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "no data read\n");
|
|
|
|
|
ret = 1;
|
|
|
|
|
}
|
|
|
|
|
waitpid(pid, NULL, 0); /* write for child process to finish and unzombie it */
|
|
|
|
|
signal(SIGPIPE, SIG_DFL); /* restore default SIGPIPE signal action */
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2022-01-27 20:47:27 +01:00
|
|
|
#else
|
|
|
|
|
int filter_data(const char* din, const size_t ilen,
|
|
|
|
|
char** dout, size_t* olen,
|
|
|
|
|
const char* cmd)
|
|
|
|
|
{
|
|
|
|
|
*dout = NULL;
|
|
|
|
|
*olen = 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2022-01-20 18:28:29 +01:00
|
|
|
|
2022-01-19 18:39:23 +01:00
|
|
|
/* Caller should free returned buffer */
|
2022-09-15 19:39:16 +02:00
|
|
|
/* set brk to 1 if you want newlines added */
|
2022-01-23 04:51:41 +01:00
|
|
|
char *base64_encode(const unsigned char *data, const size_t input_length, size_t *output_length, int brk) {
|
2022-01-20 01:57:53 +01:00
|
|
|
static const char b64_enc[] = {
|
2022-01-19 18:39:23 +01:00
|
|
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
|
|
|
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
|
|
|
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
|
|
|
|
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
|
|
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
|
|
|
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
|
|
|
|
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
|
|
|
|
'4', '5', '6', '7', '8', '9', '+', '/'
|
|
|
|
|
};
|
|
|
|
|
static int mod_table[] = {0, 2, 1};
|
2022-01-20 18:28:29 +01:00
|
|
|
int i, j, cnt;
|
|
|
|
|
size_t alloc_length;
|
2022-01-19 18:39:23 +01:00
|
|
|
char *encoded_data;
|
2022-01-20 18:28:29 +01:00
|
|
|
int octet_a, octet_b, octet_c, triple;
|
2022-01-21 19:17:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
*output_length = 4 * ((input_length + 2) / 3);
|
|
|
|
|
alloc_length = (1 + (*output_length / 4096)) * 4096;
|
2022-01-20 18:28:29 +01:00
|
|
|
encoded_data = my_malloc(1469, alloc_length);
|
2022-01-19 18:39:23 +01:00
|
|
|
if (encoded_data == NULL) return NULL;
|
2022-01-20 18:28:29 +01:00
|
|
|
cnt = 0;
|
|
|
|
|
|
2022-01-19 18:39:23 +01:00
|
|
|
for (i = 0, j = 0; i < input_length;) {
|
2022-01-20 18:28:29 +01:00
|
|
|
octet_a = i < input_length ? (unsigned char)data[i++] : 0;
|
|
|
|
|
octet_b = i < input_length ? (unsigned char)data[i++] : 0;
|
|
|
|
|
octet_c = i < input_length ? (unsigned char)data[i++] : 0;
|
|
|
|
|
triple = (octet_a << 16) + (octet_b << 8) + octet_c;
|
|
|
|
|
if(j + 10 >= alloc_length) {
|
|
|
|
|
dbg(1, "alloc-length=%ld, j=%d, output_length=%ld\n", alloc_length, j, *output_length);
|
|
|
|
|
alloc_length += 4096;
|
|
|
|
|
my_realloc(1471, &encoded_data, alloc_length);
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
if(brk && ( (cnt & 31) == 0) ) {
|
2022-01-20 18:28:29 +01:00
|
|
|
*output_length += 1;
|
|
|
|
|
encoded_data[j++] = '\n';
|
|
|
|
|
}
|
|
|
|
|
encoded_data[j++] = b64_enc[(triple >> 18) & 0x3F];
|
|
|
|
|
encoded_data[j++] = b64_enc[(triple >> 12) & 0x3F];
|
|
|
|
|
encoded_data[j++] = b64_enc[(triple >> 6) & 0x3F];
|
|
|
|
|
encoded_data[j++] = b64_enc[(triple) & 0x3F];
|
|
|
|
|
cnt++;
|
2022-01-19 18:39:23 +01:00
|
|
|
}
|
|
|
|
|
for (i = 0; i < mod_table[input_length % 3]; i++)
|
|
|
|
|
encoded_data[*output_length - 1 - i] = '=';
|
2022-01-21 19:17:43 +01:00
|
|
|
encoded_data[*output_length] = '\0'; /* add \0 at end so it can be used as a regular char string */
|
2022-01-19 18:39:23 +01:00
|
|
|
return encoded_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Caller should free returned buffer */
|
2022-01-23 04:51:41 +01:00
|
|
|
unsigned char *base64_decode(const char *data, const size_t input_length, size_t *output_length) {
|
2022-01-20 01:57:53 +01:00
|
|
|
static const unsigned char b64_dec[256] = {
|
2022-01-19 18:39:23 +01:00
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
|
|
|
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
|
|
|
|
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
|
|
|
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f
|
|
|
|
|
};
|
|
|
|
|
unsigned char *decoded_data;
|
2022-04-28 10:12:16 +02:00
|
|
|
int i, j, sextet[4], triple, cnt, padding;
|
|
|
|
|
size_t actual_length;
|
2022-01-20 18:28:29 +01:00
|
|
|
|
|
|
|
|
actual_length = input_length;
|
|
|
|
|
*output_length = input_length / 4 * 3 + 4; /* add 4 more just in case... */
|
|
|
|
|
padding = 0;
|
|
|
|
|
if (data[input_length - 1] == '=') padding++;
|
|
|
|
|
if (data[input_length - 2] == '=') padding++;
|
2022-01-20 00:47:15 +01:00
|
|
|
decoded_data = my_malloc(1470, *output_length);
|
2022-01-19 18:39:23 +01:00
|
|
|
if (decoded_data == NULL) return NULL;
|
2022-01-20 18:28:29 +01:00
|
|
|
cnt = 0;
|
2022-01-19 18:39:23 +01:00
|
|
|
for (i = 0, j = 0; i < input_length;) {
|
2022-01-20 18:28:29 +01:00
|
|
|
if(data[i] == '\n' || data[i] == ' ' || data[i] == '\r' || data[i] == '\t') {
|
|
|
|
|
dbg(1, "base64_decode(): white space: i=%d, cnt=%d, j=%d\n", i, cnt, j);
|
|
|
|
|
actual_length--;
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
sextet[cnt & 3] = data[i] == '=' ? 0 : b64_dec[(int)data[i]];
|
|
|
|
|
if((cnt & 3) == 3) {
|
|
|
|
|
triple = (sextet[0] << 18) + (sextet[1] << 12) + (sextet[2] << 6) + (sextet[3]);
|
2022-04-28 10:12:16 +02:00
|
|
|
decoded_data[j++] = (unsigned char)((triple >> 16) & 0xFF);
|
|
|
|
|
decoded_data[j++] = (unsigned char)((triple >> 8) & 0xFF);
|
|
|
|
|
decoded_data[j++] = (unsigned char)((triple) & 0xFF);
|
2022-01-20 18:28:29 +01:00
|
|
|
}
|
|
|
|
|
cnt++;
|
|
|
|
|
i++;
|
2022-01-19 18:39:23 +01:00
|
|
|
}
|
2022-01-20 18:28:29 +01:00
|
|
|
*output_length = actual_length / 4 * 3 - padding;
|
2022-01-19 18:39:23 +01:00
|
|
|
return decoded_data;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-21 19:17:43 +01:00
|
|
|
/* SPICE RAWFILE ROUTINES */
|
|
|
|
|
/* read the binary portion of a ngspice raw simulation file
|
|
|
|
|
* data layout in memory arranged to maximize cache locality
|
|
|
|
|
* when looking up data
|
|
|
|
|
*/
|
2022-02-02 18:33:16 +01:00
|
|
|
static void read_binary_block(FILE *fd)
|
2022-01-21 19:17:43 +01:00
|
|
|
{
|
|
|
|
|
int p, v;
|
|
|
|
|
double *tmp;
|
|
|
|
|
int offset = 0;
|
2022-02-02 18:33:16 +01:00
|
|
|
int ac = 0;
|
2022-01-21 19:17:43 +01:00
|
|
|
|
2022-09-20 16:49:42 +02:00
|
|
|
if(!strcmp(xctx->graph_sim_type, "ac")) ac = 1; /* AC analysis, complex numbers twice the size */
|
2022-01-21 19:17:43 +01:00
|
|
|
|
|
|
|
|
for(p = 0 ; p < xctx->graph_datasets; p++) {
|
|
|
|
|
offset += xctx->graph_npoints[p];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* read buffer */
|
2022-02-05 02:16:27 +01:00
|
|
|
tmp = my_calloc(1405, xctx->graph_nvars, (sizeof(double *) ));
|
2022-02-12 04:55:02 +01:00
|
|
|
/* allocate storage for binary block, add one data column for custom data plots */
|
|
|
|
|
if(!xctx->graph_values) xctx->graph_values = my_calloc(118, xctx->graph_nvars + 1, sizeof(SPICE_DATA *));
|
|
|
|
|
for(p = 0 ; p <= xctx->graph_nvars; p++) {
|
2022-02-02 00:11:46 +01:00
|
|
|
my_realloc(372,
|
2022-02-05 00:28:06 +01:00
|
|
|
&xctx->graph_values[p], (offset + xctx->graph_npoints[xctx->graph_datasets]) * sizeof(SPICE_DATA));
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
/* read binary block */
|
|
|
|
|
for(p = 0; p < xctx->graph_npoints[xctx->graph_datasets]; p++) {
|
2022-02-05 02:16:27 +01:00
|
|
|
if(fread(tmp, sizeof(double) , xctx->graph_nvars, fd) != xctx->graph_nvars) {
|
2022-01-21 19:17:43 +01:00
|
|
|
dbg(0, "Warning: binary block is not of correct size\n");
|
|
|
|
|
}
|
|
|
|
|
/* assign to xschem struct, memory aligned per variable, for cache locality */
|
2022-02-02 18:33:16 +01:00
|
|
|
if(ac) {
|
2022-02-05 02:16:27 +01:00
|
|
|
for(v = 0; v < xctx->graph_nvars; v += 2) { /*AC analysis: calculate magnitude */
|
2022-08-05 00:57:03 +02:00
|
|
|
if( v == 0 ) /* sweep var */
|
|
|
|
|
xctx->graph_values[v][offset + p] = (float)sqrt( tmp[v] * tmp[v] + tmp[v + 1] * tmp[v + 1]);
|
|
|
|
|
else /* magnitude */
|
2022-08-03 17:44:53 +02:00
|
|
|
/* avoid 0 for dB calculations */
|
|
|
|
|
if(tmp[v] == 0.0 && tmp[v + 1] == 0.0) xctx->graph_values[v][offset + p] = 1e-35f;
|
|
|
|
|
else xctx->graph_values[v][offset + p] =
|
|
|
|
|
(float)sqrt(tmp[v] * tmp[v] + tmp[v + 1] * tmp[v + 1]);
|
2022-02-04 18:21:25 +01:00
|
|
|
/* AC analysis: calculate phase */
|
2022-08-03 17:44:53 +02:00
|
|
|
if(tmp[v] == 0.0 && tmp[v + 1] == 0.0) xctx->graph_values[v + 1] [offset + p] = 0.0;
|
|
|
|
|
else xctx->graph_values[v + 1] [offset + p] =
|
|
|
|
|
(float)(atan2(tmp[v + 1], tmp[v]) * 180.0 / XSCH_PI);
|
2022-02-02 18:33:16 +01:00
|
|
|
}
|
2022-02-02 00:11:46 +01:00
|
|
|
}
|
2022-02-05 02:16:27 +01:00
|
|
|
else for(v = 0; v < xctx->graph_nvars; v++) {
|
2022-04-27 13:18:45 +02:00
|
|
|
xctx->graph_values[v][offset + p] = (float)tmp[v];
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
my_free(1406, &tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* parse ascii raw header section:
|
|
|
|
|
* returns: 1 if dataset and variables were read.
|
|
|
|
|
* 0 if transient sim dataset not found
|
|
|
|
|
* -1 on EOF
|
|
|
|
|
* Typical ascii header of raw file looks like:
|
|
|
|
|
*
|
|
|
|
|
* Title: **.subckt poweramp
|
|
|
|
|
* Date: Thu Nov 21 18:36:25 2019
|
|
|
|
|
* Plotname: Transient Analysis
|
|
|
|
|
* Flags: real
|
|
|
|
|
* No. Variables: 158
|
|
|
|
|
* No. Points: 90267
|
|
|
|
|
* Variables:
|
|
|
|
|
* 0 time time
|
|
|
|
|
* 1 v(net1) voltage
|
|
|
|
|
* 2 v(vss) voltage
|
|
|
|
|
* ...
|
|
|
|
|
* ...
|
|
|
|
|
* 155 i(v.x1.vd) current
|
|
|
|
|
* 156 i(v0) current
|
|
|
|
|
* 157 i(v1) current
|
|
|
|
|
* Binary:
|
|
|
|
|
*/
|
2022-09-20 16:49:42 +02:00
|
|
|
static int read_dataset(FILE *fd, const char *type)
|
2022-01-21 19:17:43 +01:00
|
|
|
{
|
|
|
|
|
int variables = 0, i, done_points = 0;
|
|
|
|
|
char line[PATH_MAX], varname[PATH_MAX];
|
|
|
|
|
char *ptr;
|
2022-09-20 16:49:42 +02:00
|
|
|
int n = 0, done_header = 0, ac = 0;
|
|
|
|
|
int exit_status = 0, npoints, nvars;
|
|
|
|
|
int dbglev=1;
|
|
|
|
|
xctx->graph_sim_type = NULL;
|
|
|
|
|
dbg(1, "read_dataset(): type=%s\n", type ? type : "<NULL>");
|
2022-09-13 00:31:20 +02:00
|
|
|
while((fgets(line, sizeof(line), fd)) ) {
|
2022-09-20 16:49:42 +02:00
|
|
|
/* this is an ASCII raw file. We don't handle this (yet) */
|
|
|
|
|
if(!strcmp(line, "Values:\n") || !strcmp(line, "Values:\r\n")) {
|
2022-07-26 12:05:28 +02:00
|
|
|
free_rawfile(0);
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(dbglev, "read_dataset(): ASCII raw files can not be read. "
|
2022-07-26 12:05:28 +02:00
|
|
|
"Use binary format in ngspice (set filetype=binary)\n");
|
|
|
|
|
tcleval("alert_ {read_dataset(): ASCII raw files can not be read. "
|
|
|
|
|
"Use binary format in ngspice (set filetype=binary)}");
|
2022-09-20 23:16:59 +02:00
|
|
|
free_rawfile(0);
|
2022-07-26 12:05:28 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
/* after this line comes the binary blob made of nvars * npoints * sizeof(double) bytes */
|
2022-07-28 00:36:09 +02:00
|
|
|
if(!strcmp(line, "Binary:\n") || !strcmp(line, "Binary:\r\n")) {
|
2022-02-02 18:33:16 +01:00
|
|
|
if(xctx->graph_sim_type) {
|
2022-01-21 19:17:43 +01:00
|
|
|
done_header = 1;
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(dbglev, "read_dataset(): read binary block, nvars=%d npoints=%d\n", nvars, npoints);
|
2022-09-09 18:57:34 +02:00
|
|
|
read_binary_block(fd);
|
2022-01-21 19:17:43 +01:00
|
|
|
xctx->graph_datasets++;
|
|
|
|
|
exit_status = 1;
|
|
|
|
|
} else {
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(dbglev, "read_dataset(): skip binary block, nvars=%d npoints=%d\n", nvars, npoints);
|
|
|
|
|
fseek(fd, nvars * npoints * sizeof(double), SEEK_CUR); /* skip binary block */
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
done_points = 0;
|
2022-09-20 16:49:42 +02:00
|
|
|
ac = 0;
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
/* if type is given (not NULL) choose the simulation that matches type, else take the first one */
|
|
|
|
|
/* if xctx->graph_sim_type is set skip all datasets that do not match */
|
2022-08-12 00:06:14 +02:00
|
|
|
else if(!strncmp(line, "Plotname:", 9) && strstr(line, "Transient Analysis")) {
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type && strcmp(xctx->graph_sim_type, "tran")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else if(type && !strcmp(type, "tran")) xctx->graph_sim_type = "tran";
|
|
|
|
|
else if(type && strcmp(type, "tran")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else xctx->graph_sim_type = "tran";
|
|
|
|
|
dbg(dbglev, "read_dataset(): tran graph_sim_type=%s\n", xctx->graph_sim_type ? xctx->graph_sim_type : "<NULL>");
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
2022-08-12 00:06:14 +02:00
|
|
|
else if(!strncmp(line, "Plotname:", 9) && strstr(line, "DC transfer characteristic")) {
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type && strcmp(xctx->graph_sim_type, "dc")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else if(type && !strcmp(type, "dc")) xctx->graph_sim_type = "dc";
|
|
|
|
|
else if(type && strcmp(type, "dc")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else xctx->graph_sim_type = "dc";
|
|
|
|
|
dbg(dbglev, "read_dataset(): dc graph_sim_type=%s\n", xctx->graph_sim_type ? xctx->graph_sim_type : "<NULL>");
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
2022-08-12 00:06:14 +02:00
|
|
|
else if(!strncmp(line, "Plotname:", 9) && strstr(line, "Operating Point")) {
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type && strcmp(xctx->graph_sim_type, "op")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else if(type && !strcmp(type, "op")) xctx->graph_sim_type = "op";
|
|
|
|
|
else if(type && strcmp(type, "op")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else xctx->graph_sim_type = "op";
|
|
|
|
|
dbg(dbglev, "read_dataset(): op graph_sim_type=%s\n", xctx->graph_sim_type ? xctx->graph_sim_type : "<NULL>");
|
2022-08-03 17:44:53 +02:00
|
|
|
}
|
2022-08-12 00:06:14 +02:00
|
|
|
else if(!strncmp(line, "Plotname:", 9) && strstr(line, "AC Analysis")) {
|
2022-09-20 16:49:42 +02:00
|
|
|
ac = 1;
|
|
|
|
|
if(xctx->graph_sim_type && strcmp(xctx->graph_sim_type, "ac")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else if(type && !strcmp(type, "ac")) xctx->graph_sim_type = "ac";
|
|
|
|
|
else if(type && strcmp(type, "ac")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else xctx->graph_sim_type = "ac";
|
|
|
|
|
dbg(dbglev, "read_dataset(): ac graph_sim_type=%s\n", xctx->graph_sim_type ? xctx->graph_sim_type : "<NULL>");
|
2022-08-14 14:14:19 +02:00
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
else if(!strncmp(line, "Plotname:", 9)) {
|
2022-09-20 16:49:42 +02:00
|
|
|
char name[PATH_MAX];
|
|
|
|
|
xctx->graph_sim_type = NULL;
|
|
|
|
|
n = sscanf(line, "Plotname: %s", name);
|
|
|
|
|
if(n==1) {
|
|
|
|
|
if(xctx->graph_sim_type && strcmp(xctx->graph_sim_type, "custom")) xctx->graph_sim_type = NULL;
|
|
|
|
|
else if(type && !strcmp(type, name)) xctx->graph_sim_type = "custom";
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
/* points and vars are needed for all sections (also ones we are not interested in)
|
|
|
|
|
* to skip binary blobs */
|
|
|
|
|
else if(!strncmp(line, "No. of Data Rows :", 18)) {
|
|
|
|
|
/* array of number of points of datasets (they are of varialbe length) */
|
2022-09-20 16:49:42 +02:00
|
|
|
n = sscanf(line, "No. of Data Rows : %d", &npoints);
|
2022-09-09 18:57:34 +02:00
|
|
|
if(n < 1) {
|
|
|
|
|
dbg(0, "read_dataset(): WAARNING: malformed raw file, aborting\n");
|
2022-09-20 23:16:59 +02:00
|
|
|
free_rawfile(0);
|
2022-09-09 18:57:34 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type) {
|
|
|
|
|
my_realloc(1414, &xctx->graph_npoints, (xctx->graph_datasets+1) * sizeof(int));
|
|
|
|
|
xctx->graph_npoints[xctx->graph_datasets] = npoints;
|
|
|
|
|
/* multi-point OP is equivalent to a DC sweep. Change xctx->graph_sim_type */
|
|
|
|
|
if(xctx->graph_npoints[xctx->graph_datasets] > 1 && !strcmp(xctx->graph_sim_type, "op") ) {
|
|
|
|
|
xctx->graph_sim_type = "dc";
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
done_points = 1;
|
|
|
|
|
}
|
|
|
|
|
else if(!strncmp(line, "No. Variables:", 14)) {
|
2022-09-20 16:49:42 +02:00
|
|
|
n = sscanf(line, "No. Variables: %d", &nvars);
|
|
|
|
|
dbg(dbglev, "read_dataset(): nvars=%d\n", nvars);
|
|
|
|
|
if(ac) nvars <<= 1;
|
2022-09-09 18:57:34 +02:00
|
|
|
if(n < 1) {
|
|
|
|
|
dbg(0, "read_dataset(): WAARNING: malformed raw file, aborting\n");
|
2022-09-20 23:16:59 +02:00
|
|
|
free_rawfile(0);
|
2022-09-09 18:57:34 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type) {
|
|
|
|
|
xctx->graph_nvars = nvars;
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
else if(!done_points && !strncmp(line, "No. Points:", 11)) {
|
2022-09-20 16:49:42 +02:00
|
|
|
n = sscanf(line, "No. Points: %d", &npoints);
|
2022-09-09 18:57:34 +02:00
|
|
|
if(n < 1) {
|
|
|
|
|
dbg(0, "read_dataset(): WAARNING: malformed raw file, aborting\n");
|
2022-09-20 23:16:59 +02:00
|
|
|
free_rawfile(0);
|
2022-09-09 18:57:34 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type) {
|
|
|
|
|
my_realloc(1415, &xctx->graph_npoints, (xctx->graph_datasets+1) * sizeof(int));
|
|
|
|
|
xctx->graph_npoints[xctx->graph_datasets] = npoints;
|
|
|
|
|
/* multi-point OP is equivalent to a DC sweep. Change xctx->graph_sim_type */
|
|
|
|
|
if(xctx->graph_npoints[xctx->graph_datasets] > 1 && !strcmp(xctx->graph_sim_type, "op") ) {
|
|
|
|
|
xctx->graph_sim_type = "dc";
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type && !done_header && variables) {
|
2022-01-21 19:17:43 +01:00
|
|
|
/* get the list of lines with index and node name */
|
|
|
|
|
if(!xctx->graph_names) xctx->graph_names = my_calloc(426, xctx->graph_nvars, sizeof(char *));
|
2022-09-09 18:57:34 +02:00
|
|
|
n = sscanf(line, "%d %s", &i, varname); /* read index and name of saved waveform */
|
|
|
|
|
if(n < 2) {
|
|
|
|
|
dbg(0, "read_dataset(): WAARNING: malformed raw file, aborting\n");
|
2022-09-20 23:16:59 +02:00
|
|
|
free_rawfile(0);
|
2022-09-09 18:57:34 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-09-11 10:52:52 +02:00
|
|
|
strtolower(varname);
|
2022-09-13 00:31:20 +02:00
|
|
|
/* transform ':' hierarchy separators (Xyce) to '.' */
|
|
|
|
|
ptr = varname;
|
|
|
|
|
while(*ptr) {
|
|
|
|
|
if(*ptr == ':') *ptr = '.';
|
|
|
|
|
ptr++;
|
2022-09-11 10:52:52 +02:00
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->graph_sim_type && !strcmp(xctx->graph_sim_type, "ac")) { /* AC */
|
2022-02-04 17:35:07 +01:00
|
|
|
my_strcat(415, &xctx->graph_names[i << 1], varname);
|
2022-08-27 12:56:33 +02:00
|
|
|
int_hash_lookup(xctx->graph_raw_table, xctx->graph_names[i << 1], (i << 1), XINSERT_NOREPLACE);
|
2022-09-11 10:52:52 +02:00
|
|
|
if(strstr(varname, "v(") == varname || strstr(varname, "i(") == varname)
|
2022-02-04 17:35:07 +01:00
|
|
|
my_mstrcat(664, &xctx->graph_names[(i << 1) + 1], "ph(", varname + 2, NULL);
|
2022-02-02 18:33:16 +01:00
|
|
|
else
|
2022-02-03 00:40:59 +01:00
|
|
|
my_mstrcat(540, &xctx->graph_names[(i << 1) + 1], "ph(", varname, ")", NULL);
|
2022-08-27 12:56:33 +02:00
|
|
|
int_hash_lookup(xctx->graph_raw_table, xctx->graph_names[(i << 1) + 1], (i << 1) + 1, XINSERT_NOREPLACE);
|
2022-02-02 18:33:16 +01:00
|
|
|
} else {
|
|
|
|
|
my_strcat(541, &xctx->graph_names[i], varname);
|
2022-08-27 12:56:33 +02:00
|
|
|
int_hash_lookup(xctx->graph_raw_table, xctx->graph_names[i], i, XINSERT_NOREPLACE);
|
2022-02-02 18:33:16 +01:00
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
/* use hash table to store index number of variables */
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(dbglev, "read_dataset(): get node list -> names[%d] = %s\n", i, xctx->graph_names[i]);
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
/* after this line comes the list of indexes and associated nodes */
|
2022-02-02 18:33:16 +01:00
|
|
|
if(xctx->graph_sim_type && !strncmp(line, "Variables:", 10)) {
|
2022-01-21 19:17:43 +01:00
|
|
|
variables = 1 ;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
if(exit_status == 0 && xctx->graph_datasets && xctx->graph_npoints) {
|
|
|
|
|
dbg(dbglev, "raw file read: datasets=%d, last dataset points=%d, nvars=%d\n",
|
|
|
|
|
xctx->graph_datasets, xctx->graph_npoints[xctx->graph_datasets-1], xctx->graph_nvars);
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
return exit_status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void free_rawfile(int dr)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
int deleted = 0;
|
|
|
|
|
if(xctx->graph_names) {
|
|
|
|
|
deleted = 1;
|
|
|
|
|
for(i = 0 ; i < xctx->graph_nvars; i++) {
|
|
|
|
|
my_free(510, &xctx->graph_names[i]);
|
|
|
|
|
}
|
|
|
|
|
my_free(968, &xctx->graph_names);
|
|
|
|
|
}
|
|
|
|
|
if(xctx->graph_values) {
|
|
|
|
|
deleted = 1;
|
2022-02-12 04:55:02 +01:00
|
|
|
/* free also extra column for custom data plots */
|
|
|
|
|
for(i = 0 ; i <= xctx->graph_nvars; i++) {
|
2022-01-21 19:17:43 +01:00
|
|
|
my_free(512, &xctx->graph_values[i]);
|
|
|
|
|
}
|
|
|
|
|
my_free(528, &xctx->graph_values);
|
|
|
|
|
}
|
|
|
|
|
if(xctx->graph_npoints) my_free(1413, &xctx->graph_npoints);
|
2022-02-05 00:28:06 +01:00
|
|
|
xctx->graph_allpoints = 0;
|
2022-08-27 12:56:33 +02:00
|
|
|
if(xctx->graph_raw_schname) my_free(1393, &xctx->graph_raw_schname);
|
2022-09-21 13:58:01 +02:00
|
|
|
xctx->graph_raw_level = -1;
|
|
|
|
|
tclsetintvar("graph_raw_level", -1);
|
2022-01-21 19:17:43 +01:00
|
|
|
xctx->graph_datasets = 0;
|
|
|
|
|
xctx->graph_nvars = 0;
|
2022-09-21 11:25:45 +02:00
|
|
|
xctx->graph_annotate_p = -1;
|
2022-08-27 12:56:33 +02:00
|
|
|
int_hash_free(xctx->graph_raw_table);
|
2022-01-21 19:17:43 +01:00
|
|
|
if(deleted && dr) draw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* caller must free returned pointer */
|
|
|
|
|
char *base64_from_file(const char *f, size_t *length)
|
|
|
|
|
{
|
|
|
|
|
FILE *fd;
|
|
|
|
|
struct stat st;
|
|
|
|
|
unsigned char *s = NULL;
|
|
|
|
|
char *b64s = NULL;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
if (stat(f, &st) == 0 && ( (st.st_mode & S_IFMT) == S_IFREG) ) {
|
|
|
|
|
len = st.st_size;
|
|
|
|
|
fd = fopen(f, fopen_read_mode);
|
|
|
|
|
if(fd) {
|
|
|
|
|
s = my_malloc(1475, len);
|
|
|
|
|
fread(s, len, 1, fd);
|
|
|
|
|
fclose(fd);
|
|
|
|
|
b64s = base64_encode(s, len, length, 1);
|
|
|
|
|
my_free(1477, &s);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
dbg(0, "base64_from_file(): failed to open file %s for reading\n", f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return b64s;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-20 16:49:42 +02:00
|
|
|
int raw_read_from_attr(const char *type)
|
2022-01-21 19:17:43 +01:00
|
|
|
{
|
|
|
|
|
int res = 0;
|
|
|
|
|
unsigned char *s;
|
|
|
|
|
size_t decoded_length;
|
|
|
|
|
FILE *fd;
|
|
|
|
|
char *tmp_filename;
|
|
|
|
|
|
2022-09-20 16:49:42 +02:00
|
|
|
|
2022-01-21 19:17:43 +01:00
|
|
|
if(xctx->graph_values || xctx->graph_npoints || xctx->graph_nvars || xctx->graph_datasets) {
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(0, "raw_read(_from_attr(): must clear current raw file before loading new\n");
|
2022-01-21 19:17:43 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
if(xctx->lastsel==1 && xctx->sel_array[0].type==ELEMENT) {
|
|
|
|
|
xInstance *i = &xctx->inst[xctx->sel_array[0].n];
|
|
|
|
|
const char *b64_spice_data;
|
|
|
|
|
size_t length;
|
|
|
|
|
if(i->prop_ptr && (b64_spice_data = get_tok_value(i->prop_ptr, "spice_data", 0))[0]) {
|
|
|
|
|
length = strlen(b64_spice_data);
|
|
|
|
|
if( (fd = open_tmpfile("embedded_rawfile_", &tmp_filename)) ) {
|
|
|
|
|
s = base64_decode(b64_spice_data, length, &decoded_length);
|
|
|
|
|
fwrite(s, decoded_length, 1, fd);
|
|
|
|
|
fclose(fd);
|
|
|
|
|
my_free(1479, &s);
|
|
|
|
|
res = raw_read(tmp_filename, type);
|
|
|
|
|
unlink(tmp_filename);
|
|
|
|
|
} else {
|
|
|
|
|
dbg(0, "read_rawfile_from_attr(): failed to open file %s for reading\n", tmp_filename);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* read a ngspice raw file (with data portion in binary format) */
|
2022-09-20 16:49:42 +02:00
|
|
|
int raw_read(const char *f, const char *type)
|
2022-01-21 19:17:43 +01:00
|
|
|
{
|
|
|
|
|
int res = 0;
|
|
|
|
|
FILE *fd;
|
|
|
|
|
if(xctx->graph_values || xctx->graph_npoints || xctx->graph_nvars || xctx->graph_datasets) {
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(0, "raw_read(): must clear current raw file before loading new\n");
|
2022-01-21 19:17:43 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
fd = fopen(f, fopen_read_mode);
|
|
|
|
|
if(fd) {
|
2022-09-20 16:49:42 +02:00
|
|
|
if((res = read_dataset(fd, type)) == 1) {
|
2022-02-05 00:28:06 +01:00
|
|
|
int i;
|
2022-08-27 12:56:33 +02:00
|
|
|
my_strdup2(1394, &xctx->graph_raw_schname, xctx->sch[xctx->currsch]);
|
2022-09-21 13:58:01 +02:00
|
|
|
xctx->graph_raw_level = xctx->currsch;
|
|
|
|
|
tclsetintvar("graph_raw_level", xctx->currsch);
|
2022-02-05 00:28:06 +01:00
|
|
|
xctx->graph_allpoints = 0;
|
|
|
|
|
for(i = 0; i < xctx->graph_datasets; i++) {
|
|
|
|
|
xctx->graph_allpoints += xctx->graph_npoints[i];
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(0, "Raw file data read: %s\n", f);
|
|
|
|
|
dbg(0, "points=%d, vars=%d, datasets=%d\n",
|
|
|
|
|
xctx->graph_allpoints, xctx->graph_nvars, xctx->graph_datasets);
|
2022-01-21 19:17:43 +01:00
|
|
|
} else {
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(0, "raw_read(): no useful data found\n");
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
fclose(fd);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2022-09-20 16:49:42 +02:00
|
|
|
dbg(0, "raw_read(): failed to open file %s for reading\n", f);
|
2022-01-21 19:17:43 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-09 02:11:09 +02:00
|
|
|
|
|
|
|
|
/* given a node XXyy try XXyy , xxyy, XXYY, v(XXyy), v(xxyy), V(XXYY) */
|
2022-01-21 19:17:43 +01:00
|
|
|
int get_raw_index(const char *node)
|
|
|
|
|
{
|
2022-09-09 18:57:34 +02:00
|
|
|
char inode[512];
|
2022-09-09 02:11:09 +02:00
|
|
|
char vnode[512];
|
2022-01-21 19:17:43 +01:00
|
|
|
Int_hashentry *entry;
|
2022-09-09 18:57:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
dbg(1, "get_raw_index(): node=%s\n", node);
|
2022-09-21 11:25:45 +02:00
|
|
|
if(sch_waves_loaded() >= 0) {
|
2022-09-11 10:52:52 +02:00
|
|
|
my_strncpy(inode, node, S(inode));
|
|
|
|
|
strtolower(inode);
|
2022-09-09 18:57:34 +02:00
|
|
|
entry = int_hash_lookup(xctx->graph_raw_table, inode, 0, XLOOKUP);
|
2022-01-21 19:17:43 +01:00
|
|
|
if(!entry) {
|
2022-09-11 10:52:52 +02:00
|
|
|
my_snprintf(vnode, S(vnode), "v(%s)", inode);
|
|
|
|
|
entry = int_hash_lookup(xctx->graph_raw_table, vnode, 0, XLOOKUP);
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
2022-09-13 00:31:20 +02:00
|
|
|
if(!entry && strstr(inode, "i(v.x")) {
|
|
|
|
|
char *ptr = inode;
|
|
|
|
|
inode[2] = 'i';
|
|
|
|
|
inode[3] = '(';
|
|
|
|
|
ptr += 2;
|
|
|
|
|
entry = int_hash_lookup(xctx->graph_raw_table, ptr, 0, XLOOKUP);
|
|
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
if(entry) return entry->value;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-17 01:37:04 +01:00
|
|
|
/* store calculated custom graph data for later retrieval as in running average calculations
|
|
|
|
|
* what:
|
2022-02-16 20:24:22 +01:00
|
|
|
* 0: clear data
|
|
|
|
|
* 1: store value
|
|
|
|
|
* 2: retrieve value
|
|
|
|
|
*/
|
|
|
|
|
static double ravg_store(int what , int i, int p, int last, double integ)
|
|
|
|
|
{
|
|
|
|
|
static int imax = 0;
|
|
|
|
|
static double **arr = NULL;
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
if(what == 0 && imax) {
|
|
|
|
|
for(j = 0; j < imax; j++) {
|
|
|
|
|
my_free(1512, &arr[j]);
|
|
|
|
|
}
|
|
|
|
|
my_free(1513, &arr);
|
|
|
|
|
imax = 0;
|
|
|
|
|
} else if(what == 1) {
|
|
|
|
|
if(i >= imax) {
|
|
|
|
|
int new_size = i + 4;
|
|
|
|
|
my_realloc(1514, &arr, sizeof(double *) * new_size);
|
|
|
|
|
for(j = imax; j < new_size; j++) {
|
|
|
|
|
arr[j] = my_calloc(1515, last + 1, sizeof(double));
|
|
|
|
|
}
|
|
|
|
|
imax = new_size;
|
|
|
|
|
}
|
|
|
|
|
arr[i][p] = integ;
|
|
|
|
|
} else if(what == 2) {
|
|
|
|
|
return arr[i][p];
|
|
|
|
|
}
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-13 02:51:14 +01:00
|
|
|
#define STACKMAX 200
|
2022-02-12 04:55:02 +01:00
|
|
|
#define PLUS -2
|
|
|
|
|
#define MINUS -3
|
|
|
|
|
#define MULT -4
|
|
|
|
|
#define DIVIS -5
|
|
|
|
|
#define POW -6
|
|
|
|
|
#define SIN -7
|
|
|
|
|
#define COS -8
|
2022-02-13 02:51:14 +01:00
|
|
|
#define EXP -9
|
|
|
|
|
#define LN -10
|
|
|
|
|
#define LOG10 -11
|
|
|
|
|
#define ABS -12
|
|
|
|
|
#define SGN -13
|
2022-02-14 22:32:45 +01:00
|
|
|
#define SQRT -14
|
|
|
|
|
#define TAN -15
|
|
|
|
|
#define INTEG -34
|
|
|
|
|
#define AVG -35
|
|
|
|
|
#define DERIV -36
|
|
|
|
|
#define EXCH -37
|
|
|
|
|
#define DUP -38
|
2022-02-16 20:24:22 +01:00
|
|
|
#define RAVG -39 /* running average */
|
2022-08-03 17:44:53 +02:00
|
|
|
#define DB20 -40
|
2022-09-16 12:16:26 +02:00
|
|
|
#define DERIV0 -41 /* derivative to first sweep variable, regardless of specified sweep_idx */
|
2022-02-12 04:55:02 +01:00
|
|
|
#define NUMBER -60
|
2022-02-13 02:51:14 +01:00
|
|
|
|
2022-09-29 18:22:55 +02:00
|
|
|
#define ORDER_DERIV 2 /* 1 or 2: 1st order or 2nd order differentiation. 1st order is faster */
|
|
|
|
|
|
2022-02-12 04:55:02 +01:00
|
|
|
typedef struct {
|
|
|
|
|
int i;
|
|
|
|
|
double d;
|
2022-02-12 13:20:24 +01:00
|
|
|
double prevy;
|
2022-09-29 18:22:55 +02:00
|
|
|
double prevprevy;
|
2022-02-16 20:24:22 +01:00
|
|
|
double prev;
|
|
|
|
|
int prevp;
|
2022-02-12 04:55:02 +01:00
|
|
|
} Stack1;
|
|
|
|
|
|
2022-02-14 19:28:24 +01:00
|
|
|
int plot_raw_custom_data(int sweep_idx, int first, int last, const char *expr)
|
2022-02-05 00:28:06 +01:00
|
|
|
{
|
2022-02-12 13:20:24 +01:00
|
|
|
int i, p, idx;
|
2022-02-12 04:55:02 +01:00
|
|
|
const char *n;
|
2022-02-12 11:04:39 +01:00
|
|
|
char *endptr, *ntok_copy = NULL, *ntok_save, *ntok_ptr;
|
2022-02-13 02:51:14 +01:00
|
|
|
Stack1 stack1[STACKMAX];
|
2022-09-22 21:12:40 +02:00
|
|
|
double stack2[STACKMAX], tmp, integ, deriv, avg;
|
2022-02-12 04:55:02 +01:00
|
|
|
int stackptr1 = 0, stackptr2 = 0;
|
|
|
|
|
SPICE_DATA *y = xctx->graph_values[xctx->graph_nvars]; /* custom plot data column */
|
2022-02-05 02:16:27 +01:00
|
|
|
SPICE_DATA *x = xctx->graph_values[sweep_idx];
|
2022-09-16 12:16:26 +02:00
|
|
|
SPICE_DATA *sweepx = xctx->graph_values[0];
|
2022-02-12 04:55:02 +01:00
|
|
|
|
2022-02-12 11:04:39 +01:00
|
|
|
my_strdup2(574, &ntok_copy, expr);
|
|
|
|
|
ntok_ptr = ntok_copy;
|
2022-02-14 17:51:18 +01:00
|
|
|
dbg(1, "plot_raw_custom_data(): expr=%s\n", expr);
|
2022-02-13 02:51:14 +01:00
|
|
|
while( (n = my_strtok_r(ntok_ptr, " \t\n", "", &ntok_save)) ) {
|
2022-02-14 17:51:18 +01:00
|
|
|
if(stackptr1 >= STACKMAX -2) {
|
2022-02-13 02:51:14 +01:00
|
|
|
dbg(0, "stack overflow in graph expression parsing. Interrupted\n");
|
|
|
|
|
my_free(576, &ntok_copy);
|
2022-02-14 19:28:24 +01:00
|
|
|
return -1;
|
2022-02-13 02:51:14 +01:00
|
|
|
}
|
2022-02-12 11:04:39 +01:00
|
|
|
ntok_ptr = NULL;
|
|
|
|
|
dbg(1, " plot_raw_custom_data(): n = %s\n", n);
|
2022-02-12 04:55:02 +01:00
|
|
|
if(!strcmp(n, "+")) stack1[stackptr1++].i = PLUS;
|
|
|
|
|
else if(!strcmp(n, "-")) stack1[stackptr1++].i = MINUS;
|
|
|
|
|
else if(!strcmp(n, "*")) stack1[stackptr1++].i = MULT;
|
|
|
|
|
else if(!strcmp(n, "/")) stack1[stackptr1++].i = DIVIS;
|
|
|
|
|
else if(!strcmp(n, "**")) stack1[stackptr1++].i = POW;
|
|
|
|
|
else if(!strcmp(n, "sin()")) stack1[stackptr1++].i = SIN;
|
|
|
|
|
else if(!strcmp(n, "cos()")) stack1[stackptr1++].i = COS;
|
|
|
|
|
else if(!strcmp(n, "abs()")) stack1[stackptr1++].i = ABS;
|
|
|
|
|
else if(!strcmp(n, "sgn()")) stack1[stackptr1++].i = SGN;
|
2022-02-14 22:32:45 +01:00
|
|
|
else if(!strcmp(n, "sqrt()")) stack1[stackptr1++].i = SQRT;
|
|
|
|
|
else if(!strcmp(n, "tan()")) stack1[stackptr1++].i = TAN;
|
2022-02-13 02:51:14 +01:00
|
|
|
else if(!strcmp(n, "exp()")) stack1[stackptr1++].i = EXP;
|
|
|
|
|
else if(!strcmp(n, "ln()")) stack1[stackptr1++].i = LN;
|
|
|
|
|
else if(!strcmp(n, "log10()")) stack1[stackptr1++].i = LOG10;
|
2022-02-12 04:55:02 +01:00
|
|
|
else if(!strcmp(n, "integ()")) stack1[stackptr1++].i = INTEG;
|
2022-02-12 13:20:24 +01:00
|
|
|
else if(!strcmp(n, "avg()")) stack1[stackptr1++].i = AVG;
|
2022-02-16 20:24:22 +01:00
|
|
|
else if(!strcmp(n, "ravg()")) stack1[stackptr1++].i = RAVG;
|
2022-08-03 17:44:53 +02:00
|
|
|
else if(!strcmp(n, "db20()")) stack1[stackptr1++].i = DB20;
|
2022-02-12 04:55:02 +01:00
|
|
|
else if(!strcmp(n, "deriv()")) stack1[stackptr1++].i = DERIV;
|
2022-09-16 12:16:26 +02:00
|
|
|
else if(!strcmp(n, "deriv0()")) stack1[stackptr1++].i = DERIV0;
|
2022-02-14 17:51:18 +01:00
|
|
|
else if(!strcmp(n, "exch()")) stack1[stackptr1++].i = EXCH;
|
|
|
|
|
else if(!strcmp(n, "dup()")) stack1[stackptr1++].i = DUP;
|
2022-09-22 21:12:40 +02:00
|
|
|
else if( (strtod(n, &endptr)), endptr > n) {
|
2022-02-12 04:55:02 +01:00
|
|
|
stack1[stackptr1].i = NUMBER;
|
2022-09-22 21:12:40 +02:00
|
|
|
stack1[stackptr1++].d = atof_spice(n);
|
2022-02-12 04:55:02 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
idx = get_raw_index(n);
|
|
|
|
|
if(idx == -1) {
|
|
|
|
|
dbg(1, "plot_raw_custom_data(): no data found: %s\n", n);
|
2022-02-13 02:51:14 +01:00
|
|
|
my_free(645, &ntok_copy);
|
2022-02-14 19:28:24 +01:00
|
|
|
return -1; /* no data found in raw file */
|
2022-02-12 04:55:02 +01:00
|
|
|
}
|
|
|
|
|
stack1[stackptr1].i = idx;
|
|
|
|
|
stackptr1++;
|
|
|
|
|
}
|
|
|
|
|
dbg(1, " plot_raw_custom_data(): stack1= %d\n", stack1[stackptr1 - 1].i);
|
2022-02-14 22:32:45 +01:00
|
|
|
} /* while(n = my_strtok_r(...) */
|
2022-02-12 11:04:39 +01:00
|
|
|
my_free(575, &ntok_copy);
|
2022-02-12 13:20:24 +01:00
|
|
|
for(p = first ; p <= last; p++) {
|
|
|
|
|
stackptr2 = 0;
|
|
|
|
|
for(i = 0; i < stackptr1; i++) { /* number */
|
|
|
|
|
if(stack1[i].i == NUMBER) {
|
|
|
|
|
stack2[stackptr2++] = stack1[i].d;
|
|
|
|
|
}
|
2022-02-14 17:51:18 +01:00
|
|
|
else if(stack1[i].i >=0 && stack1[i].i < xctx->graph_nvars) { /* spice node */
|
2022-02-12 13:20:24 +01:00
|
|
|
stack2[stackptr2++] = xctx->graph_values[stack1[i].i][p];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(stackptr2 > 1) { /* 2 argument operators */
|
2022-02-14 22:32:45 +01:00
|
|
|
switch(stack1[i].i) {
|
|
|
|
|
case PLUS:
|
2022-09-22 13:45:55 +02:00
|
|
|
stack2[stackptr2 - 2] = stack2[stackptr2 - 2] + stack2[stackptr2 - 1];
|
2022-02-14 22:32:45 +01:00
|
|
|
stackptr2--;
|
|
|
|
|
break;
|
|
|
|
|
case MINUS:
|
2022-09-22 13:45:55 +02:00
|
|
|
stack2[stackptr2 - 2] = stack2[stackptr2 - 2] - stack2[stackptr2 - 1];
|
2022-02-14 22:32:45 +01:00
|
|
|
stackptr2--;
|
|
|
|
|
break;
|
|
|
|
|
case MULT:
|
2022-09-22 13:45:55 +02:00
|
|
|
stack2[stackptr2 - 2] = stack2[stackptr2 - 2] * stack2[stackptr2 - 1];
|
2022-02-14 22:32:45 +01:00
|
|
|
stackptr2--;
|
|
|
|
|
break;
|
|
|
|
|
case DIVIS:
|
|
|
|
|
if(stack2[stackptr2 - 1]) {
|
2022-09-22 13:45:55 +02:00
|
|
|
stack2[stackptr2 - 2] = stack2[stackptr2 - 2] / stack2[stackptr2 - 1];
|
|
|
|
|
} else if(stack2[stackptr2 - 2] == 0.0) {
|
|
|
|
|
stack2[stackptr2 - 2] = 0;
|
2022-02-14 22:32:45 +01:00
|
|
|
} else {
|
2022-02-16 20:24:22 +01:00
|
|
|
stack2[stackptr2 - 2] = y[p - 1];
|
|
|
|
|
}
|
|
|
|
|
stackptr2--;
|
|
|
|
|
break;
|
|
|
|
|
case RAVG:
|
|
|
|
|
if( p == first ) {
|
|
|
|
|
integ = 0;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 2];
|
|
|
|
|
stack1[i].prev = 0;
|
|
|
|
|
stack1[i].prevp = first;
|
|
|
|
|
} else {
|
|
|
|
|
integ = stack1[i].prev + (x[p] - x[p - 1]) * (stack1[i].prevy + stack2[stackptr2 - 2]) * 0.5;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 2];
|
|
|
|
|
stack1[i].prev = integ;
|
2022-02-14 22:32:45 +01:00
|
|
|
}
|
2022-02-16 20:24:22 +01:00
|
|
|
ravg_store(1, i, p, last, integ);
|
|
|
|
|
|
|
|
|
|
while(stack1[i].prevp <= last && x[p] - x[stack1[i].prevp] > stack2[stackptr2 - 1]) {
|
|
|
|
|
dbg(1, "%g --> %g\n", x[stack1[i].prevp], x[p]);
|
|
|
|
|
stack1[i].prevp++;
|
|
|
|
|
}
|
|
|
|
|
stack2[stackptr2 - 2] = (integ - ravg_store(2, i, stack1[i].prevp, 0, 0)) / stack2[stackptr2 - 1];
|
|
|
|
|
dbg(1, "integ=%g ravg_store=%g\n", integ, ravg_store(2, i, stack1[i].prevp, 0, 0));
|
2022-02-14 22:32:45 +01:00
|
|
|
stackptr2--;
|
|
|
|
|
break;
|
|
|
|
|
case POW:
|
|
|
|
|
stack2[stackptr2 - 2] = pow(stack2[stackptr2 - 2], stack2[stackptr2 - 1]);
|
|
|
|
|
stackptr2--;
|
|
|
|
|
break;
|
|
|
|
|
case EXCH:
|
|
|
|
|
tmp = stack2[stackptr2 - 2];
|
|
|
|
|
stack2[stackptr2 - 2] = stack2[stackptr2 - 1];
|
|
|
|
|
stack2[stackptr2 - 1] = tmp;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
} /* switch(...) */
|
|
|
|
|
} /* if(stackptr2 > 1) */
|
2022-02-12 13:20:24 +01:00
|
|
|
if(stackptr2 > 0) { /* 1 argument operators */
|
2022-02-14 22:32:45 +01:00
|
|
|
switch(stack1[i].i) {
|
|
|
|
|
case AVG:
|
|
|
|
|
if( p == first ) {
|
|
|
|
|
avg = stack2[stackptr2 - 1];
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
2022-02-16 20:24:22 +01:00
|
|
|
stack1[i].prev = stack2[stackptr2 - 1];
|
2022-02-14 22:32:45 +01:00
|
|
|
} else {
|
2022-02-16 20:24:22 +01:00
|
|
|
if((x[p] != x[first])) {
|
|
|
|
|
avg = stack1[i].prev * (x[p - 1] - x[first]) +
|
2022-02-14 22:32:45 +01:00
|
|
|
(x[p] - x[p - 1]) * (stack1[i].prevy + stack2[stackptr2 - 1]) * 0.5;
|
2022-02-16 20:24:22 +01:00
|
|
|
avg /= (x[p] - x[first]);
|
2022-02-14 22:32:45 +01:00
|
|
|
} else {
|
|
|
|
|
avg = stack1[i].prev;
|
|
|
|
|
}
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
2022-02-16 20:24:22 +01:00
|
|
|
stack1[i].prev = avg;
|
2022-02-14 22:32:45 +01:00
|
|
|
}
|
|
|
|
|
stack2[stackptr2 - 1] = avg;
|
|
|
|
|
break;
|
|
|
|
|
case DUP:
|
|
|
|
|
stack2[stackptr2] = stack2[stackptr2 - 1];
|
|
|
|
|
stackptr2++;
|
|
|
|
|
break;
|
|
|
|
|
case INTEG:
|
|
|
|
|
if( p == first ) {
|
|
|
|
|
integ = 0;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
2022-02-16 20:24:22 +01:00
|
|
|
stack1[i].prev = 0;
|
2022-02-14 22:32:45 +01:00
|
|
|
} else {
|
|
|
|
|
integ = stack1[i].prev + (x[p] - x[p - 1]) * (stack1[i].prevy + stack2[stackptr2 - 1]) * 0.5;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
2022-02-16 20:24:22 +01:00
|
|
|
stack1[i].prev = integ;
|
2022-02-14 22:32:45 +01:00
|
|
|
}
|
|
|
|
|
stack2[stackptr2 - 1] = integ;
|
|
|
|
|
break;
|
2022-09-29 18:22:55 +02:00
|
|
|
#if ORDER_DERIV==1
|
2022-02-14 22:32:45 +01:00
|
|
|
case DERIV:
|
|
|
|
|
if( p == first ) {
|
|
|
|
|
deriv = 0;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
2022-02-16 20:24:22 +01:00
|
|
|
stack1[i].prev = 0;
|
2022-02-14 22:32:45 +01:00
|
|
|
} else {
|
|
|
|
|
if((x[p] != x[p - 1]))
|
|
|
|
|
deriv = (stack2[stackptr2 - 1] - stack1[i].prevy) / (x[p] - x[p - 1]);
|
|
|
|
|
else
|
2022-02-16 20:24:22 +01:00
|
|
|
deriv = stack1[i].prev;
|
2022-02-14 22:32:45 +01:00
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1] ;
|
|
|
|
|
stack1[i].prev = deriv;
|
2022-02-14 17:51:18 +01:00
|
|
|
}
|
2022-02-14 22:32:45 +01:00
|
|
|
stack2[stackptr2 - 1] = deriv;
|
|
|
|
|
break;
|
2022-09-16 12:16:26 +02:00
|
|
|
case DERIV0:
|
|
|
|
|
if( p == first ) {
|
|
|
|
|
deriv = 0;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
|
|
|
|
stack1[i].prev = 0;
|
|
|
|
|
} else {
|
|
|
|
|
if((sweepx[p] != sweepx[p - 1]))
|
|
|
|
|
deriv = (stack2[stackptr2 - 1] - stack1[i].prevy) / (sweepx[p] - sweepx[p - 1]);
|
|
|
|
|
else
|
|
|
|
|
deriv = stack1[i].prev;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1] ;
|
|
|
|
|
stack1[i].prev = deriv;
|
|
|
|
|
}
|
|
|
|
|
stack2[stackptr2 - 1] = deriv;
|
|
|
|
|
break;
|
2022-09-29 18:22:55 +02:00
|
|
|
#else /* second order backward differentiation formulas */
|
|
|
|
|
case DERIV:
|
|
|
|
|
if( p == first ) {
|
|
|
|
|
deriv = 0;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
|
|
|
|
stack1[i].prev = 0;
|
|
|
|
|
} else if(p == first + 1) {
|
|
|
|
|
if((x[p] != x[p - 1]))
|
|
|
|
|
deriv = (stack2[stackptr2 - 1] - stack1[i].prevy) / (x[p] - x[p - 1]);
|
|
|
|
|
else
|
|
|
|
|
deriv = stack1[i].prev;
|
|
|
|
|
stack1[i].prevprevy = stack1[i].prevy;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1] ;
|
|
|
|
|
stack1[i].prev = deriv;
|
|
|
|
|
} else {
|
|
|
|
|
double a = x[p - 2] - x[p];
|
|
|
|
|
double c = x[p - 1] - x[p];
|
|
|
|
|
double b = a * a / 2.0;
|
|
|
|
|
double d = c * c / 2.0;
|
|
|
|
|
double b_on_d = b / d;
|
|
|
|
|
double fa = stack1[i].prevprevy;
|
|
|
|
|
double fb = stack1[i].prevy;
|
|
|
|
|
double fc = stack2[stackptr2 - 1];
|
|
|
|
|
if(a != 0.0)
|
|
|
|
|
deriv = (fa - b_on_d * fb - (1 - b_on_d) * fc ) / (a - c * b_on_d);
|
|
|
|
|
else
|
|
|
|
|
deriv = stack1[i].prev;
|
|
|
|
|
stack1[i].prevprevy = stack1[i].prevy;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1] ;
|
|
|
|
|
stack1[i].prev = deriv;
|
|
|
|
|
}
|
|
|
|
|
stack2[stackptr2 - 1] = deriv;
|
|
|
|
|
break;
|
|
|
|
|
case DERIV0:
|
|
|
|
|
if( p == first ) {
|
|
|
|
|
deriv = 0;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1];
|
|
|
|
|
stack1[i].prev = 0;
|
|
|
|
|
} else if(p == first + 1) {
|
|
|
|
|
if((sweepx[p] != sweepx[p - 1]))
|
|
|
|
|
deriv = (stack2[stackptr2 - 1] - stack1[i].prevy) / (sweepx[p] - sweepx[p - 1]);
|
|
|
|
|
else
|
|
|
|
|
deriv = stack1[i].prev;
|
|
|
|
|
stack1[i].prevprevy = stack1[i].prevy;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1] ;
|
|
|
|
|
stack1[i].prev = deriv;
|
|
|
|
|
} else {
|
|
|
|
|
double a = sweepx[p - 2] - sweepx[p];
|
|
|
|
|
double c = sweepx[p - 1] - sweepx[p];
|
|
|
|
|
double b = a * a / 2.0;
|
|
|
|
|
double d = c * c / 2.0;
|
|
|
|
|
double b_on_d = b / d;
|
|
|
|
|
double fa = stack1[i].prevprevy;
|
|
|
|
|
double fb = stack1[i].prevy;
|
|
|
|
|
double fc = stack2[stackptr2 - 1];
|
|
|
|
|
if(a != 0.0)
|
|
|
|
|
deriv = (fa - b_on_d * fb - (1 - b_on_d) * fc ) / (a - c * b_on_d);
|
|
|
|
|
else
|
|
|
|
|
deriv = stack1[i].prev;
|
|
|
|
|
stack1[i].prevprevy = stack1[i].prevy;
|
|
|
|
|
stack1[i].prevy = stack2[stackptr2 - 1] ;
|
|
|
|
|
stack1[i].prev = deriv;
|
|
|
|
|
}
|
|
|
|
|
stack2[stackptr2 - 1] = deriv;
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
2022-02-14 22:32:45 +01:00
|
|
|
case SQRT:
|
|
|
|
|
stack2[stackptr2 - 1] = sqrt(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
|
|
|
|
case TAN:
|
|
|
|
|
stack2[stackptr2 - 1] = tan(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
|
|
|
|
case SIN:
|
|
|
|
|
stack2[stackptr2 - 1] = sin(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
|
|
|
|
case COS:
|
|
|
|
|
stack2[stackptr2 - 1] = cos(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
|
|
|
|
case ABS:
|
|
|
|
|
stack2[stackptr2 - 1] = fabs(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
|
|
|
|
case EXP:
|
|
|
|
|
stack2[stackptr2 - 1] = exp(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
|
|
|
|
case LN:
|
|
|
|
|
stack2[stackptr2 - 1] = log(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
|
|
|
|
case LOG10:
|
|
|
|
|
stack2[stackptr2 - 1] = log10(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
2022-08-03 17:44:53 +02:00
|
|
|
case DB20:
|
|
|
|
|
stack2[stackptr2 - 1] = 20 * log10(stack2[stackptr2 - 1]);
|
|
|
|
|
break;
|
2022-02-14 22:32:45 +01:00
|
|
|
case SGN:
|
|
|
|
|
stack2[stackptr2 - 1] = stack2[stackptr2 - 1] > 0.0 ? 1 :
|
|
|
|
|
stack2[stackptr2 - 1] < 0.0 ? -1 : 0;
|
|
|
|
|
break;
|
|
|
|
|
} /* switch(...) */
|
|
|
|
|
} /* if(stackptr2 > 0) */
|
2022-02-12 13:20:24 +01:00
|
|
|
} /* for(i = 0; i < stackptr1; i++) */
|
2022-04-27 13:18:45 +02:00
|
|
|
y[p] = (float)stack2[0];
|
2022-02-16 20:24:22 +01:00
|
|
|
} /* for(p = first ...) */
|
|
|
|
|
ravg_store(0, 0, 0, 0, 0.0); /* clear data */
|
2022-02-14 19:28:24 +01:00
|
|
|
return xctx->graph_nvars;
|
2022-02-05 00:28:06 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-21 19:17:43 +01:00
|
|
|
double get_raw_value(int dataset, int idx, int point)
|
|
|
|
|
{
|
|
|
|
|
int i, ofs;
|
|
|
|
|
ofs = 0;
|
|
|
|
|
if(xctx->graph_values) {
|
2022-02-05 00:28:06 +01:00
|
|
|
if(dataset == -1) {
|
|
|
|
|
if(point < xctx->graph_allpoints)
|
|
|
|
|
return xctx->graph_values[idx][point];
|
|
|
|
|
} else {
|
|
|
|
|
for(i = 0; i < dataset; i++) {
|
|
|
|
|
ofs += xctx->graph_npoints[i];
|
|
|
|
|
}
|
2022-08-08 01:18:42 +02:00
|
|
|
if(ofs + point < xctx->graph_allpoints) {
|
2022-08-08 09:52:33 +02:00
|
|
|
return xctx->graph_values[idx][ofs + point];
|
2022-08-08 01:18:42 +02:00
|
|
|
}
|
2022-01-21 19:17:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
/* END SPICE RAWFILE ROUTINES */
|
|
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
/*
|
|
|
|
|
read an unknown xschem record usually like:
|
2020-08-08 15:47:34 +02:00
|
|
|
text {string} text {string}....
|
|
|
|
|
until a '\n' (outside the '{' '}' brackets) or EOF is found.
|
|
|
|
|
within the brackets use load_ascii_string so escapes and string
|
|
|
|
|
newlines are correctly handled
|
|
|
|
|
*/
|
2020-09-26 01:15:33 +02:00
|
|
|
void read_record(int firstchar, FILE *fp, int dbg_level)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
char *str = NULL;
|
2022-09-14 11:37:39 +02:00
|
|
|
int unget = 1;
|
|
|
|
|
|
|
|
|
|
if(firstchar == -1) {
|
|
|
|
|
firstchar = fgetc(fp);
|
|
|
|
|
unget = 0;
|
|
|
|
|
}
|
2020-09-28 15:21:26 +02:00
|
|
|
dbg(dbg_level, "SKIP RECORD\n");
|
2021-11-16 22:28:10 +01:00
|
|
|
if(firstchar != '{') {
|
|
|
|
|
dbg(dbg_level, "%c", firstchar);
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
while((c = fgetc(fp)) != EOF) {
|
2020-10-03 12:49:45 +02:00
|
|
|
if (c=='\r') continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
if(c == '\n') {
|
2020-09-26 01:15:33 +02:00
|
|
|
dbg(dbg_level, "\n");
|
2022-09-14 11:37:39 +02:00
|
|
|
if(unget) ungetc(c, fp); /* so following read_line does not skip next line */
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(c == '{') {
|
|
|
|
|
ungetc(c, fp);
|
|
|
|
|
load_ascii_string(&str, fp);
|
2020-09-26 01:15:33 +02:00
|
|
|
dbg(dbg_level, "{%s}", str);
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2020-09-26 01:15:33 +02:00
|
|
|
dbg(dbg_level, "%c", c);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 15:21:26 +02:00
|
|
|
dbg(dbg_level, "END SKIP RECORD\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
my_free(881, &str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* skip line of text from file, stopping before '\n' or EOF */
|
2020-09-28 15:21:26 +02:00
|
|
|
/* return first portion of line if found or NULL if EOF */
|
2020-08-08 15:47:34 +02:00
|
|
|
char *read_line(FILE *fp, int dbg_level)
|
|
|
|
|
{
|
2020-10-12 13:13:31 +02:00
|
|
|
char s[300];
|
2021-11-20 02:37:56 +01:00
|
|
|
static char ret[300]; /* safe to keep even with multiple schematics */
|
2020-09-28 15:21:26 +02:00
|
|
|
int first = 0, items;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-09-28 15:21:26 +02:00
|
|
|
ret[0] = '\0';
|
2020-10-03 19:50:29 +02:00
|
|
|
while((items = fscanf(fp, "%298[^\r\n]", s)) > 0) {
|
2020-08-08 15:47:34 +02:00
|
|
|
if(!first) {
|
2020-09-28 15:21:26 +02:00
|
|
|
dbg(dbg_level, "SKIPPING |");
|
2020-09-28 08:35:00 +02:00
|
|
|
my_strncpy(ret, s, S(ret)); /* store beginning of line for return */
|
2020-08-08 15:47:34 +02:00
|
|
|
first = 1;
|
|
|
|
|
}
|
2020-09-26 10:30:16 +02:00
|
|
|
dbg(dbg_level, "%s", s);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-09-28 15:21:26 +02:00
|
|
|
if(first) dbg(dbg_level, "|\n");
|
|
|
|
|
return !first && items == EOF ? NULL : ret;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* */
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2021-11-19 23:22:54 +01:00
|
|
|
/* return "/<prefix><random string of random_size characters>"
|
|
|
|
|
* example: "/xschem_undo_dj5hcG38T2"
|
|
|
|
|
*/
|
2022-02-19 14:31:55 +01:00
|
|
|
static const char *random_string(const char *prefix)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-12-22 04:39:23 +01:00
|
|
|
static const char *charset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
2021-11-19 23:22:54 +01:00
|
|
|
static const int random_size=10;
|
|
|
|
|
static char str[PATH_MAX]; /* safe even with multiple schematics, if immediately copied */
|
2022-04-28 10:12:16 +02:00
|
|
|
size_t prefix_size, i;
|
2021-11-20 02:37:56 +01:00
|
|
|
static unsigned short once=1; /* safe even with multiple schematics, set once and never changed */
|
2020-08-08 15:47:34 +02:00
|
|
|
int idx;
|
|
|
|
|
if(once) {
|
|
|
|
|
srand((unsigned short) time(NULL));
|
|
|
|
|
once=0;
|
|
|
|
|
}
|
|
|
|
|
prefix_size = strlen(prefix);
|
|
|
|
|
str[0]='/';
|
|
|
|
|
memcpy(str+1, prefix, prefix_size);
|
|
|
|
|
for(i=prefix_size+1; i < prefix_size + random_size+1; i++) {
|
|
|
|
|
idx = rand()%(sizeof(charset)-1);
|
|
|
|
|
str[i] = charset[idx];
|
|
|
|
|
}
|
|
|
|
|
str[i] ='\0';
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* */
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2021-11-19 23:22:54 +01:00
|
|
|
/* try to create a tmp directory in XSCHEM_TMP_DIR */
|
|
|
|
|
/* XSCHEM_TMP_DIR/<prefix><trailing random chars> */
|
2020-08-08 15:47:34 +02:00
|
|
|
/* after 5 unsuccessfull attemps give up */
|
|
|
|
|
/* and return NULL */
|
|
|
|
|
/* */
|
|
|
|
|
const char *create_tmpdir(char *prefix)
|
|
|
|
|
{
|
2021-11-19 23:22:54 +01:00
|
|
|
static char str[PATH_MAX]; /* safe even with multiple schematics if immediately copied */
|
2020-08-08 15:47:34 +02:00
|
|
|
int i;
|
|
|
|
|
struct stat buf;
|
|
|
|
|
for(i=0; i<5;i++) {
|
|
|
|
|
my_snprintf(str, S(str), "%s%s", tclgetvar("XSCHEM_TMP_DIR"), random_string(prefix));
|
|
|
|
|
if(stat(str, &buf) && !mkdir(str, 0700) ) { /* dir must not exist */
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(1, "create_tmpdir(): created dir: %s\n", str);
|
2020-08-08 15:47:34 +02:00
|
|
|
return str;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(1, "create_tmpdir(): failed to create %s\n", str);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
fprintf(errfp, "create_tmpdir(): failed to create %s, aborting\n", str);
|
|
|
|
|
return NULL; /* failed to create random dir 5 times */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* */
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-12-16 18:30:33 +01:00
|
|
|
/* try to create a tmp file in $XSCHEM_TMP_DIR */
|
|
|
|
|
/* ${XSCHEM_TMP_DIR}/<prefix><trailing random chars> */
|
2020-08-08 15:47:34 +02:00
|
|
|
/* after 5 unsuccessfull attemps give up */
|
|
|
|
|
/* and return NULL */
|
|
|
|
|
/* */
|
|
|
|
|
FILE *open_tmpfile(char *prefix, char **filename)
|
|
|
|
|
{
|
2021-11-19 23:22:54 +01:00
|
|
|
static char str[PATH_MAX]; /* safe even with multiple schematics, if immediately copied */
|
2020-08-08 15:47:34 +02:00
|
|
|
int i;
|
|
|
|
|
FILE *fd;
|
|
|
|
|
struct stat buf;
|
|
|
|
|
for(i=0; i<5;i++) {
|
|
|
|
|
my_snprintf(str, S(str), "%s%s", tclgetvar("XSCHEM_TMP_DIR"), random_string(prefix));
|
|
|
|
|
*filename = str;
|
|
|
|
|
if(stat(str, &buf) && (fd = fopen(str, "w")) ) { /* file must not exist */
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(1, "open_tmpfile(): created file: %s\n", str);
|
2020-08-08 15:47:34 +02:00
|
|
|
return fd;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(1, "open_tmpfile(): failed to create %s\n", str);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
fprintf(errfp, "open_tmpfile(): failed to create %s, aborting\n", str);
|
|
|
|
|
return NULL; /* failed to create random filename 5 times */
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
void updatebbox(int count, xRect *boundbox, xRect *tmp)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
RECTORDER(tmp->x1, tmp->y1, tmp->x2, tmp->y2);
|
2020-10-12 13:13:31 +02:00
|
|
|
/* dbg(1, "updatebbox(): count=%d, tmp = %g %g %g %g\n",
|
2020-08-08 15:47:34 +02:00
|
|
|
count, tmp->x1, tmp->y1, tmp->x2, tmp->y2); */
|
|
|
|
|
if(count==1) *boundbox = *tmp;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(tmp->x1<boundbox->x1) boundbox->x1 = tmp->x1;
|
|
|
|
|
if(tmp->x2>boundbox->x2) boundbox->x2 = tmp->x2;
|
|
|
|
|
if(tmp->y1<boundbox->y1) boundbox->y1 = tmp->y1;
|
|
|
|
|
if(tmp->y2>boundbox->y2) boundbox->y2 = tmp->y2;
|
|
|
|
|
}
|
2020-10-12 13:13:31 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2021-01-06 03:01:14 +01:00
|
|
|
void save_ascii_string(const char *ptr, FILE *fd, int newline)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2022-04-28 10:12:16 +02:00
|
|
|
int c;
|
|
|
|
|
size_t len, strbuf_pos = 0;
|
2021-11-20 02:37:56 +01:00
|
|
|
static char *strbuf = NULL; /* safe even with multiple schematics */
|
2022-04-28 10:12:16 +02:00
|
|
|
static size_t strbuf_size=0; /* safe even with multiple schematics */
|
2021-01-06 03:01:14 +01:00
|
|
|
|
|
|
|
|
if(ptr == NULL) {
|
|
|
|
|
if( fd == NULL) { /* used to clear static data */
|
|
|
|
|
my_free(139, &strbuf);
|
|
|
|
|
strbuf_size = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(newline) fputs("{}\n", fd);
|
|
|
|
|
else fputs("{}", fd);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
len = strlen(ptr) + CADCHUNKALLOC;
|
|
|
|
|
if(strbuf_size < len ) my_realloc(140, &strbuf, (strbuf_size = len));
|
|
|
|
|
|
|
|
|
|
strbuf[strbuf_pos++] = '{';
|
|
|
|
|
while( (c = *ptr++) ) {
|
|
|
|
|
if(strbuf_pos > strbuf_size - 6) my_realloc(525, &strbuf, (strbuf_size += CADCHUNKALLOC));
|
|
|
|
|
if( c=='\\' || c=='{' || c=='}') strbuf[strbuf_pos++] = '\\';
|
2022-04-28 10:12:16 +02:00
|
|
|
strbuf[strbuf_pos++] = (char)c;
|
2021-01-06 03:01:14 +01:00
|
|
|
}
|
|
|
|
|
strbuf[strbuf_pos++] = '}';
|
|
|
|
|
if(newline) strbuf[strbuf_pos++] = '\n';
|
|
|
|
|
strbuf[strbuf_pos] = '\0';
|
|
|
|
|
fwrite(strbuf, 1, strbuf_pos, fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_embedded_symbol(xSymbol *s, FILE *fd)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int c, i, j;
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "v {xschem version=%s file_version=%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION);
|
2022-02-02 02:14:23 +01:00
|
|
|
fprintf(fd, "K ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(s->prop_ptr,fd, 1);
|
2022-02-02 02:14:23 +01:00
|
|
|
fprintf(fd, "G {}\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "V {}\n");
|
|
|
|
|
fprintf(fd, "S {}\n");
|
2020-09-25 18:09:49 +02:00
|
|
|
fprintf(fd, "E {}\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-12 13:13:31 +02:00
|
|
|
xLine *ptr;
|
|
|
|
|
ptr=s->line[c];
|
2020-08-08 15:47:34 +02:00
|
|
|
for(i=0;i<s->lines[c];i++)
|
|
|
|
|
{
|
|
|
|
|
fprintf(fd, "L %d %.16g %.16g %.16g %.16g ", c,ptr[i].x1, ptr[i].y1,ptr[i].x2,
|
|
|
|
|
ptr[i].y2 );
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-12 13:13:31 +02:00
|
|
|
xRect *ptr;
|
|
|
|
|
ptr=s->rect[c];
|
2020-08-08 15:47:34 +02:00
|
|
|
for(i=0;i<s->rects[c];i++)
|
|
|
|
|
{
|
|
|
|
|
fprintf(fd, "B %d %.16g %.16g %.16g %.16g ", c,ptr[i].x1, ptr[i].y1,ptr[i].x2,
|
|
|
|
|
ptr[i].y2);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
|
|
|
|
xArc *ptr;
|
2020-10-12 13:13:31 +02:00
|
|
|
ptr=s->arc[c];
|
2020-08-08 15:47:34 +02:00
|
|
|
for(i=0;i<s->arcs[c];i++)
|
|
|
|
|
{
|
|
|
|
|
fprintf(fd, "A %d %.16g %.16g %.16g %.16g %.16g ", c,ptr[i].x, ptr[i].y,ptr[i].r,
|
|
|
|
|
ptr[i].a, ptr[i].b);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(i=0;i<s->texts;i++)
|
|
|
|
|
{
|
2020-10-12 13:13:31 +02:00
|
|
|
xText *ptr;
|
|
|
|
|
ptr = s->text;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "T ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].txt_ptr,fd, 0);
|
2020-12-05 03:16:01 +01:00
|
|
|
fprintf(fd, " %.16g %.16g %hd %hd %.16g %.16g ",
|
2020-08-08 15:47:34 +02:00
|
|
|
ptr[i].x0, ptr[i].y0, ptr[i].rot, ptr[i].flip, ptr[i].xscale,
|
|
|
|
|
ptr[i].yscale);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-12 13:13:31 +02:00
|
|
|
xPoly *ptr;
|
|
|
|
|
ptr=s->poly[c];
|
2020-08-08 15:47:34 +02:00
|
|
|
for(i=0;i<s->polygons[c];i++)
|
|
|
|
|
{
|
|
|
|
|
fprintf(fd, "P %d %d ", c,ptr[i].points);
|
|
|
|
|
for(j=0;j<ptr[i].points;j++) {
|
|
|
|
|
fprintf(fd, "%.16g %.16g ", ptr[i].x[j], ptr[i].y[j]);
|
|
|
|
|
}
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_inst(FILE *fd, int select_only)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-01-06 03:01:14 +01:00
|
|
|
int i, oldversion;
|
2020-10-12 13:13:31 +02:00
|
|
|
xInstance *ptr;
|
2020-08-08 15:47:34 +02:00
|
|
|
char *tmp = NULL;
|
2022-02-02 02:14:23 +01:00
|
|
|
int *embedded_saved = NULL;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
ptr=xctx->inst;
|
2021-01-06 03:01:14 +01:00
|
|
|
oldversion = !strcmp(xctx->file_version, "1.0");
|
2020-10-15 17:39:21 +02:00
|
|
|
for(i=0;i<xctx->symbols;i++) xctx->sym[i].flags &=~EMBEDDED;
|
2022-02-04 17:35:07 +01:00
|
|
|
embedded_saved = my_calloc(663, xctx->symbols, sizeof(int));
|
2020-10-15 17:39:21 +02:00
|
|
|
for(i=0;i<xctx->instances;i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-05-29 00:45:01 +02:00
|
|
|
if (select_only && ptr[i].sel != SELECTED) continue;
|
2021-01-06 03:01:14 +01:00
|
|
|
fputs("C ", fd);
|
|
|
|
|
if(oldversion) {
|
2021-11-22 12:42:33 +01:00
|
|
|
my_strdup2(57, &tmp, add_ext(ptr[i].name, ".sym"));
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(tmp, fd, 0);
|
|
|
|
|
my_free(882, &tmp);
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].name, fd, 0);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-12-05 03:16:01 +01:00
|
|
|
fprintf(fd, " %.16g %.16g %hd %hd ",ptr[i].x0, ptr[i].y0, ptr[i].rot, ptr[i].flip );
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2022-08-25 00:25:29 +02:00
|
|
|
if( embedded_saved && !embedded_saved[ptr[i].ptr] &&
|
|
|
|
|
!strcmp(get_tok_value(ptr[i].prop_ptr, "embed", 0), "true") ) {
|
2020-10-15 17:39:21 +02:00
|
|
|
/* && !(xctx->sym[ptr[i].ptr].flags & EMBEDDED)) { */
|
2022-02-02 02:14:23 +01:00
|
|
|
embedded_saved[ptr[i].ptr] = 1;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "[\n");
|
2020-10-15 17:39:21 +02:00
|
|
|
save_embedded_symbol( xctx->sym+ptr[i].ptr, fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "]\n");
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->sym[ptr[i].ptr].flags |= EMBEDDED;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-02-02 02:14:23 +01:00
|
|
|
my_free(539, &embedded_saved);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_wire(FILE *fd, int select_only)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int i;
|
2020-10-12 13:13:31 +02:00
|
|
|
xWire *ptr;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
ptr=xctx->wire;
|
|
|
|
|
for(i=0;i<xctx->wires;i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-05-29 00:45:01 +02:00
|
|
|
if (select_only && ptr[i].sel != SELECTED) continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "N %.16g %.16g %.16g %.16g ",ptr[i].x1, ptr[i].y1, ptr[i].x2,
|
|
|
|
|
ptr[i].y2);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-10-12 13:13:31 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_text(FILE *fd, int select_only)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int i;
|
2020-10-12 13:13:31 +02:00
|
|
|
xText *ptr;
|
2020-10-15 17:39:21 +02:00
|
|
|
ptr=xctx->text;
|
|
|
|
|
for(i=0;i<xctx->texts;i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-05-29 00:45:01 +02:00
|
|
|
if (select_only && ptr[i].sel != SELECTED) continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "T ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].txt_ptr,fd, 0);
|
2020-12-05 03:16:01 +01:00
|
|
|
fprintf(fd, " %.16g %.16g %hd %hd %.16g %.16g ",
|
2020-08-08 15:47:34 +02:00
|
|
|
ptr[i].x0, ptr[i].y0, ptr[i].rot, ptr[i].flip, ptr[i].xscale,
|
|
|
|
|
ptr[i].yscale);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_polygon(FILE *fd, int select_only)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int c, i, j;
|
2020-10-12 13:13:31 +02:00
|
|
|
xPoly *ptr;
|
2020-08-08 15:47:34 +02:00
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
ptr=xctx->poly[c];
|
|
|
|
|
for(i=0;i<xctx->polygons[c];i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-05-29 00:45:01 +02:00
|
|
|
if (select_only && ptr[i].sel != SELECTED) continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "P %d %d ", c,ptr[i].points);
|
|
|
|
|
for(j=0;j<ptr[i].points;j++) {
|
|
|
|
|
fprintf(fd, "%.16g %.16g ", ptr[i].x[j], ptr[i].y[j]);
|
|
|
|
|
}
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_arc(FILE *fd, int select_only)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int c, i;
|
|
|
|
|
xArc *ptr;
|
|
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
ptr=xctx->arc[c];
|
|
|
|
|
for(i=0;i<xctx->arcs[c];i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-05-29 00:45:01 +02:00
|
|
|
if (select_only && ptr[i].sel != SELECTED) continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "A %d %.16g %.16g %.16g %.16g %.16g ", c,ptr[i].x, ptr[i].y,ptr[i].r,
|
|
|
|
|
ptr[i].a, ptr[i].b);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_box(FILE *fd, int select_only)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int c, i;
|
2020-10-12 13:13:31 +02:00
|
|
|
xRect *ptr;
|
2020-08-08 15:47:34 +02:00
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
ptr=xctx->rect[c];
|
|
|
|
|
for(i=0;i<xctx->rects[c];i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-05-29 00:45:01 +02:00
|
|
|
if (select_only && ptr[i].sel != SELECTED) continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "B %d %.16g %.16g %.16g %.16g ", c,ptr[i].x1, ptr[i].y1,ptr[i].x2,
|
|
|
|
|
ptr[i].y2);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void save_line(FILE *fd, int select_only)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int c, i;
|
2020-10-12 13:13:31 +02:00
|
|
|
xLine *ptr;
|
2020-08-08 15:47:34 +02:00
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
ptr=xctx->line[c];
|
|
|
|
|
for(i=0;i<xctx->lines[c];i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-05-29 00:45:01 +02:00
|
|
|
if (select_only && ptr[i].sel != SELECTED) continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "L %d %.16g %.16g %.16g %.16g ", c,ptr[i].x1, ptr[i].y1,ptr[i].x2,
|
|
|
|
|
ptr[i].y2 );
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(ptr[i].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:14:23 +01:00
|
|
|
static void write_xschem_file(FILE *fd)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2022-04-28 10:12:16 +02:00
|
|
|
size_t ty=0;
|
2020-12-17 02:01:38 +01:00
|
|
|
char *ptr;
|
2020-10-09 17:29:04 +02:00
|
|
|
|
2020-12-17 03:48:34 +01:00
|
|
|
if(xctx->version_string && (ptr = strstr(xctx->version_string, "xschem")) &&
|
|
|
|
|
(ptr - xctx->version_string < 50)) {
|
2020-12-17 02:01:38 +01:00
|
|
|
my_strdup2(59, &xctx->version_string, subst_token(xctx->version_string, "xschem", NULL));
|
|
|
|
|
}
|
|
|
|
|
my_strdup2(1183, &xctx->version_string, subst_token(xctx->version_string, "version", NULL));
|
|
|
|
|
my_strdup2(1184, &xctx->version_string, subst_token(xctx->version_string, "file_version", NULL));
|
|
|
|
|
ptr = xctx->version_string;
|
2022-09-01 15:10:00 +02:00
|
|
|
while(*ptr == ' ' || *ptr == '\t' || *ptr == '\n') ptr++; /* strip leading spaces */
|
|
|
|
|
fprintf(fd, "v {xschem version=%s file_version=%s\n%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION, ptr);
|
2020-10-12 13:13:31 +02:00
|
|
|
|
|
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
if(xctx->schvhdlprop && !xctx->schsymbolprop) {
|
|
|
|
|
get_tok_value(xctx->schvhdlprop,"type",0);
|
2022-02-04 17:35:07 +01:00
|
|
|
ty = xctx->tok_size;
|
2020-10-15 17:39:21 +02:00
|
|
|
if(ty && !strcmp(xctx->sch[xctx->currsch] + strlen(xctx->sch[xctx->currsch]) - 4,".sym") ) {
|
2020-09-14 10:27:45 +02:00
|
|
|
fprintf(fd, "G {}\nK ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schvhdlprop,fd, 1);
|
2020-09-14 10:27:45 +02:00
|
|
|
} else {
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "G ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schvhdlprop,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(fd, "K ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schsymbolprop,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-09-14 10:27:45 +02:00
|
|
|
} else {
|
|
|
|
|
fprintf(fd, "G ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schvhdlprop,fd, 1);
|
2020-09-14 10:27:45 +02:00
|
|
|
fprintf(fd, "K ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schsymbolprop,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-09-14 10:27:45 +02:00
|
|
|
|
|
|
|
|
fprintf(fd, "V ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schverilogprop,fd, 1);
|
2020-09-14 10:27:45 +02:00
|
|
|
|
|
|
|
|
fprintf(fd, "S ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schprop,fd, 1);
|
2020-09-14 10:27:45 +02:00
|
|
|
|
|
|
|
|
fprintf(fd, "E ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->schtedaxprop,fd, 1);
|
2020-09-14 10:27:45 +02:00
|
|
|
|
2021-05-29 00:45:01 +02:00
|
|
|
save_line(fd, 0);
|
|
|
|
|
save_box(fd, 0);
|
|
|
|
|
save_arc(fd, 0);
|
|
|
|
|
save_polygon(fd, 0);
|
|
|
|
|
save_text(fd, 0);
|
|
|
|
|
save_wire(fd, 0);
|
|
|
|
|
save_inst(fd, 0);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_text(FILE *fd)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2020-09-23 18:15:26 +02:00
|
|
|
const char *str;
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(3, "load_text(): start\n");
|
|
|
|
|
check_text_storage();
|
2020-10-15 17:39:21 +02:00
|
|
|
i=xctx->texts;
|
|
|
|
|
xctx->text[i].txt_ptr=NULL;
|
|
|
|
|
load_ascii_string(&xctx->text[i].txt_ptr,fd);
|
2020-12-05 03:16:01 +01:00
|
|
|
if(fscanf(fd, "%lf %lf %hd %hd %lf %lf ",
|
2020-10-15 17:39:21 +02:00
|
|
|
&xctx->text[i].x0, &xctx->text[i].y0, &xctx->text[i].rot,
|
|
|
|
|
&xctx->text[i].flip, &xctx->text[i].xscale,
|
|
|
|
|
&xctx->text[i].yscale)<6) {
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(errfp,"WARNING: missing fields for TEXT object, ignoring\n");
|
|
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->text[i].prop_ptr=NULL;
|
|
|
|
|
xctx->text[i].font=NULL;
|
|
|
|
|
xctx->text[i].sel=0;
|
|
|
|
|
load_ascii_string(&xctx->text[i].prop_ptr,fd);
|
|
|
|
|
if( xctx->text[i].prop_ptr)
|
|
|
|
|
my_strdup(318, &xctx->text[i].font, get_tok_value(xctx->text[i].prop_ptr, "font", 0));
|
|
|
|
|
|
|
|
|
|
str = get_tok_value(xctx->text[i].prop_ptr, "hcenter", 0);
|
|
|
|
|
xctx->text[i].hcenter = strcmp(str, "true") ? 0 : 1;
|
|
|
|
|
str = get_tok_value(xctx->text[i].prop_ptr, "vcenter", 0);
|
|
|
|
|
xctx->text[i].vcenter = strcmp(str, "true") ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
str = get_tok_value(xctx->text[i].prop_ptr, "layer", 0);
|
|
|
|
|
if(str[0]) xctx->text[i].layer = atoi(str);
|
|
|
|
|
else xctx->text[i].layer = -1;
|
|
|
|
|
xctx->text[i].flags = 0;
|
|
|
|
|
str = get_tok_value(xctx->text[i].prop_ptr, "slant", 0);
|
2022-01-13 12:46:55 +01:00
|
|
|
xctx->text[i].flags |= strcmp(str, "oblique") ? 0 : TEXT_OBLIQUE;
|
|
|
|
|
xctx->text[i].flags |= strcmp(str, "italic") ? 0 : TEXT_ITALIC;
|
2020-10-15 17:39:21 +02:00
|
|
|
str = get_tok_value(xctx->text[i].prop_ptr, "weight", 0);
|
2022-01-13 12:46:55 +01:00
|
|
|
xctx->text[i].flags |= strcmp(str, "bold") ? 0 : TEXT_BOLD;
|
|
|
|
|
str = get_tok_value(xctx->text[i].prop_ptr, "hide", 0);
|
2022-02-22 12:09:04 +01:00
|
|
|
xctx->text[i].flags |= strcmp(str, "true") ? 0 : HIDE_TEXT;
|
2020-10-15 17:39:21 +02:00
|
|
|
|
|
|
|
|
xctx->texts++;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_wire(FILE *fd)
|
|
|
|
|
{
|
2020-11-30 22:48:08 +01:00
|
|
|
xWire *ptr;
|
|
|
|
|
int i;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-11-30 22:48:08 +01:00
|
|
|
check_wire_storage();
|
|
|
|
|
ptr = xctx->wire;
|
|
|
|
|
i = xctx->wires;
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(3, "load_wire(): start\n");
|
2020-11-30 22:48:08 +01:00
|
|
|
if(fscanf(fd, "%lf %lf %lf %lf",&ptr[i].x1, &ptr[i].y1, &ptr[i].x2, &ptr[i].y2 )<4) {
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(errfp,"WARNING: missing fields for WIRE object, ignoring\n");
|
|
|
|
|
read_line(fd, 0);
|
2020-11-30 22:48:08 +01:00
|
|
|
return;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-11-30 22:48:08 +01:00
|
|
|
ptr[i].prop_ptr = NULL;
|
|
|
|
|
ptr[i].end1 = ptr[i].end2 = ptr[i].bus = ptr[i].sel = 0;
|
|
|
|
|
load_ascii_string( &ptr[i].prop_ptr, fd);
|
|
|
|
|
ORDER(ptr[i].x1, ptr[i].y1, ptr[i].x2, ptr[i].y2);
|
|
|
|
|
if(!strcmp(get_tok_value(ptr[i].prop_ptr, "bus", 0), "true") ) ptr[i].bus = 1;
|
|
|
|
|
ptr[i].node = NULL;
|
|
|
|
|
xctx->wires++;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_inst(int k, FILE *fd)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char *prop_ptr=NULL;
|
|
|
|
|
char name[PATH_MAX];
|
|
|
|
|
char *tmp = NULL;
|
|
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
i=xctx->instances;
|
2020-08-08 15:47:34 +02:00
|
|
|
check_inst_storage();
|
|
|
|
|
load_ascii_string(&tmp, fd);
|
|
|
|
|
if(!tmp) return;
|
|
|
|
|
my_strncpy(name, tmp, S(name));
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(1, "load_inst(): 1: name=%s\n", name);
|
2020-10-15 17:39:21 +02:00
|
|
|
if(!strcmp(xctx->file_version,"1.0") ) {
|
2020-08-08 15:47:34 +02:00
|
|
|
my_strncpy(name, add_ext(name, ".sym"), S(name));
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->inst[i].name=NULL;
|
2021-01-06 03:01:14 +01:00
|
|
|
/* avoid as much as possible calls to rel_sym_path (slow) */
|
|
|
|
|
#ifdef __unix__
|
|
|
|
|
if(name[0] == '/') my_strdup2(56, &xctx->inst[i].name, rel_sym_path(name));
|
|
|
|
|
else my_strdup2(762, &xctx->inst[i].name, name);
|
|
|
|
|
#else
|
2021-01-11 19:31:47 +01:00
|
|
|
my_strdup2(777, &xctx->inst[i].name, rel_sym_path(name));
|
2021-01-06 03:01:14 +01:00
|
|
|
#endif
|
2022-01-19 00:49:46 +01:00
|
|
|
my_free(884, &tmp);
|
2020-12-05 03:16:01 +01:00
|
|
|
if(fscanf(fd, "%lf %lf %hd %hd", &xctx->inst[i].x0, &xctx->inst[i].y0,
|
2020-11-17 01:29:47 +01:00
|
|
|
&xctx->inst[i].rot, &xctx->inst[i].flip) < 4) {
|
2020-10-12 13:13:31 +02:00
|
|
|
fprintf(errfp,"WARNING: missing fields for INSTANCE object, ignoring.\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(fd, 0);
|
|
|
|
|
} else {
|
2020-12-28 04:47:26 +01:00
|
|
|
xctx->inst[i].color=-10000;
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->inst[i].flags=0;
|
|
|
|
|
xctx->inst[i].sel=0;
|
|
|
|
|
xctx->inst[i].ptr=-1; /*04112003 was 0 */
|
|
|
|
|
xctx->inst[i].prop_ptr=NULL;
|
|
|
|
|
xctx->inst[i].instname=NULL;
|
2020-12-19 03:22:38 +01:00
|
|
|
xctx->inst[i].lab=NULL; /* assigned in link_symbols_to_instances */
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->inst[i].node=NULL;
|
2020-08-08 15:47:34 +02:00
|
|
|
load_ascii_string(&prop_ptr,fd);
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strdup(319, &xctx->inst[i].prop_ptr, prop_ptr);
|
|
|
|
|
my_strdup2(320, &xctx->inst[i].instname, get_tok_value(xctx->inst[i].prop_ptr, "name", 0));
|
2022-01-16 14:49:59 +01:00
|
|
|
if(!strcmp(get_tok_value(xctx->inst[i].prop_ptr,"highlight",0), "true"))
|
|
|
|
|
xctx->inst[i].flags |= HILIGHT_CONN;
|
2020-12-19 03:22:38 +01:00
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(2, "load_inst(): n=%d name=%s prop=%s\n", i, xctx->inst[i].name? xctx->inst[i].name:"<NULL>",
|
|
|
|
|
xctx->inst[i].prop_ptr? xctx->inst[i].prop_ptr:"<NULL>");
|
|
|
|
|
xctx->instances++;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
my_free(885, &prop_ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_polygon(FILE *fd)
|
|
|
|
|
{
|
|
|
|
|
int i,c, j, points;
|
2020-10-12 13:13:31 +02:00
|
|
|
xPoly *ptr;
|
2020-09-02 18:28:20 +02:00
|
|
|
const char *dash;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
dbg(3, "load_polygon(): start\n");
|
|
|
|
|
if(fscanf(fd, "%d %d",&c, &points)<2) {
|
2020-10-12 13:13:31 +02:00
|
|
|
fprintf(errfp,"WARNING: missing fields for POLYGON object, ignoring.\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(c<0 || c>=cadlayers) {
|
2020-10-12 13:13:31 +02:00
|
|
|
fprintf(errfp,"WARNING: wrong layer number for POLYGON object, ignoring.\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
check_polygon_storage(c);
|
2020-10-15 17:39:21 +02:00
|
|
|
i=xctx->polygons[c];
|
|
|
|
|
ptr=xctx->poly[c];
|
2020-08-08 15:47:34 +02:00
|
|
|
ptr[i].x=NULL;
|
|
|
|
|
ptr[i].y=NULL;
|
|
|
|
|
ptr[i].selected_point=NULL;
|
|
|
|
|
ptr[i].prop_ptr=NULL;
|
|
|
|
|
ptr[i].x = my_calloc(321, points, sizeof(double));
|
|
|
|
|
ptr[i].y = my_calloc(322, points, sizeof(double));
|
|
|
|
|
ptr[i].selected_point= my_calloc(323, points, sizeof(unsigned short));
|
|
|
|
|
ptr[i].points=points;
|
|
|
|
|
ptr[i].sel=0;
|
|
|
|
|
for(j=0;j<points;j++) {
|
|
|
|
|
if(fscanf(fd, "%lf %lf ",&(ptr[i].x[j]), &(ptr[i].y[j]))<2) {
|
2020-10-12 13:13:31 +02:00
|
|
|
fprintf(errfp,"WARNING: missing fields for POLYGON points, ignoring.\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
my_free(886, &ptr[i].x);
|
|
|
|
|
my_free(887, &ptr[i].y);
|
|
|
|
|
my_free(888, &ptr[i].selected_point);
|
|
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
load_ascii_string( &ptr[i].prop_ptr, fd);
|
|
|
|
|
if( !strcmp(get_tok_value(ptr[i].prop_ptr,"fill",0),"true") )
|
|
|
|
|
ptr[i].fill =1;
|
|
|
|
|
else
|
|
|
|
|
ptr[i].fill =0;
|
2020-09-02 18:28:20 +02:00
|
|
|
dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
|
|
|
|
|
if(strcmp(dash, "")) {
|
2020-09-03 00:19:39 +02:00
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
ptr[i].dash = (short)(d >= 0 ? d : 0);
|
2020-09-02 18:28:20 +02:00
|
|
|
} else {
|
|
|
|
|
ptr[i].dash = 0;
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->polygons[c]++;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_arc(FILE *fd)
|
|
|
|
|
{
|
2021-01-10 16:11:34 +01:00
|
|
|
int n,i,c;
|
2020-08-08 15:47:34 +02:00
|
|
|
xArc *ptr;
|
2020-09-02 23:59:58 +02:00
|
|
|
const char *dash;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
dbg(3, "load_arc(): start\n");
|
2021-01-10 16:11:34 +01:00
|
|
|
n = fscanf(fd, "%d",&c);
|
|
|
|
|
if(n != 1 || c < 0 || c >= cadlayers) {
|
|
|
|
|
fprintf(errfp,"WARNING: wrong or missing layer number for ARC object, ignoring.\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
check_arc_storage(c);
|
2020-10-15 17:39:21 +02:00
|
|
|
i=xctx->arcs[c];
|
|
|
|
|
ptr=xctx->arc[c];
|
2020-08-08 15:47:34 +02:00
|
|
|
if(fscanf(fd, "%lf %lf %lf %lf %lf ",&ptr[i].x, &ptr[i].y,
|
|
|
|
|
&ptr[i].r, &ptr[i].a, &ptr[i].b) < 5) {
|
|
|
|
|
fprintf(errfp,"WARNING: missing fields for ARC object, ignoring\n");
|
|
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ptr[i].prop_ptr=NULL;
|
|
|
|
|
ptr[i].sel=0;
|
|
|
|
|
load_ascii_string(&ptr[i].prop_ptr, fd);
|
|
|
|
|
if( !strcmp(get_tok_value(ptr[i].prop_ptr,"fill",0),"true") )
|
|
|
|
|
ptr[i].fill =1;
|
|
|
|
|
else
|
|
|
|
|
ptr[i].fill =0;
|
2020-09-02 23:59:58 +02:00
|
|
|
dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
|
|
|
|
|
if(strcmp(dash, "")) {
|
2020-10-12 13:13:31 +02:00
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
ptr[i].dash = (short)(d >= 0 ? d : 0);
|
2020-09-02 23:59:58 +02:00
|
|
|
} else {
|
|
|
|
|
ptr[i].dash = 0;
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->arcs[c]++;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_box(FILE *fd)
|
|
|
|
|
{
|
2021-01-10 16:11:34 +01:00
|
|
|
int i,n,c;
|
2020-10-12 13:13:31 +02:00
|
|
|
xRect *ptr;
|
2022-01-20 18:28:29 +01:00
|
|
|
const char *dash;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
dbg(3, "load_box(): start\n");
|
2021-01-10 16:11:34 +01:00
|
|
|
n = fscanf(fd, "%d",&c);
|
|
|
|
|
if(n != 1 || c < 0 || c >= cadlayers) {
|
|
|
|
|
fprintf(errfp,"WARNING: wrong or missing layer number for xRECT object, ignoring.\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
check_box_storage(c);
|
2020-10-15 17:39:21 +02:00
|
|
|
i=xctx->rects[c];
|
|
|
|
|
ptr=xctx->rect[c];
|
2020-10-12 13:13:31 +02:00
|
|
|
if(fscanf(fd, "%lf %lf %lf %lf ",&ptr[i].x1, &ptr[i].y1,
|
2020-08-08 15:47:34 +02:00
|
|
|
&ptr[i].x2, &ptr[i].y2) < 4) {
|
|
|
|
|
fprintf(errfp,"WARNING: missing fields for xRECT object, ignoring\n");
|
|
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-25 18:09:49 +02:00
|
|
|
RECTORDER(ptr[i].x1, ptr[i].y1, ptr[i].x2, ptr[i].y2);
|
2022-01-19 23:28:19 +01:00
|
|
|
ptr[i].extraptr=NULL;
|
2020-08-08 15:47:34 +02:00
|
|
|
ptr[i].prop_ptr=NULL;
|
|
|
|
|
ptr[i].sel=0;
|
|
|
|
|
load_ascii_string( &ptr[i].prop_ptr, fd);
|
2020-09-02 18:28:20 +02:00
|
|
|
dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
|
|
|
|
|
if(strcmp(dash, "")) {
|
2020-09-03 00:19:39 +02:00
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
ptr[i].dash = (short)(d >= 0 ? d : 0);
|
2020-09-02 18:28:20 +02:00
|
|
|
} else {
|
|
|
|
|
ptr[i].dash = 0;
|
|
|
|
|
}
|
2022-01-20 18:28:29 +01:00
|
|
|
set_rect_flags(&xctx->rect[c][i]); /* set cached .flags bitmask from on attributes */
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->rects[c]++;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void load_line(FILE *fd)
|
|
|
|
|
{
|
2021-01-10 16:11:34 +01:00
|
|
|
int i,n, c;
|
2020-10-12 13:13:31 +02:00
|
|
|
xLine *ptr;
|
2020-09-02 18:28:20 +02:00
|
|
|
const char *dash;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
dbg(3, "load_line(): start\n");
|
2021-01-10 16:11:34 +01:00
|
|
|
n = fscanf(fd, "%d",&c);
|
|
|
|
|
if(n != 1 || c < 0 || c >= cadlayers) {
|
|
|
|
|
fprintf(errfp,"WARNING: Wrong or missing layer number for LINE object, ignoring\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
2020-10-12 13:13:31 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
check_line_storage(c);
|
2020-10-15 17:39:21 +02:00
|
|
|
i=xctx->lines[c];
|
|
|
|
|
ptr=xctx->line[c];
|
2020-11-30 22:48:08 +01:00
|
|
|
if(fscanf(fd, "%lf %lf %lf %lf ",&ptr[i].x1, &ptr[i].y1, &ptr[i].x2, &ptr[i].y2) < 4) {
|
2020-08-08 15:47:34 +02:00
|
|
|
fprintf(errfp,"WARNING: missing fields for LINE object, ignoring\n");
|
|
|
|
|
read_line(fd, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-25 18:09:49 +02:00
|
|
|
ORDER(ptr[i].x1, ptr[i].y1, ptr[i].x2, ptr[i].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
ptr[i].prop_ptr=NULL;
|
|
|
|
|
ptr[i].sel=0;
|
|
|
|
|
load_ascii_string( &ptr[i].prop_ptr, fd);
|
2020-09-07 13:12:34 +02:00
|
|
|
|
|
|
|
|
if(!strcmp(get_tok_value(ptr[i].prop_ptr, "bus", 0), "true") )
|
|
|
|
|
ptr[i].bus = 1;
|
|
|
|
|
else
|
|
|
|
|
ptr[i].bus = 0;
|
|
|
|
|
|
2020-09-02 18:28:20 +02:00
|
|
|
dash = get_tok_value(ptr[i].prop_ptr,"dash",0);
|
|
|
|
|
if(strcmp(dash, "")) {
|
2020-09-03 00:19:39 +02:00
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
ptr[i].dash = (short)(d >= 0 ? d : 0);
|
2020-09-02 18:28:20 +02:00
|
|
|
} else {
|
|
|
|
|
ptr[i].dash = 0;
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->lines[c]++;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-19 14:31:55 +01:00
|
|
|
static void read_xschem_file(FILE *fd)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int i, found, endfile;
|
|
|
|
|
char name_embedded[PATH_MAX];
|
|
|
|
|
char tag[1];
|
|
|
|
|
int inst_cnt;
|
2022-04-28 10:12:16 +02:00
|
|
|
size_t ty=0;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
dbg(2, "read_xschem_file(): start\n");
|
|
|
|
|
inst_cnt = endfile = 0;
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->file_version[0] = '\0';
|
2020-08-08 15:47:34 +02:00
|
|
|
while(!endfile)
|
|
|
|
|
{
|
2022-01-14 14:56:13 +01:00
|
|
|
if(fscanf(fd," %c",tag)==EOF) break; /* space before %c --> eat white space */
|
2020-08-08 15:47:34 +02:00
|
|
|
switch(tag[0])
|
|
|
|
|
{
|
|
|
|
|
case 'v':
|
2020-10-15 17:39:21 +02:00
|
|
|
load_ascii_string(&xctx->version_string, fd);
|
|
|
|
|
if(xctx->version_string) {
|
|
|
|
|
my_snprintf(xctx->file_version, S(xctx->file_version), "%s",
|
|
|
|
|
get_tok_value(xctx->version_string, "file_version", 0));
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(1, "read_xschem_file(): file_version=%s\n", xctx->file_version);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
2022-01-14 14:56:13 +01:00
|
|
|
case '#':
|
|
|
|
|
read_line(fd, 1);
|
|
|
|
|
break;
|
2022-01-16 12:42:55 +01:00
|
|
|
case 'F': /* extension for future symbol floater labels */
|
|
|
|
|
read_line(fd, 1);
|
|
|
|
|
break;
|
2020-08-08 15:47:34 +02:00
|
|
|
case 'E':
|
2020-10-15 17:39:21 +02:00
|
|
|
load_ascii_string(&xctx->schtedaxprop,fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
case 'S':
|
2020-10-15 17:39:21 +02:00
|
|
|
load_ascii_string(&xctx->schprop,fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
case 'V':
|
2020-10-15 17:39:21 +02:00
|
|
|
load_ascii_string(&xctx->schverilogprop,fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
case 'K':
|
2020-10-15 17:39:21 +02:00
|
|
|
load_ascii_string(&xctx->schsymbolprop,fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
case 'G':
|
2020-10-15 17:39:21 +02:00
|
|
|
load_ascii_string(&xctx->schvhdlprop,fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
case 'L':
|
|
|
|
|
load_line(fd);
|
|
|
|
|
break;
|
|
|
|
|
case 'P':
|
|
|
|
|
load_polygon(fd);
|
|
|
|
|
break;
|
|
|
|
|
case 'A':
|
|
|
|
|
load_arc(fd);
|
|
|
|
|
break;
|
|
|
|
|
case 'B':
|
|
|
|
|
load_box(fd);
|
|
|
|
|
break;
|
|
|
|
|
case 'T':
|
|
|
|
|
load_text(fd);
|
|
|
|
|
break;
|
|
|
|
|
case 'N':
|
|
|
|
|
load_wire(fd);
|
|
|
|
|
break;
|
|
|
|
|
case 'C':
|
|
|
|
|
load_inst(inst_cnt++, fd);
|
|
|
|
|
break;
|
|
|
|
|
case '[':
|
2022-01-14 16:59:40 +01:00
|
|
|
found=0;
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strdup(324, &xctx->inst[xctx->instances-1].prop_ptr,
|
|
|
|
|
subst_token(xctx->inst[xctx->instances-1].prop_ptr, "embed", "true"));
|
|
|
|
|
if(xctx->inst[xctx->instances-1].name) {
|
2020-10-12 13:13:31 +02:00
|
|
|
my_snprintf(name_embedded, S(name_embedded), "%s/.xschem_embedded_%d_%s",
|
2020-10-15 17:39:21 +02:00
|
|
|
tclgetvar("XSCHEM_TMP_DIR"), getpid(), get_cell_w_ext(xctx->inst[xctx->instances-1].name, 0));
|
|
|
|
|
for(i=0;i<xctx->symbols;i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(1, "read_xschem_file(): sym[i].name=%s, name_embedded=%s\n", xctx->sym[i].name, name_embedded);
|
|
|
|
|
dbg(1, "read_xschem_file(): inst[instances-1].name=%s\n", xctx->inst[xctx->instances-1].name);
|
2020-08-08 15:47:34 +02:00
|
|
|
/* symbol has already been loaded: skip [..] */
|
2022-02-04 02:56:11 +01:00
|
|
|
if(!xctx->x_strcmp(xctx->sym[i].name, xctx->inst[xctx->instances-1].name)) {
|
2020-08-08 15:47:34 +02:00
|
|
|
found=1; break;
|
|
|
|
|
}
|
|
|
|
|
/* if loading file coming back from embedded symbol delete temporary file */
|
2022-01-14 16:59:40 +01:00
|
|
|
/* symbol from this temp file has already been loaded in go_back() */
|
2022-02-04 02:56:11 +01:00
|
|
|
if(!xctx->x_strcmp(name_embedded, xctx->sym[i].name)) {
|
2021-11-22 12:42:33 +01:00
|
|
|
my_strdup2(325, &xctx->sym[i].name, xctx->inst[xctx->instances-1].name);
|
2020-08-08 15:47:34 +02:00
|
|
|
xunlink(name_embedded);
|
|
|
|
|
found=1;break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 15:21:26 +02:00
|
|
|
read_line(fd, 0); /* skip garbage after '[' */
|
2022-01-14 16:59:40 +01:00
|
|
|
if(!found) {
|
|
|
|
|
load_sym_def(xctx->inst[xctx->instances-1].name, fd);
|
2022-01-14 17:07:17 +01:00
|
|
|
found = 2;
|
2022-01-14 16:59:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-01-14 17:07:17 +01:00
|
|
|
if(found != 2) {
|
2022-01-14 16:59:40 +01:00
|
|
|
char *str;
|
|
|
|
|
int n;
|
|
|
|
|
while(1) { /* skip embedded [ ... ] */
|
|
|
|
|
str = read_line(fd, 1);
|
|
|
|
|
if(!str || !strncmp(str, "]", 1)) break;
|
|
|
|
|
n = fscanf(fd, " ");
|
|
|
|
|
(void)n; /* avoid compiler warnings if n unused. can not remove n since ignoring
|
|
|
|
|
* fscanf return value yields another warning */
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if( tag[0] == '{' ) ungetc(tag[0], fd);
|
2020-09-26 01:15:33 +02:00
|
|
|
read_record(tag[0], fd, 0);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
read_line(fd, 0); /* discard any remaining characters till (but not including) newline */
|
2020-09-14 10:27:45 +02:00
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
if(xctx->schvhdlprop) {
|
|
|
|
|
char *str = xctx->sch[xctx->currsch];
|
|
|
|
|
get_tok_value(xctx->schvhdlprop, "type",0);
|
2022-02-04 17:35:07 +01:00
|
|
|
ty = xctx->tok_size;
|
2020-10-15 17:39:21 +02:00
|
|
|
if(!xctx->schsymbolprop && ty && !strcmp(str + strlen(str) - 4,".sym")) {
|
|
|
|
|
str = xctx->schsymbolprop;
|
|
|
|
|
xctx->schsymbolprop = xctx->schvhdlprop;
|
|
|
|
|
xctx->schvhdlprop = str;
|
2020-09-14 10:27:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
if(!xctx->file_version[0]) {
|
|
|
|
|
my_snprintf(xctx->file_version, S(xctx->file_version), "1.0");
|
|
|
|
|
dbg(1, "read_xschem_file(): no file_version, assuming file_version=%s\n", xctx->file_version);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void load_ascii_string(char **ptr, FILE *fd)
|
|
|
|
|
{
|
|
|
|
|
int c, escape=0;
|
|
|
|
|
int i=0, begin=0;
|
|
|
|
|
char *str=NULL;
|
|
|
|
|
int strlength=0;
|
|
|
|
|
|
|
|
|
|
for(;;)
|
|
|
|
|
{
|
|
|
|
|
if(i+5>strlength) my_realloc(326, &str,(strlength+=CADCHUNKALLOC));
|
|
|
|
|
c=fgetc(fd);
|
2020-10-03 12:49:45 +02:00
|
|
|
if (c=='\r') continue;
|
2020-08-08 15:47:34 +02:00
|
|
|
if(c==EOF) {
|
|
|
|
|
fprintf(errfp, "EOF reached, malformed {...} string input, missing close brace\n");
|
|
|
|
|
my_free(1149, ptr);
|
|
|
|
|
my_free(889, &str);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(begin) {
|
2020-08-15 10:48:26 +02:00
|
|
|
if(!escape) {
|
|
|
|
|
if(c=='}') {
|
|
|
|
|
str[i]='\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(c=='\\') {
|
|
|
|
|
escape=1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2022-04-28 10:12:16 +02:00
|
|
|
str[i]=(char)c;
|
2020-08-15 10:48:26 +02:00
|
|
|
escape = 0;
|
2020-08-08 15:47:34 +02:00
|
|
|
i++;
|
|
|
|
|
} else if(c=='{') begin=1;
|
|
|
|
|
}
|
|
|
|
|
dbg(2, "load_ascii_string(): string read=%s\n",str? str:"<NULL>");
|
|
|
|
|
my_strdup(329, ptr, str);
|
|
|
|
|
dbg(2, "load_ascii_string(): loaded %s\n",*ptr? *ptr:"<NULL>");
|
|
|
|
|
my_free(891, &str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void make_symbol(void)
|
|
|
|
|
{
|
|
|
|
|
char name[1024]; /* overflow safe 20161122 */
|
|
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
if( strcmp(xctx->sch[xctx->currsch],"") )
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
my_snprintf(name, S(name), "make_symbol {%s}", xctx->sch[xctx->currsch] );
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(1, "make_symbol(): making symbol: name=%s\n", name);
|
|
|
|
|
tcleval(name);
|
|
|
|
|
}
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-19 14:31:55 +01:00
|
|
|
static void make_schematic(const char *schname)
|
2021-05-29 00:45:01 +02:00
|
|
|
{
|
|
|
|
|
FILE *fd=NULL;
|
2021-11-20 13:33:40 +01:00
|
|
|
|
2021-05-29 00:45:01 +02:00
|
|
|
rebuild_selected_array();
|
2021-11-20 13:33:40 +01:00
|
|
|
if(!xctx->lastsel) return;
|
2021-05-29 00:45:01 +02:00
|
|
|
if (!(fd = fopen(schname, "w")))
|
|
|
|
|
{
|
|
|
|
|
fprintf(errfp, "make_schematic(): problems opening file %s \n", schname);
|
|
|
|
|
tcleval("alert_ {file opening for write failed!} {}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fprintf(fd, "v {xschem version=%s file_version=%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION);
|
|
|
|
|
fprintf(fd, "G {}");
|
|
|
|
|
fputc('\n', fd);
|
|
|
|
|
fprintf(fd, "V {}");
|
|
|
|
|
fputc('\n', fd);
|
|
|
|
|
fprintf(fd, "E {}");
|
|
|
|
|
fputc('\n', fd);
|
|
|
|
|
fprintf(fd, "S {}");
|
|
|
|
|
fputc('\n', fd);
|
|
|
|
|
fprintf(fd, "K {type=subcircuit\nformat=\"@name @pinlist @symname\"\n");
|
|
|
|
|
fprintf(fd, "%s\n", "template=\"name=x1\"");
|
|
|
|
|
fprintf(fd, "%s", "}\n");
|
|
|
|
|
fputc('\n', fd);
|
|
|
|
|
save_line(fd, 1);
|
|
|
|
|
save_box(fd, 1);
|
|
|
|
|
save_arc(fd, 1);
|
|
|
|
|
save_polygon(fd, 1);
|
|
|
|
|
save_text(fd, 1);
|
|
|
|
|
save_wire(fd, 1);
|
|
|
|
|
save_inst(fd, 1);
|
|
|
|
|
fclose(fd);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 17:51:14 +02:00
|
|
|
/* ALWAYS call with absolute path in schname!!! */
|
2021-11-22 00:26:49 +01:00
|
|
|
/* return value:
|
|
|
|
|
* 0 : did not save
|
|
|
|
|
* 1 : schematic saved
|
|
|
|
|
*/
|
2020-08-27 12:57:49 +02:00
|
|
|
int save_schematic(const char *schname) /* 20171020 added return value */
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
FILE *fd;
|
|
|
|
|
char name[PATH_MAX]; /* overflow safe 20161122 */
|
2021-11-20 13:33:40 +01:00
|
|
|
struct stat buf;
|
2021-11-16 22:28:10 +01:00
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
if( strcmp(schname,"") ) my_strncpy(xctx->sch[xctx->currsch], schname, S(xctx->sch[xctx->currsch]));
|
2021-11-22 00:26:49 +01:00
|
|
|
else return 0;
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(1, "save_schematic(): currsch=%d name=%s\n",xctx->currsch, schname);
|
|
|
|
|
dbg(1, "save_schematic(): sch[currsch]=%s\n", xctx->sch[xctx->currsch]);
|
|
|
|
|
dbg(1, "save_schematic(): abs_sym_path=%s\n", abs_sym_path(xctx->sch[xctx->currsch], ""));
|
|
|
|
|
my_strncpy(name, xctx->sch[xctx->currsch], S(name));
|
2022-01-09 05:14:25 +01:00
|
|
|
set_modify(-1);
|
2021-11-20 13:33:40 +01:00
|
|
|
if(!stat(name, &buf)) {
|
|
|
|
|
if(xctx->time_last_modify && xctx->time_last_modify != buf.st_mtime) {
|
2021-12-05 12:39:05 +01:00
|
|
|
tclvareval("ask_save \"Schematic file: ", name,
|
2021-11-20 13:47:25 +01:00
|
|
|
"\nHas been changed since opening.\nSave anyway?\" 0", NULL);
|
2021-11-22 00:26:49 +01:00
|
|
|
if(strcmp(tclresult(), "yes") ) return 0;
|
2021-11-20 13:33:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
if(!(fd=fopen(name,"w")))
|
|
|
|
|
{
|
|
|
|
|
fprintf(errfp, "save_schematic(): problems opening file %s \n",name);
|
2020-09-25 18:09:49 +02:00
|
|
|
tcleval("alert_ {file opening for write failed!} {}");
|
2021-11-22 00:26:49 +01:00
|
|
|
return 0;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2022-08-25 13:59:36 +02:00
|
|
|
unselect_all(1);
|
2020-08-08 15:47:34 +02:00
|
|
|
write_xschem_file(fd);
|
|
|
|
|
fclose(fd);
|
2021-11-20 13:33:40 +01:00
|
|
|
/* update time stamp */
|
2021-11-20 13:47:25 +01:00
|
|
|
if(!stat(name, &buf)) {
|
2021-11-20 13:33:40 +01:00
|
|
|
xctx->time_last_modify = buf.st_mtime;
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strncpy(xctx->current_name, rel_sym_path(name), S(xctx->current_name));
|
2021-11-24 13:52:59 +01:00
|
|
|
/* why clear all these? */
|
|
|
|
|
/*
|
|
|
|
|
* xctx->prep_hi_structs=0;
|
|
|
|
|
* xctx->prep_net_structs=0;
|
|
|
|
|
* xctx->prep_hash_inst=0;
|
|
|
|
|
* xctx->prep_hash_wires=0;
|
|
|
|
|
*/
|
2020-10-15 17:39:21 +02:00
|
|
|
if(!strstr(xctx->sch[xctx->currsch], ".xschem_embedded_")) {
|
2020-08-08 15:47:34 +02:00
|
|
|
set_modify(0);
|
|
|
|
|
}
|
2021-11-22 00:26:49 +01:00
|
|
|
return 1;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2021-01-22 01:03:16 +01:00
|
|
|
/* from == -1 --> link symbols to all instances, from 0 to instances-1 */
|
|
|
|
|
void link_symbols_to_instances(int from) /* from >= 0 : linking symbols from pasted schematic / clipboard */
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-01-22 01:03:16 +01:00
|
|
|
int cond, i, merge = 1;
|
2020-12-19 03:22:38 +01:00
|
|
|
char *type=NULL;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2021-01-22 01:03:16 +01:00
|
|
|
if(from < 0 ) {
|
|
|
|
|
from = 0;
|
|
|
|
|
merge = 0;
|
|
|
|
|
}
|
2020-12-22 16:10:27 +01:00
|
|
|
for(i = from; i < xctx->instances; i++) {
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(2, "link_symbols_to_instances(): inst=%d\n", i);
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(2, "link_symbols_to_instances(): matching inst %d name=%s \n",i, xctx->inst[i].name);
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(2, "link_symbols_to_instances(): -------\n");
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->inst[i].ptr = match_symbol(xctx->inst[i].name);
|
2020-10-12 13:13:31 +02:00
|
|
|
}
|
2020-12-19 03:22:38 +01:00
|
|
|
for(i = from; i < xctx->instances; i++) {
|
2020-10-15 17:39:21 +02:00
|
|
|
type=xctx->sym[xctx->inst[i].ptr].type;
|
2020-10-04 19:53:09 +02:00
|
|
|
cond= !type || !IS_LABEL_SH_OR_PIN(type);
|
2020-10-15 17:39:21 +02:00
|
|
|
if(cond) xctx->inst[i].flags|=2; /* ordinary symbol */
|
2020-12-19 03:22:38 +01:00
|
|
|
else {
|
|
|
|
|
xctx->inst[i].flags &=~2; /* label or pin */
|
|
|
|
|
my_strdup(1216, &xctx->inst[i].lab, get_tok_value(xctx->inst[i].prop_ptr,"lab",0));
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-12-22 16:10:27 +01:00
|
|
|
/* symbol_bbox() might call translate() that might call prepare_netlist_structs() that
|
|
|
|
|
* needs .lab field set above, so this must be done last */
|
|
|
|
|
for(i = from; i < xctx->instances; i++) {
|
|
|
|
|
symbol_bbox(i, &xctx->inst[i].x1, &xctx->inst[i].y1, &xctx->inst[i].x2, &xctx->inst[i].y2);
|
2022-01-19 02:05:05 +01:00
|
|
|
if(merge) select_element(i,SELECTED,1, 0); /* leave elements selected if a paste/copy from windows is done */
|
2020-12-22 16:10:27 +01:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-12-19 03:22:38 +01:00
|
|
|
|
2020-10-13 17:51:14 +02:00
|
|
|
/* ALWAYS use absolute pathname for filename!!! */
|
2020-08-08 15:47:34 +02:00
|
|
|
void load_schematic(int load_symbols, const char *filename, int reset_undo) /* 20150327 added reset_undo */
|
|
|
|
|
{
|
|
|
|
|
FILE *fd;
|
|
|
|
|
char name[PATH_MAX];
|
2021-11-20 02:37:56 +01:00
|
|
|
char msg[PATH_MAX+100];
|
2020-08-08 15:47:34 +02:00
|
|
|
struct stat buf;
|
|
|
|
|
int i;
|
2020-12-02 15:10:47 +01:00
|
|
|
xctx->prep_hi_structs=0;
|
|
|
|
|
xctx->prep_net_structs=0;
|
|
|
|
|
xctx->prep_hash_inst=0;
|
|
|
|
|
xctx->prep_hash_wires=0;
|
2021-11-29 11:52:32 +01:00
|
|
|
if(reset_undo) xctx->clear_undo();
|
2021-11-21 02:08:27 +01:00
|
|
|
if(reset_undo) xctx->prev_set_modify = -1; /* will force set_modify(0) to set window title */
|
|
|
|
|
else xctx->prev_set_modify = 0; /* will prevent set_modify(0) from setting window title */
|
2020-08-08 15:47:34 +02:00
|
|
|
if(filename && filename[0]) {
|
|
|
|
|
my_strncpy(name, filename, S(name));
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strncpy(xctx->sch[xctx->currsch], name, S(xctx->sch[xctx->currsch]));
|
2020-12-03 04:20:05 +01:00
|
|
|
/* if name is /some/path/. remove /. at end */
|
|
|
|
|
my_snprintf(msg, S(msg), "regsub {/\\.$} [file dirname {%s}] {}", name);
|
|
|
|
|
my_strncpy(xctx->current_dirname, tcleval(msg), S(xctx->current_dirname));
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strncpy(xctx->current_name, rel_sym_path(name), S(xctx->current_name));
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(1, "load_schematic(): opening file for loading:%s, filename=%s\n", name, filename);
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(1, "load_schematic(): sch[currsch]=%s\n", xctx->sch[xctx->currsch]);
|
2020-08-08 15:47:34 +02:00
|
|
|
if(!name[0]) return;
|
2021-11-20 13:33:40 +01:00
|
|
|
|
2021-11-21 23:04:48 +01:00
|
|
|
if(reset_undo) {
|
|
|
|
|
if(!stat(name, &buf)) { /* file exists */
|
|
|
|
|
xctx->time_last_modify = buf.st_mtime;
|
|
|
|
|
} else {
|
2022-09-22 14:46:52 +02:00
|
|
|
/* xctx->time_last_modify = time(NULL); */ /* file does not exist, set mtime to current time */
|
|
|
|
|
xctx->time_last_modify = 0; /* file does not exist, set mtime to 0 (undefined)*/
|
2021-11-21 23:04:48 +01:00
|
|
|
}
|
2021-11-20 13:33:40 +01:00
|
|
|
}
|
2020-10-02 03:21:22 +02:00
|
|
|
if( (fd=fopen(name,fopen_read_mode))== NULL) {
|
2020-10-12 13:13:31 +02:00
|
|
|
fprintf(errfp, "load_schematic(): unable to open file: %s, filename=%s\n",
|
2020-08-08 15:47:34 +02:00
|
|
|
name, filename ? filename : "<NULL>");
|
2021-10-10 00:44:01 +02:00
|
|
|
my_snprintf(msg, S(msg), "update; alert_ {Unable to open file: %s}", filename ? filename: "(null)");
|
2020-08-08 15:47:34 +02:00
|
|
|
tcleval(msg);
|
|
|
|
|
clear_drawing();
|
2022-08-25 00:25:29 +02:00
|
|
|
if(reset_undo) set_modify(0);
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
|
|
|
|
clear_drawing();
|
|
|
|
|
dbg(1, "load_schematic(): reading file: %s\n", name);
|
|
|
|
|
read_xschem_file(fd);
|
|
|
|
|
fclose(fd); /* 20150326 moved before load symbols */
|
2021-11-21 23:04:48 +01:00
|
|
|
if(reset_undo) set_modify(0);
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(2, "load_schematic(): loaded file:wire=%d inst=%d\n",xctx->wires , xctx->instances);
|
2021-01-22 01:03:16 +01:00
|
|
|
if(load_symbols) link_symbols_to_instances(-1);
|
2020-09-15 11:19:57 +02:00
|
|
|
if(reset_undo) {
|
2021-12-05 12:39:05 +01:00
|
|
|
tclvareval("is_xschem_file {", xctx->sch[xctx->currsch], "}", NULL);
|
2020-09-15 11:19:57 +02:00
|
|
|
if(!strcmp(tclresult(), "SYMBOL")) {
|
2021-11-18 01:55:01 +01:00
|
|
|
xctx->save_netlist_type = xctx->netlist_type;
|
2021-11-16 22:28:10 +01:00
|
|
|
xctx->netlist_type = CAD_SYMBOL_ATTRS;
|
2021-11-17 01:12:55 +01:00
|
|
|
set_tcl_netlist_type();
|
2021-11-18 01:55:01 +01:00
|
|
|
xctx->loaded_symbol = 1;
|
2020-09-15 11:19:57 +02:00
|
|
|
} else {
|
2021-11-18 01:55:01 +01:00
|
|
|
if(xctx->loaded_symbol) {
|
|
|
|
|
xctx->netlist_type = xctx->save_netlist_type;
|
2021-11-17 01:12:55 +01:00
|
|
|
set_tcl_netlist_type();
|
2020-09-15 11:19:57 +02:00
|
|
|
}
|
2021-11-18 01:55:01 +01:00
|
|
|
xctx->loaded_symbol = 0;
|
2020-09-15 11:19:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(1, "load_schematic(): %s, returning\n", xctx->sch[xctx->currsch]);
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2022-09-22 14:46:52 +02:00
|
|
|
/* if(reset_undo) xctx->time_last_modify = time(NULL); */ /* no file given, set mtime to current time */
|
|
|
|
|
if(reset_undo) xctx->time_last_modify = 0; /* no file given, set mtime to 0 (undefined) */
|
2020-08-08 15:47:34 +02:00
|
|
|
clear_drawing();
|
|
|
|
|
for(i=0;;i++) {
|
2021-11-16 22:28:10 +01:00
|
|
|
if(xctx->netlist_type == CAD_SYMBOL_ATTRS) {
|
2021-10-09 00:41:39 +02:00
|
|
|
if(i == 0) my_snprintf(name, S(name), "%s.sym", "untitled");
|
|
|
|
|
else my_snprintf(name, S(name), "%s-%d.sym", "untitled", i);
|
|
|
|
|
} else {
|
|
|
|
|
if(i == 0) my_snprintf(name, S(name), "%s.sch", "untitled");
|
|
|
|
|
else my_snprintf(name, S(name), "%s-%d.sch", "untitled", i);
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
if(stat(name, &buf)) break;
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
my_snprintf(xctx->sch[xctx->currsch], S(xctx->sch[xctx->currsch]), "%s/%s", pwd_dir, name);
|
|
|
|
|
my_strncpy(xctx->current_name, name, S(xctx->current_name));
|
2021-11-21 23:04:48 +01:00
|
|
|
if(reset_undo) set_modify(0);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2022-01-13 03:09:45 +01:00
|
|
|
check_collapsing_objects();
|
2021-11-10 13:43:08 +01:00
|
|
|
if(tclgetboolvar("autotrim_wires")) trim_wires();
|
2020-08-08 15:47:34 +02:00
|
|
|
update_conn_cues(0, 0);
|
2021-12-15 15:17:45 +01:00
|
|
|
if(xctx->hilight_nets && load_symbols) {
|
2021-12-05 01:34:19 +01:00
|
|
|
propagate_hilights(1, 1, XINSERT_NOREPLACE);
|
|
|
|
|
}
|
2022-08-19 10:56:26 +02:00
|
|
|
/* warning if two symbols perfectly overlapped */
|
2022-09-27 18:35:42 +02:00
|
|
|
warning_overlapped_symbols(0);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2021-11-29 02:47:37 +01:00
|
|
|
void clear_undo(void)
|
|
|
|
|
{
|
|
|
|
|
xctx->cur_undo_ptr = 0;
|
|
|
|
|
xctx->tail_undo_ptr = 0;
|
|
|
|
|
xctx->head_undo_ptr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-25 18:09:49 +02:00
|
|
|
void delete_undo(void)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char diff_name[PATH_MAX]; /* overflow safe 20161122 */
|
|
|
|
|
|
2021-11-29 02:47:37 +01:00
|
|
|
dbg(1, "delete_undo(): undo_initialized = %d\n", xctx->undo_initialized);
|
|
|
|
|
if(!xctx->undo_initialized) return;
|
|
|
|
|
clear_undo();
|
2021-10-26 00:04:13 +02:00
|
|
|
for(i=0; i<MAX_UNDO; i++) {
|
2020-12-04 00:30:13 +01:00
|
|
|
my_snprintf(diff_name, S(diff_name), "%s/undo%d",xctx->undo_dirname, i);
|
2020-08-08 15:47:34 +02:00
|
|
|
xunlink(diff_name);
|
|
|
|
|
}
|
2020-12-04 00:30:13 +01:00
|
|
|
rmdir(xctx->undo_dirname);
|
|
|
|
|
my_free(895, &xctx->undo_dirname);
|
2021-11-29 02:47:37 +01:00
|
|
|
xctx->undo_initialized = 0;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2021-11-29 02:47:37 +01:00
|
|
|
/* create undo directory in XSCHEM_TEMP_DIR */
|
|
|
|
|
static void init_undo(void)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-11-29 02:47:37 +01:00
|
|
|
if(!xctx->undo_initialized) {
|
|
|
|
|
/* create undo directory */
|
|
|
|
|
if( !my_strdup(644, &xctx->undo_dirname, create_tmpdir("xschem_undo_") )) {
|
2021-11-29 17:29:09 +01:00
|
|
|
dbg(0, "xinit(): problems creating tmp undo dir, Undo will be disabled\n");
|
2021-11-29 18:26:20 +01:00
|
|
|
dbg(0, "xinit(): Check permissions in %s\n", tclgetvar("XSCHEM_TMP_DIR"));
|
2021-11-29 17:29:09 +01:00
|
|
|
xctx->no_undo = 1; /* disable undo */
|
2021-11-29 02:47:37 +01:00
|
|
|
}
|
|
|
|
|
xctx->undo_initialized = 1;
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-25 18:09:49 +02:00
|
|
|
void push_undo(void)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
#if HAS_PIPE==1
|
|
|
|
|
int pd[2];
|
|
|
|
|
pid_t pid;
|
|
|
|
|
FILE *diff_fd;
|
|
|
|
|
#endif
|
|
|
|
|
FILE *fd;
|
|
|
|
|
char diff_name[PATH_MAX+100]; /* overflow safe 20161122 */
|
|
|
|
|
|
2021-10-25 17:05:43 +02:00
|
|
|
if(xctx->no_undo)return;
|
2020-12-06 16:40:08 +01:00
|
|
|
dbg(1, "push_undo(): cur_undo_ptr=%d tail_undo_ptr=%d head_undo_ptr=%d\n",
|
2020-12-04 00:30:13 +01:00
|
|
|
xctx->cur_undo_ptr, xctx->tail_undo_ptr, xctx->head_undo_ptr);
|
2021-11-29 02:47:37 +01:00
|
|
|
init_undo();
|
2020-08-08 15:47:34 +02:00
|
|
|
#if HAS_POPEN==1
|
2021-11-28 14:35:55 +01:00
|
|
|
my_snprintf(diff_name, S(diff_name), "gzip --fast -c > %s/undo%d",
|
|
|
|
|
xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO);
|
2020-08-08 15:47:34 +02:00
|
|
|
fd = popen(diff_name,"w");
|
|
|
|
|
if(!fd) {
|
2021-11-29 11:52:32 +01:00
|
|
|
fprintf(errfp, "push_undo(): failed to open write pipe %s\n", diff_name);
|
2021-10-25 17:05:43 +02:00
|
|
|
xctx->no_undo=1;
|
2020-08-08 15:47:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#elif HAS_PIPE==1
|
2021-10-26 00:04:13 +02:00
|
|
|
my_snprintf(diff_name, S(diff_name), "%s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO);
|
2020-10-12 13:13:31 +02:00
|
|
|
pipe(pd);
|
2020-08-08 15:47:34 +02:00
|
|
|
if((pid = fork()) ==0) { /* child process */
|
|
|
|
|
close(pd[1]); /* close write side of pipe */
|
|
|
|
|
if(!(diff_fd=freopen(diff_name,"w", stdout))) /* redirect stdout to file diff_name */
|
|
|
|
|
{
|
|
|
|
|
dbg(1, "push_undo(): problems opening file %s \n",diff_name);
|
2021-12-05 12:39:05 +01:00
|
|
|
tcleval("exit");
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* the following 2 statements are a replacement for dup2() which is not c89
|
2020-10-12 13:13:31 +02:00
|
|
|
* however these are not atomic, if another thread takes stdin
|
2020-08-08 15:47:34 +02:00
|
|
|
* in between we are in trouble */
|
2021-10-25 01:53:00 +02:00
|
|
|
#if(HAS_DUP2)
|
|
|
|
|
dup2(pd[0], 0);
|
|
|
|
|
#else
|
2020-08-08 15:47:34 +02:00
|
|
|
close(0); /* close stdin */
|
|
|
|
|
dup(pd[0]); /* duplicate read side of pipe to stdin */
|
2021-10-25 01:53:00 +02:00
|
|
|
#endif
|
2021-11-20 02:37:56 +01:00
|
|
|
execlp("gzip", "gzip", "--fast", "-c", NULL); /* replace current process with comand */
|
2020-08-08 15:47:34 +02:00
|
|
|
/* never gets here */
|
2021-11-29 11:52:32 +01:00
|
|
|
fprintf(errfp, "push_undo(): problems with execlp\n");
|
2021-12-05 12:39:05 +01:00
|
|
|
tcleval("exit");
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
close(pd[0]); /* close read side of pipe */
|
|
|
|
|
fd=fdopen(pd[1],"w");
|
|
|
|
|
#else /* uncompressed undo */
|
2021-10-26 00:04:13 +02:00
|
|
|
my_snprintf(diff_name, S(diff_name), "%s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO);
|
2020-08-08 15:47:34 +02:00
|
|
|
fd = fopen(diff_name,"w");
|
|
|
|
|
if(!fd) {
|
2021-11-29 11:52:32 +01:00
|
|
|
fprintf(errfp, "push_undo(): failed to open undo file %s\n", diff_name);
|
2021-10-25 17:05:43 +02:00
|
|
|
xctx->no_undo=1;
|
2020-08-08 15:47:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
write_xschem_file(fd);
|
2020-12-04 00:30:13 +01:00
|
|
|
xctx->cur_undo_ptr++;
|
|
|
|
|
xctx->head_undo_ptr = xctx->cur_undo_ptr;
|
2021-10-26 00:04:13 +02:00
|
|
|
xctx->tail_undo_ptr = xctx->head_undo_ptr <= MAX_UNDO? 0: xctx->head_undo_ptr-MAX_UNDO;
|
2020-08-08 15:47:34 +02:00
|
|
|
#if HAS_POPEN==1
|
|
|
|
|
pclose(fd);
|
|
|
|
|
#elif HAS_PIPE==1
|
|
|
|
|
fclose(fd);
|
|
|
|
|
waitpid(pid, NULL,0);
|
|
|
|
|
#else
|
|
|
|
|
fclose(fd);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-24 03:47:04 +01:00
|
|
|
/* redo:
|
|
|
|
|
* 0: undo (with push current state for allowing following redo)
|
|
|
|
|
* 1: redo
|
|
|
|
|
* 2: read top data from undo stack without changing undo stack
|
|
|
|
|
*/
|
2021-11-21 23:04:48 +01:00
|
|
|
void pop_undo(int redo, int set_modify_status)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
FILE *fd;
|
|
|
|
|
char diff_name[PATH_MAX+12];
|
|
|
|
|
#if HAS_PIPE==1
|
|
|
|
|
int pd[2];
|
|
|
|
|
pid_t pid;
|
|
|
|
|
FILE *diff_fd;
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-11-24 03:47:04 +01:00
|
|
|
if(xctx->no_undo) return;
|
|
|
|
|
if(redo == 1) {
|
2020-12-04 00:30:13 +01:00
|
|
|
if(xctx->cur_undo_ptr < xctx->head_undo_ptr) {
|
2020-12-06 16:40:08 +01:00
|
|
|
dbg(1, "pop_undo(): redo; cur_undo_ptr=%d tail_undo_ptr=%d head_undo_ptr=%d\n",
|
2020-12-04 00:30:13 +01:00
|
|
|
xctx->cur_undo_ptr, xctx->tail_undo_ptr, xctx->head_undo_ptr);
|
|
|
|
|
xctx->cur_undo_ptr++;
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-11-24 03:47:04 +01:00
|
|
|
} else if(redo == 0) { /* undo */
|
2020-12-04 00:30:13 +01:00
|
|
|
if(xctx->cur_undo_ptr == xctx->tail_undo_ptr) return;
|
2020-12-06 16:40:08 +01:00
|
|
|
dbg(1, "pop_undo(): undo; cur_undo_ptr=%d tail_undo_ptr=%d head_undo_ptr=%d\n",
|
2020-12-04 00:30:13 +01:00
|
|
|
xctx->cur_undo_ptr, xctx->tail_undo_ptr, xctx->head_undo_ptr);
|
|
|
|
|
if(xctx->head_undo_ptr == xctx->cur_undo_ptr) {
|
2021-11-29 11:52:32 +01:00
|
|
|
xctx->push_undo();
|
2020-12-04 00:30:13 +01:00
|
|
|
xctx->head_undo_ptr--;
|
|
|
|
|
xctx->cur_undo_ptr--;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-12-04 00:30:13 +01:00
|
|
|
if(xctx->cur_undo_ptr<=0) return; /* check undo tail */
|
|
|
|
|
xctx->cur_undo_ptr--;
|
2021-11-24 03:47:04 +01:00
|
|
|
} else { /* redo == 2, get data without changing undo stack */
|
|
|
|
|
if(xctx->cur_undo_ptr<=0) return; /* check undo tail */
|
|
|
|
|
xctx->cur_undo_ptr--; /* will be restored after building file name */
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
clear_drawing();
|
2022-08-25 13:59:36 +02:00
|
|
|
unselect_all(1);
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
#if HAS_POPEN==1
|
2021-10-26 00:04:13 +02:00
|
|
|
my_snprintf(diff_name, S(diff_name), "gzip -d -c %s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO);
|
2020-08-08 15:47:34 +02:00
|
|
|
fd=popen(diff_name, "r");
|
|
|
|
|
if(!fd) {
|
2021-11-29 11:52:32 +01:00
|
|
|
fprintf(errfp, "pop_undo(): failed to open read pipe %s\n", diff_name);
|
2021-10-25 17:05:43 +02:00
|
|
|
xctx->no_undo=1;
|
2020-08-08 15:47:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#elif HAS_PIPE==1
|
2021-10-26 00:04:13 +02:00
|
|
|
my_snprintf(diff_name, S(diff_name), "%s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO);
|
2020-08-08 15:47:34 +02:00
|
|
|
pipe(pd);
|
|
|
|
|
if((pid = fork())==0) { /* child process */
|
|
|
|
|
close(pd[0]); /* close read side of pipe */
|
|
|
|
|
if(!(diff_fd=freopen(diff_name,"r", stdin))) /* redirect stdin from file name */
|
|
|
|
|
{
|
|
|
|
|
dbg(1, "pop_undo(): problems opening file %s \n",diff_name);
|
2021-12-05 12:39:05 +01:00
|
|
|
tcleval("exit");
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
/* connect write side of pipe to stdout */
|
2021-10-25 01:53:00 +02:00
|
|
|
#if HAS_DUP2
|
|
|
|
|
dup2(pd[1], 1);
|
|
|
|
|
#else
|
2020-08-08 15:47:34 +02:00
|
|
|
close(1); /* close stdout */
|
|
|
|
|
dup(pd[1]); /* write side of pipe --> stdout */
|
2021-10-25 01:53:00 +02:00
|
|
|
#endif
|
2021-11-20 02:37:56 +01:00
|
|
|
execlp("gzip", "gzip", "-d", "-c", NULL); /* replace current process with command */
|
2020-08-08 15:47:34 +02:00
|
|
|
/* never gets here */
|
2021-10-25 01:53:00 +02:00
|
|
|
dbg(1, "pop_undo(): problems with execlp\n");
|
2021-12-05 12:39:05 +01:00
|
|
|
tcleval("exit");
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
close(pd[1]); /* close write side of pipe */
|
|
|
|
|
fd=fdopen(pd[0],"r");
|
|
|
|
|
#else /* uncompressed undo */
|
2021-10-26 00:04:13 +02:00
|
|
|
my_snprintf(diff_name, S(diff_name), "%s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO);
|
2020-08-08 15:47:34 +02:00
|
|
|
fd=fopen(diff_name, "r");
|
|
|
|
|
if(!fd) {
|
2021-11-29 11:52:32 +01:00
|
|
|
fprintf(errfp, "pop_undo(): failed to open read pipe %s\n", diff_name);
|
2021-10-25 17:05:43 +02:00
|
|
|
xctx->no_undo=1;
|
2020-08-08 15:47:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
read_xschem_file(fd);
|
2021-11-24 03:47:04 +01:00
|
|
|
if(redo == 2) xctx->cur_undo_ptr++; /* restore undo stack pointer */
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
#if HAS_POPEN==1
|
|
|
|
|
pclose(fd); /* 20150326 moved before load symbols */
|
|
|
|
|
#elif HAS_PIPE==1
|
|
|
|
|
fclose(fd);
|
|
|
|
|
waitpid(pid, NULL, 0);
|
|
|
|
|
#else
|
|
|
|
|
fclose(fd);
|
|
|
|
|
#endif
|
2020-10-15 17:39:21 +02:00
|
|
|
dbg(2, "pop_undo(): loaded file:wire=%d inst=%d\n",xctx->wires , xctx->instances);
|
2021-11-21 23:04:48 +01:00
|
|
|
if(set_modify_status) set_modify(1);
|
2020-12-02 15:10:47 +01:00
|
|
|
xctx->prep_hash_inst=0;
|
|
|
|
|
xctx->prep_hash_wires=0;
|
|
|
|
|
xctx->prep_net_structs=0;
|
|
|
|
|
xctx->prep_hi_structs=0;
|
2021-12-03 19:15:07 +01:00
|
|
|
link_symbols_to_instances(-1);
|
2020-08-08 15:47:34 +02:00
|
|
|
update_conn_cues(0, 0);
|
2021-12-05 01:34:19 +01:00
|
|
|
if(xctx->hilight_nets) {
|
|
|
|
|
propagate_hilights(1, 1, XINSERT_NOREPLACE);
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
dbg(2, "pop_undo(): returning\n");
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
/* given a 'symname' component instantiation in a LCC schematic instance
|
2020-09-26 01:15:33 +02:00
|
|
|
* get the type attribute from symbol global properties.
|
|
|
|
|
* first look in already loaded symbols else inspect symbol file
|
2020-10-12 13:13:31 +02:00
|
|
|
* do not load all symname data, just get the type
|
2020-09-27 12:41:36 +02:00
|
|
|
* return symbol type in type pointer or "" if no type or no symbol found
|
2020-09-29 11:17:10 +02:00
|
|
|
* if pintable given (!=NULL) hash all symbol pins
|
|
|
|
|
* if embed_fd is not NULL read symbol from embedded '[...]' tags using embed_fd file pointer */
|
2021-11-28 14:35:55 +01:00
|
|
|
static void get_sym_type(const char *symname, char **type,
|
2021-12-28 01:33:01 +01:00
|
|
|
Int_hashentry **pintable, FILE *embed_fd, int *sym_n_pins)
|
2020-09-26 01:15:33 +02:00
|
|
|
{
|
2020-09-27 12:41:36 +02:00
|
|
|
int i, c, n = 0;
|
2020-09-26 01:15:33 +02:00
|
|
|
char name[PATH_MAX];
|
|
|
|
|
FILE *fd;
|
|
|
|
|
char tag[1];
|
|
|
|
|
int found = 0;
|
2020-10-15 17:39:21 +02:00
|
|
|
if(!strcmp(xctx->file_version,"1.0")) {
|
2020-09-26 01:15:33 +02:00
|
|
|
my_strncpy(name, abs_sym_path(symname, ".sym"), S(name));
|
|
|
|
|
} else {
|
|
|
|
|
my_strncpy(name, abs_sym_path(symname, ""), S(name));
|
|
|
|
|
}
|
|
|
|
|
found=0;
|
2020-10-15 17:39:21 +02:00
|
|
|
/* first look in already loaded symbols in xctx->sym[] array... */
|
|
|
|
|
for(i=0;i<xctx->symbols;i++) {
|
2022-02-04 02:56:11 +01:00
|
|
|
if(xctx->x_strcmp(symname, xctx->sym[i].name) == 0) {
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strdup2(316, type, xctx->sym[i].type);
|
2020-09-26 01:15:33 +02:00
|
|
|
found = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-27 12:41:36 +02:00
|
|
|
/* hash pins to get LCC schematic have same order as corresponding symbol */
|
2021-03-07 00:15:16 +01:00
|
|
|
if(found && pintable) {
|
2021-11-28 14:35:55 +01:00
|
|
|
*sym_n_pins = xctx->sym[i].rects[PINLAYER];
|
2021-03-07 00:15:16 +01:00
|
|
|
for (c = 0; c < xctx->sym[i].rects[PINLAYER]; c++) {
|
|
|
|
|
int_hash_lookup(pintable, get_tok_value(xctx->sym[i].rect[PINLAYER][c].prop_ptr, "name", 0), c, XINSERT);
|
|
|
|
|
}
|
2020-09-27 12:41:36 +02:00
|
|
|
}
|
2020-09-26 01:15:33 +02:00
|
|
|
if( !found ) {
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "get_sym_type(): open file %s, pintable %s\n",name, pintable ? "set" : "null");
|
2020-09-26 01:15:33 +02:00
|
|
|
/* ... if not found open file and look for 'type' into the global attributes. */
|
2020-09-29 11:17:10 +02:00
|
|
|
|
|
|
|
|
if(embed_fd) fd = embed_fd;
|
2020-10-02 03:21:22 +02:00
|
|
|
else fd=fopen(name,fopen_read_mode);
|
2020-09-29 11:17:10 +02:00
|
|
|
|
|
|
|
|
if(fd==NULL) {
|
2020-10-15 13:38:27 +02:00
|
|
|
dbg(1, "get_sym_type(): Symbol not found: %s\n",name);
|
2020-09-26 01:15:33 +02:00
|
|
|
my_strdup2(1162, type, "");
|
|
|
|
|
} else {
|
2020-09-27 12:41:36 +02:00
|
|
|
char *globalprop=NULL;
|
2021-01-10 16:11:34 +01:00
|
|
|
int fscan_ret;
|
2021-12-19 01:28:39 +01:00
|
|
|
xRect rect;
|
2020-09-27 12:41:36 +02:00
|
|
|
|
2021-12-19 01:28:39 +01:00
|
|
|
rect.prop_ptr = NULL;
|
2020-09-27 12:41:36 +02:00
|
|
|
while(1) {
|
2020-09-26 01:15:33 +02:00
|
|
|
if(fscanf(fd," %c",tag)==EOF) break;
|
2020-09-29 11:17:10 +02:00
|
|
|
if(embed_fd && tag[0] == ']') break;
|
2020-09-26 01:15:33 +02:00
|
|
|
switch(tag[0]) {
|
|
|
|
|
case 'G':
|
|
|
|
|
load_ascii_string(&globalprop,fd);
|
|
|
|
|
if(!found) {
|
|
|
|
|
my_strdup2(1164, type, get_tok_value(globalprop, "type", 0));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'K':
|
|
|
|
|
load_ascii_string(&globalprop,fd);
|
|
|
|
|
my_strdup2(1165, type, get_tok_value(globalprop, "type", 0));
|
2020-09-26 10:30:16 +02:00
|
|
|
if(type[0]) found = 1;
|
2020-09-26 01:15:33 +02:00
|
|
|
break;
|
2020-09-27 12:41:36 +02:00
|
|
|
case 'B':
|
2021-01-10 16:11:34 +01:00
|
|
|
fscan_ret = fscanf(fd, "%d",&c);
|
|
|
|
|
if(fscan_ret != 1 || c <0 || c>=cadlayers) {
|
2022-01-14 14:56:13 +01:00
|
|
|
fprintf(errfp,"get_sym_type(): box layer wrong or missing or > defined cadlayers, "
|
|
|
|
|
"ignoring, increase cadlayers\n");
|
2021-11-29 17:29:09 +01:00
|
|
|
ungetc(tag[0], fd);
|
|
|
|
|
read_record(tag[0], fd, 1);
|
2020-09-27 12:41:36 +02:00
|
|
|
}
|
2021-12-19 01:28:39 +01:00
|
|
|
fscan_ret = fscanf(fd, "%lf %lf %lf %lf ",&rect.x1, &rect.y1, &rect.x2, &rect.y2);
|
2021-01-10 16:11:34 +01:00
|
|
|
if(fscan_ret < 4) dbg(0, "Warning: missing fields in 'B' line\n");
|
2021-12-19 01:28:39 +01:00
|
|
|
load_ascii_string( &rect.prop_ptr, fd);
|
|
|
|
|
dbg(1, "get_sym_type(): %s rect.prop_ptr=%s\n", symname, rect.prop_ptr);
|
2020-09-27 12:41:36 +02:00
|
|
|
if (pintable && c == PINLAYER) {
|
|
|
|
|
/* hash pins to get LCC schematic have same order as corresponding symbol */
|
2021-12-19 01:28:39 +01:00
|
|
|
int_hash_lookup(pintable, get_tok_value(rect.prop_ptr, "name", 0), n++, XINSERT);
|
|
|
|
|
dbg(1, "get_sym_type() : hashing %s\n", get_tok_value(rect.prop_ptr, "name", 0));
|
2021-11-28 14:35:55 +01:00
|
|
|
++(*sym_n_pins);
|
2020-10-12 13:13:31 +02:00
|
|
|
}
|
2020-09-27 12:41:36 +02:00
|
|
|
break;
|
2020-09-26 01:15:33 +02:00
|
|
|
default:
|
|
|
|
|
if( tag[0] == '{' ) ungetc(tag[0], fd);
|
|
|
|
|
read_record(tag[0], fd, 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
read_line(fd, 0); /* discard any remaining characters till (but not including) newline */
|
|
|
|
|
}
|
|
|
|
|
my_free(1166, &globalprop);
|
2021-12-19 01:28:39 +01:00
|
|
|
my_free(1167, &rect.prop_ptr);
|
2020-09-29 11:17:10 +02:00
|
|
|
if(!embed_fd) fclose(fd);
|
2020-09-26 01:15:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "get_sym_type(): symbol=%s --> type=%s\n", symname, *type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
/* given a .sch file used as instance in LCC schematics, order its pin
|
2020-09-27 12:41:36 +02:00
|
|
|
* as in corresponding .sym file if it exists */
|
2021-11-28 14:35:55 +01:00
|
|
|
static void align_sch_pins_with_sym(const char *name, int pos)
|
2020-09-27 12:41:36 +02:00
|
|
|
{
|
|
|
|
|
char *ptr;
|
|
|
|
|
char symname[PATH_MAX];
|
|
|
|
|
char *symtype = NULL;
|
|
|
|
|
const char *pinname;
|
2021-11-28 14:35:55 +01:00
|
|
|
int i, fail = 0, sym_n_pins=0;
|
2021-12-28 01:33:01 +01:00
|
|
|
Int_hashentry *pintable[HASHSIZE];
|
2020-09-27 12:41:36 +02:00
|
|
|
|
|
|
|
|
if ((ptr = strrchr(name, '.')) && !strcmp(ptr, ".sch")) {
|
|
|
|
|
my_strncpy(symname, add_ext(name, ".sym"), S(symname));
|
2021-12-28 01:33:01 +01:00
|
|
|
memset(pintable, 0, HASHSIZE * sizeof(Int_hashentry *));
|
2020-09-27 12:41:36 +02:00
|
|
|
/* hash all symbol pins with their position into pintable hash*/
|
2021-11-28 14:35:55 +01:00
|
|
|
get_sym_type(symname, &symtype, pintable, NULL, &sym_n_pins);
|
2020-09-27 12:41:36 +02:00
|
|
|
if(symtype[0]) { /* found a .sym for current .sch LCC instance */
|
2021-12-19 01:28:39 +01:00
|
|
|
xRect *rect = NULL;
|
2021-11-28 14:35:55 +01:00
|
|
|
if (sym_n_pins!=xctx->sym[pos].rects[PINLAYER]) {
|
2021-03-07 00:15:16 +01:00
|
|
|
dbg(0, " align_sch_pins_with_sym(): warning: number of pins mismatch between %s and %s\n",
|
|
|
|
|
name, symname);
|
|
|
|
|
fail = 1;
|
|
|
|
|
}
|
2021-12-19 01:28:39 +01:00
|
|
|
rect = (xRect *) my_malloc(1168, sizeof(xRect) * sym_n_pins);
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "align_sch_pins_with_sym(): symbol: %s\n", symname);
|
2020-10-15 17:39:21 +02:00
|
|
|
for(i=0; i < xctx->sym[pos].rects[PINLAYER]; i++) {
|
2021-12-28 01:33:01 +01:00
|
|
|
Int_hashentry *entry;
|
2020-10-15 17:39:21 +02:00
|
|
|
pinname = get_tok_value(xctx->sym[pos].rect[PINLAYER][i].prop_ptr, "name", 0);
|
2020-09-27 12:41:36 +02:00
|
|
|
entry = int_hash_lookup(pintable, pinname, 0 , XLOOKUP);
|
2020-10-12 13:13:31 +02:00
|
|
|
if(!entry) {
|
2020-11-16 12:33:06 +01:00
|
|
|
dbg(0, " align_sch_pins_with_sym(): warning: pin mismatch between %s and %s : %s\n",
|
|
|
|
|
name, symname, pinname);
|
2020-09-27 12:41:36 +02:00
|
|
|
fail = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-12-19 01:28:39 +01:00
|
|
|
rect[entry->value] = xctx->sym[pos].rect[PINLAYER][i]; /* rect[] is the pin array ordered as in symbol */
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "align_sch_pins_with_sym(): i=%d, pin name=%s entry->value=%d\n", i, pinname, entry->value);
|
|
|
|
|
}
|
|
|
|
|
if(!fail) {
|
2021-12-19 01:28:39 +01:00
|
|
|
/* copy rect[] ordererd array to LCC schematic instance */
|
2020-11-22 00:51:24 +01:00
|
|
|
for(i=0; i < xctx->sym[pos].rects[PINLAYER]; i++) {
|
2021-12-19 01:28:39 +01:00
|
|
|
xctx->sym[pos].rect[PINLAYER][i] = rect[i];
|
2020-09-27 12:41:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-11-23 15:03:51 +01:00
|
|
|
int_hash_free(pintable);
|
2021-12-19 01:28:39 +01:00
|
|
|
my_free(1169, &rect);
|
2020-09-27 12:41:36 +02:00
|
|
|
}
|
|
|
|
|
my_free(1170, &symtype);
|
|
|
|
|
}
|
2020-09-26 01:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* replace i/o/iopin instances of LCC schematics with symbol pins (boxes on PINLAYER layer) */
|
2021-11-28 14:35:55 +01:00
|
|
|
static void add_pinlayer_boxes(int *lastr, xRect **bb,
|
|
|
|
|
const char *symtype, char *prop_ptr, double i_x0, double i_y0)
|
2020-09-26 01:15:33 +02:00
|
|
|
{
|
2022-04-28 10:12:16 +02:00
|
|
|
int i;
|
|
|
|
|
size_t save;
|
2020-09-26 01:15:33 +02:00
|
|
|
const char *label;
|
|
|
|
|
char *pin_label = NULL;
|
2020-09-27 12:41:36 +02:00
|
|
|
|
2020-09-26 01:15:33 +02:00
|
|
|
i = lastr[PINLAYER];
|
2020-10-12 13:13:31 +02:00
|
|
|
my_realloc(652, &bb[PINLAYER], (i + 1) * sizeof(xRect));
|
2020-12-02 15:10:47 +01:00
|
|
|
bb[PINLAYER][i].x1 = i_x0 - 2.5; bb[PINLAYER][i].x2 = i_x0 + 2.5;
|
|
|
|
|
bb[PINLAYER][i].y1 = i_y0 - 2.5; bb[PINLAYER][i].y2 = i_y0 + 2.5;
|
2020-09-26 01:15:33 +02:00
|
|
|
RECTORDER(bb[PINLAYER][i].x1, bb[PINLAYER][i].y1, bb[PINLAYER][i].x2, bb[PINLAYER][i].y2);
|
|
|
|
|
bb[PINLAYER][i].prop_ptr = NULL;
|
|
|
|
|
label = get_tok_value(prop_ptr, "lab", 0);
|
|
|
|
|
save = strlen(label)+30;
|
|
|
|
|
pin_label = my_malloc(315, save);
|
|
|
|
|
pin_label[0] = '\0';
|
|
|
|
|
if (!strcmp(symtype, "ipin")) {
|
|
|
|
|
my_snprintf(pin_label, save, "name=%s dir=in ", label);
|
|
|
|
|
} else if (!strcmp(symtype, "opin")) {
|
|
|
|
|
my_snprintf(pin_label, save, "name=%s dir=out ", label);
|
|
|
|
|
} else if (!strcmp(symtype, "iopin")) {
|
|
|
|
|
my_snprintf(pin_label, save, "name=%s dir=inout ", label);
|
|
|
|
|
}
|
|
|
|
|
my_strdup(463, &bb[PINLAYER][i].prop_ptr, pin_label);
|
2022-01-24 22:58:30 +01:00
|
|
|
bb[PINLAYER][i].flags = 0;
|
|
|
|
|
bb[PINLAYER][i].extraptr = 0;
|
2020-09-26 01:15:33 +02:00
|
|
|
bb[PINLAYER][i].dash = 0;
|
|
|
|
|
bb[PINLAYER][i].sel = 0;
|
|
|
|
|
/* add to symbol pins remaining attributes from schematic pins, except name= and lab= */
|
|
|
|
|
my_strdup(157, &pin_label, get_sym_template(prop_ptr, "lab")); /* remove name=... and lab=... */
|
|
|
|
|
my_strcat(159, &bb[PINLAYER][i].prop_ptr, pin_label);
|
|
|
|
|
my_free(900, &pin_label);
|
|
|
|
|
lastr[PINLAYER]++;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-28 14:35:55 +01:00
|
|
|
static void use_lcc_pins(int level, char *symtype, char (*filename)[PATH_MAX])
|
2020-09-26 01:15:33 +02:00
|
|
|
{
|
|
|
|
|
if(level == 0) {
|
|
|
|
|
if (!strcmp(symtype, "ipin")) {
|
|
|
|
|
my_snprintf(*filename, S(*filename), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/ipin_lcc_top.sym");
|
|
|
|
|
} else if (!strcmp(symtype, "opin")) {
|
|
|
|
|
my_snprintf(*filename, S(*filename), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/opin_lcc_top.sym");
|
|
|
|
|
} else if (!strcmp(symtype, "iopin")) {
|
|
|
|
|
my_snprintf(*filename, S(*filename), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/iopin_lcc_top.sym");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (!strcmp(symtype, "ipin")) {
|
|
|
|
|
my_snprintf(*filename, S(*filename), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/ipin_lcc.sym");
|
|
|
|
|
} else if (!strcmp(symtype, "opin")) {
|
|
|
|
|
my_snprintf(*filename, S(*filename), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/opin_lcc.sym");
|
|
|
|
|
} else if (!strcmp(symtype, "iopin")) {
|
|
|
|
|
my_snprintf(*filename, S(*filename), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/iopin_lcc.sym");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-19 14:31:55 +01:00
|
|
|
static void calc_symbol_bbox(int pos)
|
2020-09-27 12:41:36 +02:00
|
|
|
{
|
2020-10-12 13:13:31 +02:00
|
|
|
int c, i, count = 0;
|
|
|
|
|
xRect boundbox, tmp;
|
2020-09-27 12:41:36 +02:00
|
|
|
|
|
|
|
|
boundbox.x1 = boundbox.x2 = boundbox.y1 = boundbox.y2 = 0;
|
|
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-15 17:39:21 +02:00
|
|
|
for(i=0;i<xctx->sym[pos].lines[c];i++)
|
2020-09-27 12:41:36 +02:00
|
|
|
{
|
|
|
|
|
count++;
|
2020-10-15 17:39:21 +02:00
|
|
|
tmp.x1=xctx->sym[pos].line[c][i].x1;tmp.y1=xctx->sym[pos].line[c][i].y1;
|
|
|
|
|
tmp.x2=xctx->sym[pos].line[c][i].x2;tmp.y2=xctx->sym[pos].line[c][i].y2;
|
2020-09-27 12:41:36 +02:00
|
|
|
updatebbox(count,&boundbox,&tmp);
|
2020-10-15 17:05:30 +02:00
|
|
|
dbg(2, "calc_symbol_bbox(): line[%d][%d]: %g %g %g %g\n",
|
2020-09-27 12:41:36 +02:00
|
|
|
c, i, tmp.x1,tmp.y1,tmp.x2,tmp.y2);
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
for(i=0;i<xctx->sym[pos].arcs[c];i++)
|
2020-09-27 12:41:36 +02:00
|
|
|
{
|
|
|
|
|
count++;
|
2020-10-15 17:39:21 +02:00
|
|
|
arc_bbox(xctx->sym[pos].arc[c][i].x, xctx->sym[pos].arc[c][i].y, xctx->sym[pos].arc[c][i].r,
|
|
|
|
|
xctx->sym[pos].arc[c][i].a, xctx->sym[pos].arc[c][i].b,
|
2020-09-27 12:41:36 +02:00
|
|
|
&tmp.x1, &tmp.y1, &tmp.x2, &tmp.y2);
|
|
|
|
|
/* printf("arc bbox: %g %g %g %g\n", tmp.x1, tmp.y1, tmp.x2, tmp.y2); */
|
|
|
|
|
updatebbox(count,&boundbox,&tmp);
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
for(i=0;i<xctx->sym[pos].rects[c];i++)
|
2020-09-27 12:41:36 +02:00
|
|
|
{
|
|
|
|
|
count++;
|
2020-10-15 17:39:21 +02:00
|
|
|
tmp.x1=xctx->sym[pos].rect[c][i].x1;tmp.y1=xctx->sym[pos].rect[c][i].y1;
|
|
|
|
|
tmp.x2=xctx->sym[pos].rect[c][i].x2;tmp.y2=xctx->sym[pos].rect[c][i].y2;
|
2020-09-27 12:41:36 +02:00
|
|
|
updatebbox(count,&boundbox,&tmp);
|
|
|
|
|
}
|
2020-10-15 17:39:21 +02:00
|
|
|
for(i=0;i<xctx->sym[pos].polygons[c];i++)
|
2020-09-27 12:41:36 +02:00
|
|
|
{
|
|
|
|
|
double x1=0., y1=0., x2=0., y2=0.;
|
|
|
|
|
int k;
|
|
|
|
|
count++;
|
2020-10-15 17:39:21 +02:00
|
|
|
for(k=0; k<xctx->sym[pos].poly[c][i].points; k++) {
|
2020-09-27 12:41:36 +02:00
|
|
|
/*fprintf(errfp, " poly: point %d: %.16g %.16g\n", k, pp[c][i].x[k], pp[c][i].y[k]); */
|
2020-10-15 17:39:21 +02:00
|
|
|
if(k==0 || xctx->sym[pos].poly[c][i].x[k] < x1) x1 = xctx->sym[pos].poly[c][i].x[k];
|
|
|
|
|
if(k==0 || xctx->sym[pos].poly[c][i].y[k] < y1) y1 = xctx->sym[pos].poly[c][i].y[k];
|
|
|
|
|
if(k==0 || xctx->sym[pos].poly[c][i].x[k] > x2) x2 = xctx->sym[pos].poly[c][i].x[k];
|
|
|
|
|
if(k==0 || xctx->sym[pos].poly[c][i].y[k] > y2) y2 = xctx->sym[pos].poly[c][i].y[k];
|
2020-09-27 12:41:36 +02:00
|
|
|
}
|
|
|
|
|
tmp.x1=x1;tmp.y1=y1;tmp.x2=x2;tmp.y2=y2;
|
|
|
|
|
updatebbox(count,&boundbox,&tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* do not include symbol text in bounding box, since text length
|
|
|
|
|
* is variable from one instance to another due to '@' variable expansions
|
|
|
|
|
*
|
|
|
|
|
* for(i=0;i<lastt;i++)
|
2020-10-12 13:13:31 +02:00
|
|
|
* {
|
2020-12-23 05:07:39 +01:00
|
|
|
int tmp;
|
2020-09-27 12:41:36 +02:00
|
|
|
* count++;
|
|
|
|
|
* rot=tt[i].rot;flip=tt[i].flip;
|
|
|
|
|
* text_bbox(tt[i].txt_ptr, tt[i].xscale, tt[i].yscale, rot, flip,
|
2022-04-28 00:00:51 +02:00
|
|
|
* tt[i].x0, tt[i].y0, &rx1,&ry1,&rx2,&ry2, &dtmp);
|
2020-09-27 12:41:36 +02:00
|
|
|
* tmp.x1=rx1;tmp.y1=ry1;tmp.x2=rx2;tmp.y2=ry2;
|
|
|
|
|
* updatebbox(count,&boundbox,&tmp);
|
|
|
|
|
* }
|
|
|
|
|
*/
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->sym[pos].minx = boundbox.x1;
|
|
|
|
|
xctx->sym[pos].maxx = boundbox.x2;
|
|
|
|
|
xctx->sym[pos].miny = boundbox.y1;
|
|
|
|
|
xctx->sym[pos].maxy = boundbox.y2;
|
2020-09-27 12:41:36 +02:00
|
|
|
}
|
|
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
/* Global (or static global) variables used:
|
2020-09-25 17:11:43 +02:00
|
|
|
* cadlayers
|
|
|
|
|
* errfp
|
2020-10-15 17:39:21 +02:00
|
|
|
* xctx->file_version
|
|
|
|
|
* xctx->sym
|
|
|
|
|
* xctx->symbols
|
2020-09-25 17:11:43 +02:00
|
|
|
* has_x
|
|
|
|
|
*/
|
2020-08-08 15:47:34 +02:00
|
|
|
int load_sym_def(const char *name, FILE *embed_fd)
|
|
|
|
|
{
|
2021-11-20 02:37:56 +01:00
|
|
|
static int recursion_counter=0; /* safe to keep even with multiple schematics, operation not interruptable */
|
2021-12-28 01:33:01 +01:00
|
|
|
Lcc *lcc; /* size = level */
|
2020-08-08 15:47:34 +02:00
|
|
|
FILE *fd_tmp;
|
2020-12-05 03:16:01 +01:00
|
|
|
short rot,flip;
|
2020-08-08 15:47:34 +02:00
|
|
|
double angle;
|
|
|
|
|
double rx1,ry1,rx2,ry2;
|
|
|
|
|
int incremented_level=0;
|
|
|
|
|
int level = 0;
|
2021-01-10 16:11:34 +01:00
|
|
|
int max_level, fscan_ret;
|
2022-04-28 10:12:16 +02:00
|
|
|
#ifdef __unix__
|
2020-09-29 11:17:10 +02:00
|
|
|
long filepos;
|
2022-04-28 10:12:16 +02:00
|
|
|
#else
|
|
|
|
|
__int3264 filepos;
|
|
|
|
|
#endif
|
2020-09-27 12:41:36 +02:00
|
|
|
char sympath[PATH_MAX];
|
|
|
|
|
int i,c, k, poly_points;
|
2020-08-08 15:47:34 +02:00
|
|
|
char *aux_ptr=NULL;
|
|
|
|
|
char *prop_ptr=NULL, *symtype=NULL;
|
|
|
|
|
double inst_x0, inst_y0;
|
2020-12-05 03:16:01 +01:00
|
|
|
short inst_rot, inst_flip;
|
2020-08-08 15:47:34 +02:00
|
|
|
char *symname = NULL;
|
2020-09-25 17:54:50 +02:00
|
|
|
char tag[1];
|
2020-10-12 13:13:31 +02:00
|
|
|
int *lastl = my_malloc(333, cadlayers * sizeof(lastl));
|
2020-08-08 15:47:34 +02:00
|
|
|
int *lastr = my_malloc(334, cadlayers * sizeof(int));
|
|
|
|
|
int *lastp = my_malloc(335, cadlayers * sizeof(int));
|
|
|
|
|
int *lasta = my_malloc(336, cadlayers * sizeof(int));
|
2020-10-12 13:13:31 +02:00
|
|
|
xLine **ll = my_malloc(337, cadlayers * sizeof(xLine *));
|
|
|
|
|
xRect **bb = my_malloc(338, cadlayers * sizeof(xRect *));
|
2020-08-08 15:47:34 +02:00
|
|
|
xArc **aa = my_malloc(339, cadlayers * sizeof(xArc *));
|
2020-10-12 13:13:31 +02:00
|
|
|
xPoly **pp = my_malloc(340, cadlayers * sizeof(xPoly *));
|
2020-09-25 17:54:50 +02:00
|
|
|
int lastt;
|
2020-10-12 13:13:31 +02:00
|
|
|
xText *tt;
|
2020-08-08 15:47:34 +02:00
|
|
|
int endfile;
|
2020-09-23 18:15:26 +02:00
|
|
|
const char *str;
|
2020-08-08 15:47:34 +02:00
|
|
|
char *skip_line;
|
2020-09-02 18:28:20 +02:00
|
|
|
const char *dash;
|
2020-10-16 23:19:20 +02:00
|
|
|
xSymbol * symbol;
|
2021-11-28 14:35:55 +01:00
|
|
|
int symbols, sym_n_pins=0;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-10-16 22:16:54 +02:00
|
|
|
check_symbol_storage();
|
|
|
|
|
symbol = xctx->sym;
|
|
|
|
|
symbols = xctx->symbols;
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "l_s_d(): recursion_counter=%d, name=%s\n", recursion_counter, name);
|
2020-08-08 15:47:34 +02:00
|
|
|
recursion_counter++;
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "l_s_d(): name=%s\n", name);
|
2020-08-08 15:47:34 +02:00
|
|
|
lcc=NULL;
|
2021-12-28 01:33:01 +01:00
|
|
|
my_realloc(647, &lcc, (level + 1) * sizeof(Lcc));
|
2020-08-08 15:47:34 +02:00
|
|
|
max_level = level + 1;
|
2020-10-15 17:39:21 +02:00
|
|
|
if(!strcmp(xctx->file_version,"1.0")) {
|
2020-09-27 12:41:36 +02:00
|
|
|
my_strncpy(sympath, abs_sym_path(name, ".sym"), S(sympath));
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2020-09-27 12:41:36 +02:00
|
|
|
my_strncpy(sympath, abs_sym_path(name, ""), S(sympath));
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
if(!embed_fd) {
|
2020-10-02 03:21:22 +02:00
|
|
|
if((lcc[level].fd=fopen(sympath,fopen_read_mode))==NULL)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-10-15 13:38:27 +02:00
|
|
|
if(recursion_counter == 1) dbg(0, "l_s_d(): Symbol not found: %s\n",sympath);
|
2020-10-15 15:37:06 +02:00
|
|
|
my_snprintf(sympath, S(sympath), "%s/%s", tclgetvar("XSCHEM_SHAREDIR"), "systemlib/missing.sym");
|
2020-10-02 03:21:22 +02:00
|
|
|
if((lcc[level].fd=fopen(sympath, fopen_read_mode))==NULL)
|
2020-10-12 13:13:31 +02:00
|
|
|
{
|
2020-09-27 12:41:36 +02:00
|
|
|
fprintf(errfp, "l_s_d(): systemlib/missing.sym missing, I give up\n");
|
2021-11-29 17:29:09 +01:00
|
|
|
tcleval("exit");
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "l_s_d(): fopen1(%s), level=%d, fd=%p\n",sympath, level, lcc[level].fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "l_s_d(): getting embed_fd, level=%d\n", level);
|
2020-08-08 15:47:34 +02:00
|
|
|
lcc[level].fd = embed_fd;
|
|
|
|
|
}
|
|
|
|
|
endfile=0;
|
2020-10-12 13:13:31 +02:00
|
|
|
for(c=0;c<cadlayers;c++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-09-26 01:15:33 +02:00
|
|
|
lasta[c] = lastl[c] = lastr[c] = lastp[c] = 0;
|
|
|
|
|
ll[c] = NULL; bb[c] = NULL; pp[c] = NULL; aa[c] = NULL;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
lastt=0;
|
|
|
|
|
tt=NULL;
|
2020-10-16 16:34:15 +02:00
|
|
|
symbol[symbols].prop_ptr = NULL;
|
|
|
|
|
symbol[symbols].type = NULL;
|
|
|
|
|
symbol[symbols].templ = NULL;
|
|
|
|
|
symbol[symbols].name=NULL;
|
2021-11-22 12:42:33 +01:00
|
|
|
my_strdup2(352, &symbol[symbols].name,name);
|
2020-09-24 15:59:01 +02:00
|
|
|
while(1)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-09-29 11:17:10 +02:00
|
|
|
if(endfile && embed_fd && level == 0) break; /* ']' line encountered --> exit */
|
2020-08-08 15:47:34 +02:00
|
|
|
if(fscanf(lcc[level].fd," %c",tag)==EOF) {
|
|
|
|
|
if (level) {
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "l_s_d(): fclose1, level=%d, fd=%p\n", level, lcc[level].fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
fclose(lcc[level].fd);
|
|
|
|
|
my_free(898, &lcc[level].prop_ptr);
|
|
|
|
|
my_free(899, &lcc[level].symname);
|
|
|
|
|
--level;
|
|
|
|
|
continue;
|
|
|
|
|
} else break;
|
|
|
|
|
}
|
2020-09-24 17:46:58 +02:00
|
|
|
if(endfile) { /* endfile due to max hierarchy: throw away rest of file and do the above '--level' cleanups */
|
2020-09-26 01:15:33 +02:00
|
|
|
read_record(tag[0], lcc[level].fd, 0);
|
2020-09-24 17:46:58 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
incremented_level = 0;
|
|
|
|
|
switch(tag[0])
|
|
|
|
|
{
|
|
|
|
|
case 'v':
|
|
|
|
|
load_ascii_string(&aux_ptr, lcc[level].fd);
|
|
|
|
|
break;
|
2022-01-14 14:56:13 +01:00
|
|
|
case '#':
|
|
|
|
|
read_line(lcc[level].fd, 1);
|
|
|
|
|
break;
|
2022-01-16 12:42:55 +01:00
|
|
|
case 'F': /* extension for future symbol floater labels */
|
|
|
|
|
read_line(lcc[level].fd, 1);
|
|
|
|
|
break;
|
2020-08-08 15:47:34 +02:00
|
|
|
case 'E':
|
|
|
|
|
load_ascii_string(&aux_ptr, lcc[level].fd);
|
|
|
|
|
break;
|
2020-10-12 13:13:31 +02:00
|
|
|
case 'V':
|
2020-08-08 15:47:34 +02:00
|
|
|
load_ascii_string(&aux_ptr, lcc[level].fd);
|
|
|
|
|
break;
|
2020-10-12 13:13:31 +02:00
|
|
|
case 'S':
|
2020-08-08 15:47:34 +02:00
|
|
|
load_ascii_string(&aux_ptr, lcc[level].fd);
|
|
|
|
|
break;
|
|
|
|
|
case 'K': /* 1.2 file format: symbol attributes for schematics placed as symbols */
|
|
|
|
|
if (level==0) {
|
2020-10-16 16:34:15 +02:00
|
|
|
load_ascii_string(&symbol[symbols].prop_ptr, lcc[level].fd);
|
|
|
|
|
if(!symbol[symbols].prop_ptr) break;
|
|
|
|
|
my_strdup2(424, &symbol[symbols].templ,
|
2020-11-29 01:59:17 +01:00
|
|
|
get_tok_value(symbol[symbols].prop_ptr, "template", 0));
|
2020-10-16 16:34:15 +02:00
|
|
|
my_strdup2(515, &symbol[symbols].type,
|
|
|
|
|
get_tok_value(symbol[symbols].prop_ptr, "type",0));
|
2022-01-16 14:49:59 +01:00
|
|
|
if(!strcmp(get_tok_value(symbol[symbols].prop_ptr,"highlight",0), "true"))
|
|
|
|
|
symbol[symbols].flags |= HILIGHT_CONN;
|
|
|
|
|
else symbol[symbols].flags &= ~HILIGHT_CONN;
|
2020-12-19 03:22:38 +01:00
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
else {
|
|
|
|
|
load_ascii_string(&aux_ptr, lcc[level].fd);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'G': /* .sym files or pre-1.2 symbol attributes for schematics placed as symbols */
|
2020-10-16 16:34:15 +02:00
|
|
|
if (level==0 && !symbol[symbols].prop_ptr) {
|
|
|
|
|
load_ascii_string(&symbol[symbols].prop_ptr, lcc[level].fd);
|
|
|
|
|
if(!symbol[symbols].prop_ptr) break;
|
|
|
|
|
my_strdup2(341, &symbol[symbols].templ,
|
2020-11-29 01:59:17 +01:00
|
|
|
get_tok_value(symbol[symbols].prop_ptr, "template", 0));
|
2020-10-16 16:34:15 +02:00
|
|
|
my_strdup2(342, &symbol[symbols].type,
|
|
|
|
|
get_tok_value(symbol[symbols].prop_ptr, "type",0));
|
2022-01-16 14:49:59 +01:00
|
|
|
if(!strcmp(get_tok_value(symbol[symbols].prop_ptr,"highlight",0), "true"))
|
|
|
|
|
symbol[symbols].flags |= HILIGHT_CONN;
|
|
|
|
|
else symbol[symbols].flags &= ~HILIGHT_CONN;
|
2020-10-12 13:13:31 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
else {
|
|
|
|
|
load_ascii_string(&aux_ptr, lcc[level].fd);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'L':
|
2021-01-10 16:11:34 +01:00
|
|
|
fscan_ret = fscanf(lcc[level].fd, "%d",&c);
|
|
|
|
|
if(fscan_ret != 1 || c < 0 || c>=cadlayers) {
|
|
|
|
|
fprintf(errfp,"l_s_d(): WARNING: wrong or missing line layer\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
2020-09-25 17:54:50 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
i=lastl[c];
|
2020-10-12 13:13:31 +02:00
|
|
|
my_realloc(343, &ll[c],(i+1)*sizeof(xLine));
|
2020-08-08 15:47:34 +02:00
|
|
|
if(fscanf(lcc[level].fd, "%lf %lf %lf %lf ",&ll[c][i].x1, &ll[c][i].y1,
|
|
|
|
|
&ll[c][i].x2, &ll[c][i].y2) < 4 ) {
|
2021-01-10 16:11:34 +01:00
|
|
|
fprintf(errfp,"l_s_d(): WARNING: missing fields for LINE object, ignoring\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (level>0) {
|
|
|
|
|
rot = lcc[level].rot; flip = lcc[level].flip;
|
2020-11-03 12:10:55 +01:00
|
|
|
ROTATION(rot, flip, 0.0, 0.0, ll[c][i].x1, ll[c][i].y1, rx1, ry1);
|
|
|
|
|
ROTATION(rot, flip, 0.0, 0.0, ll[c][i].x2, ll[c][i].y2, rx2, ry2);
|
2020-08-08 15:47:34 +02:00
|
|
|
ll[c][i].x1 = lcc[level].x0 + rx1; ll[c][i].y1 = lcc[level].y0 + ry1;
|
|
|
|
|
ll[c][i].x2 = lcc[level].x0 + rx2; ll[c][i].y2 = lcc[level].y0 + ry2;
|
|
|
|
|
}
|
2020-09-25 17:54:50 +02:00
|
|
|
ORDER(ll[c][i].x1, ll[c][i].y1, ll[c][i].x2, ll[c][i].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
ll[c][i].prop_ptr=NULL;
|
|
|
|
|
load_ascii_string( &ll[c][i].prop_ptr, lcc[level].fd);
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(2, "l_s_d(): loaded line: ptr=%lx\n", (unsigned long)ll[c]);
|
2020-09-07 13:12:34 +02:00
|
|
|
if(!strcmp(get_tok_value(ll[c][i].prop_ptr,"bus", 0), "true") )
|
|
|
|
|
ll[c][i].bus = 1;
|
2020-10-12 13:13:31 +02:00
|
|
|
else
|
2020-09-07 13:12:34 +02:00
|
|
|
ll[c][i].bus = 0;
|
2020-09-02 18:28:20 +02:00
|
|
|
dash = get_tok_value(ll[c][i].prop_ptr,"dash", 0);
|
2020-09-03 00:19:39 +02:00
|
|
|
if( strcmp(dash, "") ) {
|
|
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
ll[c][i].dash = (short)(d >= 0 ? d : 0);
|
2020-10-12 13:13:31 +02:00
|
|
|
} else
|
2020-09-02 18:28:20 +02:00
|
|
|
ll[c][i].dash = 0;
|
|
|
|
|
ll[c][i].sel = 0;
|
2020-08-08 15:47:34 +02:00
|
|
|
lastl[c]++;
|
|
|
|
|
break;
|
2020-09-25 17:54:50 +02:00
|
|
|
case 'P':
|
2020-08-08 15:47:34 +02:00
|
|
|
if(fscanf(lcc[level].fd, "%d %d",&c, &poly_points) < 2 ) {
|
2021-01-10 16:11:34 +01:00
|
|
|
fprintf(errfp,"l_s_d(): WARNING: missing fields for POLYGON object, ignoring\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(c < 0 || c>=cadlayers) {
|
2021-01-10 16:11:34 +01:00
|
|
|
fprintf(errfp,"l_s_d(): WARNING: wrong polygon layer\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
2020-09-25 17:54:50 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
i=lastp[c];
|
2020-10-12 13:13:31 +02:00
|
|
|
my_realloc(344, &pp[c],(i+1)*sizeof(xPoly));
|
2020-08-08 15:47:34 +02:00
|
|
|
pp[c][i].x = my_calloc(345, poly_points, sizeof(double));
|
|
|
|
|
pp[c][i].y = my_calloc(346, poly_points, sizeof(double));
|
|
|
|
|
pp[c][i].selected_point = my_calloc(347, poly_points, sizeof(unsigned short));
|
|
|
|
|
pp[c][i].points = poly_points;
|
|
|
|
|
for(k=0;k<poly_points;k++) {
|
|
|
|
|
if(fscanf(lcc[level].fd, "%lf %lf ",&(pp[c][i].x[k]), &(pp[c][i].y[k]) ) < 2 ) {
|
2021-01-10 16:11:34 +01:00
|
|
|
fprintf(errfp,"l_s_d(): WARNING: missing fields for POLYGON object\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
if (level>0) {
|
|
|
|
|
rot = lcc[level].rot; flip = lcc[level].flip;
|
2020-11-03 12:10:55 +01:00
|
|
|
ROTATION(rot, flip, 0.0, 0.0, pp[c][i].x[k], pp[c][i].y[k], rx1, ry1);
|
2020-08-08 15:47:34 +02:00
|
|
|
pp[c][i].x[k] = lcc[level].x0 + rx1; pp[c][i].y[k] = lcc[level].y0 + ry1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pp[c][i].prop_ptr=NULL;
|
|
|
|
|
load_ascii_string( &pp[c][i].prop_ptr, lcc[level].fd);
|
|
|
|
|
if( !strcmp(get_tok_value(pp[c][i].prop_ptr,"fill",0),"true") )
|
|
|
|
|
pp[c][i].fill =1;
|
|
|
|
|
else
|
|
|
|
|
pp[c][i].fill =0;
|
|
|
|
|
|
2020-09-02 18:28:20 +02:00
|
|
|
dash = get_tok_value(pp[c][i].prop_ptr,"dash", 0);
|
2020-09-03 00:19:39 +02:00
|
|
|
if( strcmp(dash, "") ) {
|
|
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
pp[c][i].dash = (short)(d >= 0 ? d : 0);
|
2020-10-12 13:13:31 +02:00
|
|
|
} else
|
2020-09-02 18:28:20 +02:00
|
|
|
pp[c][i].dash = 0;
|
|
|
|
|
pp[c][i].sel = 0;
|
|
|
|
|
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(2, "l_s_d(): loaded polygon: ptr=%lx\n", (unsigned long)pp[c]);
|
2020-08-08 15:47:34 +02:00
|
|
|
lastp[c]++;
|
|
|
|
|
break;
|
|
|
|
|
case 'A':
|
2021-01-10 16:11:34 +01:00
|
|
|
fscan_ret = fscanf(lcc[level].fd, "%d",&c);
|
|
|
|
|
if(fscan_ret != 1 || c < 0 || c>=cadlayers) {
|
|
|
|
|
fprintf(errfp,"l_s_d(): Wrong or missing arc layer\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
i=lasta[c];
|
|
|
|
|
my_realloc(348, &aa[c],(i+1)*sizeof(xArc));
|
|
|
|
|
if( fscanf(lcc[level].fd, "%lf %lf %lf %lf %lf ",&aa[c][i].x, &aa[c][i].y,
|
|
|
|
|
&aa[c][i].r, &aa[c][i].a, &aa[c][i].b) < 5 ) {
|
2021-01-10 16:11:34 +01:00
|
|
|
fprintf(errfp,"l_s_d(): WARNING: missing fields for ARC object, ignoring\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (level>0) {
|
|
|
|
|
rot = lcc[level].rot; flip = lcc[level].flip;
|
|
|
|
|
if (flip) {
|
|
|
|
|
angle = 270. * rot + 180. - aa[c][i].b - aa[c][i].a;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
angle = aa[c][i].a + rot * 270.;
|
|
|
|
|
}
|
|
|
|
|
angle = fmod(angle, 360.);
|
|
|
|
|
if (angle < 0.) angle += 360.;
|
2020-11-03 12:10:55 +01:00
|
|
|
ROTATION(rot, flip, 0.0, 0.0, aa[c][i].x, aa[c][i].y, rx1, ry1);
|
2020-08-08 15:47:34 +02:00
|
|
|
aa[c][i].x = lcc[level].x0 + rx1; aa[c][i].y = lcc[level].y0 + ry1;
|
|
|
|
|
aa[c][i].a = angle;
|
|
|
|
|
}
|
|
|
|
|
aa[c][i].prop_ptr=NULL;
|
|
|
|
|
load_ascii_string( &aa[c][i].prop_ptr, lcc[level].fd);
|
|
|
|
|
if( !strcmp(get_tok_value(aa[c][i].prop_ptr,"fill",0),"true") )
|
|
|
|
|
aa[c][i].fill =1;
|
|
|
|
|
else
|
|
|
|
|
aa[c][i].fill =0;
|
2020-09-02 23:59:58 +02:00
|
|
|
dash = get_tok_value(aa[c][i].prop_ptr,"dash", 0);
|
2020-09-03 00:19:39 +02:00
|
|
|
if( strcmp(dash, "") ) {
|
|
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
aa[c][i].dash = (short)(d >= 0 ? d : 0);
|
2020-09-03 00:19:39 +02:00
|
|
|
} else
|
2020-09-02 23:59:58 +02:00
|
|
|
aa[c][i].dash = 0;
|
|
|
|
|
aa[c][i].sel = 0;
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(2, "l_s_d(): loaded arc: ptr=%lx\n", (unsigned long)aa[c]);
|
2020-08-08 15:47:34 +02:00
|
|
|
lasta[c]++;
|
|
|
|
|
break;
|
|
|
|
|
case 'B':
|
2021-01-10 16:11:34 +01:00
|
|
|
fscan_ret = fscanf(lcc[level].fd, "%d",&c);
|
|
|
|
|
if(fscan_ret != 1 || c < 0 || c>=cadlayers) {
|
|
|
|
|
fprintf(errfp,"l_s_d(): WARNING: wrong or missing box layer\n");
|
|
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
2020-09-25 17:54:50 +02:00
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
if (level>0 && c == PINLAYER) /* Don't care about pins inside SYM */
|
|
|
|
|
c = 7;
|
|
|
|
|
i=lastr[c];
|
2020-10-12 13:13:31 +02:00
|
|
|
my_realloc(349, &bb[c],(i+1)*sizeof(xRect));
|
2021-01-10 16:11:34 +01:00
|
|
|
if(fscanf(lcc[level].fd, "%lf %lf %lf %lf ",&bb[c][i].x1, &bb[c][i].y1,
|
|
|
|
|
&bb[c][i].x2, &bb[c][i].y2) < 4 ) {
|
|
|
|
|
fprintf(errfp,"l_s_d(): WARNING: missing fields for Box object, ignoring\n");
|
|
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
if (level>0) {
|
|
|
|
|
rot = lcc[level].rot; flip = lcc[level].flip;
|
2020-11-03 12:10:55 +01:00
|
|
|
ROTATION(rot, flip, 0.0, 0.0, bb[c][i].x1, bb[c][i].y1, rx1, ry1);
|
|
|
|
|
ROTATION(rot, flip, 0.0, 0.0, bb[c][i].x2, bb[c][i].y2, rx2, ry2);
|
2020-08-08 15:47:34 +02:00
|
|
|
bb[c][i].x1 = lcc[level].x0 + rx1; bb[c][i].y1 = lcc[level].y0 + ry1;
|
|
|
|
|
bb[c][i].x2 = lcc[level].x0 + rx2; bb[c][i].y2 = lcc[level].y0 + ry2;
|
|
|
|
|
}
|
2020-09-25 17:54:50 +02:00
|
|
|
RECTORDER(bb[c][i].x1, bb[c][i].y1, bb[c][i].x2, bb[c][i].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
bb[c][i].prop_ptr=NULL;
|
|
|
|
|
load_ascii_string( &bb[c][i].prop_ptr, lcc[level].fd);
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(2, "l_s_d(): loaded rect: ptr=%lx\n", (unsigned long)bb[c]);
|
2021-12-20 00:01:10 +01:00
|
|
|
|
2020-09-02 18:28:20 +02:00
|
|
|
dash = get_tok_value(bb[c][i].prop_ptr,"dash", 0);
|
2020-09-03 00:19:39 +02:00
|
|
|
if( strcmp(dash, "") ) {
|
|
|
|
|
int d = atoi(dash);
|
2022-04-28 10:12:16 +02:00
|
|
|
bb[c][i].dash = (short)(d >= 0 ? d : 0);
|
2020-09-03 00:19:39 +02:00
|
|
|
} else
|
2020-09-02 18:28:20 +02:00
|
|
|
bb[c][i].dash = 0;
|
|
|
|
|
bb[c][i].sel = 0;
|
2022-01-24 22:58:30 +01:00
|
|
|
bb[c][i].extraptr = NULL;
|
|
|
|
|
set_rect_flags(&bb[c][i]);
|
2020-08-08 15:47:34 +02:00
|
|
|
lastr[c]++;
|
|
|
|
|
break;
|
|
|
|
|
case 'T':
|
|
|
|
|
i=lastt;
|
2020-10-12 13:13:31 +02:00
|
|
|
my_realloc(350, &tt,(i+1)*sizeof(xText));
|
2020-08-08 15:47:34 +02:00
|
|
|
tt[i].txt_ptr=NULL;
|
|
|
|
|
tt[i].font=NULL;
|
|
|
|
|
load_ascii_string(&tt[i].txt_ptr, lcc[level].fd);
|
2021-01-10 16:11:34 +01:00
|
|
|
if(fscanf(lcc[level].fd, "%lf %lf %hd %hd %lf %lf ",&tt[i].x0, &tt[i].y0, &tt[i].rot,
|
|
|
|
|
&tt[i].flip, &tt[i].xscale, &tt[i].yscale) < 6 ) {
|
|
|
|
|
fprintf(errfp,"l_s_d(): WARNING: missing fields for Text object, ignoring\n");
|
|
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
if (level>0) {
|
2020-08-31 02:25:41 +02:00
|
|
|
const char* tmp = translate2(lcc, level, tt[i].txt_ptr);
|
2020-09-30 23:55:07 +02:00
|
|
|
rot = lcc[level].rot; flip = lcc[level].flip;
|
2020-08-08 15:47:34 +02:00
|
|
|
if (tmp) my_strdup(651, &tt[i].txt_ptr, tmp);
|
2020-11-03 12:10:55 +01:00
|
|
|
ROTATION(rot, flip, 0.0, 0.0, tt[i].x0, tt[i].y0, rx1, ry1);
|
2020-08-08 15:47:34 +02:00
|
|
|
tt[i].x0 = lcc[level].x0 + rx1; tt[i].y0 = lcc[level].y0 + ry1;
|
2020-12-02 15:10:47 +01:00
|
|
|
tt[i].rot = (tt[i].rot + ((lcc[level].flip && (tt[i].rot & 1)) ?
|
|
|
|
|
lcc[level].rot + 2 : lcc[level].rot)) & 0x3;
|
2020-08-08 15:47:34 +02:00
|
|
|
tt[i].flip = lcc[level].flip ^ tt[i].flip;
|
|
|
|
|
}
|
|
|
|
|
tt[i].prop_ptr=NULL;
|
|
|
|
|
load_ascii_string(&tt[i].prop_ptr, lcc[level].fd);
|
2020-09-04 10:29:15 +02:00
|
|
|
if(level > 0 && symtype && !strcmp(symtype, "label")) {
|
|
|
|
|
char lay[30];
|
|
|
|
|
my_snprintf(lay, S(lay), " layer=%d", WIRELAYER);
|
2020-09-15 11:19:57 +02:00
|
|
|
my_strcat(1163, &tt[i].prop_ptr, lay);
|
2020-09-04 10:29:15 +02:00
|
|
|
}
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(1, "l_s_d(): loaded text : t=%s p=%s\n", tt[i].txt_ptr, tt[i].prop_ptr ? tt[i].prop_ptr : "NULL");
|
2020-09-25 17:54:50 +02:00
|
|
|
my_strdup(351, &tt[i].font, get_tok_value(tt[i].prop_ptr, "font", 0));
|
2020-09-23 18:15:26 +02:00
|
|
|
str = get_tok_value(tt[i].prop_ptr, "hcenter", 0);
|
|
|
|
|
tt[i].hcenter = strcmp(str, "true") ? 0 : 1;
|
|
|
|
|
str = get_tok_value(tt[i].prop_ptr, "vcenter", 0);
|
|
|
|
|
tt[i].vcenter = strcmp(str, "true") ? 0 : 1;
|
2020-09-25 17:54:50 +02:00
|
|
|
str = get_tok_value(tt[i].prop_ptr, "layer", 0);
|
2020-09-23 18:15:26 +02:00
|
|
|
if(str[0]) tt[i].layer = atoi(str);
|
2020-08-08 15:47:34 +02:00
|
|
|
else tt[i].layer = -1;
|
2020-09-23 18:15:26 +02:00
|
|
|
tt[i].flags = 0;
|
|
|
|
|
str = get_tok_value(tt[i].prop_ptr, "slant", 0);
|
|
|
|
|
tt[i].flags |= strcmp(str, "oblique") ? 0 : TEXT_OBLIQUE;
|
|
|
|
|
tt[i].flags |= strcmp(str, "italic") ? 0 : TEXT_ITALIC;
|
|
|
|
|
str = get_tok_value(tt[i].prop_ptr, "weight", 0);
|
|
|
|
|
tt[i].flags |= strcmp(str, "bold") ? 0 : TEXT_BOLD;
|
2022-01-13 12:46:55 +01:00
|
|
|
str = get_tok_value(tt[i].prop_ptr, "hide", 0);
|
2022-02-22 12:09:04 +01:00
|
|
|
tt[i].flags |= strcmp(str, "true") ? 0 : HIDE_TEXT;
|
2020-08-08 15:47:34 +02:00
|
|
|
lastt++;
|
|
|
|
|
break;
|
|
|
|
|
case 'N': /* store wires as lines on layer WIRELAYER. */
|
|
|
|
|
i = lastl[WIRELAYER];
|
2020-10-12 13:13:31 +02:00
|
|
|
my_realloc(314, &ll[WIRELAYER],(i+1)*sizeof(xLine));
|
2020-08-08 15:47:34 +02:00
|
|
|
if(fscanf(lcc[level].fd, "%lf %lf %lf %lf ",&ll[WIRELAYER][i].x1, &ll[WIRELAYER][i].y1,
|
|
|
|
|
&ll[WIRELAYER][i].x2, &ll[WIRELAYER][i].y2) < 4 ) {
|
2021-01-10 16:11:34 +01:00
|
|
|
fprintf(errfp,"l_s_d(): WARNING: missing fields for LINE object, ignoring\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (level>0) {
|
|
|
|
|
rot = lcc[level].rot; flip = lcc[level].flip;
|
2020-11-03 12:10:55 +01:00
|
|
|
ROTATION(rot, flip, 0.0, 0.0, ll[WIRELAYER][i].x1, ll[WIRELAYER][i].y1, rx1, ry1);
|
|
|
|
|
ROTATION(rot, flip, 0.0, 0.0, ll[WIRELAYER][i].x2, ll[WIRELAYER][i].y2, rx2, ry2);
|
2020-08-08 15:47:34 +02:00
|
|
|
ll[WIRELAYER][i].x1 = lcc[level].x0 + rx1; ll[WIRELAYER][i].y1 = lcc[level].y0 + ry1;
|
|
|
|
|
ll[WIRELAYER][i].x2 = lcc[level].x0 + rx2; ll[WIRELAYER][i].y2 = lcc[level].y0 + ry2;
|
|
|
|
|
}
|
2020-09-25 17:54:50 +02:00
|
|
|
ORDER(ll[WIRELAYER][i].x1, ll[WIRELAYER][i].y1, ll[WIRELAYER][i].x2, ll[WIRELAYER][i].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
ll[WIRELAYER][i].prop_ptr=NULL;
|
|
|
|
|
load_ascii_string( &ll[WIRELAYER][i].prop_ptr, lcc[level].fd);
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(2, "l_s_d(): loaded line: ptr=%lx\n", (unsigned long)ll[WIRELAYER]);
|
2020-09-02 18:28:20 +02:00
|
|
|
ll[WIRELAYER][i].dash = 0;
|
2020-09-07 13:12:34 +02:00
|
|
|
if(!strcmp(get_tok_value(ll[WIRELAYER][i].prop_ptr, "bus", 0), "true"))
|
|
|
|
|
ll[WIRELAYER][i].bus = 1;
|
|
|
|
|
else
|
|
|
|
|
ll[WIRELAYER][i].bus = 0;
|
2020-09-02 18:28:20 +02:00
|
|
|
ll[WIRELAYER][i].sel = 0;
|
2020-08-08 15:47:34 +02:00
|
|
|
lastl[WIRELAYER]++;
|
|
|
|
|
break;
|
|
|
|
|
case 'C':
|
|
|
|
|
load_ascii_string(&symname, lcc[level].fd);
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(1, "l_s_d(): C line: symname=%s\n", symname);
|
2020-12-05 03:16:01 +01:00
|
|
|
if (fscanf(lcc[level].fd, "%lf %lf %hd %hd", &inst_x0, &inst_y0, &inst_rot, &inst_flip) < 4) {
|
2021-01-10 16:11:34 +01:00
|
|
|
fprintf(errfp, "l_s_d(): WARNING: missing fields for COMPONENT object, ignoring\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
load_ascii_string(&prop_ptr, lcc[level].fd);
|
|
|
|
|
if(level + 1 >=CADMAXHIER) {
|
2021-05-31 07:39:23 +02:00
|
|
|
fprintf(errfp, "l_s_d(): Symbol recursively instantiating symbol: max depth reached, skipping\n");
|
2020-10-12 13:13:31 +02:00
|
|
|
if(has_x) tcleval("alert_ {xSymbol recursively instantiating symbol: max depth reached, skipping} {} 1");
|
2020-08-08 15:47:34 +02:00
|
|
|
endfile = 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-29 11:17:10 +02:00
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
{
|
2020-09-29 11:17:10 +02:00
|
|
|
char c;
|
2020-10-02 03:21:22 +02:00
|
|
|
filepos = xftell(lcc[level].fd); /* store file pointer position to inspect next line */
|
2020-09-29 11:17:10 +02:00
|
|
|
fd_tmp = NULL;
|
|
|
|
|
read_line(lcc[level].fd, 1);
|
2021-01-10 16:11:34 +01:00
|
|
|
fscan_ret = fscanf(lcc[level].fd, " ");
|
2020-09-29 11:17:10 +02:00
|
|
|
if(fscanf(lcc[level].fd," %c",&c)!=EOF) {
|
|
|
|
|
if( c == '[') {
|
|
|
|
|
fd_tmp = lcc[level].fd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* get symbol type by looking into list of loaded symbols or (if not found) by
|
|
|
|
|
* opening/closing the symbol file and getting the 'type' attribute from global symbol attributes
|
|
|
|
|
* if fd_tmp set read symbol from embedded tags '[...]' */
|
2021-11-28 14:35:55 +01:00
|
|
|
get_sym_type(symname, &symtype, NULL, fd_tmp, &sym_n_pins);
|
2020-10-02 03:21:22 +02:00
|
|
|
xfseek(lcc[level].fd, filepos, SEEK_SET); /* rewind file pointer */
|
2020-09-29 11:17:10 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "l_s_d(): level=%d, symname=%s symtype=%s\n", level, symname, symtype);
|
2020-08-08 15:47:34 +02:00
|
|
|
if( /* add here symbol types not to consider when loading schematic-as-symbol instances */
|
|
|
|
|
!strcmp(symtype, "logo") ||
|
|
|
|
|
!strcmp(symtype, "netlist_commands") ||
|
|
|
|
|
!strcmp(symtype, "arch_declarations") ||
|
|
|
|
|
!strcmp(symtype, "architecture") ||
|
|
|
|
|
!strcmp(symtype, "attributes") ||
|
|
|
|
|
!strcmp(symtype, "package") ||
|
|
|
|
|
!strcmp(symtype, "port_attributes") ||
|
|
|
|
|
!strcmp(symtype, "use") ||
|
|
|
|
|
!strcmp(symtype, "launcher") ||
|
|
|
|
|
!strcmp(symtype, "verilog_preprocessor") ||
|
2020-10-12 13:13:31 +02:00
|
|
|
!strcmp(symtype, "timescale")
|
2020-08-08 15:47:34 +02:00
|
|
|
) break;
|
2020-09-26 01:15:33 +02:00
|
|
|
/* add PINLAYER boxes (symbol pins) at schematic i/o/iopin coordinates. */
|
2020-10-04 19:53:09 +02:00
|
|
|
if( level==0 && IS_PIN(symtype) ) {
|
2020-09-26 01:15:33 +02:00
|
|
|
add_pinlayer_boxes(lastr, bb, symtype, prop_ptr, inst_x0, inst_y0);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-09-26 01:15:33 +02:00
|
|
|
/* build symbol filename to be loaded */
|
2020-10-15 17:39:21 +02:00
|
|
|
if (!strcmp(xctx->file_version, "1.0")) {
|
2020-09-27 12:41:36 +02:00
|
|
|
my_strncpy(sympath, abs_sym_path(symname, ".sym"), S(sympath));
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-09-27 12:41:36 +02:00
|
|
|
my_strncpy(sympath, abs_sym_path(symname, ""), S(sympath));
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-09-26 01:15:33 +02:00
|
|
|
/* replace i/o/iopin.sym filename with better looking (for LCC symbol) pins */
|
2020-09-27 12:41:36 +02:00
|
|
|
use_lcc_pins(level, symtype, &sympath);
|
2020-08-08 15:47:34 +02:00
|
|
|
|
2020-09-29 11:17:10 +02:00
|
|
|
/* find out if symbol is in an external file or embedded, set fd_tmp accordingly */
|
2020-10-02 03:21:22 +02:00
|
|
|
if ((fd_tmp = fopen(sympath, fopen_read_mode)) == NULL) {
|
2020-09-29 11:17:10 +02:00
|
|
|
char c;
|
2020-09-27 12:41:36 +02:00
|
|
|
fprintf(errfp, "l_s_d(): unable to open file to read schematic: %s\n", sympath);
|
2020-10-02 03:21:22 +02:00
|
|
|
filepos = xftell(lcc[level].fd); /* store file pointer position to inspect next char */
|
2020-09-29 11:17:10 +02:00
|
|
|
read_line(lcc[level].fd, 1);
|
2021-01-10 16:11:34 +01:00
|
|
|
fscan_ret = fscanf(lcc[level].fd, " ");
|
2020-09-29 11:17:10 +02:00
|
|
|
if(fscanf(lcc[level].fd," %c",&c)!=EOF) {
|
|
|
|
|
if( c == '[') {
|
|
|
|
|
fd_tmp = lcc[level].fd;
|
|
|
|
|
} else {
|
2020-10-02 03:21:22 +02:00
|
|
|
xfseek(lcc[level].fd, filepos, SEEK_SET); /* rewind file pointer */
|
2020-09-29 11:17:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(fd_tmp) {
|
2020-08-08 15:47:34 +02:00
|
|
|
if (level+1 >= max_level) {
|
2021-12-28 01:33:01 +01:00
|
|
|
my_realloc(653, &lcc, (max_level + 1) * sizeof(Lcc));
|
2020-08-08 15:47:34 +02:00
|
|
|
max_level++;
|
|
|
|
|
}
|
|
|
|
|
++level;
|
|
|
|
|
incremented_level = 1;
|
|
|
|
|
lcc[level].fd = fd_tmp;
|
|
|
|
|
lcc[level].prop_ptr = NULL;
|
|
|
|
|
lcc[level].symname = NULL;
|
|
|
|
|
lcc[level].x0 = inst_x0;
|
|
|
|
|
lcc[level].y0 = inst_y0;
|
|
|
|
|
lcc[level].rot = inst_rot;
|
|
|
|
|
lcc[level].flip = inst_flip;
|
2020-10-12 13:13:31 +02:00
|
|
|
/* calculate LCC sub-schematic x0, y0, rotation and flip */
|
2020-08-08 15:47:34 +02:00
|
|
|
if (level > 1) {
|
2020-12-05 03:16:01 +01:00
|
|
|
short rot, flip;
|
2021-11-20 02:37:56 +01:00
|
|
|
static const int map[4]={0,3,2,1};
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
flip = lcc[level-1].flip;
|
|
|
|
|
rot = lcc[level-1].rot;
|
2020-11-03 12:10:55 +01:00
|
|
|
ROTATION(rot, flip, 0.0, 0.0, lcc[level].x0, lcc[level].y0,lcc[level].x0, lcc[level].y0);
|
2022-04-28 10:12:16 +02:00
|
|
|
lcc[level].rot = (short)((lcc[(level-1)].flip ? map[lcc[level].rot] :
|
|
|
|
|
lcc[level].rot) + lcc[(level-1)].rot);
|
2020-08-08 15:47:34 +02:00
|
|
|
lcc[level].rot &= 0x3;
|
|
|
|
|
lcc[level].flip = lcc[level].flip ^ lcc[level-1].flip;
|
|
|
|
|
lcc[level].x0 += lcc[(level-1)].x0;
|
|
|
|
|
lcc[level].y0 += lcc[(level-1)].y0;
|
|
|
|
|
}
|
|
|
|
|
my_strdup(654, &lcc[level].prop_ptr, prop_ptr);
|
|
|
|
|
my_strdup(657, &lcc[level].symname, symname);
|
2020-11-16 12:33:06 +01:00
|
|
|
dbg(1, "level incremented: level=%d, symname=%s, prop_ptr=%s sympath=%s\n",
|
|
|
|
|
level, symname, prop_ptr, sympath);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '[':
|
|
|
|
|
while(1) { /* skip embedded [ ... ] */
|
2020-09-29 11:17:10 +02:00
|
|
|
skip_line = read_line(lcc[level].fd, 1);
|
2020-09-28 15:21:26 +02:00
|
|
|
if(!skip_line || !strncmp(skip_line, "]", 1)) break;
|
2021-01-10 16:11:34 +01:00
|
|
|
fscan_ret = fscanf(lcc[level].fd, " ");
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ']':
|
2020-09-29 11:17:10 +02:00
|
|
|
if(level) {
|
2020-09-30 00:55:34 +02:00
|
|
|
my_free(1173, &lcc[level].prop_ptr);
|
|
|
|
|
my_free(1174, &lcc[level].symname);
|
2020-09-29 11:17:10 +02:00
|
|
|
--level;
|
|
|
|
|
} else {
|
|
|
|
|
endfile=1;
|
|
|
|
|
}
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if( tag[0] == '{' ) ungetc(tag[0], lcc[level].fd);
|
2020-09-26 01:15:33 +02:00
|
|
|
read_record(tag[0], lcc[level].fd, 0);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* if a 'C' line was encountered and level was incremented, rest of line must be read
|
|
|
|
|
with lcc[level-1].fd file pointer */
|
2020-10-12 13:13:31 +02:00
|
|
|
if(incremented_level)
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level-1].fd, 0); /* discard any remaining characters till (but not including) newline */
|
2020-10-12 13:13:31 +02:00
|
|
|
else
|
2020-08-08 15:47:34 +02:00
|
|
|
read_line(lcc[level].fd, 0); /* discard any remaining characters till (but not including) newline */
|
|
|
|
|
}
|
|
|
|
|
if(!embed_fd) {
|
2020-09-27 12:41:36 +02:00
|
|
|
dbg(1, "l_s_d(): fclose2, level=%d, fd=%p\n", level, lcc[0].fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
fclose(lcc[0].fd);
|
|
|
|
|
}
|
|
|
|
|
if(embed_fd || strstr(name, ".xschem_embedded_")) {
|
2020-10-16 16:34:15 +02:00
|
|
|
symbol[symbols].flags |= EMBEDDED;
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2020-10-16 16:34:15 +02:00
|
|
|
symbol[symbols].flags &= ~EMBEDDED;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-11-16 02:25:43 +01:00
|
|
|
dbg(2, "l_s_d(): finished parsing file\n");
|
2020-08-08 15:47:34 +02:00
|
|
|
for(c=0;c<cadlayers;c++)
|
|
|
|
|
{
|
2020-10-16 16:34:15 +02:00
|
|
|
symbol[symbols].arcs[c] = lasta[c];
|
|
|
|
|
symbol[symbols].lines[c] = lastl[c];
|
|
|
|
|
symbol[symbols].rects[c] = lastr[c];
|
|
|
|
|
symbol[symbols].polygons[c] = lastp[c];
|
|
|
|
|
symbol[symbols].arc[c] = aa[c];
|
|
|
|
|
symbol[symbols].line[c] = ll[c];
|
|
|
|
|
symbol[symbols].poly[c] = pp[c];
|
|
|
|
|
symbol[symbols].rect[c] = bb[c];
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-10-16 16:34:15 +02:00
|
|
|
symbol[symbols].texts = lastt;
|
|
|
|
|
symbol[symbols].text = tt;
|
|
|
|
|
calc_symbol_bbox(symbols);
|
2020-10-12 13:13:31 +02:00
|
|
|
/* given a .sch file used as instance in LCC schematics, order its pin
|
2020-09-27 12:41:36 +02:00
|
|
|
* as in corresponding .sym file if it exists */
|
2020-10-16 16:34:15 +02:00
|
|
|
align_sch_pins_with_sym(name, symbols);
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->symbols++;
|
2020-09-27 12:41:36 +02:00
|
|
|
my_free(910, &prop_ptr);
|
2020-08-08 15:47:34 +02:00
|
|
|
my_free(901, &lastl);
|
|
|
|
|
my_free(902, &lastr);
|
|
|
|
|
my_free(903, &lastp);
|
|
|
|
|
my_free(904, &lasta);
|
|
|
|
|
my_free(905, &ll);
|
|
|
|
|
my_free(906, &bb);
|
|
|
|
|
my_free(907, &aa);
|
|
|
|
|
my_free(908, &pp);
|
|
|
|
|
my_free(909, &lcc);
|
|
|
|
|
my_free(911, &aux_ptr);
|
|
|
|
|
my_free(912, &symname);
|
|
|
|
|
my_free(913, &symtype);
|
|
|
|
|
recursion_counter--;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-05 08:58:38 +02:00
|
|
|
void make_schematic_symbol_from_sel(void)
|
|
|
|
|
{
|
|
|
|
|
char filename[PATH_MAX] = "";
|
|
|
|
|
char name[1024];
|
|
|
|
|
|
2022-09-27 13:15:04 +02:00
|
|
|
my_snprintf(name, S(name), "save_file_dialog {Save file} *.\\{sch,sym\\} INITIALLOADDIR");
|
2021-06-05 08:58:38 +02:00
|
|
|
tcleval(name);
|
|
|
|
|
my_strncpy(filename, tclresult(), S(filename));
|
|
|
|
|
if (!strcmp(filename, xctx->sch[xctx->currsch])) {
|
|
|
|
|
if (has_x)
|
2021-12-17 03:29:53 +01:00
|
|
|
tcleval("tk_messageBox -type ok -parent [xschem get topwindow] "
|
|
|
|
|
"-message {Cannot overwrite current schematic}");
|
2021-06-05 08:58:38 +02:00
|
|
|
}
|
|
|
|
|
else if (strlen(filename)) {
|
2021-11-29 11:52:32 +01:00
|
|
|
if (xctx->lastsel) xctx->push_undo();
|
2021-06-05 08:58:38 +02:00
|
|
|
make_schematic(filename);
|
|
|
|
|
delete(0/*to_push_undo*/);
|
|
|
|
|
place_symbol(-1, filename, 0, 0, 0, 0, NULL, 4, 1, 0/*to_push_undo*/);
|
|
|
|
|
if (has_x)
|
|
|
|
|
{
|
2021-11-24 13:52:59 +01:00
|
|
|
my_snprintf(name, S(name),
|
2021-12-17 03:29:53 +01:00
|
|
|
"tk_messageBox -type okcancel -parent [xschem get topwindow] "
|
|
|
|
|
"-message {do you want to make symbol view for %s ?}", filename);
|
2021-06-05 08:58:38 +02:00
|
|
|
tcleval(name);
|
|
|
|
|
}
|
|
|
|
|
if (!has_x || !strcmp(tclresult(), "ok")) {
|
|
|
|
|
my_snprintf(name, S(name), "make_symbol_lcc {%s}", filename);
|
|
|
|
|
dbg(1, "make_symbol_lcc(): making symbol: name=%s\n", filename);
|
|
|
|
|
tcleval(name);
|
|
|
|
|
}
|
2021-06-07 00:15:00 +02:00
|
|
|
draw();
|
2021-06-05 08:58:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
void create_sch_from_sym(void)
|
|
|
|
|
{
|
2020-10-12 13:13:31 +02:00
|
|
|
xSymbol *ptr;
|
2020-08-08 15:47:34 +02:00
|
|
|
int i, j, npin, ypos;
|
|
|
|
|
double x;
|
|
|
|
|
int p=0;
|
2020-10-12 13:13:31 +02:00
|
|
|
xRect *rct;
|
2020-08-08 15:47:34 +02:00
|
|
|
FILE *fd;
|
|
|
|
|
char *pindir[3] = {"in", "out", "inout"};
|
|
|
|
|
char *pinname[3] = {"devices/ipin.sym", "devices/opin.sym", "devices/iopin.sym"};
|
|
|
|
|
char *generic_pin = {"devices/generic_pin.sym"};
|
|
|
|
|
char *pinname2[3] = {"ipin.sym", "opin.sym", "iopin.sym"};
|
|
|
|
|
char *generic_pin2 = {"generic_pin.sym"};
|
|
|
|
|
int indirect;
|
|
|
|
|
|
|
|
|
|
char *dir = NULL;
|
|
|
|
|
char *prop = NULL;
|
|
|
|
|
char schname[PATH_MAX];
|
|
|
|
|
char *sub_prop;
|
|
|
|
|
char *sub2_prop=NULL;
|
|
|
|
|
char *str=NULL;
|
|
|
|
|
struct stat buf;
|
2021-06-17 00:25:39 +02:00
|
|
|
char *sch = NULL;
|
2022-04-28 10:12:16 +02:00
|
|
|
size_t ln;
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
if(!stat(abs_sym_path(pinname[0], ""), &buf)) {
|
|
|
|
|
indirect=1;
|
|
|
|
|
} else {
|
|
|
|
|
indirect=0;
|
|
|
|
|
}
|
|
|
|
|
/* printf("indirect=%d\n", indirect); */
|
|
|
|
|
|
|
|
|
|
rebuild_selected_array();
|
2020-12-02 15:10:47 +01:00
|
|
|
if(xctx->lastsel > 1) return;
|
|
|
|
|
if(xctx->lastsel==1 && xctx->sel_array[0].type==ELEMENT)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2021-06-17 00:25:39 +02:00
|
|
|
my_strdup2(1250, &sch,
|
|
|
|
|
get_tok_value((xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->prop_ptr, "schematic",0 ));
|
|
|
|
|
my_strncpy(schname, abs_sym_path(sch, ""), S(schname));
|
|
|
|
|
my_free(1251, &sch);
|
2020-08-08 15:47:34 +02:00
|
|
|
if(!schname[0]) {
|
2020-12-02 15:10:47 +01:00
|
|
|
my_strncpy(schname, add_ext(abs_sym_path(xctx->inst[xctx->sel_array[0].n].name, ""), ".sch"), S(schname));
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
if( !stat(schname, &buf) ) {
|
2021-12-05 12:39:05 +01:00
|
|
|
tclvareval("ask_save \"Create schematic file: ", schname,
|
2021-11-20 13:33:40 +01:00
|
|
|
"?\nWARNING: This schematic file already exists, it will be overwritten\"", NULL);
|
2020-08-16 03:34:45 +02:00
|
|
|
if(strcmp(tclresult(), "yes") ) {
|
2020-08-08 15:47:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!(fd=fopen(schname,"w")))
|
|
|
|
|
{
|
|
|
|
|
fprintf(errfp, "create_sch_from_sym(): problems opening file %s \n",schname);
|
2020-09-25 17:54:50 +02:00
|
|
|
tcleval("alert_ {file opening for write failed!} {}");
|
2020-08-08 15:47:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fprintf(fd, "v {xschem version=%s file_version=%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION);
|
|
|
|
|
fprintf(fd, "G {}");
|
|
|
|
|
fputc('\n', fd);
|
|
|
|
|
fprintf(fd, "V {}");
|
|
|
|
|
fputc('\n', fd);
|
2020-09-25 17:54:50 +02:00
|
|
|
fprintf(fd, "E {}");
|
2020-08-08 15:47:34 +02:00
|
|
|
fputc('\n', fd);
|
|
|
|
|
fprintf(fd, "S {}");
|
|
|
|
|
fputc('\n', fd);
|
2020-12-02 15:10:47 +01:00
|
|
|
ptr = xctx->inst[xctx->sel_array[0].n].ptr+xctx->sym;
|
2020-08-08 15:47:34 +02:00
|
|
|
npin = ptr->rects[GENERICLAYER];
|
2020-10-12 13:13:31 +02:00
|
|
|
rct = ptr->rect[GENERICLAYER];
|
2020-08-08 15:47:34 +02:00
|
|
|
ypos=0;
|
|
|
|
|
for(i=0;i<npin;i++) {
|
2020-10-12 13:13:31 +02:00
|
|
|
my_strdup(356, &prop, rct[i].prop_ptr);
|
2020-08-08 15:47:34 +02:00
|
|
|
if(!prop) continue;
|
|
|
|
|
sub_prop=strstr(prop,"name=")+5;
|
|
|
|
|
if(!sub_prop) continue;
|
|
|
|
|
x=-120.0;
|
|
|
|
|
ln = 100+strlen(sub_prop);
|
|
|
|
|
my_realloc(357, &str, ln);
|
|
|
|
|
my_snprintf(str, ln, "name=g%d lab=%s", p++, sub_prop);
|
|
|
|
|
if(indirect)
|
|
|
|
|
fprintf(fd, "C {%s} %.16g %.16g %.16g %.16g ", generic_pin, x, 20.0*(ypos++), 0.0, 0.0 );
|
|
|
|
|
else
|
|
|
|
|
fprintf(fd, "C {%s} %.16g %.16g %.16g %.16g ", generic_pin2, x, 20.0*(ypos++), 0.0, 0.0 );
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(str, fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
} /* for(i) */
|
|
|
|
|
npin = ptr->rects[PINLAYER];
|
2020-10-12 13:13:31 +02:00
|
|
|
rct = ptr->rect[PINLAYER];
|
2020-08-08 15:47:34 +02:00
|
|
|
for(j=0;j<3;j++) {
|
|
|
|
|
if(j==1) ypos=0;
|
|
|
|
|
for(i=0;i<npin;i++) {
|
2020-10-12 13:13:31 +02:00
|
|
|
my_strdup(358, &prop, rct[i].prop_ptr);
|
2020-08-08 15:47:34 +02:00
|
|
|
if(!prop) continue;
|
|
|
|
|
sub_prop=strstr(prop,"name=")+5;
|
|
|
|
|
if(!sub_prop) continue;
|
|
|
|
|
/* remove dir=... from prop string 20171004 */
|
|
|
|
|
my_strdup(360, &sub2_prop, subst_token(sub_prop, "dir", NULL));
|
|
|
|
|
|
2020-10-12 13:13:31 +02:00
|
|
|
my_strdup(361, &dir, get_tok_value(rct[i].prop_ptr,"dir",0));
|
2020-08-08 15:47:34 +02:00
|
|
|
if(!sub2_prop) continue;
|
|
|
|
|
if(!dir) continue;
|
|
|
|
|
if(j==0) x=-120.0; else x=120.0;
|
2020-10-12 13:13:31 +02:00
|
|
|
if(!strcmp(dir, pindir[j])) {
|
2020-08-08 15:47:34 +02:00
|
|
|
ln = 100+strlen(sub2_prop);
|
|
|
|
|
my_realloc(362, &str, ln);
|
|
|
|
|
my_snprintf(str, ln, "name=g%d lab=%s", p++, sub2_prop);
|
|
|
|
|
if(indirect)
|
|
|
|
|
fprintf(fd, "C {%s} %.16g %.16g %.16g %.16g ", pinname[j], x, 20.0*(ypos++), 0.0, 0.0);
|
|
|
|
|
else
|
|
|
|
|
fprintf(fd, "C {%s} %.16g %.16g %.16g %.16g ", pinname2[j], x, 20.0*(ypos++), 0.0, 0.0);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(str, fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
} /* if() */
|
|
|
|
|
} /* for(i) */
|
|
|
|
|
} /* for(j) */
|
|
|
|
|
fclose(fd);
|
2020-12-02 15:10:47 +01:00
|
|
|
} /* if(xctx->lastsel...) */
|
2020-08-08 15:47:34 +02:00
|
|
|
my_free(916, &dir);
|
|
|
|
|
my_free(917, &prop);
|
|
|
|
|
my_free(919, &sub2_prop);
|
|
|
|
|
my_free(920, &str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void descend_symbol(void)
|
|
|
|
|
{
|
|
|
|
|
char *str=NULL;
|
|
|
|
|
FILE *fd;
|
|
|
|
|
char name[PATH_MAX];
|
|
|
|
|
char name_embedded[PATH_MAX];
|
|
|
|
|
rebuild_selected_array();
|
2020-12-02 15:10:47 +01:00
|
|
|
if(xctx->lastsel > 1) return;
|
|
|
|
|
if(xctx->lastsel==1 && xctx->sel_array[0].type==ELEMENT) {
|
2021-11-22 00:42:53 +01:00
|
|
|
if(xctx->modified)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = save(1);
|
|
|
|
|
/* if circuit is changed but not saved before descending
|
|
|
|
|
* state will be inconsistent when returning, can not propagare hilights
|
|
|
|
|
* save() return value:
|
|
|
|
|
* 1 : file saved
|
|
|
|
|
* -1 : user cancel
|
|
|
|
|
* 0 : file not saved due to errors or per user request
|
|
|
|
|
*/
|
|
|
|
|
if(ret == 0) clear_all_hilights();
|
|
|
|
|
if(ret == -1) return; /* user cancel */
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2020-12-02 15:10:47 +01:00
|
|
|
my_snprintf(name, S(name), "%s", xctx->inst[xctx->sel_array[0].n].name);
|
2020-08-08 15:47:34 +02:00
|
|
|
/* dont allow descend in the default missing symbol */
|
2020-12-02 15:10:47 +01:00
|
|
|
if((xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->type &&
|
|
|
|
|
!strcmp( (xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->type,"missing")) return;
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
else return;
|
|
|
|
|
|
|
|
|
|
/* build up current hierarchy path */
|
2020-12-02 15:10:47 +01:00
|
|
|
my_strdup(363, &str, xctx->inst[xctx->sel_array[0].n].instname);
|
2020-10-15 17:39:21 +02:00
|
|
|
my_strdup(364, &xctx->sch_path[xctx->currsch+1], xctx->sch_path[xctx->currsch]);
|
|
|
|
|
my_strcat(365, &xctx->sch_path[xctx->currsch+1], str);
|
|
|
|
|
my_strcat(366, &xctx->sch_path[xctx->currsch+1], ".");
|
2021-01-02 01:55:01 +01:00
|
|
|
xctx->sch_path_hash[xctx->currsch+1] = 0;
|
2022-03-07 01:42:53 +01:00
|
|
|
|
|
|
|
|
my_strdup(1518, &xctx->hier_attr[xctx->currsch].prop_ptr,
|
|
|
|
|
xctx->inst[xctx->sel_array[0].n].prop_ptr);
|
|
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->sch_inst_number[xctx->currsch+1] = 1;
|
2020-08-08 15:47:34 +02:00
|
|
|
my_free(921, &str);
|
2020-12-02 15:10:47 +01:00
|
|
|
xctx->previous_instance[xctx->currsch]=xctx->sel_array[0].n;
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->zoom_array[xctx->currsch].x=xctx->xorigin;
|
|
|
|
|
xctx->zoom_array[xctx->currsch].y=xctx->yorigin;
|
|
|
|
|
xctx->zoom_array[xctx->currsch].zoom=xctx->zoom;
|
|
|
|
|
++xctx->currsch;
|
2020-12-02 15:10:47 +01:00
|
|
|
if((xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->flags & EMBEDDED ||
|
|
|
|
|
!strcmp(get_tok_value(xctx->inst[xctx->sel_array[0].n].prop_ptr,"embed", 0), "true")) {
|
2020-08-08 15:47:34 +02:00
|
|
|
/* save embedded symbol into a temporary file */
|
|
|
|
|
my_snprintf(name_embedded, S(name_embedded),
|
|
|
|
|
"%s/.xschem_embedded_%d_%s", tclgetvar("XSCHEM_TMP_DIR"), getpid(), get_cell_w_ext(name, 0));
|
|
|
|
|
if(!(fd = fopen(name_embedded, "w")) ) {
|
|
|
|
|
fprintf(errfp, "descend_symbol(): problems opening file %s \n", name_embedded);
|
|
|
|
|
}
|
2020-12-02 15:10:47 +01:00
|
|
|
save_embedded_symbol(xctx->inst[xctx->sel_array[0].n].ptr+xctx->sym, fd);
|
2020-08-08 15:47:34 +02:00
|
|
|
fclose(fd);
|
2022-08-25 13:59:36 +02:00
|
|
|
unselect_all(1);
|
2020-08-08 15:47:34 +02:00
|
|
|
remove_symbols(); /* must follow save (if) embedded */
|
|
|
|
|
/* load_symbol(name_embedded); */
|
|
|
|
|
load_schematic(1, name_embedded, 1);
|
|
|
|
|
} else {
|
|
|
|
|
/* load_symbol(abs_sym_path(name, "")); */
|
2022-08-25 13:59:36 +02:00
|
|
|
unselect_all(1);
|
2020-08-08 15:47:34 +02:00
|
|
|
remove_symbols(); /* must follow save (if) embedded */
|
|
|
|
|
load_schematic(1, abs_sym_path(name, ""), 1);
|
|
|
|
|
}
|
2020-12-22 00:13:25 +01:00
|
|
|
zoom_full(1, 0, 1, 0.97);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 20111023 align selected object to current grid setting */
|
2021-12-17 15:40:19 +01:00
|
|
|
#define SNAP_TO_GRID(a) (a=my_round(( a)/c_snap)*c_snap )
|
2021-11-10 13:43:08 +01:00
|
|
|
void round_schematic_to_grid(double c_snap)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
int i, c, n, p;
|
|
|
|
|
rebuild_selected_array();
|
2020-12-02 15:10:47 +01:00
|
|
|
for(i=0;i<xctx->lastsel;i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-12-02 15:10:47 +01:00
|
|
|
c = xctx->sel_array[i].col; n = xctx->sel_array[i].n;
|
|
|
|
|
switch(xctx->sel_array[i].type)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
case xTEXT:
|
2020-10-15 17:39:21 +02:00
|
|
|
SNAP_TO_GRID(xctx->text[n].x0);
|
|
|
|
|
SNAP_TO_GRID(xctx->text[n].y0);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case xRECT:
|
|
|
|
|
if(c == PINLAYER) {
|
|
|
|
|
double midx, midx_round, deltax;
|
|
|
|
|
double midy, midy_round, deltay;
|
2020-10-15 17:39:21 +02:00
|
|
|
midx_round = midx = (xctx->rect[c][n].x1 + xctx->rect[c][n].x2) / 2;
|
|
|
|
|
midy_round = midy = (xctx->rect[c][n].y1 + xctx->rect[c][n].y2) / 2;
|
2020-08-08 15:47:34 +02:00
|
|
|
SNAP_TO_GRID(midx_round);
|
|
|
|
|
SNAP_TO_GRID(midy_round);
|
|
|
|
|
deltax = midx_round - midx;
|
|
|
|
|
deltay = midy_round - midy;
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->rect[c][n].x1 += deltax;
|
|
|
|
|
xctx->rect[c][n].x2 += deltax;
|
|
|
|
|
xctx->rect[c][n].y1 += deltay;
|
|
|
|
|
xctx->rect[c][n].y2 += deltay;
|
2020-08-08 15:47:34 +02:00
|
|
|
} else {
|
2020-10-15 17:39:21 +02:00
|
|
|
SNAP_TO_GRID(xctx->rect[c][n].x1);
|
|
|
|
|
SNAP_TO_GRID(xctx->rect[c][n].y1);
|
|
|
|
|
SNAP_TO_GRID(xctx->rect[c][n].x2);
|
|
|
|
|
SNAP_TO_GRID(xctx->rect[c][n].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WIRE:
|
2020-10-15 17:39:21 +02:00
|
|
|
SNAP_TO_GRID(xctx->wire[n].x1);
|
|
|
|
|
SNAP_TO_GRID(xctx->wire[n].y1);
|
|
|
|
|
SNAP_TO_GRID(xctx->wire[n].x2);
|
|
|
|
|
SNAP_TO_GRID(xctx->wire[n].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LINE:
|
2020-10-15 17:39:21 +02:00
|
|
|
SNAP_TO_GRID(xctx->line[c][n].x1);
|
|
|
|
|
SNAP_TO_GRID(xctx->line[c][n].y1);
|
|
|
|
|
SNAP_TO_GRID(xctx->line[c][n].x2);
|
|
|
|
|
SNAP_TO_GRID(xctx->line[c][n].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARC:
|
2020-10-15 17:39:21 +02:00
|
|
|
SNAP_TO_GRID(xctx->arc[c][n].x);
|
|
|
|
|
SNAP_TO_GRID(xctx->arc[c][n].y);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
case POLYGON:
|
2020-10-15 17:39:21 +02:00
|
|
|
for(p=0;p<xctx->poly[c][n].points; p++) {
|
|
|
|
|
SNAP_TO_GRID(xctx->poly[c][n].x[p]);
|
|
|
|
|
SNAP_TO_GRID(xctx->poly[c][n].y[p]);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ELEMENT:
|
2020-10-15 17:39:21 +02:00
|
|
|
SNAP_TO_GRID(xctx->inst[n].x0);
|
|
|
|
|
SNAP_TO_GRID(xctx->inst[n].y0);
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-10-15 17:39:21 +02:00
|
|
|
symbol_bbox(n, &xctx->inst[n].x1, &xctx->inst[n].y1, &xctx->inst[n].x2, &xctx->inst[n].y2);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* what: */
|
|
|
|
|
/* 1: save selection */
|
|
|
|
|
/* 2: save clipboard */
|
|
|
|
|
void save_selection(int what)
|
|
|
|
|
{
|
|
|
|
|
FILE *fd;
|
|
|
|
|
int i, c, n, k;
|
|
|
|
|
char name[PATH_MAX];
|
|
|
|
|
|
|
|
|
|
dbg(3, "save_selection():\n");
|
|
|
|
|
if(what==1)
|
2020-09-25 18:09:49 +02:00
|
|
|
my_snprintf(name, S(name), "%s/%s.sch",user_conf_dir , ".selection");
|
2020-08-08 15:47:34 +02:00
|
|
|
else /* what=2 */
|
2020-09-25 18:09:49 +02:00
|
|
|
my_snprintf(name, S(name), "%s/%s.sch",user_conf_dir , ".clipboard");
|
2020-08-08 15:47:34 +02:00
|
|
|
|
|
|
|
|
if(!(fd=fopen(name,"w")))
|
|
|
|
|
{
|
|
|
|
|
fprintf(errfp, "save_selection(): problems opening file %s \n", name);
|
2020-09-25 18:09:49 +02:00
|
|
|
tcleval("alert_ {file opening for write failed!} {}");
|
2020-08-08 15:47:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fprintf(fd, "v {xschem version=%s file_version=%s}\n", XSCHEM_VERSION, XSCHEM_FILE_VERSION);
|
2020-12-02 15:10:47 +01:00
|
|
|
fprintf(fd, "G { %.16g %.16g }\n", xctx->mousex_snap, xctx->mousey_snap);
|
|
|
|
|
for(i=0;i<xctx->lastsel;i++)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
2020-12-02 15:10:47 +01:00
|
|
|
c = xctx->sel_array[i].col;n = xctx->sel_array[i].n;
|
|
|
|
|
switch(xctx->sel_array[i].type)
|
2020-08-08 15:47:34 +02:00
|
|
|
{
|
|
|
|
|
case xTEXT:
|
|
|
|
|
fprintf(fd, "T ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->text[n].txt_ptr,fd, 0);
|
2020-12-05 03:16:01 +01:00
|
|
|
fprintf(fd, " %.16g %.16g %hd %hd %.16g %.16g ",
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->text[n].x0, xctx->text[n].y0, xctx->text[n].rot, xctx->text[n].flip,
|
|
|
|
|
xctx->text[n].xscale, xctx->text[n].yscale);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->text[n].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
case ARC:
|
2020-12-02 15:10:47 +01:00
|
|
|
fprintf(fd, "A %d %.16g %.16g %.16g %.16g %.16g ",
|
|
|
|
|
c, xctx->arc[c][n].x, xctx->arc[c][n].y, xctx->arc[c][n].r,
|
2020-10-15 17:39:21 +02:00
|
|
|
xctx->arc[c][n].a, xctx->arc[c][n].b);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->arc[c][n].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case xRECT:
|
2020-10-15 17:39:21 +02:00
|
|
|
fprintf(fd, "B %d %.16g %.16g %.16g %.16g ", c,xctx->rect[c][n].x1, xctx->rect[c][n].y1,xctx->rect[c][n].x2,
|
|
|
|
|
xctx->rect[c][n].y2);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->rect[c][n].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
2020-09-25 18:09:49 +02:00
|
|
|
case POLYGON:
|
2020-10-15 17:39:21 +02:00
|
|
|
fprintf(fd, "P %d %d ", c, xctx->poly[c][n].points);
|
|
|
|
|
for(k=0; k<xctx->poly[c][n].points; k++) {
|
|
|
|
|
fprintf(fd, "%.16g %.16g ", xctx->poly[c][n].x[k], xctx->poly[c][n].y[k]);
|
2020-08-08 15:47:34 +02:00
|
|
|
}
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->poly[c][n].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
2020-10-12 13:13:31 +02:00
|
|
|
|
2020-08-08 15:47:34 +02:00
|
|
|
case WIRE:
|
2020-11-16 12:33:06 +01:00
|
|
|
fprintf(fd, "N %.16g %.16g %.16g %.16g ",xctx->wire[n].x1, xctx->wire[n].y1,
|
|
|
|
|
xctx->wire[n].x2, xctx->wire[n].y2);
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->wire[n].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LINE:
|
2020-11-16 12:33:06 +01:00
|
|
|
fprintf(fd, "L %d %.16g %.16g %.16g %.16g ", c,xctx->line[c][n].x1, xctx->line[c][n].y1,
|
|
|
|
|
xctx->line[c][n].x2, xctx->line[c][n].y2 );
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->line[c][n].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ELEMENT:
|
|
|
|
|
fprintf(fd, "C ");
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->inst[n].name,fd, 0);
|
2020-12-05 03:16:01 +01:00
|
|
|
fprintf(fd, " %.16g %.16g %hd %hd ",xctx->inst[n].x0, xctx->inst[n].y0,
|
2020-11-16 12:33:06 +01:00
|
|
|
xctx->inst[n].rot, xctx->inst[n].flip );
|
2021-01-06 03:01:14 +01:00
|
|
|
save_ascii_string(xctx->inst[n].prop_ptr,fd, 1);
|
2020-08-08 15:47:34 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fclose(fd);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|