[net.sources] PCB part 5 of 10

agn@cmu-cs-unh.ARPA (Andreas Nowatzyk) (08/10/85)

#
# type    sh /usru0/agn/pcb/distr/../usenet/part5   to unpack this archive.
#
echo extracting pcif.c...
cat >pcif.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	CIF output routines					*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/

#include <stdio.h>
#include "pparm.h"
#include "pcdst.h"

extern FILE *fwantread(), *fwantwrite();

extern int rot_m[4][4];	/* rotation matrix (in pplace)	 */
extern int pdr[8];	/* direction offsets (for ptrs)	 */

FILE *icf, *ocf;	/* Cif - I/O			 */

#define pinsym 1	/* ordinary pin symbol		 */
#define viasym 2	/* via - symbol			 */
#define pwrsym 3	/* power plane connection	 */
#define gndsym 4	/* ground plane connection	 */
#define tlhsym 5	/* tool hole symbol		 */
#define sigsym 6	/* signal pin: no pwr/gnd conn.	 */
#define pn1sym 7	/* pin #1 marking		 */
#define algsym 8	/* alignment symbol		 */

/**********************************************************\
* 							   *
* A note on coordinates:				   *
*    internally: 1 unit = 100mil/rsun			   *
*    CIF output: 1 unit = 0.5 mil for the main section	   *
* 		      = 1 mil for the symbol definition	   *
* 							   *
\**********************************************************/

#define almoff 32	/* offset for alignment marks 	 */
#define ucf 25		/* unit conversion factor	 */
#define pgd 9		/* pin guard zone displacement	 */
#define cmww 100	/* crop mark wire width		 */
#define coww 40		/* component outline wire width	 */
#define gzww 400	/* guard zone wire width	 */
#define sgww0 16	/* signal wire width (near hole) */
#define sgww1 26	/* signal wire width (elsewhere) */
#define min_dst 16	/* min distance between wires	 */
#define cpsb 1000	/* base for component symbols > ex_cifH	 */
#define chhgh 128	/* character hight		 */
#define chwdf 4		/* character width factor	 */
#define clm_off 50	/* offset of clm-s to boarder	 */
#define max_wcp 7	/* max. wire coordinate pairs in a line	*/

/********************************************************************\
* 								     *
*  Some obsolete stuff:						     *
*   dynamic labeling was used to generate the silk-screen lable for  *
*   a component based on its instantiation name. People prefered     *
*   the type definition name.					     *
* 								     *
*   Alignment marks are no longer required by mossis.		     *
* 								     *
*   (the code for tooling holes was entirely ripped out: external    *
*    cif symbols can do as well if required)			     *
* 								     *
\********************************************************************/
/* #define dyna_lab */	/* dynamic labeling		 */
/* #define align_mrk */	/* alignment marks 		 */

static int chdst[128][2];	/* character descriptor table	 */

cifout()			/* output a cif file		 */
{
    char    buf[82];
    int i, c1, c2, s, w, c;

    printf ("Start writing CIF-file\n");

    icf = fwantread (".", "/usr/agn/pcb/pcbsdef.CIF", buf,
	    "Symbol definition file:");
    ocf = fwantwrite (".", "pcb.cif", buf, "CIF output file:", 1);
    if (!ocf)
      err("-NO CIF output file written", 0, 0, 0, 0);
    c1 = c2 = 0;
    for (i = 0; i < 128; ++i)
	chdst[i][0] = (-1);

    while (fgets (buf, 82, icf)) {
	if (buf[0] == '%') {
	    switch (buf[1]) {
		case 'c': 	/* character descriptor	 */
		    i = sscanf (&buf[2], "%d%d%d", &c, &w, &s);
		    if ((i != 3) || (c<=0) || (c>127) || (w<0) || (w>300)) {
			printf ("Illegal character descriptor -- ignored\n");
			break;
		    };
		    if (chdst[c][0] >= 0) {
			printf (
			"Multiple character descriptor (%d) -- ignored\n", c);
			break;
		    };
		    chdst[c][0] = s;
		    chdst[c][1] = w * chwdf;
		    break;
		case 's': 	/* insert component symbols	 */
		    if (c1)
			err ("invalid pcbsdef.CIF - multiple %s", c1, 0, 0, 0);
		    c1 = 1;
		    ocps ();	/* output component symbols	 */
		    break;
		case 'p': 	/* insert PC-board symbol	 */
		    if (c2)
			err ("invalid pcbsdef.CIF - multiple %p", c2, 0, 0, 0);
		    c2 = 1;
		    ofps ();	/* output frame and components	 */
		    opgc ();	/* output pwr / gnd connections  */
		    osws ();	/* output signal wires		 */
		    ohfs ();	/* output hole 'fillet'-s	 */
		    oclm ();	/* output cmpnt location marks	 */
		    clean_up ();	/* remove temp. marks	 */
		    break;
		default: 
		    err ("invalid pcbsdef.CIF - unknown escape",
			(int)buf[1] & 255, 0, 0, 0);
	    };
	}
	else
	    fputs (buf, ocf);
    };

    if (!c1 || !c2)
	err ("invalid pcbsdef.CIF - missing %s or %p", c1, c2, 0, 0);

    fclose (icf);
    fclose (ocf);
}


ofps()				/* output frame components	 */
{
    int i;

#ifdef align_mrk
    scall (-almoff, -almoff, algsym);	/* alignment marks	 */
    scall (V.BSX + almoff, -almoff, algsym);
    scall (-almoff, V.BSY + almoff, algsym);
    scall (V.BSX + almoff, V.BSY + almoff, algsym);
#endif

    cmrk (-2, 18, -2, -2, 18, -2);	/* crop - marks		 */
    cmrk (V.BSX - 18, -2, V.BSX + 2, -2, V.BSX + 2, 18);
    cmrk (V.BSX + 2, V.BSY - 18, V.BSX + 2, V.BSY + 2, V.BSX - 18, V.BSY + 2);
    cmrk (18, V.BSY + 2, -2, V.BSY + 2, -2, V.BSY - 18);

    fputs (" L PN2;\n", ocf);	/* guard zone for inner layers	 */
    cwire_S (    0,     0, 0, 0, gzww);
    cwire_C (V.BSX,     0, 0, 0);
    cwire_C (V.BSX, V.BSY, 0, 0);
    cwire_C (    0, V.BSY, 0, 0);
    cwire_E (    0,     0, 0, 0);
    fputs (" L PN3;\n", ocf);
    cwire_S (    0,     0, 0, 0, gzww);
    cwire_C (V.BSX,     0, 0, 0);
    cwire_C (V.BSX, V.BSY, 0, 0);
    cwire_C (    0, V.BSY, 0, 0);
    cwire_E (    0,     0, 0, 0);

    for (i = 0; i < V.ncp; ++i)	/* scan components to call sym	 */
	if (strcmp (CP[i].name, DELETED))
	    dcp (&CP[i]);
}

ocps ()				/* output component symbols	 */
{
    register int i, j, k, x, y;
    int ext = 0;
    register struct pin *pp;
    char buf[inp_lnl], fname[80];
    FILE *ex_cif;

    for (j = 0; j < V.nty; ++j) {

	if (!strcmp (TY[j].name, DELETED))
	    continue;		/* skip deleted entries		 */

	if (TY[j].cif) {	/* skip external components	 */
	    ext = 1;
	    continue;
	}

	fprintf (ocf, "DS %d 1270 1;\n", j + cpsb);
	pp = TY[j].p;
	for (i = 0; i < TY[j].np; ++i) {
	    x = pp -> x;
	    y = pp -> y;
	    if (!i)
		scall (x, y, pn1sym);
	    switch (pp -> p) {
		case 0: 
		    scall (x, y, pinsym);
		    break;
		case 1: 
		    scall (x, y, pinsym);
		    scall (x, y, gndsym);
		    break;
		case 2: 
		case 3: 
		case 4: 
		    scall (x, y, pinsym);
		    scall (x, y, pwrsym);
		    break;
		default: 
		    err ("illegal pin type", pp -> p, i, 0, 0);
	    };
	    pp++;
	};

	fputs (" L PSSC;\n", ocf);	/* outline component	 */
	cwire_S (         -3,          -3, 0, 0, coww);
	cwire_C (TY[j].x + 3,          -3, 0, 0);
	cwire_C (TY[j].x + 3, TY[j].y + 3, 0, 0);
	cwire_C (         -3, TY[j].y + 3, 0, 0);
	cwire_E (         -3,          -3, 0, 0);
	if (TY[j].y >= rsun * 3 && TY[j].x >= rsun * 3)	/* add an IC mark */
	    fprintf (ocf, "  B 200 200 -50 %d;\n", (TY[j].y >> 1) * ucf);
	fputs (" L PF;\n", ocf);
	cwire_S (         -3,          -3, 0, 0, coww);
	cwire_C (TY[j].x + 3,          -3, 0, 0);
	cwire_C (TY[j].x + 3, TY[j].y + 3, 0, 0);
	cwire_C (         -3, TY[j].y + 3, 0, 0);
	cwire_E (         -3,          -3, 0, 0);
	if (TY[j].y >= rsun * 3 && TY[j].x >= rsun * 3)	/* add an IC mark */
	    fprintf (ocf, "  B 200 200 -50 %d;\n", (TY[j].y >> 1) * ucf);

#ifndef dyna_lab
	for (i = nmmax; i; i--)	/* truncate string if necessary	 */
	    if ((k = txt_len (TY[j].name, i)) <= (TY[j].x + 4) * ucf)
		break;
	x = ((TY[j].x + 4) * ucf - k) / 2 - 2 * ucf;/* center text */
	y = ((TY[j].y + 4) * ucf - chhgh) / 2 - 2 * ucf;
	ctxt (x, y, 0, TY[j].name, i);
#endif

	fputs ("DF;\n", ocf);
    }

    if (ext) {			/* external components present	 */
	printf ("List of external components:\n");
	for (i = 0; i < V.nty; i++)
	    if (TY[i].cif)
		printf ("\t'%s':\tcif-symbol#=%d\n",
			TY[i].name, CIF[TY[i].cif-1].symn);
	ex_cif = fwantread (".", "", fname, "External CIF-symbol file:");
	if (!ex_cif)
	    err ("Could not open external CIF-symbol file", 0, 0, 0, 0);
	while (fgets (buf, inp_lnl, ex_cif))
	   fputs (buf, ocf);
	fclose (ex_cif);
    }
}

dcp (C)				/* call a component symbol	 */
    struct comp *C;
{
    static int  rm[4][4] = { { 1,  1,  0,  1},
			     {-1,  1,  1,  0},
			     {-1, -1,  0, -1},
			     { 1, -1, -1,  0}  };
    union ptr_int {		/* allow arithmetic on pointer	*/
	unsigned i;
	struct type *ty;
    } p1, p2;
    register int i, r, x, y;

    x = C -> x;
    y = C -> y;
    r = C -> r;

    i = C -> ty -> cif;
    if (i) 			/* external symbol		 */
	i = CIF[i - 1].symn;
    else {			/* internal symbol		 */
	p1.ty = C -> ty;
	p2.ty = V.ty;
	i = (p1.i - p2.i) / sizeof (TY[0]) + cpsb;
    }

    fprintf (ocf, "C %d R%d %d T%d %d;\n", i, rm[r][3], rm[r][2],
	     x * ucf, y * ucf);

#ifdef dyna_lab
    i = (C -> ty -> y * ucf - chhgh) / 2;
    ctxt (C -> x * ucf + i * rm[C -> r][0],
          C -> y * ucf + i * rm[C -> r][1], C -> r, C -> name, nmmax);
#endif
}

ctxt (x, y, r, s, l)		/* create text			 */
    int x, y, r, l;
    char *s;
{
    while (*s && l--) {
	*s &= 127;
	if (chdst[*s][0] > 0) {
	    switch (r) {
		case 1: 
		    fprintf (ocf, "C %d R 0 1 T %d %d;\n",
			     chdst[*s][0], x, y);
		    y += chdst[*s][1];
		    break;
		case 2: 
		    fprintf (ocf, "C %d R -1 0 T %d %d;\n",
			     chdst[*s][0], x, y);
		    x -= chdst[*s][1];
		    break;
		case 3: 
		    fprintf (ocf, "C %d R 0 -1 T %d %d;\n",
			     chdst[*s][0], x, y);
		    y -= chdst[*s][1];
		    break;
		default: 
		    fprintf (ocf, "C %d T %d %d;\n",
			     chdst[*s][0], x, y);
		    x += chdst[*s][1];
		    break;
	    };
	};
	s++;
    };
}

