#include <stdio.h>

/*
#ifndef M_XENIX
#include <stdlib.h>
#endif
*/

/*
#include <string.h>
#include <malloc.h>
*/
extern char *Alloc();
extern char *strchr();

#include <ctype.h>
#include "cell.h"

/* board dimensions */
extern int Nrows;
extern int Ncols;

extern int InitBoardDone; /* sanity check */

/* memory usage */
extern long Ltotal; /* for board */
extern long Itotal; /* for dist */
extern long Ctotal; /* for dir */

/*
** the following types of input lines are legal (spaces and tabs can separate
** tokens, and case is not significant):
**
**  1) a blank line (ignored)
**  2) ';' followed by anything (ignored)
**     use semicolon to insert comments.
**  3) DIMENSION (row,column)
**     this defines the number of rows and columns on the board, and must be
**     given before any of the lines below. note that the user sees the board
**     coordinate space as being 1-based, but internally it is 0-based.
**  4) HOLE (row,column)
**     this defines a hole location.
**  5) CONNECT thing AND thing
**     this declares that two holes are to be electrically connected. a thing
**     can be (row,column), or name1.name2, where name1 is the name of a
**     CHIPAT-defined chip, and name2 is the name of one of its pins, or a
**     number, giving the pin number of the named chip. you can use '='
**     instead of 'AND' if you want.
**  6) PRIORITY CONNECT thing AND thing
**     same as above, except the order of connections will be preserved. the
**     autorouter is free to reorder the non-PRIORITY CONNECTs, and in fact
**     reorders them shortest first. if there are PRIORITY CONNECTs, they will
**     all be routed before non-PRIORITY CONNECTs.
**  7) INCLUDE filename
**     this causes the input to be temporarily taken from the given filename.
**     when the given filename is completely processed (EOF encountered),
**     control returns to the current file. INCLUDE statements may be nested
**     (they may occur inside the given filename). complete and partial
**     pathnames can be used (C:\TTL.INC, ..\TTL.INC, \TTL.INC, FOO\TTL.INC).
**  8) CHIP TYPE=type PINS=number HORIZONTAL=number VERTICAL=number
**     this declares a chip type, which can be used to place chips on the
**     board (see CHIPAT, below), but does not itself place anything on the
**     board. TYPE gives the name that will be used in later CHIPAT
**     statements. PINS declares the number of pins. HORIZONTAL gives the
**     number of 50-mil units separating adjacent pins (along the long side of
**     the chip). and VERTICAL gives the number of 50-mil units separating
**     pins across from each other (across the skinny width of the chip).
**     standard values for HORIZONTAL and VERTICAL are 2 and 6, respectively.
**     all CHIP type names must be unique.
**  9) number=name
**     this declares a pin name for the chip that is currently being defined.
**     this statement must follow a CHIP statement. pins not defined will have
**     no name, but you can still refer to them by number. each pin on a chip
**     can be named at most once.
** 10) name=number
**     same as above.
** 11) CHIPAT (row,column) NAME=name TYPE=type ORIENTATION=orientation
**     this defines an instance of a chip, and places the appropriate holes on
**     the board. (row,column) is the location of pin 1. NAME defines the name
**     to be used in following CONNECT statements. TYPE declares the
**     CHIPAT-defined type of the chip. ORIENTATION can have the values
**     NORMAL, UP, DOWN, and UPSIDEDOWN. all CHIPAT names must be unique.
**
**      NORMAL           UP           DOWN        UPSIDEDOWN
**
**       6 5 4          +---+         +---+          3 2 1
**     +-*-*-*-+      4 *   * 3     1 * | * 6      +-*-*-*-+
**     |  ->   |      5 * ^ * 2     2 * v * 5      |   <-  |
**     +-*-*-*-+      6 * | * 1     3 *   * 4      +-*-*-*-+
**       1 2 3          +---+         +---+          4 5 6
**
**     usually the highest-numbered pin (pin N) is Vcc (power) and the pin
**     farthest from it (pin N/2) is GND (ground).
*/

/* chip orientations (rotations) */
#define ORIENT_NORMAL		1
#define ORIENT_UP		2
#define ORIENT_DOWN		3
#define ORIENT_UPSIDEDOWN	4

