view ueda/libuschem/graphsym_load.c @ 105:1629fff165fb

SC75A.fp: created based on E-Sample version, with simplified silk courtyard
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 02 Oct 2019 05:12:36 +0000
parents cd92449fdb51
children
line wrap: on
line source

/*
 * The black magic of loading/prescanning gschem-based uschem symbols
 */

#include <ctype.h>
#include <stdio.h>
#include <strings.h>
#include "graphsym.h"

extern char *malloc();
extern char *copystr();

#define	MAXLINE		256

static struct graphsym *symstruct;
static FILE *inf;
static int lineno;
static struct graphsym_pindef **pintail;

read_symbol_file(gs, f)
	struct graphsym *gs;
	FILE *f;
{
	symstruct = gs;
	inf = f;
	lineno = 0;
	pintail = &gs->gs_pins;
	mymain();
	if (!gs->gs_npins) {
		fprintf(stderr, "%s: symbol has no pins (invalid)\n",
			gs->gs_pathname);
		exit(1);
	}
}

static
mymain()
{
	char line[MAXLINE];
	register char *cp;
	register int c;

	while (getline(line)) {
		if (line[0] == '%')	/* PS-like comments */
			continue;
		if (line[0] == '\0')	/* allow blank lines too */
			continue;
		if (!isalpha(line[0])) {
inv:			fprintf(stderr, "%s: line %d: invalid symbol data\n",
				symstruct->gs_pathname, lineno);
			exit(1);
		}
		for (cp = line; isalpha(*cp); cp++)
			;
		if (!isspace(*cp))
			goto inv;
		*cp++ = '\0';
		while (isspace(*cp))
			cp++;
		if (!strcmp(line, "PS")) {
			if (strcmp(cp, "{"))
				goto inv;
			skip_ps_block();
			continue;
		} else if (strlen(line) != 1)
			goto inv;
		line[1] = ' ';
		/* dispatch by single-char type */
		switch (line[0]) {
		case 'v':
			continue;	/* ignore */
		/* simple graphics */
		case 'L':
		case 'B':
		case 'V':
		case 'A':
			/* ignore at this stage too */
			continue;
		case 'P':
			handle_pin(line, lineno);
			continue;
		case 'T':
			handle_T_obj(line, lineno);
			continue;
		default:
			goto inv;
		}
	}
}

static
handle_pin(objline, objlineno)
	char *objline;
{
	int numparams[7];
	char junkline[MAXLINE];
	register struct graphsym_pindef *pin;

	parse_numline(objline, objlineno, numparams, 7);
	pin = (struct graphsym_pindef *) malloc(sizeof(struct graphsym_pindef));
	if (!pin) {
		perror("malloc");
		exit(1);
	}
	bzero(pin, sizeof(struct graphsym_pindef));
	if (numparams[6]) {
		pin->gspd_x = numparams[2];
		pin->gspd_y = numparams[3];
	} else {
		pin->gspd_x = numparams[0];
		pin->gspd_y = numparams[1];
	}
	*pintail = pin;
	pintail = &pin->gspd_next;
	symstruct->gs_npins++;
	if (!getline(junkline) || strcmp(junkline, "{")) {
		fprintf(stderr,
			"%s: line %d: P line must be followed by '{' line\n",
			symstruct->gs_pathname, objlineno);
		exit(1);
	}
	read_pin_attrs(pin, objlineno);
}

static
read_pin_attrs(pin, objlineno)
	struct graphsym_pindef *pin;
{
	char line[MAXLINE];
	int Tline_parsed[9];
	register char *cp;

	for (;;) {
		if (!getline(line)) {
badeof:			fprintf(stderr, "%s: EOF in pin attribute block\n",
				symstruct->gs_pathname);
			exit(1);
		}
		if (line[0] == '%')	/* PS-like comments */
			continue;
		if (line[0] == '\0')	/* allow blank lines too */
			continue;
		if (line[0] == '}')
			return;
		if (!isalpha(line[0])) {
inv:			fprintf(stderr, "%s: line %d: invalid symbol data\n",
				symstruct->gs_pathname, lineno);
			exit(1);
		}
		for (cp = line; isalpha(*cp); cp++)
			;
		if (!isspace(*cp))
			goto inv;
		*cp++ = '\0';
		if (!strcmp(line, "attr")) {
			while (isspace(*cp))
				cp++;
			handle_attr(pin, cp);
			continue;
		} else if (strcmp(line, "T")) {
			fprintf(stderr,
		      "%s: line %d: wrong object type in pin attribute block\n",
				symstruct->gs_pathname, lineno);
			exit(1);
		}
		line[1] = ' ';
		parse_numline(line, lineno, Tline_parsed, 9);
		if (Tline_parsed[8] < 1) {
			fprintf(stderr, "%s: line %d: T object: num_lines<1!\n",
				symstruct->gs_pathname, lineno);
			exit(1);
		}
		if (Tline_parsed[8] > 1) {
			fprintf(stderr,
	"%s: line %d: multiline text object in attribute block not supported\n",
				symstruct->gs_pathname, lineno);
			exit(1);
		}
		if (!getline(line))
			goto badeof;
		handle_attr(pin, line);
	}
}