txt_len (s, l)			/* text length function		 */
    char *s;
    int l;
{
    register int i = 0;

    while (*(s++) && l--)
	i += chdst[*s & 127][1];

    return i;
}


cmrk (x1, y1, x2, y2, x3, y3)		/* crop mark		 */
    int x1, y1, x2, y2, x3, y3;
{
    fputs (" L PC1;\n", ocf);
    cwire_S (x1, y1, 0, 0, cmww);
    cwire_C (x2, y2, 0, 0);
    cwire_E (x3, y3, 0, 0);
    fputs (" L PC4;\n", ocf);
    cwire_S (x1, y1, 0, 0, cmww);
    cwire_C (x2, y2, 0, 0);
    cwire_E (x3, y3, 0, 0);
    fputs (" L PSSC;\n", ocf);
    cwire_S (x1, y1, 0, 0, cmww);
    cwire_C (x2, y2, 0, 0);
    cwire_E (x3, y3, 0, 0);
    fputs (" L PSMC;\n", ocf);
    cwire_S (x1, y1, 0, 0, cmww);
    cwire_C (x2, y2, 0, 0);
    cwire_E (x3, y3, 0, 0);
    fputs (" L PD;\n", ocf);
    cwire_S (x1, y1, 0, 0, cmww);
    cwire_C (x2, y2, 0, 0);
    cwire_E (x3, y3, 0, 0);
    fputs (" L PF;\n", ocf);
    cwire_S (x1, y1, 0, 0, cmww);
    cwire_C (x2, y2, 0, 0);
    cwire_E (x3, y3, 0, 0);
}

scall (x, y, t)			/* symbol call		 */
    int x, y, t;
{
    fprintf (ocf, "C %d T %d,%d;\n", t, x * ucf, y * ucf);
}

#ifdef simple			/* simple wire routines		 */
osws ()				/* output signal wire stuff	 */
{
    int     i, chplt (), cvplt ();

    wtvf = cvplt;
    wthf = chplt;
    for (i = 0; i < V.nnh; ++i)	/* trace all nets		 */
	if (NH[i].l > 1)
	    wtrace (NH[i].lp -> c -> x, NH[i].lp -> c -> y, vec);
}

#else
osws ()				/* output signal wire stuff	 */
{
    int     chplt (), cvplt (), mrk_hole (), umrk_hole ();
    register int i, x, y;

    for (i = 0; i < V.nnh; ++i)	/* trace all nets		 */
	if (NH[i].l > 1) {
	    wtvf = nil;		/* mark all holes of this net	 */
	    wthf = mrk_hole;
	    x = NH[i].lp -> c -> x;
	    y = NH[i].lp -> c -> y;
	    wtrace (x, y, vec);
	    wtvf = cvplt;	/* plot the net			 */
	    wthf = chplt;
	    wtrace (x, y, vec);
	    wtvf = nil;		/* remove the hole marks	 */
	    wthf = umrk_hole;
	    wtrace (x, y, vec);
	}
}
#endif


#ifdef simple			/* simple wire routines		 */
cvplt (x1, y1, x2, y2)		/* output a wire segment	 */
    int x1, y1, x2, y2;
/******************************************************************\
* 								   *
*  Plot part of a signal wire from <x1,y1> to <x2,y2>. This draws  *
*  just a straight line on the desired side of the board.	   *
* 								   *
\******************************************************************/
{
    static int  s = 0;
    if (s != wtsb) {		/* side check			 */
	if (wtsb == s1b)
	    fputs (" L PC1;\n", ocf);
	else
	    fputs (" L PC4;\n", ocf);
	s = wtsb;
    };
    cwire_S (x1, y1, 0, 0, sgww1);
    cwire_E (x2, y2, 0, 0);
}

#else				/* conservative wire routine	 */
cvplt (x1, y1, x2, y2)		/* output a wire segment	 */
    int x1, y1, x2, y2;
/**********************************************************************\
* 								       *
*  A wire is drawn from <x1,y1> to <x2,y2> on the desired board side.  *
*  A minimal distance to holes is maintained. This calles for bends    *
*  in the wire path if it 1 raster unit apart from a hole.	       *
* 								       *
\**********************************************************************/
{
    register int i, j, t;
    register char *p;
    static int  s = 0;

    if (s != wtsb) {		/* side check			 */
	if (wtsb == s1b)
	    fputs (" L PC1;\n", ocf);
	else
	    fputs (" L PC4;\n", ocf);
	s = wtsb;
    }


    p = &pcb[(y1 + y2) >> 1][(x1 + x2) >> 1];
    for (i = 0, j = 0; i < 8; i++)	/* wide wire locator	 */
	if (*(p + pdr[i]) & wtsb)
	    j++;		/* count adjacent points	 */
    if (j > 6)
	wwb_trc ((x1 + x2) >> 1, (y1 + y2) >> 1, wtsb);


    if ((y2 < y1) || ((y2 == y1) && (x2 < x1))) {
	t = x1;			/* direction confined 0 to 3	 */
	x1 = x2;
	x2 = t;
	t = y1;
	y1 = y2;
	y2 = t;
    }

    if (x2 > x1) {
	if (y2 > y1)
	    plt_d1wire (x1, y1, x2, y2);	/* dir = 1	 */
	else
	    plt_hwire (x1, y1, x2, y2);}	/* dir = 0	 */
    else {
	if (x2 < x1)
	    plt_d2wire (x1, y1, x2, y2);	/* dir = 3	 */
	else
	    plt_vwire (x1, y1, x2, y2);		/* dir = 2	 */
    }
}

plt_d1wire (x1, y1, x2, y2)	/* plot diag. wire		 */
    int x1, y1, x2, y2;
/***********************************************************\
* 							    *
*  Plot a diagonal wire from <x1,y1> to <x2,y2>. The slope  *
*  is dx = 1, dy = 1.					    *
* 							    *
\***********************************************************/
{
    register int enable, nh1, nh2;

    nh1 = near_hl (x1, y1);
    nh2 = near_hl (x2, y2);
    enable = 3 <= (!nh1 + !nh2 + y2 - y1); /* attn: trick! */

    switch (nh1) {		/* check start point		 */
	case 0:
	    if (enable)
	        cwire_S (x1, y1, 0, 0, sgww1);
	    else
		cwire_S (x1, y1, 0, 0, sgww0);
	    break;
	case 1: 
	    cwire_S (x1, y1, 0, 1, sgww0);
	    if (enable) {
	        cwire_C (x1, y1, 1, 1);
		cwire_E (x1 + 1, y1 + 1, 0, 0);
		cwire_S (x1 + 1, y1 + 1, 0, 0, sgww1);}
	    else
		cwire_C (x1, y1, 1, 1);
	    break;
	case 4: 
	    cwire_S (x1, y1, 1, 0, sgww0);
	    if (enable) {
	        cwire_C (x1, y1, 1, 1);
		cwire_E (x1 + 1, y1 + 1, 0, 0);
		cwire_S (x1 + 1, y1 + 1, 0, 0, sgww1);}
	    else
		cwire_C (x1, y1, 1, 1);
	    break;
	default: 
	    err ("plt_d1wire: wire / hole collision", x1, y1, nh1, 0);
    }

    switch (nh2) {
	case 0: 
	    cwire_E (x2, y2, 0, 0);
	    break;
	case 2: 
	    if (enable) {
		cwire_E (x2 - 1, y2 - 1, 0, 0);
		cwire_S (x2 - 1, y2 - 1, 0, 0, sgww0);
	    }
	    cwire_C (x2, y2, -1, -1);
	    cwire_E (x2, y2, -1, 0);
	    break;
	case 3: 
	    if (enable) {
		cwire_E (x2 - 1, y2 - 1, 0, 0);
		cwire_S (x2 - 1, y2 - 1, 0, 0, sgww0);
	    }
	    cwire_C (x2, y2, -1, -1);
	    cwire_E (x2, y2, 0, -1);
	    break;
	default: 
	    err ("plt_d1wire: wire / hole intersection", x2, y2, nh2, 0);
    }
}


plt_d2wire (x1, y1, x2, y2)	/* plot diag. wire		 */
    int x1, y1, x2, y2;
/***********************************************************\
* 							    *
*  Plot a diagonal wire from <x1,y1> to <x2,y2>. The slope  *
*  is dx = -1, dy = 1.					    *
* 							    *
\***********************************************************/
{
    register int enable, nh1, nh2;

    nh1 = near_hl (x1, y1);
    nh2 = near_hl (x2, y2);
    enable = 3 <= (!nh1 + !nh2 + y2 - y1); /* attn: trick! */

    switch (nh1) {		/* check start point	 */
	case 0:
	    if (enable)
		cwire_S (x1, y1, 0, 0, sgww1);
	    else
		cwire_S (x1, y1, 0, 0, sgww0);
	    break;
	case 1: 
	    cwire_S (x1, y1, 0, 1, sgww0);
	    if (enable) {
	        cwire_C (x1, y1, -1, 1);
		cwire_E (x1 - 1, y1 + 1, 0, 0);
		cwire_S (x1 - 1, y1 + 1, 0, 0, sgww1);}
	    else
		cwire_C (x1, y1, -1, 1);
	    break;
	case 2: 
	    cwire_S (x1, y1, -1, 0, sgww0);
	    if (enable) {
		cwire_C (x1, y1, -1, 1);
		cwire_E (x1 - 1, y1 + 1, 0, 0);
		cwire_S (x1 - 1, y1 + 1, 0, 0, sgww1);}
	    else
		cwire_C (x1, y1, -1, 1);
	    break;
	default: 
	    err ("plt_d2wire: wire / hole collision", x1, y1, nh1, 0);
    }

    switch (nh2) {		/* check end point		 */
	case 0: 
	    cwire_E (x2, y2, 0, 0);
	    break;
	case 3:
	    if (enable) {
		cwire_E (x2 + 1, y2 - 1, 0, 0);
		cwire_S (x2 + 1, y2 - 1, 0, 0, sgww0);
	    }
	    cwire_C (x2, y2, 1, -1);
	    cwire_E (x2, y2, 0, -1);
	    break;
	case 4: 
	    if (enable) {
		cwire_E (x2 + 1, y2 - 1, 0, 0);
		cwire_S (x2 + 1, y2 - 1, 0, 0, sgww0);
	    }
	    cwire_C (x2, y2, 1, -1);
	    cwire_E (x2, y2, 1, 0);
	    break;
	default: 
	    err ("plt_d2wire: wire / hole intersection", x2, y2, nh2, 0);
    }
}

plt_hwire (x1, y1, x2, y2)	/* plot a horizontal wire	 */
    int x1, y1, x2, y2;