/* input token types */
#define TOK_EOF		1	/* end of file, no more tokens		*/
#define TOK_NEWLINE	2	/* end of line				*/
#define TOK_NUMBER	3	/* number (digits)			*/
#define TOK_HOLE	4	/* "HOLE"				*/
#define TOK_ROWCOLUMN	5	/* "(row,column)"			*/
#define TOK_CONNECT	6	/* "CONNECT"				*/
#define TOK_EQUAL	7	/* "="					*/
#define TOK_AND		8	/* "AND"				*/
#define TOK_ALPHANUM	9	/* name (letters, digits, ':','.','\')	*/
#define TOK_CHIP	10	/* "CHIP"				*/
#define TOK_NAME	11	/* "NAME"				*/
#define TOK_PINS	12	/* "PINS"				*/
#define TOK_HORIZONTAL	13	/* "HORIZONTAL"				*/
#define TOK_VERTICAL	14	/* "VERTICAL"				*/
#define TOK_INCLUDE	15	/* "INCLUDE"				*/
#define TOK_CHIPAT	16	/* "CHIPAT"				*/
#define TOK_TYPE	17	/* "TYPE"				*/
#define TOK_ORIENTATION	18	/* "ORIENTATION"			*/
#define TOK_NORMAL	19	/* "NORMAL"				*/
#define TOK_UP		20	/* "UP"					*/
#define TOK_DOWN	21	/* "DOWN"				*/
#define TOK_UPSIDEDOWN	22	/* "UPSIDEDOWN"				*/
#define TOK_DIMENSION	23	/* "DIMENSION"				*/
#define TOK_PRIORITY	24	/* "PRIORITY"				*/

struct reserved { /* reserved word input tokens */
	char *tokenname;
	int tokenvalue;
	};

static struct reserved tokenmatch[] = { /* reserved word table */
  { "HOLE",       TOK_HOLE       },  { "CONNECT",     TOK_CONNECT     },
  { "AND",        TOK_AND        },  { "CHIP",        TOK_CHIP        },
  { "NAME",       TOK_NAME       },  { "PINS",        TOK_PINS        },
  { "HORIZONTAL", TOK_HORIZONTAL },  { "VERTICAL",    TOK_VERTICAL    },
  { "INCLUDE",    TOK_INCLUDE    },  { "CHIPAT",      TOK_CHIPAT      },
  { "TYPE",       TOK_TYPE       },  { "ORIENTATION", TOK_ORIENTATION },
  { "NORMAL",     TOK_NORMAL     },  { "UP",          TOK_UP          },
  { "DOWN",       TOK_DOWN       },  { "UPSIDEDOWN",  TOK_UPSIDEDOWN  },
  { "DIMENSION",  TOK_DIMENSION  },  { "PRIORITY",    TOK_PRIORITY    }
 };

#define MAXTOK	80	/* maximum token length (including null) */

static int numres = sizeof(tokenmatch) / sizeof(tokenmatch[0]);
static char token[MAXTOK]; /* the current token is formed here */

struct pinassign { /* for assigning names to pins */
	int	index;
	char *name;
	struct pinassign *next;
	};

struct template { /* for "CHIP" declarations */
	char 		*type;
	int			pins;
	int			horizontal;
	int			vertical;
	struct pinassign 	*pinlist;
	struct template 	*next;
	};

struct instance { /* for "CHIPAT" definitions */
	int			row;
	int			column;
	char 		*name;
	struct template 	*type;
	int			orientation;
	struct instance 	*next;
	};

static struct template *chip = NULL; /* list of CHIPs */
static struct instance *chipat = NULL; /* list of CHIPATs */

#ifdef M_XENIX

#include <ctype.h>

#ifndef _toupper
#define _toupper	toupper
#endif


char *strupr(string)
char *string;
{
	register char *cp = string;

	while (*cp) {
		if (islower(*cp))
			*cp = _toupper(*cp);
		cp++;
	}
	return(string);
}

static char str1u[201], str2u[201];

int stricmp(str1, str2)
char *str1;
char *str2;
{
	strcpy(str1u, str1);
	strcpy(str2u, str2);
	(void)strupr(str1u);
	(void)strupr(str2u);

	return(strcmp(str1u, str2u));
}
#endif

extern void InitBoard();
extern long GetCell();
extern void SetCell();
extern void InitWork();
extern void SetWork();
extern void SortWork();
extern void Nomem();

void Initialize();
static void initfile();
static void initchip();
static void locate();
static int gettoken();
static char *fcopy();
static int same();
void Report();

