view ueda/uschem-print/gschemcode.c @ 154:2328205328a9 default tip

m4-fp: WR-FPC 1mm pitch FFC/FPC connectors
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 25 Oct 2022 07:36:09 +0000
parents cd92449fdb51
children
line wrap: on
line source

/*
 * We print gschem code in two places: symbols and graphblocks.
 */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <strings.h>
#include "../libuschem/graphsym.h"
#include "../libuschem/schemstruct.h"

static char leftstr[] = "/left";
static char rightstr[] = "/right";
static char topstr[] = "/top";
static char bottomstr[] = "/bottom";
static char ctrstr[] = "/ctr";

char *gschem_text_halign[9] =  {leftstr,  leftstr,  leftstr,
				ctrstr,   ctrstr,   ctrstr,
				rightstr, rightstr, rightstr};
char *gschem_text_valign[9] =  {bottomstr,ctrstr,   topstr,
				bottomstr,ctrstr,   topstr,
				bottomstr,ctrstr,   topstr};

#define	MAXLINE		256

static FILE *inf;
static char *pathname;
static int lineno;
static int issym, in_pinblock;
static int linewidth, dashed;
static int font_ptsize;
static int varpin_count;

print_gschem_code_sym(file, sym)
	FILE *file;
	struct graphsym *sym;
{
	inf = file;
	pathname = sym->gs_pathname;
	lineno = 0;
	issym = 1;
	mymain();
}

print_gschem_code_graphblk(file, blk, orig_filename)
	FILE *file;
	struct graphblock *blk;
	char *orig_filename;
{
	inf = file;
	pathname = orig_filename;
	lineno = blk->lineno;
	issym = 0;
	fseek(inf, blk->offset, 0);
	mymain();
}

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

	in_pinblock = 0;
	linewidth = -1;
	dashed = 0;
	font_ptsize = 0;
	varpin_count = 0;
	while (getline(line)) {
		switch (line[0]) {
		case '%':		/* PS-like comments */
		case '\0':		/* allow blank lines too */
			continue;
		case '{':
			in_pinblock++;
			continue;
		case '}':
			if (!in_pinblock)
				return;
			in_pinblock--;
			continue;
		}
		if (!isalpha(line[0])) {
inv:			fprintf(stderr, "%s: line %d: invalid gschem code\n",
				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;
			do_ps_block();
			/* be safe about the graphics state */
			linewidth = -1;
			font_ptsize = 0;
			continue;
		} else if (strlen(line) != 1)
			continue;	/* ignore these */
		line[1] = ' ';
		/* dispatch by single-char type */
		switch (line[0]) {
		case 'v':
			continue;	/* ignore */
		/* simple graphics */
		case 'L':
			do_line(line);
			continue;
		case 'B':
			do_box(line);
			continue;
		case 'V':
			do_circle(line);
			continue;
		case 'A':
			do_arc(line);
			continue;
		case 'P':
			handle_pin(line);
			continue;
		case 'T':
			handle_T_obj(line, lineno);
			continue;
		default:
			goto inv;
		}
	}
}

static
do_line(objline)
	char *objline;
{
	int numparams[10];

	parse_numline(objline, lineno, numparams, 10);
	if (setdash(numparams[7], numparams[8], numparams[9]) < 0)
		return;
	setlinewidth(numparams[5]);
	emit_coordpair(numparams[0], numparams[1]);
	fputs("moveto ", stdout);
	emit_coordpair(numparams[2], numparams[3]);
	puts("lineto stroke");
}

static
do_box(objline)
	char *objline;
{
	int numparams[16];

	parse_numline(objline, lineno, numparams, 16);
	switch (numparams[10]) {
	case 0:
		if (setdash(numparams[7], numparams[8], numparams[9]) < 0)
			return;
		setlinewidth(numparams[5]);
		emit_coordpair(numparams[0], numparams[1]);
		emit_coordpair(numparams[2], numparams[3]);
		puts("rectstroke");
		return;
	case 1:
		emit_coordpair(numparams[0], numparams[1]);
		emit_coordpair(numparams[2], numparams[3]);
		puts("rectfill");
		return;
	default:
		fprintf(stderr,
		"%s: line %d: fill type %d not implemented; object omitted\n",
			pathname, lineno, numparams[10]);
	}
}

