view ueda/libueda/readmcl.c @ 139:bf188727e606

donl-rename-parts reader: no tEDAx-style escapes
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 07 Sep 2020 04:25:11 +0000
parents c91e7a30fab3
children
line wrap: on
line source

/*
 * This is the MCL parser for the uEDA suite.
 */

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "mcl.h"

extern char *copystr();

#define	MAX_COMPS	1024
#define	MAX_PARTDEFS	128
#define	MAX_ATTRS	2048
#define	MAX_REFDES_ON_LINE	16

char *MCLfile = "MCL";

/* the following vars capture the distilled output of the parser */
struct component components[MAX_COMPS], partdefs[MAX_PARTDEFS];
int ncomponents, npartdefs;
static struct attrib attrs[MAX_ATTRS];
static int nattrs;

/* the following static vars are used only in the reading & parsing process */
static FILE *mclf;
static char line[1024];		/* size arbitrary, sizeof used in the code */
static int lineno;

static struct component *curcomp;
static char *curcomp_refdes[MAX_REFDES_ON_LINE];
static int curcomp_nrefdes;

static
setup_partdef(np)
	register char *np;
{
	register char *cp;

	while (isspace(*np))
		np++;
	cp = index(np, ':');
	if (!cp || cp == np || cp[1]) {
		fprintf(stderr, "%s: line %d: invalid part definition\n",
			MCLfile, lineno);
		exit(1);
	}
	*cp = '\0';
	if (npartdefs >= MAX_PARTDEFS) {
		fprintf(stderr, "%s: line %d: too many part definitions\n",
			MCLfile, lineno);
		exit(1);
	}
	curcomp = partdefs + npartdefs;
	curcomp->name = copystr(np);
	curcomp->attrs = attrs + nattrs;
	curcomp->nattrs = 0;
	npartdefs++;
	curcomp_nrefdes = 0;
}

static
parse_refdes_list()
{
	int i;
	register char *cp, *np;
	register int c;

	for (cp = line, i = 0; ; ) {
		if (!isupper(*cp)) {
inv:			fprintf(stderr, "%s: line %d: invalid refdes line\n",
				MCLfile, lineno);
			exit(1);
		}
		for (np = cp; isalnum(*cp); cp++)
			;
		c = *cp;
		if (c != ':' && c != ',')
			goto inv;
		*cp++ = '\0';
		curcomp_refdes[i++] = copystr(np);
		if (c == ':')
			break;
	}
	curcomp_nrefdes = i;
	if (*cp)
		goto inv;
}

static
clone_component()
{
	register int i;
	register struct component *newcomp;

	for (i = 1; i < curcomp_nrefdes; i++) {
		if (ncomponents >= MAX_COMPS) {
			fprintf(stderr, "%s: %s: too many components\n",
				MCLfile, curcomp_refdes[i]);
			exit(1);
		}
		newcomp = components + ncomponents;
		bcopy(curcomp, newcomp, sizeof(struct component));
		newcomp->name = curcomp_refdes[i];
		ncomponents++;
	}
}

static
finish_component()
{
	extern char *get_comp_attr();

	if (curcomp_nrefdes == 0)
		return;			/* nothing to do for part defs */
	if (!curcomp->partdef &&
		(get_comp_attr(curcomp, "manufacturer") &&
		 get_comp_attr(curcomp, "manufacturer_part_number") ||
		 get_comp_attr(curcomp, "bom_part_title")))
			curcomp->partdef = curcomp;	/* self-defines part */
	if (curcomp_nrefdes > 1)
		clone_component();
}

static
handle_part_ref(partname)
	char *partname;
{
	register struct component *part;
	register int i;

	if (curcomp_nrefdes == 0) {
	    fprintf(stderr,
	    "%s: line %d: can't use a part reference in a part definition!\n",
			MCLfile, lineno);
	    exit(1);
	}
	if (!strcmp(partname, "none")) {
		curcomp->partdef = NULL;
		return;
	}
	if (!strcmp(partname, "yes")) {
		curcomp->partdef = curcomp;	/* self-defines the part */
		return;
	}
	for (part = partdefs, i = 0; i < npartdefs; part++, i++)
		if (!strcmp(part->name, partname)) {
gotit:			curcomp->partdef = part;
			return;
		}
	/* can also refer to a previous component that self-defines a part */
	for (part = components, i = 0; i < ncomponents-1; part++, i++)
		if (!strcmp(part->name, partname)) {
			if (part->partdef == part)
				goto gotit;
			else {
				fprintf(stderr,
"%s: line %d: can't use %s as a part because it doesn't define a part\n",
					MCLfile, lineno, partname);
				exit(1);
			}
		}
	fprintf(stderr, "%s: line %d: part %s not defined\n", MCLfile, lineno,
			partname);
	exit(1);
}

static
get_line()
{
	register char *cp;

	if (fgets(line, sizeof line, mclf) == NULL)
		return(0);
	lineno++;
	/* strip trailing comments and whitespace */
	cp = index(line, '#');
	if (!cp)
		cp = index(line, '\0');
	while (cp > line && isspace(cp[-1]))
		cp--;
	*cp = '\0';
	return(1);
}

read_MCL()
{
	register char *cp, *name, *value;

	mclf = fopen(MCLfile, "r");
	if (!mclf) {
		perror(MCLfile);
		exit(1);
	}

	for (lineno = 0, curcomp = NULL; get_line(); ) {
		/* ignore blank lines and comments */
		if (line[0] == '\0' || line[0] == '#')
			continue;
		if (!strncmp(line, "part", 4) && isspace(line[4])) {
			finish_component();
			setup_partdef(line + 5);
		} else if (!isspace(line[0])) {	/* refdes */
			finish_component();
			parse_refdes_list();
			if (ncomponents >= MAX_COMPS) {
				fprintf(stderr,
					"%s: line %d: too many components\n",
					MCLfile, lineno);
				exit(1);
			}
			curcomp = components + ncomponents;
			curcomp->name = curcomp_refdes[0];
			curcomp->attrs = attrs + nattrs;
			curcomp->nattrs = 0;
			ncomponents++;
		} else {			/* attribute */
			for (cp = line; isspace(*cp); cp++)
				;
			name = cp;
			cp = index(cp, '=');
			if (!cp) {
invattr:			fprintf(stderr,
				    "%s: line %d: invalid attribute line\n",
					MCLfile, lineno);
				exit(1);
			}
			*cp = '\0';
			value = cp + 1;
			if (name[0] == '\0')
				goto invattr;
			if (!curcomp) {
				fprintf(stderr,
			"%s: line %d: attribute listed without a component\n",
					MCLfile, lineno);
				exit(1);
			}
			if (value[0] == '\0') {
				fprintf(stderr,
				"%s: line %d: attribute must have a value\n",
					MCLfile, lineno);
				exit(1);
			}
			if (nattrs >= MAX_ATTRS) {
				fprintf(stderr,
					"%s: line %d: too many attributes\n",
					MCLfile, lineno);
				exit(1);
			}
			attrs[nattrs].name = copystr(name);
			attrs[nattrs].value = copystr(value);
			nattrs++;
			curcomp->nattrs++;
			if (!strcmp(name, "part"))
				handle_part_ref(value);
		}
	}
	fclose(mclf);
	finish_component();
}