void Initialize ( fin ) /* get hole coordinates and connections */
	FILE *fin;
	{
	printf( "enter Initialize()\n" );
	InitWork(); /* clear work list */
	initfile( fin ); /* read input file(s) */
	SortWork(); /* arrange to do shortest ones first */
	printf( "  %ld bytes used for board\n", Ltotal );
	printf( "  %ld bytes used for dist\n", Itotal );
	printf( "  %ld bytes used for dir\n", Ctotal );
	printf( "leave Initialize()\n" );
	}

/* some useful macros (common code sequences) */

#define SkipRest	{ while ((tok = gettoken( fin )) != TOK_EOF \
				&& tok != TOK_NEWLINE) ; }

#define SkipTokRest	{ while (tok != TOK_EOF && tok != TOK_NEWLINE) \
				tok = gettoken( fin ); } \
			continue;

#define CheckInit	{ if (!InitBoardDone) { \
				printf( "error: need dimensions first\n" ); \
				SkipRest; \
				continue; } }

static void initfile ( fin ) /* read and process input file(s) */
FILE *fin;
{
	int tok, r1, c1, r2, c2, i;
	char *p;
	char *n1;
	char *n2;
	long cell;
	struct template *p1;
	struct pinassign *p2;
	struct pinassign *p22;
	struct instance *p3;
	FILE *fnew;

	while ((tok = gettoken( fin )) != TOK_EOF) {
		if (tok == TOK_DIMENSION) {
			if (InitBoardDone) { /* can only do it once */
				printf( "error: redundant dimensions\n" );
				SkipRest;
				continue;
				}
			if ((tok = gettoken( fin )) != TOK_ROWCOLUMN) {
				printf( "expect (row,column)\n" );
				SkipTokRest;
				}
			sscanf( token, "(%d,%d)", &Nrows, &Ncols );
			if (Nrows <= 0 || Ncols <= 0)
				printf( "dimension error\n" );
			else /* allocate memory for data structures */
				InitBoard();
			}
		else if (tok == TOK_HOLE) {
			CheckInit; /* must get dimensions first */
			if ((tok = gettoken( fin )) != TOK_ROWCOLUMN) {
				printf( "expect (row,column)\n" );
				SkipTokRest;
				}
			sscanf( token, "(%d,%d)", &r1, &c1 );
			if (r1 <= 0 || r1 > Nrows || c1 <= 0 || c1 > Ncols)
				printf( "out of range\n" );
			else { /* position the hole on the board */
				/* should check for neighbor holes (error) */
				SetCell( r1-1, c1-1, TOP, HOLE );
				SetCell( r1-1, c1-1, BOTTOM, HOLE );
				}
			}
		else if (tok == TOK_CONNECT) {
			CheckInit; /* must get dimensions first */
			if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
				sscanf( token, "(%d,%d)", &r1, &c1 );
			else if (tok == TOK_ALPHANUM)
				locate( token, &r1, &c1 );
			else {
				printf( "expect (row,column) or name\n" );
				SkipTokRest;
				}
			n1 = fcopy( token );
			if ((tok = gettoken( fin )) != TOK_EQUAL
				&& tok != TOK_AND) {
				printf( "expect = or AND\n" );
				SkipTokRest;
				}
			if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
				sscanf( token, "(%d,%d)", &r2, &c2 );
			else if (tok == TOK_ALPHANUM)
				locate( token, &r2, &c2 );
			else {
				printf( "expect (row,column) or name\n" );
				SkipTokRest;
				}
			n2 = fcopy( token );
			if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
				|| c1 <= 0 || c1 > Ncols
				|| c2 <= 0 || c2 > Ncols) {
				printf( "out of range\n" );
				Free( n1 );
				Free( n2 );
				}
			else {
				cell = GetCell( r1-1, c1-1, TOP );
				if (!(cell & HOLE)) {
					printf( "error: no source hole\n" );
					Free( n1 );
					Free( n2 );
					SkipRest;
					continue;
					}
				cell = GetCell( r2-1, c2-1, TOP );
				if (!(cell & HOLE)) {
					printf( "error: no target hole\n" );
					Free( n1 );
					Free( n2 );
					SkipRest;
					continue;
					}
				SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 0 );
				}
			}
		else if (tok == TOK_PRIORITY) {
			CheckInit; /* must get dimensions first */
			if ((tok = gettoken( fin )) != TOK_CONNECT) {
				printf( "expect CONNECT\n" );
				SkipTokRest;
				}
			if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
				sscanf( token, "(%d,%d)", &r1, &c1 );
			else if (tok == TOK_ALPHANUM)
				locate( token, &r1, &c1 );
			else {
				printf( "expect (row,column) or name\n" );
				SkipTokRest;
				}
			n1 = fcopy( token );
			if ((tok = gettoken( fin )) != TOK_EQUAL
				&& tok != TOK_AND) {
				printf( "expect = or AND\n" );
				SkipTokRest;
				}
			if ((tok = gettoken( fin )) == TOK_ROWCOLUMN)
				sscanf( token, "(%d,%d)", &r2, &c2 );
			else if (tok == TOK_ALPHANUM)
				locate( token, &r2, &c2 );
			else {
				printf( "expect (row,column) or name\n" );
				SkipTokRest;
				}
			n2 = fcopy( token );
			if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
				|| c1 <= 0 || c1 > Ncols
				|| c2 <= 0 || c2 > Ncols) {
				printf( "out of range\n" );
				Free( n1 );
				Free( n2 );
				}
			else {
				cell = GetCell( r1-1, c1-1, TOP );
				if (!(cell & HOLE)) {
					printf( "error: no source hole\n" );
					Free( n1 );
					Free( n2 );
					SkipRest;
					continue;
					}
				cell = GetCell( r2-1, c2-1, TOP );
				if (!(cell & HOLE)) {
					printf( "error: no target hole\n" );
					Free( n1 );
					Free( n2 );
					SkipRest;
					continue;
					}
				SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 1 );
				}
			}
		else if (tok == TOK_INCLUDE) {
			CheckInit; /* must get dimensions first */
			if ((tok = gettoken( fin )) != TOK_ALPHANUM) {
				printf( "expect name for INCLUDE\n" );
				SkipTokRest;
			}
			if (!(fnew = fopen( token, "r" ))) {
				printf( "can't open INCLUDE file %s\n",
					token );
				SkipRest;
				continue;
				}
			if ((tok = gettoken( fin )) != TOK_EOF
				&& tok != TOK_NEWLINE) {
				printf( "extra chars on INCLUDE line\n" );
				SkipRest;
				}
			initfile( fnew ); /* recurse */
			if (fclose( fnew ))
				printf( "error closing INCLUDE file\n" );
			continue; /* already ate the NEWLINE, if any */
			}
		else if (tok == TOK_CHIP) {
			CheckInit; /* must get dimensions first */
			if ((tok = gettoken( fin )) != TOK_TYPE
				|| (tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_ALPHANUM) {
				printf( "expect TYPE=type\n" );
				SkipTokRest;
				}
			if (!(p1 = (struct template *)
				Alloc( (long)sizeof(struct template) )))
				Nomem();
			p1->type = fcopy( token );
			if ((tok = gettoken( fin )) != TOK_PINS
				|| (tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_NUMBER) {
				printf( "expect PINS=number\n" );
				Free( p1->type );
				Free( p1 );
				SkipTokRest;
				}
			sscanf( token, "%d", &i );
			p1->pins = i;
			if ((p1->pins = i) < 0 || (i & 1))
				printf( "PINS negative or odd\n" );
			if ((tok = gettoken( fin )) != TOK_HORIZONTAL
				|| (tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_NUMBER) {
				printf( "expect HORIZONTAL=number\n" );
				Free( p1->type );
				Free( p1 );
				SkipTokRest;
				}
			sscanf( token, "%d", &i );
			if ((p1->horizontal = i) <= 0)
				printf( "HORIZONTAL nonpositive\n" );
			if ((tok = gettoken( fin )) != TOK_VERTICAL
				|| (tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_NUMBER) {
				printf( "expect VERTICAL=number\n" );
				Free( p1->type );
				Free( p1 );
				SkipTokRest;
				}
			sscanf( token, "%d", &i );
			if ((p1->vertical = i) < 0)
				printf( "VERTICAL nonpositive\n" );
			p1->pinlist = NULL;
			p1->next = chip;
			chip = p1;
			}
		else if (tok == TOK_NUMBER) {
			CheckInit; /* must get dimensions first */
			if (!chip) {
				printf( "no template\n" );
				SkipRest;
				continue;
				}
			sscanf( token, "%d", &i );
			if ((tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_ALPHANUM) {
				printf( "expect number=name\n" );
				SkipTokRest;
				}
			if (!(p2 = (struct pinassign *)
				Alloc( (long)sizeof(struct pinassign) )))
				Nomem();
			p2->name = fcopy( token );
			p2->index = i;
			/* check uniqueness of name and index */
			for (p22 = chip->pinlist; p22; p22 = p22->next)
				if (p22->index == i
					|| same( p22->name, p )) {
					printf( "warning: repeated pin\n" );
					break;
					}
			p2->next = chip->pinlist;
			chip->pinlist = p2;
			}
		else if (tok == TOK_ALPHANUM) {
			CheckInit; /* must get dimensions first */
			if (!chip) {
				printf( "no template\n" );
				SkipRest;
				continue;
				}
			p = fcopy( token );
			if ((tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_NUMBER) {
				printf( "expect name=number\n" );
				Free( p );
				SkipTokRest;
				}
			sscanf( token, "%d", &i );
			if (!(p2 = (struct pinassign *)
				Alloc( (long)sizeof(struct pinassign) )))
				Nomem();
			p2->name = p;
			p2->index = i;
			/* check uniqueness of name and index */
			for (p22 = chip->pinlist; p22; p22 = p22->next)
				if (p22->index == i
					|| same( p22->name, p )) {
					printf( "warning: repeated pin\n" );
					break;
					}
			p2->next = chip->pinlist;
			chip->pinlist = p2;
			}
		else if (tok == TOK_CHIPAT) {
			CheckInit; /* must get dimensions first */
			if ((tok = gettoken( fin )) != TOK_ROWCOLUMN) {
				printf( "expect (row,column)\n" );
				SkipTokRest;
				}
			sscanf( token, "(%d,%d)", &r1, &c1 );
			if ((tok = gettoken( fin )) != TOK_NAME
				|| (tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_ALPHANUM) {
				printf( "expect NAME=name\n" );
				SkipTokRest;
				}
			if (!(p3 = (struct instance *)
				Alloc( (long)sizeof(struct instance) )))
				Nomem();
			p3->name = fcopy( token );
			p3->row = r1;
			p3->column = c1;
			if ((tok = gettoken( fin )) != TOK_TYPE
				|| (tok = gettoken( fin )) != TOK_EQUAL
				|| (tok = gettoken( fin )) != TOK_ALPHANUM) {
				printf( "expect TYPE=type\n" );
				Free( p3->name );
				Free( p3 );
				SkipTokRest;
				}
			for (p3->type = chip; p3->type;
				p3->type = p3->type->next)
				if (same( token, p3->type->type ))
					break;
			if (!(p3->type)) {
				printf( "couldn't find chip type\n" );
				Free( p3->name );
				Free( p3 );
				SkipTokRest;
				}
			if ((tok = gettoken( fin )) != TOK_ORIENTATION
				|| (tok = gettoken( fin )) != TOK_EQUAL
				|| ((tok = gettoken( fin )) != TOK_NORMAL
				&& tok != TOK_UP && tok != TOK_DOWN
				&& tok != TOK_UPSIDEDOWN)) {
				printf( "expect ORIENTATION=orientation\n" );
				Free( p3->name );
				Free( p3 );
				SkipTokRest;
				}
			switch (tok) {
			case TOK_NORMAL:
				p3->orientation = ORIENT_NORMAL;	break;
			case TOK_UP:
				p3->orientation = ORIENT_UP;		break;
			case TOK_DOWN:
				p3->orientation = ORIENT_DOWN;		break;
			case TOK_UPSIDEDOWN:
				p3->orientation = ORIENT_UPSIDEDOWN;	break;
			default:
				printf( "internal error\n" );
				exit( -1 );
				break;
				}
			p3->next = chipat;
			chipat = p3;
			initchip( p3 );
			}
		else if (tok == TOK_NEWLINE)
			continue;
		else /* something unexpected */
			printf( "syntax error: unexpected input\n" );
		if ((tok = gettoken( fin )) != TOK_EOF && tok != TOK_NEWLINE) {
			printf( "syntax error: expected end of line\n" );
			SkipRest;
			}
		}
	}

static void initchip ( p ) /* initialize a chip definition (create holes) */
	struct instance *p;
	{
	int r, c, pin;
	struct template *t;

	pin = 1;
	r = p->row;
	c = p->column;
	t = p->type;
	/* should check for neighboring holes (warning if so) */
	switch (p->orientation) {
	case ORIENT_NORMAL:
		while (pin <= t->pins / 2) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			c += t->horizontal;
			}
		c -= t->horizontal;
		r += t->vertical;
		while (pin <= t->pins) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			c -= t->horizontal;
			}
		break;
	case ORIENT_UP:
		while (pin <= t->pins / 2) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			r += t->horizontal;
			}
		r -= t->horizontal;
		c -= t->vertical;
		while (pin <= t->pins) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			r -= t->horizontal;
			}
		break;
	case ORIENT_DOWN:
		while (pin <= t->pins / 2) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			r -= t->horizontal;
			}
		r += t->horizontal;
		c += t->vertical;
		while (pin <= t->pins) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			r += t->horizontal;
			}
		break;
	case ORIENT_UPSIDEDOWN:
		while (pin <= t->pins / 2) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			c -= t->horizontal;
			}
		c += t->horizontal;
		r -= t->vertical;
		while (pin <= t->pins) {
			SetCell( r-1, c-1, TOP, HOLE );
			SetCell( r-1, c-1, BOTTOM, HOLE );
			pin++;
			c += t->horizontal;
			}
		break;
	default:
		printf( "internal error: unexpected orientation\n" );
		exit( -1 );
		break;
		}
	}