static
handle_attr(pin, line)
	register struct graphsym_pindef *pin;
	register char *line;
{
	register char *cp;

	cp = index(line, '=');
	if (!cp)
		return;
	*cp++ = '\0';
	if (!*cp)		/* avoid null string values */
		return;
	if (!strcmp(line, "pinname")) {
		if (pin->gspd_pinname) {
dup:			fprintf(stderr,
			"%s: line %d: duplicate %s attribute (ignored)\n",
				symstruct->gs_pathname, lineno, line);
			return;
		}
		pin->gspd_pinname = copystr(cp);
	} else if (!strcmp(line, "pinnumber")) {
		if (pin->gspd_pinnumber)
			goto dup;
		pin->gspd_pinnumber = copystr(cp);
		if (!strcmp(cp, "%d"))
			symstruct->gs_varpins++;
	} else if (!strcmp(line, "forcenet")) {
		if (pin->gspd_forcenet)
			goto dup;
		pin->gspd_forcenet = copystr(cp);
		symstruct->gs_forcenets++;
	}
}

static
handle_T_obj(objline, objlineno)
	char *objline;
{
	int numparams[9];
	char junkline[MAXLINE];
	register int i;

	parse_numline(objline, objlineno, numparams, 9);
	if (numparams[8] < 1) {
		fprintf(stderr, "%s: line %d: T object: num_lines<1!\n",
			symstruct->gs_pathname, objlineno);
		exit(1);
	}
	for (i = numparams[8]; i; i--) {
		if (!getline(junkline)) {
			fprintf(stderr, "%s: EOF in T object\n",
				symstruct->gs_pathname);
			exit(1);
		}
	}
}

static
parse_numline(line, lineno, numarray, nfields)
	char *line;
	int lineno;
	int *numarray;
	int nfields;
{
	register char *cp, *np;
	register int i;

	for (i = 0, cp = line+1; i < nfields; i++) {
		if (!isspace(*cp)) {
inv:			fprintf(stderr, "%s: line %d: invalid numeric line\n",
				symstruct->gs_pathname, lineno);
			exit(1);
		}
		while (isspace(*cp))
			cp++;
		np = cp;
		if (*cp == '-')
			cp++;
		if (!isdigit(*cp))
			goto inv;
		while (isdigit(*cp))
			cp++;
		numarray[i] = atoi(np);
	}
	if (*cp)
		goto inv;
}

static
getline(linebuf)
	char *linebuf;
{
	register char *cp;

	if (fgets(linebuf, MAXLINE, inf) == NULL)
		return(0);
	lineno++;
	/* strip trailing newline or other whitespace */
	cp = index(linebuf, '\0');
	while (cp > linebuf && isspace(cp[-1]))
		cp--;
	*cp = '\0';
	return(1);
}

static
skip_ps_block()
{
	register int c, n;

	for (n = 0; n >= 0; ) {
		c = getc(inf);
		switch (c) {
		case EOF:
badeof:			fprintf(stderr, "%s: EOF in a PS block\n",
				symstruct->gs_pathname);
			exit(1);
		case '%':
			for (;;) {
				c = getc(inf);
				if (c == EOF)
					goto badeof;
				if (c == '\n')
					break;
			}
			/* FALL THRU */
		case '\n':
			lineno++;
			continue;
		case '(':
			skip_over_ps_string();
			continue;
		case ')':
			fprintf(stderr,
				"%s: line %d: unmatched \')\' in a PS block",
				symstruct->gs_pathname, lineno);
			exit(1);
		case '{':
			n++;
			continue;
		case '}':
			n--;
			continue;
		}
	}
	c = getc(inf);
	if (c != '\n') {
		fprintf(stderr,
"%s: line %d: '}' closing PS block must be directly followed by newline\n",
			symstruct->gs_pathname, lineno);
		exit(1);
	}
	lineno++;
}

static
skip_over_ps_string()
{
	register int c, n;

	for (n = 1; n > 0; ) {
		c = getc(inf);
		switch (c) {
		case EOF:
badeof:			fprintf(stderr, "%s: EOF in a PS block\n",
				symstruct->gs_pathname);
			exit(1);
		case '\n':
			lineno++;
			continue;
		case '(':
			n++;
			continue;
		case ')':
			n--;
			continue;
		case '\\':
			c = getc(inf);
			if (c == EOF)
				goto badeof;
			if (c == '\n')
				lineno++;
			continue;
		}
	}
}