/*************************************************************\
* 							      *
*  Draw a horizontal wire from <x1,y1> to <x2,y2>. The slope  *
*  is: dx = 1, dy = 0;					      *
* 							      *
\*************************************************************/
{
    register int dy, nh1, nh2, wide;

    dy = 0;			/* default displacement		 */

    nh1 = near_hl (x1, y1);
    nh2 = near_hl (x1 + 1, y1);	/* look ahead			 */

    switch (nh1) {		/* check start point		 */
	case 0:
	    if (!nh2) {
		cwire_S (x1, y1, 0, 0, sgww1);
		wide = 1;}
	    else {
		cwire_S (x1, y1, 0, 0, sgww0);
		wide = 0;
	    }
	    break;
	case 1: 
	    cwire_S (x1, y1, 0, 1, sgww0);
	    dy = 1;
	    wide = 0;
	    break;
	case 3: 
	    cwire_S (x1, y1, 0, -1, sgww0);
	    dy = -1;
	    wide = 0;
	    break;
	case 4: 
	    cwire_S (x1, y1, 1, 0, sgww0);
	    wide = 0;
	    break;
	default: 
	    err ("plt_hwire: wire / hole collision", x1, y1, nh1, 0);
    }

    while (++x1 < x2) {		/* scan wire 			 */
	nh1 = nh2;
	nh2 = near_hl (x1 + 1, y1);
	switch (nh1) {
	    case 0:
		if (!wide && !nh2) {
		    if (dy) {	/* end any bend			 */
			cwire_C (x1 - 1, y1, 0, dy);
		    	dy = 0;
		    }
		    cwire_E (x1, y1, 0, 0);
		    cwire_S (x1, y1, 0, 0, sgww1);
		    wide = 1;}
		else if (dy) {
		    cwire_C (x1 - 1, y1, 0, dy);
		    cwire_C (x1, y1, 0, 0);
		    dy = 0;
		}
		break;
	    case 1: 
		if (dy != 1) {	/* start a bend up	 */
		    if (wide) {
			cwire_E (x1 - 1, y1, 0, dy);
			cwire_S (x1 - 1, y1, 0, dy, sgww0);
			wide = 0;}
		    else
			cwire_C (x1 - 1, y1, 0, dy);
		    cwire_C (x1, y1, 0, 1);
		    dy = 1;
		}
		break;
	    case 3: 
		if (dy != -1) {	/* start a bend down	 */
		    if (wide) {
			cwire_E (x1 - 1, y1, 0, dy);
			cwire_S (x1 - 1, y1, 0, dy, sgww0);
			wide = 0;}
		    else
			cwire_C (x1 - 1, y1, 0, dy);
		    cwire_C (x1, y1, 0, -1);
		    dy = -1;
		}
		break;
	    default: 
		err ("plt_hwire: illegal wire/hole realtion", x1,y1, nh1, dy);
	}
    }

    switch (nh2) {		/* check end point		 */
	case 0: 
	    if (dy != 0)	/* finish any bend		 */
		cwire_C (x2 - 1, y2, 0, dy);
	    cwire_E (x2, y2, 0, 0);
	    break;
	case 1: 
	    if (dy != 1) {	/* start an incomplete bend up	 */
		if (wide) {
		    cwire_E (x1 - 1, y1, 0, dy);
		    cwire_S (x1 - 1, y1, 0, dy, sgww0);}
		else
		    cwire_C (x1 - 1, y1, 0, dy);
	    }
	    cwire_E (x2, y2, 0, 1);
	    break;
	case 2: 
	    if (dy != 0)	/* finish any bend		 */
		cwire_C (x2 - 1, y2, 0, dy);
	    else if (wide) {
		cwire_E (x2 - 1, y2, 0, 0);
		cwire_S (x2 - 1, y2, 0, 0, sgww0);
	    }
	    cwire_E (x2, y2, -1, 0);
	    break;
	case 3: 
	    if (dy != -1) {	/* start an incomplete bend down */
		if (wide) {
		    cwire_E (x1 - 1, y1, 0, dy);
		    cwire_S (x1 - 1, y1, 0, dy, sgww0);}
		else
		    cwire_C (x1 - 1, y1, 0, dy);
	    }
	    cwire_E (x2, y2, 0, -1);
	    break;
	default: 
	    err ("plt_hwire: trouble at end point", x2, y2, nh2, dy);
    }
}

plt_vwire (x1, y1, x2, y2)	/* plot a vertcal wire		 */
    int x1, y1, x2, y2;
/**********************************************************\
* 							   *
*  Draw a vertcal wire from <x1,y1> to <x2,y2>. The slope  *
*  is: dx = 0, dy = 1;					   *
* 							   *
\**********************************************************/
{
    register int dx, nh1, nh2, wide;

    dx = 0;			/* default displacement		 */

    nh1 = near_hl (x1, y1);
    nh2 = near_hl (x1, y1 + 1);	/* look ahead			 */

    switch (nh1) {		/* check start			 */
	case 0:
	    if (!nh2) {
	        cwire_S (x1, y1, 0, 0, sgww1);
		wide = 1;}
	    else {
	        cwire_S (x1, y1, 0, 0, sgww0);
		wide = 0;
	    }
	    break;
	case 1: 
	    cwire_S (x1, y1, 0, 1, sgww0);
	    wide = 0;
	    break;
	case 2: 
	    cwire_S (x1, y1, -1, 0, sgww0);
	    dx = -1;
	    wide = 0;
	    break;
	case 4: 
	    cwire_S (x1, y1, 1, 0, sgww0);
	    dx = 1;
	    wide = 0;
	    break;
	default: 
	    err ("plt_vwire: wire / hole collision", x1, y1, nh1, dx);
    }

    while (++y1 < y2) {		/* scan wire 			 */
	nh1 = nh2;
	nh2 = near_hl (x1, y1 + 1);
	switch (nh1) {
	    case 0:
		if (!wide && !nh2) { 
		    if (dx) {	/* end any bend			 */
		        cwire_C (x1, y1 - 1, dx, 0);
			dx = 0;
		    }
		    cwire_E (x1, y1, 0, 0);
		    cwire_S (x1, y1, 0, 0, sgww1);
		    wide = 1;}
		else if (dx) {	/* end any bend			 */
		    cwire_C (x1, y1 - 1, dx, 0);
		    cwire_C (x1, y1, 0, 0);
		    dx = 0;
		}
		break;
	    case 2: 
		if (dx != -1) {	/* start a bend left		 */
		    if (wide) {
			cwire_E (x1, y1 - 1, dx, 0);
			cwire_S (x1, y1 - 1, dx, 0, sgww0);
			wide = 0;}
		    else
			cwire_C (x1, y1 - 1, dx, 0);
		    cwire_C (x1, y1, -1, 0);
		    dx = -1;
		}
		break;
	    case 4: 
		if (dx != 1) {	/* start a bend right		 */
		    if (wide) {
			cwire_E (x1, y1 - 1, dx, 0);
			cwire_S (x1, y1 - 1, dx, 0, sgww0);
			wide = 0;}
		    else
			cwire_C (x1, y1 - 1, dx, 0);
		    cwire_C (x1, y1, 1, 0);
		    dx = 1;
		}
		break;
	    default: 
		err ("plt_vwire: illegal wire/hole realtion", x1,y1, nh1, dx);
	}
    }

    switch (nh2) {		/* check end point		 */
	case 0: 
	    if (dx != 0)	/* finish any bend		 */
		cwire_C (x2, y2 - 1, dx, 0);
	    cwire_E (x2, y2, 0, 0);
	    break;
	case 2: 
	    if (dx != -1) {	/* start an incomplte bend left	 */
		if (wide) {
		    cwire_E (x2, y2 - 1, dx, 0);
		    cwire_S (x2, y2 - 1, dx, 0, sgww0);}
		else
		    cwire_C (x2, y2 - 1, dx, 0);
	    }
	    cwire_E (x2, y2, -1, 0);
	    break;
	case 3: 
	    if (dx != 0)	/* finish any bend		 */
		cwire_C (x2, y2 - 1, dx, 0);
	    else if (wide) {
		cwire_E (x2 - 1, y2, 0, 0);
		cwire_S (x2 - 1, y2, 0, 0, sgww0);
	    }
	    cwire_E (x2, y2, 0, -1);
	    break;
	case 4: 
	    if (dx != 1) {	/* start an incomplete bend up	 */
		if (wide) {
		    cwire_E (x2, y2 - 1, dx, 0);
		    cwire_S (x2, y2 - 1, dx, 0, sgww0);}
		else
		    cwire_C (x2, y2 - 1, dx, 0);
	    }
	    cwire_E (x2, y2, 1, 0);
	    break;
	default: 
	    err ("plt_vwire: trouble at end point", x2, y2, nh2, dx);
    }
}

on_hole (x, y)			/* on hole check		 */
    int x, y;
/**************************************************************\
* 							       *
*  Returns '1' if <x,y> is part of a hole that is not part     *
*  of the current net (unselected). It returns '0' otherwise.  *
*  This routine is not fooled by guard bits for via-holes.     *
* 							       *
\**************************************************************/
{
    if (!(pcb[y][x] & ahb))	/* no hole at all		 */
	return (0);

    if (pcb[y][x - 1] & ahb) {
	if (!(pcb[y][x + 1] & ahb)) {
	    x--;
	    if (!(pcb[y][x - 1] & ahb))
		return (0);
	}}
    else {
	x++;
	if (!(pcb[y][x] & pcb[y][x + 1] & ahb))
	    return (0);
    }

    if (pcb[y - 1][x] & ahb) {
	if (!(pcb[y + 1][x] & ahb)) {
	    y--;
	    if (!(pcb[y - 1][x] & ahb))
		return (0);
	}}
    else {
	y++;
	if (!(pcb[y][x] & pcb[y + 1][x] & ahb))
	    return (0);
    }

    return (!(pcb[y][x] & selb)); /* test for selection		 */
}

near_hl (x, y)			/* near hole test		 */
    int x, y;
/*******************************************************************\
* 								    *
*  The relation of <x,y> to the nearest hole (if any) is reported.  *
*  if no hole is present, a 0 is returned. values returned (Hex):   *
* 								    *
*         .  .  1  1  1  .  .					    *
*         .  .  .  .  .  .  .					    *
*         2  .  *  *  *  .  4					    *
*         2  .  *  *  *  .  4					    *
*         2  .  *  *  *  .  4					    *
*         .  .  .  .  .  .  .					    *
*         .  .  3  3  3  .  .					    *
* 								    *
\*******************************************************************/
{   int i;
    static int  Rx[4] = { 0, 2, 0,-2};
    static int  Ry[4] = {-2, 0, 2, 0};

    for (i = 0; i < 4; ++i)	/* look for nearby hole		 */
	if (on_hole (x + Rx[i], y + Ry[i]))
	    return (i + 1);

    return (0);			/* not near a hole		 */
}

mrk_hole (x, y)			/* mark a hole			 */
    int x, y;
{
    pcb[y][x] |= selb;
    return (0);
}

umrk_hole (x, y)		/* mark a hole			 */
    int x, y;
{
    pcb[y][x] &= ~selb;
    return (0);
}

#endif

chplt (x, y)		/* output via holes		 */
    int x, y;
{
    if (pcb[y][x] & ishb)
	scall (x, y, viasym);
    return (0);
}

static int real_x, real_y, cnt;	/* common to cwire_*		 */
cwire_S (x, y, dx, dy, w)	/* start a CIF - wire		 */
    int x, y, dx, dy, w;
/********************************************************************\
* 								     *
*  A CIF wire of width w is started at location <x,y>, which is	     *
*  given in raster units. A displacement <dx,dy> is applied to this  *
*  location.							     *
* 								     *
\********************************************************************/
{
    fprintf (ocf, " W %d: %d,%d",
	    w, real_x = x * ucf + dx * pgd, real_y = y * ucf + dy * pgd);
    cnt = 1;
}

cwire_C (x, y, dx, dy)		/* continue a CIF - wire	 */
    int x, y, dx, dy;
{   int     rx, ry;

    rx = x * ucf + dx * pgd;
    ry = y * ucf + dy * pgd;
    if (rx != real_x || ry != real_y) {
	real_x = rx;
	real_y = ry;
	if (++cnt < max_wcp)
	    fprintf (ocf, " %d,%d", rx, ry);
	else {
	    cnt = 0;
	    fprintf (ocf, "\n  %d,%d", rx, ry);
	}
    }
}

cwire_E (x, y, dx, dy)		/* and a CIF - wire	 */
    int x, y, dx, dy;
{   int rx, ry;

    rx = x * ucf + dx * pgd;
    ry = y * ucf + dy * pgd;
    if (rx != real_x || ry != real_y)
	fprintf (ocf, " %d,%d;\n", rx, ry);
    else
	fprintf (ocf, ";\n");
}