static void locate ( p, r, c ) /* find location of name1.{name2,number} */
	char *p;
	int *r, *c;
	{
	char *q;
	int i;
	struct instance *s;
	struct pinassign *t;

	if (!(q = strchr( p, '.' ))) {
		printf( "expect name1.{name2,number}\n" );
		return;
		}
	*q++ = 0; /* separate into two parts & point at second part */
	for (s = chipat; s; s = s->next) /* find proper chip */
		if (same( p, s->name ))
			break;
	if (!s || !(s->type)) {
		printf( "can't find chip or chip type\n" );
		return;
		}
	if (isdigit( *q )) { /* get pin number */
		i = atoi( q );
		if (i <= 0 || i > s->type->pins) {
			printf( "pin out of range\n" );
			return;
			}
		}
	else { /* get index of named pin via the template */
		for (t = s->type->pinlist; t; t = t->next)
			if (same( q, t->name ))
				break;
		if (!t) {
			printf( "can't find pin\n" );
			return;
			}
		i = t->index;
		}
	*r = s->row;
	*c = s->column;
	switch (s->orientation) {
	case ORIENT_NORMAL:
		if (i <= s->type->pins / 2)
			*c += (i-1) * s->type->horizontal;
		else {
			*r += s->type->vertical;
			*c += (s->type->pins - i) * s->type->horizontal;
			}
		break;
	case ORIENT_UP:
		if (i <= s->type->pins / 2)
			*r += (i-1) * s->type->horizontal;
		else {
			*c -= s->type->vertical;
			*r += (s->type->pins - i) * s->type->horizontal;
			}
		break;
	case ORIENT_DOWN:
		if (i <= s->type->pins / 2)
			*r -= (i-1) * s->type->horizontal;
		else {
			*c += s->type->vertical;
			*r -= (s->type->pins - i) * s->type->horizontal;
			}
		break;
	case ORIENT_UPSIDEDOWN:
		if (i <= s->type->pins / 2)
			*c -= (i-1) * s->type->horizontal;
		else {
			*r -= s->type->vertical;
			*c -= (s->type->pins - i) * s->type->horizontal;
			}
		break;
	default:
		printf( "internal error: unexpected orientation\n" );
		exit( -1 );
		break;
		}
	*--q = '.'; /* put back the separator */
	}