static
do_circle(objline)
	char *objline;
{
	int numparams[15];

	parse_numline(objline, lineno, numparams, 15);
	switch (numparams[9]) {
	case 0:
		if (setdash(numparams[6], numparams[7], numparams[8]) < 0)
			return;
		setlinewidth(numparams[4]);
		emit_coordpair(numparams[0], numparams[1]);
		printf("%d circlestroke\n", numparams[2]);
		return;
	case 1:
		emit_coordpair(numparams[0], numparams[1]);
		printf("%d circlefill\n", numparams[2]);
		return;
	default:
		fprintf(stderr,
		"%s: line %d: fill type %d not implemented; object omitted\n",
			pathname, lineno, numparams[9]);
	}
}

static
do_arc(objline)
	char *objline;
{
	int numparams[11];

	parse_numline(objline, lineno, numparams, 11);
	if (!numparams[4])	/* degenerate? */
		return;		/* ignore those */
	if (setdash(numparams[8], numparams[9], numparams[10]) < 0)
		return;
	setlinewidth(numparams[6]);
	puts("newpath");
	emit_coordpair(numparams[0], numparams[1]);
	printf("%d %d %d%s%s arc stroke\n", numparams[2], numparams[3],
		numparams[3] + numparams[4], numparams[4] > 0 ? "" : " exch",
		issym ? " mirrorarc" : "");
}

static
setlinewidth(newval)
{
	if (newval != linewidth) {
		linewidth = newval;
		if (linewidth)
			printf("%d setlinewidth\n", linewidth);
		else
			puts("defaultlinewidth setlinewidth");
	}
	return(0);
}

static
setdash(dashstyle, dashlength, dashspace)
{
	switch (dashstyle) {
	case 0:
		if (dashed) {
			puts("setsolid");
			dashed = 0;
		}
		return(0);
	case 2:
		printf("[%d %d] 0 setdash\n", dashlength, dashspace);
		dashed = 1;
		return(0);
	default:
		fprintf(stderr,
		"%s: line %d: dash style %d not implemented; object omitted\n",
			pathname, lineno, dashstyle);
		return(-1);
	}
}

static
emit_coordpair(x, y)
{
	printf("%d%s %d ", x, issym ? " mirror" : "", y);
}

static
handle_pin(objline)
	char *objline;
{
	int numparams[7];

	parse_numline(objline, lineno, numparams, 7);
	printf("%d mirror %d %d mirror %d drawpin\n", numparams[0],
		numparams[1], numparams[2], numparams[3]);
}

static
handle_T_obj(objline, objlineno)
	char *objline;
{
	int numparams[9];
	char textline[MAXLINE];
	register int i;
	register char *cp;
	int readystr, isvarpin;

	parse_numline(objline, objlineno, numparams, 9);
	if (numparams[8] < 1) {
		fprintf(stderr, "%s: line %d: T object: num_lines<1!\n",
			pathname, objlineno);
		exit(1);
	}
	if (numparams[8] > 1)
		fprintf(stderr,
		"warning: multiline T objects not implemented (found in %s)\n",
			pathname);
	for (i = numparams[8]; i; i--) {
		if (!getline(textline)) {
			fprintf(stderr, "%s: EOF in T object\n", pathname);
			exit(1);
		}
		if (!numparams[4])	/* visible? */
			continue;	/* nope */
		isvarpin = 0;
		if (issym) {
			readystr = 0;
			cp = index(textline, '=');
			if (cp) {
				cp++;
				if (!in_pinblock)	/* we don't print */
					continue;	/* top level attrs */
				if (!strcmp(cp, "%d"))
					isvarpin = 1;
			} else
				cp = textline;
		} else {
			cp = textline;
			readystr = (cp[0] == '(');
		}
		if (numparams[7] < 0 || numparams[7] > 8) {
			fprintf(stderr,
			"%s: line %d: T object: alignment %d is invalid\n",
				pathname, objlineno, numparams[7]);
			continue;
		}
		if (font_ptsize != numparams[3]) {
			font_ptsize = numparams[3];
			printf("/Helvetica %d selisofnt\n", font_ptsize);
		}
		if (isvarpin)
			printf("pins %d get", varpin_count++);
		else if (readystr)
			fputs(cp, stdout);
		else
			emit_ps_string(cp);
		printf(" %s%s %s %d ", gschem_text_halign[numparams[7]],
			issym ? " mirrortext" : "",
			gschem_text_valign[numparams[7]], numparams[6]);
		emit_coordpair(numparams[0], numparams[1]);
		puts("Tshow");
	}
}

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",
				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
do_ps_block()
{
	register int c, n;

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

static
skip_over_ps_string()
{
	register int c, n;

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