opgc ()
/*******************************************************************\
* 								    *
*  Output power/ground connections:				    *
* 								    *
*  Connections to the internal layers (VCC,GND ...) can be made by  *
*  2 different methods:						    *
*  a) by defining a pin to be VCC/GND/VEE/VTT in the type file.	    *
*     this is taken care off by the component symbol generation	    *
*     in 'ocps'.						    *
*  b) by connecting a pin to the special nets VCC/GND/VEE/VTT in    *
*     a given instantiation of the type: this is done here!	    *
* 								    *
\*******************************************************************/
{
    register int j, r, xp, yp;
    int i, x, y;
    register struct pin *pin;
    struct hole *hp;
    register struct nlhd *net;
    struct hole *fndh ();	

    for (i = 0; i < V.ncp; i++) {	/* scan all components	 */

	if (!strcmp (CP[i].name, DELETED))
	    continue;			/* skip deleted entries	 */

	if (CP[i].ty -> cif)
	    continue;			/* skip external cifs	 */

	x = CP[i].x;			/* get borad position	 */
	y = CP[i].y;
	r = CP[i].r;
	for (j = CP[i].ty -> np, pin = CP[i].ty -> p; j; j--, pin++) {
				/* scan component pins		 */
	    if (pin -> p)
		continue;	/* pwr/gnd is done in symbol def */

	    xp = x + (pin -> x) * rot_m[r][0] + (pin -> y) * rot_m[r][1];
	    yp = y + (pin -> x) * rot_m[r][2] + (pin -> y) * rot_m[r][3];

	    hp = fndh (xp, yp);	/* find hole			 */
	    if (!hp)
		err ("opgc: missing hole", xp, yp, 0, 0);

	    net = hp -> n -> nlp;	/* insert proper symbols */
	    if (net == &V.GND)		
		scall (xp, yp, gndsym);
	    else if (net == &V.VCC || net == &V.VEE || net == &V.VTT)
		scall (xp, yp, pwrsym);
	    else
		scall (xp, yp, sigsym);
	}
    }
}

ohfs ()
/****************************************************************\
* 								 *
*  Hole 'fillet'-s:						 *
*     In order to prevent demage to the board if components are	 *
*     replaced, extra cooper is added to the area where a wire	 *
*     enters a component hole.					 *
* 								 *
\****************************************************************/
{
    register int i, x, y;

    fprintf (ocf, "L PC1;\n");		/* side 1 first		 */
    for (i = 0; i < V.nch; i++)
	if (pcb[CH[i].y][CH[i].x] & s1b) {
	    x = CH[i].x;
	    y = CH[i].y;
	    fillet (x, y, s1b);
	}

    fprintf (ocf, "L PC4;\n");		/* now side 2		 */
    for (i = 0; i < V.nch; i++)
	if (pcb[CH[i].y][CH[i].x] & s2b) {
	    x = CH[i].x;
	    y = CH[i].y;
	    fillet (x, y, s2b);
	}
}

/* geometric constraints for fillet round-flash			 */

#define r0 72 	/* = (ucf*sqrt(2^2 + 4^2) - min_dst - via_hole_radius) * 2 */
#define r1 42	/* = (ucf*2 - (sgww1/2 + min_dst)) * 2		 */
#define r2 54	/* = (sqrt((ucf*2)^2 + ucf^2) - (sgww1/2 + min_dst)) * 2 */
#define r3 83	/* = (sqrt(2)*ucf*2 - (sgww1/2 + min_dst)) * 2	 */

fillet (x, y, s)			/* draw a 'fillet'	 */
    int x, y, s;
{
    static int pdx[16] = {2,2,2,1,0,-1,-2,-2,-2,-2,-2,-1,0,1,2,2};
    static int pdy[16] = {0,1,2,2,2,2,2,1,0,-1,-2,-2,-2,-2,-2,-1};
    static int msk[8] = { 0x8003, 0x001f, 0x0038, 0x01f0,
			  0x0380, 0x1f00, 0x3800, 0xf001  };
    static int d[16] = {r1,r2,r3,r2,r1,r2,r3,r2,r1,r2,r3,r2,r1,r2,r3,r2};

    register int xx, yy, j, k, l, r;
    int i;

    for (i = 0; i < 16; i++) {	/* scan potential candidates	 */
	xx = x + pdx[i];
	yy = y + pdy[i];
	if (pcb[yy][xx] & s) {	/* found a wire			 */

	    r = r0;		/* default radius		 */

	    j = 0;		/* reset search mask		 */
	    for (k = 0; k < 8; k++) {
		l = pcb[yy + dr[k][1]][xx + dr[k][0]];
		if (l & ishb)
		    r = r1;
		if (l & (chb | s) && !(l & ishb))
		    j |= msk[k];
	    }
	    for (k = 0; k < 16; k++) {	/* find max legal radius */
		if (j & (1 << k))
		   continue;	/* skip this point		 */
		if (pcb[yy + pdy[k]][xx + pdx[k]] & (ahb | s)) {
		     if (r > d[k])
			r = d[k];
		}
	    }

	    fprintf (ocf, "R %d %d %d;\n", r, xx * ucf, yy * ucf);
	}
    }
}

oclm ()				/* output component location marks    */
{
    register int i, j, k, l, dis;
    char buf[10];

    dis = 5 * rsun;		/* distance to next mark		 */
    dis /= 2;

    buf[1] = 0;
    for (i = dis, j = 1, k = 0; i < V.BSX - 2 * rsun; i += dis) {
	if (j) {		/* character time */
	    j = 0;
	    buf[0] = 'A' + k++;
	    l = i * ucf - txt_len (buf, 2) / 2;
	    ctxt (l, clm_off, 0, buf, 2);
	    ctxt (l, V.BSY * ucf - chhgh - clm_off, 0, buf, 2);}
	else {
	    fputs ("L PSSC;\n", ocf);
	    cwire_S (i, 2, 0, 0, coww);
	    cwire_E (i, 5, 0, 0);
	    cwire_S (i, V.BSY - 2, 0, 0, coww);
	    cwire_E (i, V.BSY - 5, 0, 0);
	    fputs ("L PF;\n", ocf);
	    cwire_S (i, 2, 0, 0, coww);
	    cwire_E (i, 5, 0, 0);
	    cwire_S (i, V.BSY - 2, 0, 0, coww);
	    cwire_E (i, V.BSY - 5, 0, 0);
	    j = 1;
	}
    }

    for (i = dis, j = 1, k = 0; i < V.BSY - 2 * rsun; i += dis) {
	if (j) {		/* character time */
	    j = 0;
	    sprintf (buf, "%d", ++k);
	    l = i * ucf - txt_len (buf, 2) / 2;
	    ctxt (clm_off + chhgh, l, 1, buf, 10);
	    ctxt (V.BSX * ucf - clm_off, l, 1, buf, 10);}
	else {
	    fputs ("L PSSC;\n", ocf);
	    cwire_S (2, i, 0, 0, coww);
	    cwire_E (5, i, 0, 0);
	    cwire_S (V.BSX - 2, i, 0, 0, coww);
	    cwire_E (V.BSX - 5, i, 0, 0);
	    fputs ("L PF;\n", ocf);
	    cwire_S (2, i, 0, 0, coww);
	    cwire_E (5, i, 0, 0);
	    cwire_S (V.BSX - 2, i, 0, 0, coww);
	    cwire_E (V.BSX - 5, i, 0, 0);
	    j = 1;
	}
    }
}

clean_up ()		/* remove the marks for wide wire traces */
{
    register int i, j, ss;
    register char *p;

    ss = ~(selb | resb);	/* bits to be cleared		 */

    for (i = 0; i < V.BSY; i++) {
	p = &pcb[i][0];
	for (j = V.BSY; j; j--)
	    *p++ &= ss;
    }
}

wwb_trc (x, y, s)	/* wide wire boarder trace		 */
    int x, y, s;
/**********************************************************************\
* 								       *
*  Wide wires tend to have a rough boarder because 'wtrace' may scan   *
*  the wide wire un-parallel to its main direction. So 'wwb_trc'       *
*  scans the boarder and produce a wire that smoothes this roughness.  *
* 								       *
\**********************************************************************/
{
    register int ss = ~(s | ahb), i, j, k;
    register char *p, *ps;

    p = &pcb[y][x];
    while (*(p + 1) & ~ss) p++;	/* find boarder			 */

    if (!(*p & ~ss) || *p & resb)
	return;			/* trouble || already done: exit */

    for (i = 1; i < 8; i++)	/* find initial direction	 */
	if (*(p + pdr[i]) & ~ss)
	    break;

    ps = p;			/* remember start point		 */

    do {
	*p |= resb;		/* mark point			 */

	p += pdr[i];		/* move to next point		 */

	for (j = (i + 6) & 7, k = 7; k; k--, j = (j + 1) & 7)
	    if (!(*(p + pdr[(j + 7) & 7]) & ~ss) && *(p + pdr[j]) & ~ss)
		break;		/* find new direction		 */

	if (i != j) {		/* change in direction		 */
	    cvplt (((int) ps - (int) pcb) % xmax,
		   ((int) ps - (int) pcb) / xmax,
		   ((int) p  - (int) pcb) % xmax,
		   ((int) p  - (int) pcb) / xmax );
	    ps = p;
	    i = j;
	}
    } while (!(*p & resb));
}
!E!O!F!
#
# type    sh /usru0/agn/pcb/distr/../usenet/part5   to unpack this archive.
#
echo extracting pcmdl.c...
cat >pcmdl.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	Command loop section					*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/


#include "pparm.h"
#include "pcdst.h"

#define iniCNTX 0		/* initial context		 */
#define nretry 2		/* retry limit for N_route	 */

int mv_wind(), zoom_in(), zoom_out(), s_menu(), c_menu();
int st_learn(), learn_sl(), learn_ov(), learn_ex(), lrn_wmv();
int w_zoomi(), w_zoomo(), wnd_urc(), wnd_llc(), exc_adel (), sel_adel();
int w_wmv(), ini_adel(), ini_art(), sel_art(), exc_art();

extern int net_sel(), 		/* manual edit functions	 */
    net_desel(), m_delete(), mr_delete(), 
    start_nt(), cont_s1(), cont_s2();

extern int exc_cmv(), cmv_plc(), cmv_rr(), cmv_rl(), cmv_sel();
extern int CPp_ini(), CPp_exc(), CPp_plc(), CPp_del();
extern int exc_plow(), plow_ini(), plow_src(), plow_dst();

static struct cntxdsc {		/* context descriptrors		 */
    char *name;			/* context name			 */
    int (*entcntx)();		/* enter context function	 */
    int (*excntx)();		/* exit context function	 */
    int (*mkfunc[8])();		/* mouse key functions		 */
} CNTX[] = {
   {"Start",   net_sel,  net_desel,
	      start_nt,    mv_wind,   start_nt,   m_delete,
	       zoom_in,     s_menu,   zoom_out,     c_menu  },
   {"Route", 	     0,  net_desel,
	       cont_s1,    mv_wind,    cont_s2,  mr_delete,
	       zoom_in,     s_menu,   zoom_out,     c_menu  },
   {"Edit",          0,          0,
		     0,	   mv_wind,	     0,   m_delete,
	       zoom_in,     s_menu,   zoom_out,     c_menu  },
   {"Learn",  st_learn,          0,
	      learn_sl,	   lrn_wmv,   learn_ex,   learn_ov,
	             0,          0,          0,          0  },
   {"AR-Del", ini_adel,          0,
	       wnd_urc,	     w_wmv,    wnd_llc,   exc_adel,
	       w_zoomi,   sel_adel,    w_zoomo,   sel_adel  },
   {"A-route", ini_art,          0,
	       wnd_urc,	     w_wmv,    wnd_llc,    exc_art,
	       w_zoomi,    sel_art,    w_zoomo,    sel_art  },
   {"CP_move",       0,          0,
	       cmv_sel,	   mv_wind,     cmv_plc,   exc_cmv,
	       zoom_in,     cmv_rl,    zoom_out,    cmv_rr  },
   {"Trace_mv", plow_ini,        0,
	      plow_src,	   mv_wind,    plow_dst,  exc_plow,
	       zoom_in,          0,    zoom_out,    c_menu  },
   {"CP_place",CPp_ini,          0,
	       CPp_exc,	   mv_wind,     CPp_plc,   CPp_del,
	       zoom_in,     s_menu,    zoom_out,    cmv_rr  }  };