static int gettoken ( fin ) /* get next token into token[], return value */
	FILE *fin;
	{
	int ch, i;

	/* burn whitespace */
	while ((ch = getc( fin )) == ' ' || ch == '\t') ;
	if (ch == EOF)
		return( TOK_EOF );
	else if (ch == '\n')
		return( TOK_NEWLINE );
	else if (ch == ';') { /* comment; burn to end of line */
		while ((ch = getc( fin )) != EOF && ch != '\n') ;
		return( (ch == '\n') ? TOK_NEWLINE : TOK_EOF );
		}
	else if (ch == '=')
		return( TOK_EQUAL );
	else if (isdigit( ch )) { /* a number; move it to the buffer */
		i = 0;
		do {
			if (i < MAXTOK-1)
				token[i++] = (char)ch;
			ch = getc( fin );
			} while (isdigit( ch ));
		token[i] = 0;
		if (ch != EOF)
			ungetc( ch, fin );
		return( TOK_NUMBER );
		}
	else if (isalpha( ch ) || ch == '.' || ch == '\\') {
		/* a name; move it to the buffer */
		i = 0;
		do {
			if (i < MAXTOK-1)
				token[i++] = (char)ch;
			ch = getc( fin );
			} while (isalnum( ch ) || ch == ':' || ch == '.'
				|| ch == '\\');
		token[i] = 0;
		if (ch != EOF)
			ungetc( ch, fin );
		/* try to identify it as a reserved word */
		for (i = 0; i < numres; i++) /* search table */
			if (!stricmp( tokenmatch[i].tokenname, token ))
				return( tokenmatch[i].tokenvalue );
		/* it's not a reserved word; just return it */
		strupr( token );
		return( TOK_ALPHANUM );
		}
	else if (ch == '(') { /* "(row,column)", move it to the buffer */
		token[0] = (char)ch;
		i = 1;
		while ((ch = getc( fin )) == ' ' || ch == '\t') ;
		if (!isdigit( ch )) {
			printf( "syntax error: expected digit\n" );
			exit( -1 );
			}
		do {
			if (i < MAXTOK-1)
				token[i++] = (char)ch;
			ch = getc( fin );
			} while (isdigit( ch ));
		while (ch == ' ' || ch == '\t')
			ch = getc( fin );
		if (ch != ',') {
			printf( "syntax error: expected comma\n" );
			exit( -1 );
			}
		if (i < MAXTOK-1)
			token[i++] = (char)ch;
		while ((ch = getc( fin )) == ' ' || ch == '\t') ;
		if (!isdigit( ch )) {
			printf( "syntax error: expected digit\n" );
			exit( -1 );
			}
		do {
			if (i < MAXTOK-1)
				token[i++] = (char)ch;
			ch = getc( fin );
			} while (isdigit( ch ));
		while (ch == ' ' || ch == '\t')
			ch = getc( fin );
		if (ch != ')') {
			printf( "syntax error: expected right paren\n" );
			exit( -1 );
			}
		if (i < MAXTOK-1)
			token[i++] = (char)ch;
		token[i] = 0;
		return( TOK_ROWCOLUMN );
		}
	else {
		printf( "syntax error: unrecognized token\n" );
		exit( -1 );
		}
	}