cmd_loop()			/* command loop			 */
{
    int     nxtc, x, y, i;
    static int  context = iniCNTX;

    do {			/* context loop			 */
	if (CNTX[context].entcntx) {/* call enter function if present	*/
	    nxtc = (*CNTX[context].entcntx) (context);
	    if (nxtc != context) {/* context was rejected	 */
		context = nxtc;
		continue;
	    }
	}
	cntx_msg (CNTX[context].name);
	do {			/* loop within context		 */
	    i = getcur (&x, &y);
	    unprev ();		/* reset pending previews	 */
	    err_msg ("");	/* clear pending error messages	 */
	    if (i < 0)
		err ("couldn't read graphic tablet", i, 0, 0, 0);
	    nxtc = context;	/* default 			 */
	    if (CNTX[context].mkfunc[i])
		nxtc = (*CNTX[context].mkfunc[i]) (x, y, context);
	    else
		err_msg ("undefined key");
	} while (nxtc == context);
	if (CNTX[context].excntx)/* call exit function if present */
	    (*CNTX[context].excntx) (nxtc);
	context = nxtc;
    } while (context >= 0);
}

mv_wind (x, y, ctx)		/* move window			 */
    int x, y, ctx;
{
    window (x - 256 / cz, y - 256 / cz);
    return (ctx);		/* don't change context		 */
}

/*ARGSUSED*/
zoom_in (x, y, ctx)		/* increase zoom		 */
    int x, y, ctx;
{
    if (cz < 16)
	zoom (cz + 1);
    return (ctx);		/* don't change context		 */
}

/*ARGSUSED*/
zoom_out (x, y, ctx)		/* decrease zoom		 */
    int x, y, ctx;
{
    if (cz > 1)
	zoom (cz - 1);
    return (ctx);		/* don't change context		 */
}

quit ()				/* quit session			 */
{
    static char *mtext[] = {
	"Continue quit: no save",
	"Abort quit" };

    if (!menu (mtext, 2))
	finish ();
}

/*ARGSUSED*/
s_menu (x, y, ctx)		/* start menu			 */
    int x, y, ctx;
{
    static char *mtext[] = {
	"Plot preview",
	"CIF - Output",
	"Exit",
	"Quit (no save)",
	"Diagnostics",
	"Learn sequence",
	"Area Delete",
	"Area Route",
	"Route sequence",
	"Save Work",
	"Change color",
	"Move Component",
	"Expand wire"
    };

    switch (menu (mtext, 13)) {
	case 0:
	    Ferr_msg ("Busy: Plotting Bitmap");
	    pntbm ();
	    err_msg ("Done");
	    beep ();
	    break;
	case 1:
	    Ferr_msg ("Busy: Writing CIF file");
	    cifout ();
	    err_msg ("Done");
	    beep ();
	    break;
	case 2:
	    Ferr_msg ("Saving Bitmap & exit");
	    save (0);
	    finish ();
	    break;
	case 3:
	    quit ();
	    break;
	case 4:
	    p_diagn ();
	    break;
	case 5:
	    return (LEARN);
	case 6:
	    return (ADELE);
	case 7:
	    return (AROUTE);
	case 8:
	    seq_rt ();
	    return (net_sel (START));
	case 9:
	    Ferr_msg ("Busy: saving Bitmap");
	    save (0);
	    beep ();
	    err_msg ("Done");
	    break;
	case 10:
	    chg_color ();
	    break;
	case 11:
	    return (CMOVE);
	case 12:
	    return wide_wire (ctx);
    }

    return (ctx);
}

/*ARGSUSED*/
c_menu (x, y, ctx)		/* configuration menu		 */
    int x, y, ctx;
{
    static char *mtext[] = {
	0,				/* beep toggle		 */
	0,				/* window toggle	 */
	0,				/* H-route toggle	 */
	0,				/* straight toggle	 */
	"learn off",
	"Route Parameters",
	"Print statistics",
	"Wire desity",
	"Congestion area",
	"List",
	"Update"
    };

				/* update toggles		 */
    mtext[0] = (no_beep) ? "Beep on" : "Beep off";
    mtext[1] = (no_adjw) ? "Adjust window" : "Stable window";
    mtext[2] = (no_hrout) ? "Enable H-route" : "Disable H-route";
    mtext[3] = (st_reroute) ? "Move straight" : "Reroute straight";

    switch (menu (mtext, 11)) {
	case 0:
	    no_beep = (no_beep) ? 0 : 1;
	    break;
	case 1:
	    no_adjw = (no_adjw) ? 0 : 1;
	    break;
	case 2:
	    no_hrout = (no_hrout) ? 0 : 1;
	    break;
	case 3:
	    st_reroute = (st_reroute) ? 0 : 1;
	    break;
	case 4:
	    flush_lb ();
	    break;
	case 5:
	    Ferr_msg("See your Terminal");
	    get_rtprm ();
	    break;
        case 6:
	    pgen_stat ();
	    break;
	case 7:
	    dis_pro ();
	    break;
	case 8:
	    dis_cc ();
	    break;
	case 9:
	    P_list ();
	    break;
	case 10:
	    return P_update (ctx);
    }

    return (ctx);
}

static int ov_on = 0;		/* over-view display is on	 */

view_on ()			/* display a wire over-view	 */
{
    int     i, xl, yl, xh, yh, x0, y0, x1, y1;
    struct nlst *p1, *p2;

    if (ov_on)
	view_off ();

    xl = wx;			/* get visible area		 */
    xh = wx + 511 / cz;
    yl = wy;
    yh = wy + 482 / cz;

    msg_off ();
    color (resb, resb);

    for (i = 0; i < V.nnh; ++i)	/* scan through nets		 */
	if (!NH[i].f) {		/* only unfinished nets		 */
	    p1 = NH[i].lp;
	    while (p1) {
		x0 = p1 -> c -> x;
		y0 = p1 -> c -> y;
		if (x0 < xh && x0 > xl && y0 < yh && y0 > yl) {
		    p2 = p1 -> n;
		    while (p2) {/* display full lines		 */
			x1 = p2 -> c -> x;
			y1 = p2 -> c -> y;
			if (x0 < xh && x0 > xl && y0 < yh && y0 > yl)
			    aed_plt (x0, y0, x1, y1);
			p2 = p2 -> n;
		    }
		    p2 = NH[i].lp;
		    while (p2) {/* display of-screen lines	 */
			x1 = p2 -> c -> x;
			y1 = p2 -> c -> y;
			if (x0 >= xh || x0 <= xl || y0 >= yh || y0 <= yl)
			    aed_plt (x0, y0, x1, y1);
		        p2 = p2 -> n;
		    }
		}
		p1 = p1 -> n;
	    }
	}
    ov_on = 1;
}

view_off ()			/* turn off over view		 */
{
    if (ov_on) {
	color (0, resb);
	rect (wx, wy, wx + 511 / cz, wy + 482 / cz);
	msg_on ();
    }
    ov_on = 0;
}

static int lrn_cnt = 0;		/* learn counter		 */
static int lrnfull = 0;		/* max. number of valid entries	 */
static struct nlhd *lrn_buf[lrn_max];	/* learn buffer		 */

/*ARGSUSED*/
st_learn (x, y, ctx)		/* start learn mode		 */
    int x, y, ctx;
{
    lrn_cnt = 0;
    lrnfull = 0;
    return (LEARN);
}

learn_sl (x, y, ctx)		/* select a wire		 */
    int x, y, ctx;
{
    struct nlhd *p, *loc(), *fly();
    int i;

    if (lrn_cnt >= lrn_max) {
	view_off ();
	err_msg ("Learn buffer full");
	beep ();
	return (START);
    }

    p = loc (&x, &y);
    if (!p)
	p = fly (&x, &y);

    if (!p) {
	msg_on ();
	err_msg ("No net at cursor location");
	beep ();
	return (ctx);
    }

    if (p -> f) {
	msg_on ();
	err_msg ("Net is already done");
	return (ctx);
    }

    for (i = 0; i < lrn_cnt; ++i)
	if (p == lrn_buf[i]) {
	    msg_on ();
	    err_msg ("Net already selected");
	    beep ();
	    return (ctx);
	}

    lrn_buf[lrn_cnt++] = p;
    lrnfull = lrn_cnt;
    return (ctx);
}

lrn_wmv (x, y, ctx)		/* learn: move window		 */
    int x, y, ctx;
{
    if (ov_on)
	view_off ();
    return (mv_wind (x, y, ctx));
}

/*ARGSUSED*/
learn_ex (x, y, ctx)		/* learn: exit			 */
    int x, y, ctx;
{
    if (ov_on)
	view_off ();
    return (START);
}

/*ARGSUSED*/
learn_ov (x, y, ctx)		/* over-view on			 */
    int x, y, ctx;
{
    if (!ov_on)
	view_on ();
    return (ctx);
}

flush_lb ()			/* flush learn buffer		 */
{
    lrn_cnt = 0;
    lrnfull = 0;
}

struct nlhd *ck_lrnb ()		/* check learn buffer		 */
{
    while (lrn_cnt > 0 && lrn_buf[lrn_cnt - 1] -> f)
	lrn_cnt--;		/* skip finished nets		 */

    if (lrn_cnt <= 0)
	return (nil);		/* is empty			 */

    return (lrn_buf[--lrn_cnt]);
}

seq_rt ()			/* sequence route		 */
{
    struct nlhd *t, *ck_lrnb ();

    lrn_cnt = lrnfull;		/* rewind learn buffer		 */

    if (lrn_cnt <= 0)
	err_msg ("Learn a sequence first");
    else {
	Ferr_msg ("Busy routing");
	while ((t = ck_lrnb ())) {
	    N_route (t, nretry, 0, 0, V.BSX, V.BSY);
	    nettgo -= t -> f;
	}
	nets_msg (nettgo);
	err_msg ("Done");
	beep ();
    }
}
!E!O!F!
#
# type    sh /usru0/agn/pcb/distr/../usenet/part5   to unpack this archive.
#
echo extracting pdiag.c...
cat >pdiag.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	Diagnostic routines					*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/

#include "pparm.h"
#include "pcdst.h"

test(x,y)
    int x, y;
{
    int     i, j;

    printf ("Test at x=%d y=%d\n", x, y);

    for (i = y + 3; i >= y - 3; --i) {
	printf ("\t%d:  ", i);
	for (j = -4; j <= 4; j++) {
	    if (i == y)
	    switch (j) {
		case 0: printf(">"); break;
		case 1: printf("<"); break;
		default: printf(" "); break;
	    }
	    else printf(" ");
	    printf("%2x",pcb[i][x + j] & 255);
	}
	printf ("\n");
    }
    abm_tst (x, y);
}

s_test(x,y,x1,y1,s)
    int x, y, x1, y1;
    char *s;
{
    int     i, j;
    char c;

    printf ("Test at x=%d y=%d   (..)=%s\n", x, y,s);

    for (i = y + 3; i >= y - 3; --i) {
	printf ("	%d:  ", i);
	for (j = -4; j <= 4; j++) {
	    c = ' ';
	    if (i == y1 && x + j == x1)
		    c = '(';
	    if (i == y1 && x + j == x1 + 1)
		    c = ')';
	    if (i == y && !j)
		    c = (c != ' ') ? '*' : '>';
	    if (i == y && j == 1)
		    c = (c != ' ') ? '*' : '<';

	    printf("%c%2x",c, pcb[i][x + j] & 255);
	}
	if(i == y1 && (x + j) == (x1+1))
	    printf(")");
	printf ("\n");
    }
    abm_tst (x, y);
}

tst1 ()
{
    int     x, y, sccm, sccc;
    sccm = ccm;
    sccc = ccc;
    getcur (&x, &y);
    test (x, y);
    ccc = sccc;
    ccm = sccm;
}

tst2 (x1, y1, x2, y2, c)
    int x1, y1, x2, y2, c;
{
    int     x, y;
    for (x = x1; x <= x2; ++x)
	for (y = y1; y <= y2; ++y)
	    pcb[y][x] = c;
}

verify ()			/* verify connectivity		 */
{
    int     i, j;

    for (nettgo = i = 0; i < V.nnh; ++i) {
	if (NH[i].l > 0) {
	    j = cchk (&NH[i]);
	    if (j != NH[i].f) {
		printf ("Net %d: f=%d cchk=%d\n", i, NH[i].f, j);
		NH[i].f = j;
	    }
	    nettgo += !NH[i].f;}
	else
	    printf ("Net %d is emty\n", i);
    }
    printf ("Done\n");
}

p_diagn ()			/* diagnostic menu		 */
{
    static char *mtext[] = {
	"View",
	"Verify",
	"Clean",
	"Flip"};

    switch (menu (mtext, 4)) {
	case 0:
	    tst1 ();
	    break;
	case 1:
	    verify ();
	    break;
	case 2:
	    clean ();
	    break;
	case 3:
	    flip_s();
	    break;
    }
}

clean ()			/* scan bitmap for wrong bits	 */
{
    register int i, j;
    struct nlhd *t;
    t = V.cnet;
    if (t)
	deseln (t);
    color (resb, resb);
    for (i = 0; i < V.BSX; i++)
	for (j = 0; j < V.BSY; j++)
	    if (pcb[j][i] & 0xa0) {
		point (i, j);
		pcb[j][i] &= 0x5f;
	    };
    window (0, 0);
    update (0, 0, 511, 511);
    fx = fy = 0;
    if (t)
	selnet (t);
}

flip_s ()			/* flip sides			 */
{
    register int i, j, k;

    for (i = 0; i < V.BSX; i++)
	for (j = 0; j < V.BSY; j++) {
	    k = pcb[j][i];
	    pcb[j][i] = (k & ~vec) | ((k & s2b) >> 1) | ((k & s1b) << 1);}

    update (0, 0, 511, 511);
    fx = fy = 0;
    window (0, 0);
}

qpat()
{
   TY[81].p = &PN[V.npn];

   PN[V.npn + 0].x = 0;
   PN[V.npn + 0].y = 0;
   PN[V.npn + 0].p = 0;

   PN[V.npn + 1].x = 0;
   PN[V.npn + 1].y = 12;
   PN[V.npn + 1].p = 0;

   PN[V.npn + 2].x = 0;
   PN[V.npn + 2].y = 24;
   PN[V.npn + 2].p = 0;

   PN[V.npn + 3].x = 12;
   PN[V.npn + 3].y = 24;
   PN[V.npn + 3].p = 0;

   PN[V.npn + 4].x = 12;
   PN[V.npn + 4].y = 12;
   PN[V.npn + 4].p = 0;

   PN[V.npn + 5].x = 12;
   PN[V.npn + 5].y = 0;
   PN[V.npn + 5].p = 0;

   V.npn += 6;
}
!E!O!F!
#
# type    sh /usru0/agn/pcb/distr/../usenet/part5   to unpack this archive.
#
echo extracting pfio.c...
cat >pfio.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	File I/O section					*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/

#include <stdio.h>
#include "pparm.h"
#include "pcdst.h"

FILE	*inp;			/* read/write channels 		 */

extern	FILE *fwantread();
extern  int rot_m[4][4];	/* rotation matrix		 */
extern	wantread(), wantwrite();
char *getstr(); 

float scalef;			/* sacle factor			 */
static inp_errs = 0;		/* input errors			 */


rdnl ()				/* read a netlist		 */
{
    register int i, j;

    if (getbool ("Do you want to read a checkpoint file?",1))
	rsto ();
    else {
        specs ();		/* promt for board specifications*/
	rdty ();		/* read types			 */
	rdcp ();		/* read components		 */
	rdnh ();		/* read net list		 */

	if (inp_errs)
	    err ("-Please correct earlier errors and try again", 0, 0, 0, 0);
    }
    for (j = 0, i = 0; i < V.nnh; i++)
	j += !NH[i].f;
    nettgo = j;
    nets_msg (nettgo);
}

rdty ()				/* read the type definition file */
{
    char    buf[inp_lnl], nm[nmmax + 2], ga[nmmax + 2];
    char    fname[40];
    int     i, j, k, ix, iy;
    float   x, y, x1, y1;
    static char pln[4][4] = {"GND", "VCC", "VEE", "VBB"};

    inp = fwantread (".", "test.ty", fname, "Type definition file:");
    if (!inp)
        err("-Failed to read type definition file", 0, 0, 0, 0);

    fgets (buf, inp_lnl, inp);
    if (strncmp (buf, "*types:", 7))
	err ("-Type-def file doesn't start with '*types:'", 0, 0, 0, 0);
    i = 1;

    while (fgets (buf, inp_lnl, inp)) {
	rms (buf);
	i++;			/* count lines for error msg	 */

	if (V.nty >= tymax)
	    err ("type table too small - increase 'tymax'", V.nty, i, 0, 0);

	for (j = 0; (j < nmmax) && (buf[j] != ':'); j++)
	    TY[V.nty].name[j] = buf[j];
	if (buf[j] == ':') {
	    if (buf[j + 1] != '\0')
		printf ("Line %d: warning: garbage ignored\n", i);
	    TY[V.nty].name[j] = '\0'; }
	else
	    if (buf[j + 1] != ':')
		printf ("Line %d: warning: missing ':'\n", i);

	for (j = 0; j < V.nty; j++)	/* kind of slow, but ... */
	    if (!strncmp (TY[V.nty].name, TY[j].name, nmmax))
		break;
	if (j < V.nty) {
	    printf ("Line %d: error: '%s' is already defined\n", 
		i, TY[V.nty].name);
	    inp_errs = 1;
	}

	TY[V.nty].x = 0;
	TY[V.nty].y = 0;
	TY[V.nty].np = 0;
	TY[V.nty].cif = 0;
	TY[V.nty].p = nil;

	while (fgets (buf, inp_lnl, inp)) {	/* read type body */
	    rms (buf);
	    i++;			/* count lines		 */

	    if (!strncmp (buf, "EXTCIF: ", 8)) { /*** EXTCIF ***/
		j = sscanf (&buf[8], "%d", &k);

		if (j != 1 || k < ex_cifL || k > ex_cifH || TY[V.nty].cif) {
		    printf ("Line %d: illegal 'EXTcif'\n", i);
		    inp_errs = 1;}
		else {
		    if (V.ncif >= cifmax)
			err ("EXTcif table too small: increase 'cifmax'",
			    V.ncif, i, 0, 0);
		    CIF[V.ncif].symn = k;
		    CIF[V.ncif].flg = 0;
		    CIF[V.ncif].blk = 0;
		    TY[V.nty].cif = V.ncif + 1;
		}}

	    else if (!strncmp (buf, "BOX: ", 5)) {  /*** BOX ***/
		j = sscanf (&buf[5], "%f %f", &x, &y);
		if (j != 2 || x < 0 || y < 0) {
		    printf ("Line %d: invalid 'Box' statement\n", i);
		    inp_errs = 1;}
		else {
		    ix = x * rsun * scalef + 0.5;
		    iy = y * rsun * scalef + 0.5;
		    if (TY[V.nty].x < ix)
			TY[V.nty].x = ix;
		    if (TY[V.nty].y < iy)
			TY[V.nty].y = iy;
		}}

	    else if (!strncmp (buf, "BLOCK: ", 7)) { /*** BLOCK ***/
		j = sscanf (&buf[7], "%f %f %f %f", &x, &y, &x1, &y1);
		ix = x1 * rsun * scalef + 0.5;
		iy = y1 * rsun * scalef + 0.5;
		if (j != 4 || x < 0 || x1 < 0 || y < 0 || y1 < 0 ||
		    x > x1 || y > y1 || !TY[V.nty].cif ||
		    ix > TY[V.nty].x || iy > TY[V.nty].y) {
		    printf ("Line %d: invalid 'Block' statement\n", i);
		    inp_errs = 1;}
		else {
		    if (CIF[V.ncif].blk) {	/* need additional record */
		        CIF[V.ncif].flg = 1;
			if (V.ncif >= cifmax)
			    err ("EXTcif table too small: increase 'cifmax'",
				V.ncif, i, 0, 0);
			CIF[++V.ncif].flg = 0;
			CIF[V.ncif].symn = CIF[V.ncif - 1].symn;
		    }
		    CIF[V.ncif].blk = 1;
		    CIF[V.ncif].xh = ix;
		    CIF[V.ncif].yh = iy;
		    CIF[V.ncif].xl = x * rsun * scalef + 0.5;
		    CIF[V.ncif].yl = y * rsun * scalef + 0.5;
		}}

	    else {		/*** normal pin statement	 ***/
		j = sscanf (buf, "%f %f %s %s", &x, &y, nm, ga);
		if (buf[0] == '\0')
		    break;	/* exit */

		k = 0;		/* default type			 */
	        switch (j) {
		case 1: 
		    printf ("Line %d: warning: missing y - line ignored\n",i);
		    break;
		case 4: 
		    printf ("Line %d: warning: grabage '%s...' ignored\n", i, ga);
		case 3: 
		    for (k = 0; k < 4; ++k)
			if (!strncmp (pln[k], nm, nmmax))
			    break;
		    k = (k + 1) % 5;
		case 2: 
		    if (V.npn >= pnmax)
			err ("pin table too small - increase 'pnmax'", V.npn, 0, 0, 0);
		    if (TY[V.nty].p == nil)
			TY[V.nty].p = &PN[V.npn];
		    (TY[V.nty].np)++;
		    ix = x * rsun * scalef + 0.5;
		    iy = y * rsun * scalef + 0.5;
		    if (TY[V.nty].x < ix)
			TY[V.nty].x = ix;
		    if (TY[V.nty].y < iy)
			TY[V.nty].y = iy;
		    PN[V.npn].x = ix;
		    PN[V.npn].y = iy;
		    PN[V.npn].p = k;
		    V.npn++;
		}
	    }
	}
	if (TY[V.nty].y > TY[V.nty].x)
	    printf ("Warning for '%s': y>x (text is aligned to the x-axis)\n",
		TY[V.nty].name);
	if (TY[V.nty].cif)
	    V.ncif++;
	V.nty++;
    }

    fclose (inp);
    printf("Type file: %d types with a total of %d pins defined\n",
	   V.nty, V.npn);
}

rms (b)
    char *b;
/******************************************************************\
* 								   *
*  remove stuff:						   *
*    The character string <b> is reformatted:			   *
*    1. [a-z] -> [A-Z]						   *
*    2. Comment are removed					   *
*    3. Multiple field seperators (' ', '\t' and ',') are removed  *
*    4. Field seperators will become ' '			   *
*    5. Field seperators before '\0' are removed		   *
*    6. Fileds are truncated to 'nmmax' characters		   *
* 								   *
\******************************************************************/
{
    register int i, j, k, s;

    s = 1;
    for (i = j = k = 0; i < inp_lnl; ++i) {
	if (('a' <= b[i]) && ('z' >= b[i]))
	    b[i] -= 'a' - 'A';	/* case folding 		*/
	switch (b[i]) {
	    case ' ': 
	    case '\t': 		/* single tab or space separator */
		if (!s)
		    b[j++] = ' ';
		s = 1;
		k = 0;
		break;
	    case ';': 		/* ignor comments		*/
	    case '\n':
	    case '\0':
		j -= s && j;	/* remove seperators at EOL	*/
		b[j] = '\0';
		i = inp_lnl;
		break;
	    case ',': 
		b[j++] = ' ';
		s = 1;
		k = 0;
		break;
	    default: 
		if (k > nmmax) {
		    b[j++] = ' ';
		    k = 0;}
		else {
		    s = 0;
		    b[j++] = b[i];
		    k++;}
		break;
	}
    }
}