static char *fcopy ( p ) /* return ptr to far string copy */
	char *p;
	{
	char *q;
	char *r;

	if (!(q = r = Alloc( (long)strlen( p ) + 1 )))
		Nomem();
	while (*r++ = *p++) ; /* copy string */
	return( q );
	}

static int same ( p, q ) /* return 1 if far strings are identical, else 0 */
	char *p;
	char *q;
	{
	while (*p && *p == *q) { /* compare bytes until mismatch or end */
		p++;
		q++;
		}
	return( (*p || *q) ? 0 : 1 );
	}

void Report ( fout ) /* output routed board */
	FILE *fout;
	{
	int r, c;
	char b;
	long x;

	printf( "enter Report()\n" );
	/* output dimensions first */
	b = (char)Nrows;	putc( b, fout );
	b = (char)(Nrows>>8);	putc( b, fout );
	b = (char)Ncols;	putc( b, fout );
	b = (char)(Ncols>>8);	putc( b, fout );
	/* now do rows and columns */
	for (r = 0; r < Nrows; r++)
		for (c = 0; c < Ncols; c++) {
			x = GetCell( r, c, TOP ); /* first do frontside */
			b = (char)x;		putc( b, fout );
			b = (char)(x>>8);	putc( b, fout );
			b = (char)(x>>16);	putc( b, fout );
			b = (char)(x>>24);	putc( b, fout );
			x = GetCell( r, c, BOTTOM ); /* then do backside */
			b = (char)x;		putc( b, fout );
			b = (char)(x>>8);	putc( b, fout );
			b = (char)(x>>16);	putc( b, fout );
			b = (char)(x>>24);	putc( b, fout );
			}
	printf( "leave Report()\n" );
	}