rdcp()				/* read component file */
{
    char    buf[inp_lnl], t[nmmax + 2];
    float   x, y;
    register int i, j, k, ix, iy;
    int r;

    inp = fwantread (".", "test.cp", buf, "Component definition file:");
    if (!inp)
      err("-Failed to read component definition file", 0, 0, 0, 0);
    fgets (buf, inp_lnl, inp);

    if (strncmp (buf, "*components:", 12))
	err ("component-def file doesn't start with '*components:'", 0, 0, 0, 0);

    j = 1;

    while (fgets (buf, inp_lnl, inp)) {
	rms (buf);
	j++;			/* count lines			 */

	if (V.ncp >= cpmax)
	    err ("Component table too small: increase 'cpmax'", V.ncp, j,0,0);

	k = sscanf (buf, "%s %s %f %f %d", CP[V.ncp].name, t, &x, &y, &r);

	if (k != 5 && k != 2) {		/*** argument check    ***/
	    printf ("Line %d error: invalid argumnet count\n", j);
	    inp_errs = 1;
	    continue;
	}

	for (i = 0; i < V.ncp; i++)	/*** multi-def check  ***/
	    if (!strncmp (CP[i].name, CP[V.ncp].name, nmmax))
		break;
	if (i < V.ncp) {
	    printf ("Line %d error: multiple defined '%s'\n",
		j, CP[V.ncp].name);
	    inp_errs = 1;
	    continue;
	}

	for (i = 0; i < V.nty; i++)	/*** get type	       ***/
	    if (!strncmp (t, TY[i].name, nmmax))
		break;
	if (i >= V.nty) {
	    printf ("Line %d error: undefined Type '%s'\n", j, t);
	    inp_errs = 1;
	    continue;
	}
	CP[V.ncp].ty = &TY[i];
	CP[V.ncp].unplaced = 1;		/* not yet placed	 */

	if (V.nch + TY[i].np > chmax)
	    err ("Hole table too small, increase 'chmax'\n", chmax, j, 0, 0);

	for (i = TY[i].np; i;) {	/* allocate holes	 */
	    CH[V.nch].x = 0;
	    CH[V.nch].y = 0;
	    CH[V.nch].pn = --i;
	    CH[V.nch].cpi = V.ncp;
	    CH[V.nch++].n = nil;
	}

	if (5 == k) {		/* explicily placed component	 */
	    if ((r < 0) || (r > 3)) {
	        printf ("Line %d error: invalid rotation - line ignored\n",j);
		inp_errs = 1;
		continue;
	    }
	    ix = rsun * x * scalef + 0.5;
	    iy = rsun * y * scalef + 0.5;
	    if (!C_place (&CP[V.ncp], ix, iy, r))
		printf ("Line %d warning: invalid location, place it later\n", j);
	}
	V.ncp++;
    }

    CH_update ();		/* sort holes			 */

    fclose (inp);
    printf ("Component file: %d components with %d pins allocated\n",
	    V.ncp, V.nch);
}

rdnh()				/* read net list		*/
{
    char    buf[inp_lnl];
    register int i, j;
    int k;
    register int mode = 0;		/* =0 Multiwire, =1 DP	*/
    register struct nlhd *hptr;

    inp = fwantread (".", "test.nl", buf, "Net list file:");
    if (!inp)
        err ("-Failed to read Net list file", 0, 0, 0, 0);
    fgets (buf, inp_lnl, inp);

    if (strncmp (buf, "Cnetlist:", 9) &&
	(mode = 1, strncmp (buf, "DPnetlist:", 10)))
	err ("-component-def file doesn't start with 'C/DPnetlist:'",
		 0, 0, 0, 0);

    i = 1;
    while (fgets (buf, inp_lnl, inp)) {
	rms (buf);
	i++;

	if (mode) {
/*******************************************************************\
* 								    *
*  DP netlist reader						    *
* 								    *
*  Warning: I am too tired to completly rewrite the reader now, so  *
*           there is the limitation that a net has to fit into the  *
* 	  line buffer (buf).					    *
* 								    *
\*******************************************************************/
	    for (j = 0; buf[j] && buf[j] != '\\'; j++);
	    if (j && !buf[j]) {
		printf ("Line %d error: DP-name without '\\'\n", i);
		inp_errs = 1;
		continue;
	    }

	    if (!j)
		continue;	/* skip empty lines		 */

	    if (buf[0] == '!') {/* power net (gnd, vcc, vee, vtt) */
		if      (!strncmp ("GND", &buf[1], 3))
		    hptr = &V.GND;
		else if (!strncmp ("VCC", &buf[1], 3)) 
		    hptr = &V.VCC;
		else if (!strncmp ("VTT", &buf[1], 3))
		    hptr = &V.VTT;
		else if (!strncmp ("VEE", &buf[1], 3))
		    hptr = &V.VEE;
	        else {
		    printf ("Line %d error: unknown power net\n");
		    inp_errs = 1;
		    continue;
		}}
	    else {		/* normal net		 */
		if (V.nnh >= nhmax)
		    err ("Netlist table too small - increase 'nhmax'",
			    V.nnh, 0, 0, 0);
		buf[j] = 0;
		strncpy (NH[V.nnh].name, buf, nmmax);
		NH[V.nnh].l = 0;
		NH[V.nnh].lp = nil;
		NH[V.nnh].x1 = xmax;
		NH[V.nnh].y1 = ymax;
		NH[V.nnh].x2 = 0;
		NH[V.nnh].y2 = 0;
		NH[V.nnh].f = 0;
		hptr = &NH[V.nnh];
		V.nnh++;
	    }
	    for (j++; (j < inp_lnl) && (buf[j] != '\0'); ++j)
		if (buf[j] == ' ')
		    addn (&buf[j + 1], hptr, i);

	    continue;		/* next net			 */
	}

	
	if (buf[0] == 'C') {	/* Multiwire net list processing */
	    j = 3;
	    if (!strncmp ("GND", &buf[1], 3))
		hptr = &V.GND;
	    else if (!strncmp ("VCC", &buf[1], 3)) 
		hptr = &V.VCC;
	    else if (!strncmp ("VTT", &buf[1], 3))
		hptr = &V.VTT;
	    else if (!strncmp ("VEE", &buf[1], 3))
		hptr = &V.VEE;
	    else
		continue;	/* normal comment		 */
	} else {
	    if (!sscanf (buf, "%d", &k)) {
		printf ("Line %d error: invalid net number\n", i);
		inp_errs = 1;
		continue;}
	    else if (k == -1)	/* Multiwire end ? */
		break;
	    else if ((k < V.nnh) || (k <= 0)) {
		printf ("Line %d error: net number %d out of sequence\n",
		    i, k);
		inp_errs = 1;
		continue;}
	    else {
		if (k > V.nnh + 1)
		    printf("Line %d warning: net %d missing, next is %d\n",
			 i, V.nnh + 1, k);
		while (k > V.nnh) {/* start a new net list */
		    if (V.nnh >= nhmax)
			err ("Netlist table too small - increase 'nhmax'",
			    V.nnh, 0, 0, 0);
		    sprintf (NH[V.nnh].name, "#%d", V.nnh + 1);
		    NH[V.nnh].l = 0;
		    NH[V.nnh].lp = nil;
		    NH[V.nnh].x1 = xmax;
		    NH[V.nnh].y1 = ymax;
		    NH[V.nnh].x2 = 0;
		    NH[V.nnh].y2 = 0;
		    NH[V.nnh].f = 0;
		    hptr = &NH[V.nnh];
		    V.nnh++;
		}
	    }
	    j = 0;
	}

	for (j++; (j < inp_lnl) && (buf[j] != '\0'); ++j)
	    if (buf[j] == ' ')
		addn (&buf[j + 1], hptr, i);

    }
    fclose (inp);
    printf ("Netlist: %d nets with %d nodes allocated\n", V.nnh, V.nnl);
}

addn(s,net,ln)		/* add a node to a net list	*/
    char s[];
    struct nlhd *net;
    int ln;
{
    int          k, x1, y1;
    register int i, j, l, r, x, y;
    struct hole  *hp, *fndh ();

    for (i = 0; s[i] != '-'; ++i)	/* isolate component name	*/
	if ((s[i] == '\0') || (i > nmmax)) {
	    printf ("Line %d error: missing pin number\n", ln);
	    inp_errs = 1;
	    return;
	}
    s[i] = '\0';		/* terminate string temporarily */

    for (j = 0; j < V.ncp; j++)	/* find componet definition	*/
	if (!strncmp (s, CP[j].name, nmmax))
	    break;
    if (j >= V.ncp) {
	printf ("Line %d error: reference to undefined component\n", ln);
	inp_errs = 1;
	return;
    }

    if ((!sscanf (&s[i + 1], "%d", &k)) || (k <= 0) || (k > CP[j].ty -> np)) {
	printf("Line %d error: '%s-%d': pin-number out of range\n", ln, s, k);
	inp_errs = 1;
	return;
    }					/* check pin number		*/
    --k;				/* pin number must start at 0	*/
    if ((CP[j].ty -> p + k) -> p)
	printf ("Line %d warning: '%s-%d' is a power/gnd pin\n", ln, s, k+1);
    s[i] = '*';				/* this is a hack		*/

    if (CP[j].unplaced) {		/* need direct search		*/
	hp = nil;
	for (l = 0; l < V.nch; l++)
	    if (CH[j].cpi == j && CH[j].pn == k) {
		hp = &CH[l];
		break;
	    }
    } else {
	x = (CP[j].ty -> p + k) -> x;	/* locate hole entry in CH	*/
 	y = (CP[j].ty -> p + k) -> y;
	r = CP[j].r;
	x1 = CP[j].x + rot_m[r][0] * x + rot_m[r][1] * y;
	y1 = CP[j].y + rot_m[r][2] * x + rot_m[r][3] * y;
	hp = fndh (x1, y1);
    }

    if (hp == nil)
	err ("addn: failed to find hole", x1, y1, j, i);

    if (hp -> n != nil) {		/* multiple net node ??		*/
	printf ("Line %d error: '%s-%d' already used in other net\n",
		ln, s, k + 1);
	inp_errs = 1;
	return;
    }

    if (V.nnl >= nlmax)
	err ("net node table too small - increase 'nlmax'", V.nnl, 0, 0, 0);

    NL[V.nnl].c = hp;			/* enter node to tables		*/
    NL[V.nnl].n = net -> lp;
    NL[V.nnl].nlp = net;
    hp -> n = net -> lp = &NL[V.nnl];
    net -> l++;
    V.nnl++;
}

struct hole *fndh (x,y)			/* find hole			*/
    int x, y;
{
    register int i, j, k, xx = x, yy = y;

    i = 0;
    j = V.nch;
    while (i <= j) {
	k = (i + j) >> 1;
	if (xx > CH[k].x) {
	    i = k + 1;
	    continue; }
	if (xx < CH[k].x) {
	    j = k - 1;
	    continue; }
	if (yy > CH[k].y) {
	    i = k + 1;
	    continue; }
	if (yy < CH[k].y) {
	    j = k - 1;
	    continue; }
	return &CH[k];
    }

    return  nil;
}

save (ety)				/* save vital data structure	*/
    int ety;
{
    int     i, och;
    char    fn[30];
    static char fname[2][8] = { "pcb.SAV", "pcb.ERR"};
    struct {int r, g, b;} crc;		/* color record			*/
    
    och = wantwrite (".", &fname[ety][0], fn, "Checkpoint file name:", 0);

    write (och, &V, sizeof (V));	/* write head information	*/

    for (i = 0; i < ymax; ++i)
	write (och, &pcb[i][0], xmax);
    for (i = 0; i < V.ncp; ++i)
	write (och, &CP[i], sizeof (CP[0]));
    for (i = 0; i < V.nty; ++i)
	write (och, &TY[i], sizeof (TY[0]));
    for (i = 0; i < V.npn; ++i)
	write (och, &PN[i], sizeof (PN[0]));
    for (i = 0; i < V.nch; ++i)
	write (och, &CH[i], sizeof (CH[0]));
    for (i = 0; i < V.nnh; ++i)
	write (och, &NH[i], sizeof (NH[0]));
    for (i = 0; i < V.nnl; ++i)
	write (och, &NL[i], sizeof (NL[0]));
    for (i = 0; i < ncolors; ++i) {
	crc.r = Color_tab[i].r;
	crc.g = Color_tab[i].g;
	crc.b = Color_tab[i].b;
	write (och, &crc, sizeof (crc));
    }
    for (i = 0; i < V.ncif; ++i)
	write (och, &CIF[i], sizeof (struct cif));

    i = mgnm;			/* mark the end of the grabage	*/
    write (och, &i, sizeof (int));
    close (och);
}

rsto()				/* Restore Checkpointed state	*/
{
    int     i, ich, old;
    char    fn[30];
    struct {int r, g, b;} crc;		/* color record			*/

    ich = wantread (".", "pcb.SAV", fn, "Checkpoint file name:");

    read (ich, &V, sizeof (V));	/* read head information	 */

    old = 0;
    if (V.pver != pversion) {
	if (V.pver == 123) 	/* conversion V 1.23 -> current	 */
	    old = 1;
	else
	    err ("-program version mismatch", V.pver, pversion, 0, 0);
    }

    if (V.errtxt[0] != '\0') {
	printf ("Warning: previous pcb run died with error message:\n");
	printf ("\t\"%s\"\n", V.errtxt);
	printf (" error-info: %d %d %d %d\n",
	    V.err_info[0], V.err_info[1], V.err_info[2], V.err_info[3]);
	V.errtxt[0] = '\0';
    }
    if ((V.x != xmax) || (V.y != ymax))
	err ("-different bit map size", V.x, V.y, xmax, ymax);
    if (V.ncp > cpmax)
	err ("-CP table too small - increase 'cpmax'", V.ncp, cpmax, 0, 0);
    if (V.nty > tymax)
	err ("-TY table too small - increase 'tymax'", V.nty, tymax, 0, 0);
    if (V.npn > pnmax)
	err ("-PN table too small - increase 'pnmax'", V.npn, pnmax, 0, 0);
    if (V.nch > chmax)
	err ("-CH table too small - increase 'chmax'", V.nch, chmax, 0, 0);
    if (V.nnh > nhmax)
	err ("-NH table too small - increase 'nhmax'", V.nnh, nhmax, 0, 0);
    if (V.nnl > nlmax)
	err ("-NL table too small - increase 'nlmax'", V.nnl, nlmax, 0, 0);
    if (V.ncif > cifmax)
	err ("-CIF table too small - increase 'cifmax'", V.ncif, cifmax,0, 0);

    for (i = 0; i < ymax; ++i)
	read (ich, &pcb[i][0], xmax);
    for (i = 0; i < V.ncp; ++i)
	read (ich, &CP[i], sizeof (CP[0]));
    for (i = 0; i < V.nty; ++i)
	read (ich, &TY[i], sizeof (TY[0]));
    for (i = 0; i < V.npn; ++i)
	read (ich, &PN[i], sizeof (PN[0]));
    for (i = 0; i < V.nch; ++i)
	read (ich, &CH[i], sizeof (CH[0]));
    for (i = 0; i < V.nnh; ++i)
	read (ich, &NH[i], sizeof (NH[0]));
    for (i = 0; i < V.nnl; ++i)
	read (ich, &NL[i], sizeof (NL[0]));
    for (i = 0; i < ncolors; i++) {
	read (ich, &crc, sizeof (crc));
	Color_tab[i].r = crc.r;
	Color_tab[i].g = crc.g;
	Color_tab[i].b = crc.b;
    }
    for (i = 0; i < V.ncif; ++i)
	    read (ich, &CIF[i], sizeof (struct cif));

    read (ich, &i, sizeof (int));	/* consistency check	 */
    if (i != mgnm)
	err ("-failed to find magic number in saved file", i, mgnm, 0, 0);

    close (ich);

    if ( (V.cp != CP) || (V.ty != TY) || (V.pn != PN) ||
         (V.ch != CH) || (V.nh != NH) || (V.nl != NL) || (V.own != &V))
	radjptr ();

    if (old)			
	convf123 ();		/* convert from version 123	 */

    if (!batch) {
	ldcmp ();
	update (0, 0, 511, 511);
	fx = fy = 0;
	window (0, 0);
    }

    if (V.cnet)			/* deselect pending nets	 */
	deseln (V.cnet);
}

radjptr ()			/* readjust pointer		 */
/************************************************************************\
* 									 *
*  If the saved file was created with an older (but similar) version of	 *
*  this program, the saved pointer may have changed due to the new	 *
*  complilation. This routine readjusts the old pointer so that they	 *
*  correspont to the new locations.					 *
* 									 *
\************************************************************************/
{
    union ptr_int {		/* allow arithmetic on pointer	*/
	unsigned i;
	struct type *ty;
	struct pin  *pn;
	struct hole *ch;
	struct nlhd *nh;
	struct nlst *nl;
        struct vtin *vi;
    } p1, p2;
    unsigned tyof, pnof, chof, nhof, nlof, viof, nh_l, nh_h;
    register int i;

    printf("Warning: pcb has been recomplied since the file was saved\n");

    p1.ty = V.ty;
    p2.ty = &TY[0];
    tyof = p2.i - p1.i;		/* get TY offset		 */

    p1.pn = V.pn;
    p2.pn = &PN[0];
    pnof = p2.i - p1.i;		/* get PN offset		 */

    p1.ch = V.ch;
    p2.ch = &CH[0];
    chof = p2.i - p1.i;		/* get CH offset		 */

    p1.nl = V.nl;
    p2.nl = &NL[0];
    nlof = p2.i - p1.i;		/* get NL offset		 */

    p1.nh = V.nh;
    p2.nh = &NH[0];
    nhof = p2.i - p1.i;		/* get NH offset		 */

    p1.vi = V.own;
    p2.vi = &V;
    viof = p2.i - p1.i;		/* get NH offset		 */

    if (tyof) {
	for (i = 0; i < V.ncp; ++i) {
	    p1.ty = CP[i].ty;
	    p1.i = p1.i ? p1.i + tyof : nil;
	    CP[i].ty = p1.ty;
	}
    }

    if (pnof) {
	for (i = 0; i < V.nty; ++i) {
	    p1.pn = TY[i].p;
	    p1.i = p1.i ? p1.i + pnof : nil;
	    TY[i].p = p1.pn;
	}
    }

    if (viof || chof || nlof || nhof) {/* adjust netlist ptr''s	 */
	p1.nh = V.nh;
	nh_l = p1.i;
	p1.nh = V.nh + V.nnh;
	nh_h = p1.i;
	for (i = 0; i < V.nnl; ++i) {
	    p1.ch = NL[i].c;
	    p1.i = p1.i ? p1.i + chof : nil;
	    NL[i].c = p1.ch;

	    p1.nl = NL[i].n;
	    p1.i = p1.i ? p1.i + nlof : nil;
	    NL[i].n = p1.nl;

	    p1.nh = NL[i].nlp;
	    if (p1.i >= nh_l && p1.i <= nh_h)
		p1.i += nhof;
	    else
	        p1.i = p1.i ? p1.i + viof : nil;
	    NL[i].nlp = p1.nh;
	}
    }

    if (nlof) {
	for (i = 0; i < V.nch; ++i) {
	    p1.nl = CH[i].n;
	    p1.i = p1.i ? p1.i + nlof : nil;
	    CH[i].n = p1.nl;
	}
	for (i = 0; i < V.nnh; ++i) {
	    p1.nl = NH[i].lp;
	    p1.i = p1.i ? p1.i + nlof : nil;
	    NH[i].lp = p1.nl;
	}
	if (V.GND.lp) {
	    p1.nl = V.GND.lp;
	    p1.i += nlof;
	    V.GND.lp = p1.nl;
	}
	if (V.VCC.lp) {
	    p1.nl = V.VCC.lp;
	    p1.i += nlof;
	    V.VCC.lp = p1.nl;
	}
	if (V.VEE.lp) {
	    p1.nl = V.VEE.lp;
	    p1.i += nlof;
	    V.VEE.lp = p1.nl;
	}
	if (V.VTT.lp) {
	    p1.nl = V.VTT.lp;
	    p1.i += nlof;
	    V.VTT.lp = p1.nl;
	}
    }
    if (nhof || nlof) {
	p1.nh = V.cnet;
	p1.i = p1.i ? p1.i + nhof : nil;
	V.cnet = p1.nh;
	p1.nh = V.enhl;
	p1.i = p1.i ? p1.i + nhof : nil;
	V.enhl = p1.nh;
	p1.nl = V.enll;
	p1.i = p1.i ? p1.i + nlof : nil;
	V.enll = p1.nl;
    }

    V.own = &V;
    V.cp = &CP[0];
    V.ty = &TY[0];
    V.pn = &PN[0];
    V.ch = &CH[0];
    V.nh = &NH[0];
    V.nl = &NL[0];		/* done ! (hopefully)	 */

/* the next is a temporary fix to correct an old ptr- problem */
/*
    for (i = 0; i < V.nnh; i++)
        if (NH[i].l) {int j; struct nlst *p;
	    for (p = NH[i].lp, j = 0; p; p = p -> n, j++)
		if (p -> nlp != &NH[i]) {
		    printf("#");
		    p -> nlp = &NH[i];
		}
	    if (j != NH[i].l)
		err ("radjptr: inconsistent length", i, j, NH[i].l, 0);
	}
*/

}

convf123 ()
/**************************************************************\
* 							       *
*  Convert from version 1.23:				       *
* 							       *
*  Changes: a) Tool holes are no longer needed -> remove them  *
*           b) The hole-structure received a reference to the  *
*              originating hole.			       *
* 							       *
\**************************************************************/
{
    register int j, r, xp, yp;
    int i, k, x, y;
    register struct pin *pin;
    register struct hole *hp;
    struct nlst *net;
    struct hole *fndh ();	

    struct oldhole {
	int x, y;		/* coordinates		 */
	struct nlst *n;		/* net pointer		 */
    } *oh;

    printf ("Updating to PCB version 1.24\n");

    V.pver = pversion;		/* update pgm version	 */

    color (0, fb);
    for (i = 0; i < 4; i++)	/* remove tool holes	 */
	if (V.reserved[i]) {
	    x = V.reserved[i];
	    y = V.reserved[i + 4];
	    for (j = x - 3; j <= x + 3; j++)
		for (k = y - 3; k <= y + 3; k++)
		    pxl (j, k);
	}
    for (i = 0; i < 8; i++)
	V.reserved[i] = 0;

    for (i = 0; i < V.nch; i++) { /* change hole structure */
	oh = (struct oldhole *) &CH[i];
	x = oh -> x;
	y = oh -> y;
	net = oh -> n;
	CH[i].x = x;
	CH[i].y = y;
	CH[i].n = net;
	CH[i].pn = 0;
	CH[i].cpi = 0;
    }

    for (i = 0; i < V.ncp; i++) {	/* scan all components	 */
	if (CP[i].unplaced)
	    err ("Hey: V1.23 had no unplaced components!", i, 0, 0, 0);
	x = CP[i].x;			/* get borad position	 */
	y = CP[i].y;
	r = CP[i].r;
	k = CP[i].ty -> np;
	for (j = 0, pin = CP[i].ty -> p; j < k; j++, pin++) {
				/* scan component pins		 */

	    xp = x + (pin -> x) * rot_m[r][0] + (pin -> y) * rot_m[r][1];
	    yp = y + (pin -> x) * rot_m[r][2] + (pin -> y) * rot_m[r][3];

	    hp = fndh (xp, yp);	/* find hole			 */
	    if (!hp)
		err ("convt124: missing hole", xp, yp, 0, 0);
	    hp -> pn = j;
	    hp -> cpi = i;
	}
    }
}

specs()				/* promt for bord specs	 */
{
    float   x, y, getfloat();

    x = getfloat ("Width of board in cm:",0.0,100.0,0.0);
    y = getfloat ("Higth of board in cm:",0.0,100.0,0.0);
    scalef = getfloat ("Scale factor for pin coordinates:",0.01,100.0,1.0);

    if ((x < 1.0) || (y < 1.0))
	err ("-Use a pencil and paper for such a board", x, y, 0, 0);
    x *= 3.937007874;		/* step by step (rounding problem) */
    y *= 3.937007874;
    x *= rsun;
    y *= rsun;
    V.BSX = 0.5 + x;
    V.BSY = 0.5 + y;
    if ((V.BSX > xmax - 4) || (V.BSY > ymax - 4)) {
	printf ("Recompile me with 'xmax'>%d and 'ymax'>%d\n",
		V.BSX + 3, V.BSY + 3);
	err ("-bitmap too small", V.BSX, V.BSY, xmax - 4, ymax - 4);
    }

    color (fb, fb);		/* plot frame			 */
    plt (2, 1, V.BSX + 1, 1);
    plt (1, 2, 1, V.BSY + 1);
    plt (V.BSX + 2, 2, V.BSX + 2, V.BSY + 1);
    plt (2, V.BSY + 2, V.BSX + 1, V.BSY + 2);
}
!E!O!F!