[net.sources] PCB part 7 of 10

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

#
# type    sh /usru0/agn/pcb/distr/../usenet/part7   to unpack this archive.
#
echo extracting pmnrt.c...
cat >pmnrt.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	Manual routing functions				*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/

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

#define maxtrc 200		/* number of items in trace buf	 */
#define sactrc 10		/* items lost on overflow	 */

extern double atan2();
extern struct nlhd *choose(), *get_net();

static plow_f = 0;		/* plow flag			 */
static int trc_cnt = 0;		/* trace counter		 */
static struct trace {		/* trace buffer (for delete last)*/
    int x, y;			/* coordinate			 */
    int ty;			/* type (hole, side)		 */
} trc_buf[maxtrc];

static int sof_seg = 0;		/* color of first segment	 */

extern int sp[9][2];		/* search pattern		 */

/*ARGSUSED*/
net_sel (ctx)			/* select a net for routing	 */
    int ctx;
{
    struct nlhd *t;

    if (!placed) {		/* routing only after placement	 */
	if (V.cnet)
	    deseln (V.cnet);	/* should not happen		 */
	if (ck_placed ())
	    placed = 1;		/* everything is placed		 */
	else
	    return PLACE;
    }

    if (V.cnet) { 		/* we are within a net		 */
	if (!(V.cnet -> f))
	    return (START);	/* continue on selected net	 */
	else
	    deseln (V.cnet);
    }

    while (t = choose ()) {/* found a net to work on	 */
	if (!selnet (t)) {
            adjw (V.cnet);
	    err_msg (t -> name);
	    return (START);
	}
	deseln (t);		/* skip complete nets		 */
    }
    return (EDIT);		/* no nets found		 */
}

net_desel (ctx)			/* deselect a net		 */
    int ctx;
/******************************************************************\
* 								   *
*  Eficiency hack: to avoid a deselec/select cycle for incomplete  *
*  nets, those net remain selected if the next context is START.   *
* 								   *
\******************************************************************/
{   int i;
    static int svcnt = 0;	/* auto save counter		 */

    plow_f = 0;

    if (ctx == ROUTE || ctx == PLOW)	/* don't deselect to enter R-cntx*/
	return;

    if (V.cnet) {
	i = cchk (V.cnet);	/* update net state		 */
	nettgo -= i ^ V.cnet -> f;
	V.cnet -> f = i;
	nets_msg (nettgo);

	if (V.cnet -> f) {	/* completed net ?		 */
	    if (++svcnt > savcnt) {	/* time to auto save ?	 */
		svcnt = 0;
		Ferr_msg ("Busy: saving work");
		save (0);
		beep ();
		err_msg ("Done!");
	    }
	}

	if (V.cnet -> f || ctx != START) {
	    deseln (V.cnet);	/* time to drop the net		 */
	}
    }
}

/*ARGSUSED*/
start_nt (x, y, ctx)		/* start a copper trace		 */
    int x, y, ctx;
/*****************************************************************\
* 								  *
*  This function tries to find a start point for a copper trace:  *
*    1. if the cursor is near a hole and the hole is part of an	  *
*       unconnected net, the hole is selected as a start.	  *
*    2. if the cursor is near a trace of an unfinished net, the	  *
*       nearest point of that trace is used as an start point.	  *
*       this might fail due to lack of space for a via hole.	  *
*    3. If everything fails, the preview map is displayed.	  *
* 								  *
\*****************************************************************/
{
    struct nlhd *p, *loc (), *fly ();
    char buf[40 + nmmax];

    sof_seg = 0;		/* reset first color		 */

    if (plow_f && trc_buf[0].x == x && trc_buf[0].y == y &&
	!(pcb[y][x] & ahb)) {
	plow_f = 0;
	plow_ini (PLOW);
	return plow_src (x, y, PLOW);
    }

    if (V.cnet -> f)		/* deselect a complted net	 */
	deseln (V.cnet);

    p = loc (&x, &y);		/* try start from hole		 */

    if (!p)
	p = fly (&x, &y);	/* failed, try a wire		 */

    if (!V.cnet) {		/* no net			 */
	if (p && !(p -> f))
	    selnet (p);
	else if (!p) {		/* p != 0 is taken care of later */
	    plow_f = 0;
	    return (net_sel (0));
	}
    }

    if (!p)	 {		/* start failed			 */
	plow_f = 0;
	prev (V.cnet, x, y);	/* display preview map		 */
	return (START);}
    else if (p -> f) {		/* net is already done		 */
	plow_f = 1;
	trc_buf[0].x = x;
	trc_buf[0].y = y;
	sprintf (buf, "Net (%s): done!", p -> name);
	err_msg (buf);
	if (V.cnet)
	    deseln (V.cnet);
	selnet (p);
	return (START);}
    else {			/* start ok: save start point	 */
	plow_f = 0;
	err_msg (p -> name);
	trc_buf[0].x = x;
	trc_buf[0].y = y;
	trc_buf[0].ty = (pcb[y][x] & ahb) ? vec :
			((~pcb[y][x] & vec) ? pcb[y][x] & vec : s1b);
	trc_cnt = 1;
    }

    if (p != V.cnet) {		/* started on unselected net	 */
	deseln (V.cnet);	/* drop current net		 */
	if (selnet (p)) {	/* trouble: net is done		 */
	    deseln (p);
	    return (net_sel (0));
	}
    }

    return (ROUTE);
}

struct nlhd *fly (x, y)		/* try flying start		 */
    int *x, *y;
{
    int     i;

    for (i = 0; i < 9; ++i)	/* look for a selected wire	 */
	if ((pcb[*y + sp[i][1]][*x + sp[i][0]] & vec) &&
	    (pcb[*y + sp[i][1]][*x + sp[i][0]] & selb)) {
		*x += sp[i][0];
		*y += sp[i][1];
		return (V.cnet);
	    }

    for (i = 0; i < 9; ++i)	/* look for any wire		 */
	if (pcb[*y + sp[i][1]][*x + sp[i][0]] & vec) {
		*x += sp[i][0];
		*y += sp[i][1];
		if (~pcb[*y][*x] & vec)
		    return get_net (*x, *y, vec);
		else
		    return get_net (*x, *y, top_side);
	    }

    return (nil);		/* not close to wire		 */
}

struct nlhd *loc(x, y)		/* locate net for given pin	 */
    int *x, *y;
{
    int i, j;

    for (i = *x - 1; i < *x + 1; ++i)/* look for holes 		 */
	for (j = *y - 1; j < *y + 1; ++j)
	    if (center (&i, &j)) { /* center coordinate		 */
		*x = i;
		*y = j;
		return get_net(i, j, vec);
	    }
    return (nil);		/* no hole found		 */
}

/*ARGSUSED*/
cont_s1 (x, y, ctx)		/* continue a wire trace	 */
    int x, y, ctx;
{
    return (cont_nt (x, y, s1b));
}

/*ARGSUSED*/
cont_s2 (x, y, ctx)		/* continue a wire trace	 */
    int x, y, ctx;
{
    return (cont_nt (x, y, s2b));
}

cont_nt (x, y, sd)		/* continue a wire trace	 */
    int x, y, sd;
{   int     i;

    if ((trc_buf[trc_cnt - 1].x == x) && (trc_buf[trc_cnt - 1].y == y)) {
	if (trc_cnt == 1 && !(pcb[y][x] & ahb)) {
	    trc_cnt = 0;
	    plow_ini (PLOW);
	    return plow_src (x, y, PLOW);
	}
	return (ROUTE);		/* ignore 0-length wires	 */
    }

    if (trc_cnt == 2)
	sof_seg = trc_buf[1].ty;

    if (trc_cnt > maxtrc - 3) {	/* sufficient space in buffer	 */
	for (i = sactrc; i < trc_cnt; i++) {
	    trc_buf[i - sactrc].x = trc_buf[i].x;
	    trc_buf[i - sactrc].y = trc_buf[i].y;
	    trc_buf[i - sactrc].ty = trc_buf[i].ty;
	}
	trc_cnt -= sactrc;
    }

    if (home (x, y, trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y,
	      trc_buf[0].x, trc_buf[0].y, sd, trc_buf[trc_cnt - 1].ty))
	return (START);		/* successfull home run		 */

    if (sd & ~trc_buf[trc_cnt - 1].ty) {/* need to change sides	 */
	if (viaalg (sd)) {
	    err_msg ("No space for a hole");
	    beep ();
	    return (ROUTE);
	}
	trc_buf[trc_cnt].ty = sd | ishb;}
    else
	trc_buf[trc_cnt].ty = sd;

    if (pnt (x, y, sd))		/* add a vector to wire		 */
	return (START);

    return (ROUTE);
}

pnt (x_cur, y_cur, si)		/* paint a wire segment		 */
    int    x_cur, y_cur, si;
{
    int     i,
            j,
            k,
            l,			/* random scratch		 */
            x,
            y,
            x1,
            y1,			/* used for test scan		 */
	    xo, yo,
            dx,
            dy,
            dxd,
            dyd;		/* direction vectors		 */

    xo = trc_buf[trc_cnt - 1].x;/* get origin			 */
    yo = trc_buf[trc_cnt - 1].y;
    i = (atan2 ((y_cur - yo) * 0.5, (x_cur - xo) * 0.5) + 6.676885) * 1.27324;
    i = i % 8;			/* chose a direction		 */

    dx = dr[i][0];
    dy = dr[i][1];
    color (si | selb, si | selb);

    j = abs (y_cur - yo);
    k = abs (x_cur - xo);
    if (i & 1)
	j = (j < k) ? j : k;	/* run min. length (diag.)	 */
    else
	j = dx ? k : j;		/* run axis projection		 */

    x = xo + dx;
    y = yo + dy;
    if (i & 1) {		/* diagonal check		 */
	dxd = (dx - dy) / 2;
	dyd = (dx + dy) / 2;
	for (k = 0; k < j; ++k) {/* check for illegal areas	 */
	    l = pchk1 (x - dy, y + dx, si, &x1, &y1);
	    if (l & 1)
		break;
	    l |= pchk1 (x + dy, y - dx, si, &x1, &y1);
	    if (l & 1)
		break;
	    if (!k && l && !(pcb[y1][x1] & ahb))
				/* something special		 */
		l = 0;
	    l |= pchk1 (x + dx, y + dy, si, &x1, &y1);
	    if (l & 1)
		break;
	    l |= pchk1 (x + dxd, y + dyd, si, &x1, &y1);
	    if (l & 1)
		break;
	    l |= pchk1 (x + dyd, y - dxd, si, &x1, &y1);
	    if (l & 1)
		break;
	    if (l & 2) {
		l = pchk2 (x, y, x1, y1, i, si);
		if (l)
		    break;
	    }
	    x += dx;
	    y += dy;
	}
    }
    else {			/* horizontal / vertical check	 */
	for (k = 0; k < j; ++k) {/* check for illegal areas	 */
	    l = pchk1 (x + dx - dy, y + dy + dx, si, &x1, &y1);
	    if (l & 1)
		break;
	    l |= pchk1 (x + dx + dy, y + dy - dx, si, &x1, &y1);
	    if (l & 1)
		break;
	    if (!k && l && !(pcb[y1][x1] & ahb))
				/* something special		 */
		l = 0;
	    l |= pchk1 (x + dx, y + dy, si, &x1, &y1);
	    if (l & 1)
		break;
	    if (l & 2) {
		l = pchk2 (x, y, x1, y1, i, si);
		if (l)
		    break;
	    }
	    x += dx;
	    y += dy;
	}
    }

    if (l == 2)			/* an end connection was made	 */
	return (1);		/* signal success		 */
    else {
	x -= dx;		/* correct length		 */
	y -= dy;
	plt (xo, yo, x, y);	/* plot new segment		 */
	trc_buf[trc_cnt].x = x;
	trc_buf[trc_cnt++].y = y;
	return (0);
    }
}

pchk1 (x, y, b, xs, ys)		/* paint check			 */
    int     x, y, b, *xs, *ys;
{
    int     i;
/* printf("pchk1: x=%d y=%d b=%2x xs=%d ys=%d\n",x,y,b,*xs,*ys); */
    i = pcb[y][x];
    if (!(i & selb))		/* not selected: peace of cake	 */
	return (0 != (i & (fb | b | ahb)));/* touches other net?	 */
    *xs = x;
    *ys = y;
    return (2);			/* needs more careful examination */
}

pchk2 (xe, ye, xt, yt, a, b)/* paint check (the same net)	 */
    int    xe, ye, xt, yt, a, b;
{
    register int i;

    i = pcb[yt][xt];

    if (i & b) {		/* touches net on same side: ok  */
	if (!(pcb[ye][xe] & b) &&
	    !(~pcb[ye + dr[a][1]][xe + dr[a][0]] & (selb | b))) {
	    xe += dr[a][0];	/* fill diagonal approach gap	 */
	    ye += dr[a][1];
	}
	plt (trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y, xe, ye);
	return (2);
    }

    if (i & ahb)		/* hole approach		 */
	return (pnt_ha (xe, ye, xt, yt, a, b));
    else	/* remaining case: touches same net on other side*/
	return (pnt_eha (xe, ye, xt, yt, a, b));
}

pnt_ha (xe, ye, xt, yt, a, b)
    int xe, ye, xt, yt, a, b;
/********************************************************************\
* 								     *
*  paint wire: hole approach - a via hole for the same net is found  *
*  in the paint - scan. A connection between the new wire and	     *
*  the hole need to be made (this is allways possible). <xe,ye> is   *
*  the end point of the new wire on side <b> with direction <a>.     *
*  <xt,yt> is part of the hole (not necessarily the center).	     *
*  <e> and <t> are one unit apart.				     *
* 								     *
*  a 2 is returned if a connection is made. 0 is returned if the     *
*  hole turns out to be a piece of guard area (pseudo hole).	     *
* 								     *
\********************************************************************/
{
    register int i;

    if (!center (&xt, &yt))	/* center on hole		 */
	return 0;

    if ((xt == xe + 2 * dr[a][0]) && (yt == ye + 2 * dr[a][1])) {
	plt (trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y,
		xe + 2 * dr[a][0], ye + 2 * dr[a][1]);
	return (2);		/* hole was staight ahead	 */
    }

    if (a & 1) {		/* diagonal approach		 */
	if ((abs (xe - xt) >= 2) && (abs (ye - yt)) &&
		(pcb[ye - yt][xe - dr[a][0]] & b)) {
	/* this is a wired case		 */
	    if (abs (yt - (ye - dr[a][1])) > 2)
		plt (xt, yt, xt, yt - 2 * dr[a][1]);
	    else
		plt (xt, yt, xt - 2 * dr[a][0], yt);
	    plt (trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y,
		    xe -= dr[a][0], ye -= dr[a][1]);
	    ckgp (xe, ye, b);
	    return (2);
	}
	xe += dr[a][0];
	ye += dr[a][1];
	for (i = 0; i < 3; ++i) {
	    if ((yt == ye) || (xt == xe)) {
		plt (xt, yt, xe, ye);
		plt (trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y, xe, ye);
		ckgp (xe, ye, b);
		return (2);
	    }
	    xe -= dr[a][0];
	    ye -= dr[a][1];
	}
	err ("pchk2: funny error - please save the details", xe, ye, xt, yt);}
    else {
	if ((abs (xt - xe) > 1) && (abs (yt - ye) > 1))
	    plt (xt, yt, xe, ye);
	else {
	    pxl (xt, yt);
	    xe += dr[a][0];
	    ye += dr[a][1];
	}
	plt (trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y, xe, ye);
	ckgp (xe, ye, b);
	return (2);
    }

    return 0;			/* to keep lint happy		 */
}

pnt_eha (xe, ye, xt, yt, de, b)
    int xe, ye, xt, yt, de, b;
/**********************************************************************\
* 								       *
*  paint: end hole allocator - tries to allocate an via-hole.	       *
*  During the paint-wire scan, the new wire finds itself	       *
*  approaching the same net on a the other pcb-side. A via-hole	       *
*  need to be allocated to connect these wires.			       *
*  <xe,ye> is the end point of the new wire, drawn in direction <de>.  *
*  <xt,yt> is the offending point of the same (selected) net on	       *
*  the other side. <e> and <t> are exactly one unit apart. The	       *
*  new wire is drawn on side <b>.				       *
* 								       *
*  On success, a 2 is returned. Unsuccesfull attemps return a 1.       *
* 								       *
\**********************************************************************/
{
    int i, j, x, y, dt;
    static struct hsp {		/* hole search pattern		 */
	int r[7];		/* relative test point position
				   -1: no displacement = xe,ye	 */
	int h[7];		/* help-point: 0=none  -1= xe,ye */
    } hasp[9] = {
	{			/* diag: xt,yt on  +2		 */
	    {  2, -1,  1,  3,  0,  4,  5},
	    {  0,  0,  0,  0,  1,  3, -1}  },
	{			/* diag: xt,yt on  +1		 */
	    {  1, -1,  0,  7,  4,  3,  5},
	    {  0,  0,  0,  0, -1,  0, -1}  },
	{			/* diag: xt,yt on   0		 */
	    {  0, -1,  1,  7,  4,  3,  7},
	    {  0,  0,  0,  0, -1, -1, -1}  },
	{			/* diag: xt,yt on  -1		 */
	    {  7, -1,  0,  1,  4,  5,  3},
	    {  0,  0,  0,  0, -1,  0, -1}  },
	{			/* diag: xt,yt on  -2		 */
	    {  6, -1,  7,  5,  0,  4,  3},
	    {  0,  0,  0,  0,  7,  5, -1}  },
	{			/* H/V:  xt,yt on  +1		 */
	    {  1, -1,  0,  2,  3,  7,  6},
	    {  0,  0,  0,  0,  2,  8,  8}  },
	{			/* H/V:  xt,yt on   0		 */
	    {  0, -1,  4,  1,  7,  2,  6},
	    {  0,  0, -1,  0,  0,  0,  0}  },
	{			/* H/V:  xt,yt on  -1		 */
	    {  7, -1,  0,  6,  5,  1,  2},
	    {  0,  0,  0,  0,  6,  8,  8}  }
    };

    for (dt = 0; dt < 8; dt++)	/* get direction of e->t	 */
	if (xt == xe + dr[dt][0] && yt == ye + dr[dt][1])
	    break;
    if (dt >= 8)
	err ("pnt_eha: <xe,ye> not adjacent to <xt,yt>", xe, ye, xt, yt);
    dt = (8 + dt - de) % 8;	/* need it relative		 */
    dt = (dt > 4) ? dt - 8 : dt;/* 0 ... 7  ->  -3 ... 4	 */

    if ((de & 1 && (dt > 2 || dt < -2)) ||
	    (!(de & 1) && (dt > 1 || dt < -1)))
	err ("pnt_eha: illegal case", xe, ye, xt, yt);

    i = (de & 1) ? 2 - dt : 6 - dt;/* select case (see table)	 */

    color (ishb | selb, ishb | selb);

    for (j = 0; j < 7; j++) {	/* scan through cases		 */
	if (hasp[i].r[j] < 0) {
	    x = xe;
	    y = ye;}
	else {
	    x = xe + dr[(hasp[i].r[j] + de) % 8][0];
	    y = ye + dr[(hasp[i].r[j] + de) % 8][1];
	}
	if ((x | y) & 1 || pin (x, y))
	    continue;		/* not aligned or no space	 */
	color (b | selb, b | selb);
	plt (xe, ye, trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y);
	color (vec, vec);
	pxl (x, y);		/* via hole is inserted		 */
	if (hasp[i].h[j]) {	/* need a intermediate point	 */
	    color (b ^ vec, b ^ vec);
	    pxl ((hasp[i].h[j] < 0) ? xe : xe + dr[(hasp[i].h[j] + de) % 8][0],
		 (hasp[i].h[j] < 0) ? ye : ye + dr[(hasp[i].h[j] + de) % 8][1]);
	}
	ckgp (x, y, b);
	return (2);
    }

    err_msg ("No space for a hole");
    beep ();
    color (b | selb, b | selb);
    return (1);
}

viaalg (b)			/* via hole alignment		 */
    int b;
/********************************************************************\
* 								     *
* tries to insert a via-hole at <trc_buf[trc_cnt-1].x/y> to allow    *
* continuation on side <b>. A intermediate vector might be added to  *
* the trace buffer. trc_buf is assumed to have enough space.	     *
* 								     *
* Returns a 0 if succesful, a 1 otherwise			     *
* 								     *
\********************************************************************/
{
    int     i, j, x, y, dx, dy;
    static int ct[9] = {5, 4, 3, 6, 8, 2, 7, 0, 1};

    x = trc_buf[trc_cnt - 1].x;
    y = trc_buf[trc_cnt - 1].y;

    color (ishb | selb, ishb | selb);
    if (!((x | y) & 1)) {	/* already aligned		 */
	if (pin (x, y))
	    return (1);		/* no space			 */
        else {
	    color (vec, vec);
	    pxl (x, y);
	    return (0); }	/* done !			 */
    }

    if (trc_cnt > 1) {		/* any prefered direction ?	 */
	dx = (trc_buf[trc_cnt - 2].x < x) - (trc_buf[trc_cnt - 2].x > x);
	dy = (trc_buf[trc_cnt - 2].y < y) - (trc_buf[trc_cnt - 2].y > y);

	if (!((x + dx) & 1) && !((y + dy) & 1) && !pin (x + dx, y + dy)) {
				/* extend previous vector	 */
	    x = trc_buf[trc_cnt - 1].x += dx;
	    y = trc_buf[trc_cnt - 1].y += dy;
	    color (vec, vec);
	    pxl (x, y);
	    return (0);
	}

	if (!((x - dx) & 1) && !((y - dy) & 1) && !pin (x - dx, y - dy)) {
				/* shorten previous vector	 */
	    trc_buf[trc_cnt - 1].x -= dx;
	    trc_buf[trc_cnt - 1].y -= dy;
	    color (vec, vec);
	    pxl (trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y);
	    color (0, vec ^ b);
	    pxl (x, y);
	    return (0);
	}
    }

    for (i = 0; i < 8; ++i)	/* brute force search		 */
	if (!((x + dr[i][0]) & 1) && !((y + dr[i][1]) & 1) &&
		!pin (x + dr[i][0], y + dr[i][1])) {
	    if (trc_cnt > 1) {
		j = ct[(dx + 1) * 3 + dy + 1];
		if (((i + 3) % 8 == j) || ((i + 4) % 8 == j) ||
		    ((i + 5) % 8 == j)) {	/* avoid dead maze	*/
		    color (0, vec ^ b);
		    pxl (trc_buf[trc_cnt - 1].x, trc_buf[trc_cnt - 1].y);
		    trc_buf[trc_cnt - 1].x -= dx;
		    trc_buf[trc_cnt - 1].y -= dy;
		}
	    }
	    color (vec, vec);
	    pxl (trc_buf[trc_cnt].x = dr[i][0] + x,
		 trc_buf[trc_cnt].y = dr[i][1] + y);
	    trc_buf[trc_cnt++].ty = vec ^ b;
	    return (0);
	}

    return (1);			/* there is just no space	 */
}

static int dex = 0;		/* delete exit feature		 */

m_delete (x, y, ctx)		/* manual delete		 */
    int x, y, ctx;
{
    plow_f = 0;

    if (del (x, y, vec)) {
	if (dex) {		/* switch to an other net	 */
	    dex = 0;
	    if (V.cnet)
	        deseln (V.cnet);
	    return (net_sel (ctx));}
	else
	    dex = 1;
    }
    return (START);
}

mr_delete (x, y, ctx)		/* manual delete in r-context	 */
    int x, y, ctx;
{
    int     dx, dy;

    plow_f = 0;
    dex = 0;
    if (del (x, y, vec)) {	/* del failed: backtrack	 */
	if (trc_cnt > 1) {
	    x = trc_buf[trc_cnt - 1].x;
	    y = trc_buf[trc_cnt - 1].y;
	    dx = (trc_buf[trc_cnt - 2].x < x) - (trc_buf[trc_cnt - 2].x > x);
	    dy = (trc_buf[trc_cnt - 2].y < y) - (trc_buf[trc_cnt - 2].y > y);
	    color (0, selb | (trc_buf[trc_cnt - 1].ty & vec));
	    plt (x, y, trc_buf[trc_cnt - 2].x + dx, trc_buf[trc_cnt - 2].y + dy);
	    if (trc_buf[trc_cnt - 1].ty & ishb) {
		color (0, selb | vec & trc_buf[trc_cnt - 1].ty);
		ck_rdnb (x = trc_buf[trc_cnt - 2].x,
		   y = trc_buf[trc_cnt - 2].y, vec & trc_buf[trc_cnt - 1].ty);
if(pcb[y][x] & ishb) {
		color (0, ishb | selb);
		dpin (x, y);
		color (selb, selb);
/* guard zones may stay unselected: cosmetic defect */
		for (dy = -1; dy <= 1; dy++)/* un-unselect	 */
		    for (dx = -1; dx <= 1; dx++)
			if (pcb[y + dy][x + dx] & vec)
			    pxl (x + dx, y + dy);
}else{
 printf("This was the bug - please report\n");
 beep();
}
		if (trc_cnt > 2 &&
		    abs(trc_buf[trc_cnt - 3].x - trc_buf[trc_cnt - 2].x) <2 &&
		    abs(trc_buf[trc_cnt - 3].y - trc_buf[trc_cnt - 2].y) <2) {
				/* remove alignment stub	 */
		    color (0, selb | trc_buf[trc_cnt - 2].ty);
		    ck_rdnb (trc_buf[trc_cnt - 3].x, trc_buf[trc_cnt - 3].y,
			trc_buf[trc_cnt - 2].ty);
		    trc_cnt--;
		}
	    }
	    trc_cnt--;
	}
	if (trc_cnt <= 1) {	/* unselect start		 */
	    ckgp (trc_buf[0].x, trc_buf[0].y, s1b);
	    ckgp (x = trc_buf[0].x, y = trc_buf[0].y, s2b);
	    color (selb, selb);
	    for (dy = -1; dy <= 1; dy++)/* un-unselect		 */
		for (dx = -1; dx <= 1; dx++)
		    if (pcb[y + dy][x + dx] & (sof_seg | ahb))
			pxl (x + dx, y + dy);
	    trc_cnt = 0;
	    return (START);
	}
    }
    return (ctx);
}

static int wxl, wyl, wxh, wyh;	/* window extensions		 */

/*ARGSUSED*/
cr_window (ctx)			/* create a window		 */
    int ctx;
{
    wxl = wx + 192 / cz;	/* default size			 */
    wyl = wy + 177 / cz;
    wxh = wx + 320 / cz;
    wyh = wy + 305 / cz;
    di_window ();
}

di_window ()			/* display window		 */
{
    color (resb, resb);
    plts (wxl, wyl, wxh, wyl);
    plts (wxh, wyl, wxh, wyh);
    plts (wxh, wyh, wxl, wyh);
    plts (wxl, wyh, wxl, wyl);
}

rm_window ()			/* remove window		 */
{
    color (0, resb);
    plts (wxl, wyl, wxh, wyl);
    plts (wxh, wyl, wxh, wyh);
    plts (wxh, wyh, wxl, wyh);
    plts (wxl, wyh, wxl, wyl);
}

/*ARGSUSED*/
w_zoomi (x, y, ctx)		/* zoom in (and maintain window) */
    int x, y, ctx;
{
    if (cz < 16) {
	rm_window ();
	zoom (cz + 1);
	di_window ();
    }
    return (ctx);		/* don't change context		 */
}

/*ARGSUSED*/
w_zoomo (x, y, ctx)		/* zoom out (and maintain window) */
    int x, y, ctx;
{
    if (cz > 1) {
	rm_window ();
	zoom (cz - 1);
	di_window ();
    }
    return (ctx);		/* don't change context		 */
}

w_wmv (x, y, ctx)		/* move window			 */
    int x, y, ctx;
{
    rm_window ();
    window (x - 256 / cz, y - 256 / cz);
    di_window ();
    return (ctx);		/* don't change context		 */
}

wnd_urc (x, y, ctx)		/* window: upper right corner	 */
    int x, y, ctx;
{
    rm_window ();

    if (x >= wxl)
	wxh = x;
    else {
	wxh = wxl;
	wxl = x;
    }

    if (y >= wyl)
	wyh = y;
    else {
	wyh = wyl;
	wyl = y;
    }

    di_window ();
    return (ctx);
}

wnd_llc (x, y, ctx)		/* window: lower left corner	*/
    int x, y, ctx;
{
    rm_window ();
    wxh = x + (wxh - wxl);
    wxl = x;
    wyh = y + (wyh - wyl);
    wyl = y;
    di_window ();
    return (ctx);
}

static int ad_ty;		/* area delete type		 */

ini_adel (ctx)			/* initialize area delete	 */
   int ctx;
{
    ad_ty = vec;
    cr_window (ctx);
    return (ctx);
}

/*ARGSUSED*/
sel_adel (x, y, ctx)		/* select area delete options	 */
    int x, y, ctx;
{
    static char *txt[] = {
	"Everything",
	"Side 1 only",
	"Side 2 only",
	"Nothing"
    };

    switch (menu (txt, 4)) {
	case 0: 
	    ad_ty = vec;
	    break;
	case 1: 
	    ad_ty = s1b;
	    break;
	case 2: 
	    ad_ty = s2b;
	    break;
	default: 
	    err_msg ("Area-delete aborted");
	    rm_window ();
	    return (START);
    }

    return (ctx);
}

/*ARGSUSED*/
exc_adel (x, y, ctx)		/* execute area delete		 */
    int x, y, ctx;
{
    int    ad_hck (), ad_vck ();
    struct nlhd *t, *get_net ();
    register int xx, yy;

    rm_window ();
    for (yy = wyl + 1; yy < wyh; yy++)/* delete loop		 */
	for (xx = wxl + 1; xx < wxh; xx++)
	    if (pcb[yy][xx] & ad_ty) {
		t = get_net (xx, yy, vec);

		if (t < &NH[0] || t > &NH[V.nnh])
		    continue;	/* skip power and ground nets	 */

		wthf = ad_hck;
		wtvf = ad_vck;
		wtrace (xx, yy, vec);
		if (t && t -> f && !cchk (t)) {
		    t -> f = 0;
		    nettgo++;
		}
	    }

    for (xx = wxl; xx <= wxh; xx++) {/* clean edges		 */
	if (pcb[wyl][xx] & (ahb | vec))
	    ad_gchk (xx, wyl);
	if (pcb[wyh][xx] & (ahb | vec))
	    ad_gchk (xx, wyh);
    }
    for (yy = wyl + 1; yy < wyh; yy++) {
	if (pcb[yy][wxl] & (ahb | vec))
	    ad_gchk (wxl, yy);
	if (pcb[yy][wxh] & (ahb | vec))
	    ad_gchk (wxh, yy);
    }

    nets_msg (nettgo);		/* update number of nets message */

    return (START);
}

ad_hck (x, y)			/* area-delete hole check	 */
    int x, y;
{
    if (pcb[y][x] & ishb && x > wxl && y > wyl && x < wxh && y < wyh) {
	color (0, ishb);
	dpin (x, y);
    }
    return (0);
}

ad_vck (x1, y1, x2, y2)		/* area-delete vector check	 */
    int x1, y1, x2, y2;
{
    int     i;

    if (y1 > y2) {		/* order y for y-band clipping	 */
	i = x1;
	x1 = x2;
	x2 = i;
	i = y1;
	y1 = y2;
	y2 = i;
    }
    i = ((x1 < x2) - (x2 < x1));

    if (y1 <= wyl) {
	if (y2 <= wyl)
	    return;
	x1 += (wyl + 1 - y1) * i;
	y1 = wyl + 1;
    };

    if (y2 >= wyh) {
	if (y1 >= wyh)
	    return;
	x2 -= (y2 - (wyh - 1)) * i;
	y2 = wyh - 1;
    }

    if (x1 > x2) {		/* order x for x-band clipping	 */
	i = x1;
	x1 = x2;
	x2 = i;
	i = y1;
	y1 = y2;
	y2 = i;
    }
    i = (y1 < y2) - (y2 < y1);

    if (x1 <= wxl) {
	if (x2 <= wxl)
	    return;
	y1 += (wxl + 1 - x1) * i;
	x1 = wxl + 1;
    }

    if (x2 >= wxh) {
	if (x1 >= wxh)
	    return;
	y2 -= (x2 - (wxh - 1)) * i;
	x2 = wxh - 1;
    }

    if (abs (x1 - x2) < 2 && abs (y1 - y2) < 2 &&
	pcb[x1][y1] & chb && pcb[x2][y2] & chb)
	return;			/* do not remove parts of a hole */

    color (0, wtsb);
    plt (x1, y1, x2, y2);
}

ad_gchk (x, y)			/* area delete: garbage check	 */
    int x, y;
{
    struct nlhd *get_net ();
    int delh (), delv ();

    if (!get_net (x, y, vec)) {
	wthf = delh;
	wtvf = delv;
	wtrace (x, y, vec);
    }
}

ini_art (ctx)			/* initialize area route	 */
    int ctx;
{
    cr_window (ctx);
    return (ctx);
}

/*ARGSUSED*/
sel_art (x, y, ctx)		/* select area route options	 */
    int x, y, ctx;
{
    err_msg ("Area-route has no options yet");
    return (ctx);
}

/*ARGSUSED*/
exc_art (x, y, ctx)		/* execute area route		 */
    int x, y, ctx;
{
    register int xx, yy, max, cnt, i;
    struct nlhd **nl, *t, *get_net ();
    char buf[40];

    max = 200;			/* assume 200 for a start	 */
    cnt = 0;
    nl = (struct nlhd **) malloc (sizeof (struct nlhd *) * max);

    rm_window ();
    Ferr_msg ("Busy: routing");
    for (yy = wyl + 1; yy < wyh; yy++)
	for (xx = wxl + 1; xx < wxh; xx++)
	    if ((pcb[yy][xx] & chb) && (t = get_net (xx, yy, vec)) && !(t -> f)) {
		for (i = 0; i < cnt; i++)
		    if (nl[i] == t)
			break;	/* got this net already		 */
		if (i >= cnt) {
		    if (cnt >= max) {
			max += max / 2;
			nl = (struct nlhd **) realloc
					(nl, sizeof (struct nlhd *) * max);
		    }
		    nl[cnt++] = t;
		}
	    }

    for (i = 0; i < cnt; i++) {
	sprintf (buf, "Routing net %d of %d", i, cnt);
	nets_msg (nettgo);
	Ferr_msg (buf);
	N_route (nl[i], 2, wxl, wyl, wxh, wyh);
	nettgo -= nl[i] -> f;
    }

    free (nl);			/* clean up			 */
    nets_msg (nettgo);
    err_msg ("Done");
    beep ();
    return (START);
}
!E!O!F!
#
# type    sh /usru0/agn/pcb/distr/../usenet/part7   to unpack this archive.
#
echo extracting pplace.c...
cat >pplace.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	Placement routines					*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/

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

int rot_m[4][4] = { { 1,  0,  0,  1},
		    { 0, -1,  1,  0},
		    {-1,  0,  0, -1},
		    { 0,  1, -1,  0}  };


fnd_cmp (x, y)			/* find component		 */
    int x, y;
{
    register int i, xl, xh, yl, yh;

    for (i = 0; i < V.ncp; i++) {
	switch (CP[i].r) {
	    case 0:
		xl = CP[i].x;
		yl = CP[i].y;
		xh = xl + CP[i].ty -> x;
		yh = yl + CP[i].ty -> y;
		break;
	    case 1:
		xh = CP[i].x;
		yl = CP[i].y;
		xl = xh - CP[i].ty -> y;
		yh = yl + CP[i].ty -> x;
		break;
	    case 2:
		xh = CP[i].x;
		yh = CP[i].y;
		xl = xh - CP[i].ty -> x;
		yl = yh - CP[i].ty -> y;
		break;
	    case 3:
		xl = CP[i].x;
		yh = CP[i].y;
		xh = xl + CP[i].ty -> y;
		yl = yh - CP[i].ty -> x;
		break;
	}
	xl--;
	yl--;
	xh++;
	yh++;
	if (x <= xh && x >= xl && y <= yh && y >= yl)
	    return (i);
    }
    return (-1);		/* no component found		 */
}

draw_cp (x, y, r, cp)		/* draw component shape		 */
    int x, y, r, cp;
{
    register int i, xl, yl, xh, yh;
    register struct pin *pp;
    int j;

    switch (r) {
	case 0: 
	    xl = x;
	    yl = y;
	    xh = xl + CP[cp].ty -> x;
	    yh = yl + CP[cp].ty -> y;
	    break;
	case 1: 
	    xh = x;
	    yl = y;
	    xl = xh - CP[cp].ty -> y;
	    yh = yl + CP[cp].ty -> x;
	    break;
	case 2: 
	    xh = x;
	    yh = y;
	    xl = xh - CP[cp].ty -> x;
	    yl = yh - CP[cp].ty -> y;
	    break;
	case 3: 
	    xl = x;
	    yh = y;
	    xh = xl + CP[cp].ty -> y;
	    yl = yh - CP[cp].ty -> x;
	    break;
    }

    xl -= 2;
    yl -= 2;
    xh += 2;
    yh += 2;

    color (resb, resb);
    plts (xl, yl, xh, yl);
    plts (xh, yl, xh, yh);
    plts (xh, yh, xl, yh);
    plts (xl, yh, xl, yl);

    for (j = 0, i = CP[cp].ty -> np, pp = CP[cp].ty -> p; i; i--, pp++) {
	xl = x + (pp -> x) * rot_m[r][0] + (pp -> y) * rot_m[r][1];
	yl = y + (pp -> x) * rot_m[r][2] + (pp -> y) * rot_m[r][3];
	if (!j) {
	    j = 1;
	    dot (xl, yl);
	}
	else
	    point (xl, yl);
    }
}

del_cp (x, y, r, cp)		/* delete component shape	 */
    int x, y, r, cp;
{
    register int xl, yl, xh, yh;

    switch (r) {
	case 0: 
	    xl = x;
	    yl = y;
	    xh = xl + CP[cp].ty -> x;
	    yh = yl + CP[cp].ty -> y;
	    break;
	case 1: 
	    xh = x;
	    yl = y;
	    xl = xh - CP[cp].ty -> y;
	    yh = yl + CP[cp].ty -> x;
	    break;
	case 2: 
	    xh = x;
	    yh = y;
	    xl = xh - CP[cp].ty -> x;
	    yl = yh - CP[cp].ty -> y;
	    break;
	case 3: 
	    xl = x;
	    yh = y;
	    xh = xl + CP[cp].ty -> y;
	    yl = yh - CP[cp].ty -> x;
	    break;
    }

    color (0, resb);
    c_rect (xl - 2, yl - 2, xh + 2, yh + 2);
}

static int active = 0;		/* !=0 if some coponent is sel	 */
static int cp_id, cp_x, cp_y, cp_r;

cmv_sel (x, y, ctx)		/* select a component		 */
    int x, y, ctx;
{
    char buf[nmmax + nmmax + 3];

    if (active)			/* remove previous selection	 */
	del_cp (cp_x, cp_y, cp_r, cp_id);

    cp_id = fnd_cmp (x, y);

    if (cp_id < 0) {
	active = 0;
	err_msg ("No component found");}
    else {
	active = 1;
	cp_x = CP[cp_id].x;
	cp_y = CP[cp_id].y;
	cp_r = CP[cp_id].r;
	draw_cp (cp_x, cp_y, cp_r, cp_id);

	sprintf (buf, "%s (%s)", CP[cp_id].name, CP[cp_id].ty -> name);
	err_msg (buf);
    }

    return (ctx);
}

/*ARGSUSED*/
exc_cmv (x, y, ctx)		/* execute CP move		 */
    int x, y, ctx;
{
    register int i, x1, y1, or;
    register struct pin *pp;

    if (!active)
	return START;		/* nothing to do		 */

    del_cp (cp_x, cp_y, cp_r, cp_id);
    active = 0;

    if (CP[cp_id].r == cp_r && CP[cp_id].x == cp_x && CP[cp_id].y == cp_y) {
	err_msg ("Not moved");
	return START;		/* move to same location	 */
    }

    or = CP[cp_id].r;		/* get old rotation		 */

    for (i = CP[cp_id].ty -> np, pp = CP[cp_id].ty -> p; i; i--, pp++) {

				/* check alignment of new location */
	x1 = cp_x + (pp -> x) * rot_m[cp_r][0] + (pp -> y) * rot_m[cp_r][1];
	y1 = cp_y + (pp -> x) * rot_m[cp_r][2] + (pp -> y) * rot_m[cp_r][3];
	if (cp_alchk (x1) || cp_alchk (y1)) {
	    err_msg ("Pins not on drill grid");
	    return START;
	}

				/* check range			 */
	if (x1 < 3 || y1 < 3 || x1 > V.BSX - 3 || y1 > V.BSY - 3) {
	    err_msg ("Can't move off board");
	    return START;
	}
	
				/* check for wires		 */
	x1 = CP[cp_id].x + pp -> x * rot_m[or][0] + pp -> y * rot_m[or][1];
	y1 = CP[cp_id].y + pp -> x * rot_m[or][2] + pp -> y * rot_m[or][3];
	if (pcb[y1][x1] & (s1b | s2b)) {
	    err_msg ("Disconnect wires first");
	    return START;
	}
    }

    x1 = CP[cp_id].x;		/* save old place		 */
    y1 = CP[cp_id].y;
    i  = CP[cp_id].r;

    if (!C_unplace (&CP[cp_id]))
	err ("exc_cmv: this should not happen", cp_id, 0, 0, 0);

    if (!C_place (&CP[cp_id], cp_x, cp_y, cp_r)) {
	err_msg ("No space at new place");
	if (!C_place (&CP[cp_id], x1, y1, i))
	    err ("exc_cmv: re-insert to old place failed", x1, y1, i, cp_id);
    }

    CH_update ();

    return START;
}


/*ARGSUSED*/
cmv_rr (x, y, ctx)		/* rotate right			 */
    int x, y, ctx;
{
    if (active) {
	del_cp (cp_x, cp_y, cp_r, cp_id);
	cp_r = 3 & (cp_r + 3);
	draw_cp (cp_x, cp_y, cp_r, cp_id);}
    else
	err_msg ("Select a CP first");

    return (ctx);
}

/*ARGSUSED*/
cmv_rl (x, y, ctx)		/* rotate left			 */
    int x, y, ctx;
{
    if (active) {
	del_cp (cp_x, cp_y, cp_r, cp_id);
	cp_r = 3 & (cp_r + 1);
	draw_cp (cp_x, cp_y, cp_r, cp_id);}
    else
	err_msg ("Select a CP first");

    return (ctx);
}

cmv_plc (x, y, ctx)		/* place component		 */
    int x, y, ctx;
{
    char buf[40];

    if (active) {
	del_cp (cp_x, cp_y, cp_r, cp_id);
	cp_x = cp_align (x);
	cp_y = cp_align (y);
	draw_cp (cp_x, cp_y, cp_r, cp_id);
	sprintf (buf, "X=%6.3f\" Y=%6.3f\"",
		((float) x / rsun) * 0.1, ((float) y / rsun) * 0.1);
	err_msg (buf);}
    else
	err_msg ("Select a CP first");

    return (ctx);
}

C_place (cmp, x, y, r)
    struct comp *cmp;
    int x, y, r;
/****************************************************************\
* 								 *
*  C_place tries to place the component <cmp> on location <x,y>	 *
*  with rotation <r>. If it succeedes, the component entry will	 *
*  be updated and a '1' is returned. A returned '0' indicates	 *
*  that the desired placement was not possible due to design	 *
*  rule constraints.						 *
* 								 *
\****************************************************************/
{
#define xtr(a, b) (x + a * rot_m[r][0] + b * rot_m[r][1])
#define ytr(a, b) (y + a * rot_m[r][2] + b * rot_m[r][3])

    register struct pin *pp;
    register int i, j, k, x1, y1;
    int x2, y2;

    if (!(cmp -> unplaced))
	err ("C_place: already placed", cmp, x, y, r);

    if (r < 0 || r > 3 || x < 3 || y < 3 || x > V.BSX - 3 || y > V.BSX - 3)
	return 0;		/* illegal paramenter		 */

    for (i = cmp -> ty -> np, pp = cmp -> ty -> p; i; pp++, i--) {
	x1 = xtr (pp -> x, pp -> y);
	y1 = ytr (pp -> x, pp -> y);

	if( x1 < 3 || x1 > V.BSX - 3 || y1 < 3 || y1 > V.BSY - 3)
	    return 0;		/* pin is off board		 */

	if (cp_alchk (x1) || cp_alchk (y1))
	    return 0;		/* illegal pin alignment	 */

	if (!ck_pin (x1, y1))
	    return 0;		/* overlapp problem		 */
    }

    if (cmp -> ty -> cif)	/* external CIF type: block check*/
	for (i = cmp -> ty -> cif - 1; CIF[i].blk; i++) {
	    for (y1 = CIF[i].yl - 1; y1 <= CIF[i].yh + 1; y1++)
		for (x1 = CIF[i].xl - 1; x1 <= CIF[i].xh + 1; x1++)
		    if (pcb[ytr (x1, y1)][xtr (x1, y1)] & (fb | ahb | vec))
			return 0;	/* Block problem	 */
	    if (!CIF[i].flg)
		break;
	}

    /**** everthing looks fine: proceed to insert component   ****/

    color (chb, chb);		/* insert pins			 */
    for (i = cmp -> ty -> np, pp = cmp -> ty -> p; i; pp++, i--)
	if (pin (xtr (pp -> x, pp -> y), ytr (pp -> x, pp -> y))) {
	    printf ("Type definition error for '%s': pins too close\n",
		cmp -> ty -> name);
	    color (0, chb);
	    for (pp = cmp -> ty -> p; i < cmp -> ty -> np; pp++, i++)
		dpin (xtr (pp -> x, pp -> y), ytr (pp -> x, pp -> y));
	    return 0;
	}

    if (cmp -> ty -> cif) {	/* insert road blocks		 */
	color (fb, fb);
	for (i = cmp -> ty -> cif - 1; CIF[i].blk; i++) {
	    x1 = xtr (CIF[i].xl, CIF[i].yl);
	    y1 = ytr (CIF[i].xl, CIF[i].yl);
	    x2 = xtr (CIF[i].xh, CIF[i].yh);
	    y2 = ytr (CIF[i].xh, CIF[i].yh);
	    if (x1 > x2) {j = x1; x1 = x2; x2 = j;}
	    if (y1 > y2) {j = y1; y1 = y2; y2 = j;}

	    c_rect (x1, y1, x2, y2);
	    for (; y1 <= y2; y1++)
		for (k = x1; k <= x2; k++)
		    pcb[y1][k] |= fb;

	    if (!CIF[i].flg)
		break;
	}
    }

    k = ((int) cmp - (int) CP) / sizeof (struct comp);	/* get own index */
    pp = cmp -> ty -> p;
    for (i = 0, j = 0; i < V.nch; i++)
	if (CH[i].cpi == k) {
	    j++;			/* count holes	 */
	    CH[i].x = xtr (pp[CH[i].pn].x, pp[CH[i].pn].y);
	    CH[i].y = ytr (pp[CH[i].pn].x, pp[CH[i].pn].y);
	}
    if (j != cmp -> ty -> np)
	err ("C_place: inconsistent pin numbers", j, cmp -> ty -> np, 0, 0);

    cmp -> x = x;		/* update component entry	 */
    cmp -> y = y;
    cmp -> r = r;
    cmp -> unplaced = 0;

    placed = 0;			/* insure update		 */

    return 1;			/* finally done!		 */

#undef xtr
#undef ytr
}

C_unplace (cmp)
    struct comp *cmp;
/***************************************************************\
* 							        *
*  C_unplace tries to remove the component <cmp> from its       *
*  current location. It returns a '1' if it succeeds.	        *
*  A returned '0' indicates that the opaeration failed because  *
*  the component had wires connected to it.		        *
* 							        *
\***************************************************************/
{
#define xtr(a, b) (x + a * rot_m[r][0] + b * rot_m[r][1])
#define ytr(a, b) (y + a * rot_m[r][2] + b * rot_m[r][3])

    register struct pin *pp;
    register int i, x1, x = cmp -> x, y = cmp -> y, r = cmp -> r;
    int j, y1, x2, y2;
    struct hole *fndh (), *hp;
    static struct hole **chl = 0;
    static int chlmax = 100;

    if (cmp -> unplaced)
	return 1;		/* is already unplaced		 */

    for (i = cmp -> ty -> np, pp = cmp -> ty -> p; i; pp++, i--) {
	if (pcb[ytr (pp -> x, pp -> y)][xtr (pp -> x, pp -> y)] & vec)
	    return 0;		/* no wires allowed		 */

    /**** everthing looks fine: proceed to remove component   ****/

    if (!chl) {			/* allocate temp table		 */
	if (chlmax < cmp -> ty -> np)
	    chlmax = 10 + cmp -> ty -> np;
	chl = (struct hole **) malloc (sizeof (struct hole *) * chlmax);}
    else if (chlmax < cmp -> ty -> np) {
	free (chl);
	chlmax = 10 + cmp -> ty -> np;
	chl = (struct hole **) malloc (sizeof (struct hole *) * chlmax);}
    }

    color (0, selb | chb);	/* remove pins			 */
    for (i = cmp -> ty -> np, pp = cmp -> ty -> p; i; pp++) {
	x1 = xtr (pp -> x, pp -> y);
	y1 = ytr (pp -> x, pp -> y);
	hp = fndh (x1, y1);
	if (!hp)
	    err ("C_unplace: missing hole", x1, y1, i, 0);
	chl[--i] = hp;		/* save hole pointer		 */
	dpin (x1, y1);
    }

    for (i = cmp -> ty -> np; i;) {
	chl[--i] -> x = 0;	/* invalidate cooradinates	 */
	chl[i] -> y = 0;
    }

    if (cmp -> ty -> cif) {	/* remove road blocks		 */
	color (0, fb);
	for (i = cmp -> ty -> cif - 1; CIF[i].blk; i++) {
	    x1 = xtr (CIF[i].xl, CIF[i].yl);
	    y1 = ytr (CIF[i].xl, CIF[i].yl);
	    x2 = xtr (CIF[i].xh, CIF[i].yh);
	    y2 = ytr (CIF[i].xh, CIF[i].yh);
	    if (x1 > x2) {j = x1; x1 = x2; x2 = j;}
	    if (y1 > y2) {j = y1; y1 = y2; y2 = j;}

	    c_rect (x1, y1, x2, y2);
	    for (; y1 <= y2; y1++)
		for (j = x1; j <= x2; j++)
		    pcb[y1][j] &= ~fb;

	    if (!CIF[i].flg)
		break;
	}
    }

    placed = 0;			/* no longer placed		 */
    cmp -> unplaced = 1;
    flush_stat ();		/* statistics are invalid	 */

    return 1;			/* finally done!		 */

#undef xtr
#undef ytr
}

CH_update ()
/****************************************************\
* 						     *
*  Sort the hole table and update the pointer to it  *
*  (this is prerequisite for 'fndh' to work)	     *
* 						     *
\****************************************************/
{
    register int i;
    int key ();

    qsort (CH, V.nch, sizeof (CH[0]), key);	/* sort holes	 */
    for (i = 0; i < V.nch; i++)			/* adj pointers  */
	if (CH[i].n)
	    CH[i].n -> c = &CH[i];
}

key (h1, h2)			/* is used to sort the holes	*/
    struct hole *h1, *h2;
{
    if (h1 -> x > h2 -> x)
	return 1;
    if (h1 -> x < h2 -> x)
	return -1;
    if (h1 -> y > h2 -> y)
	return 1;
    if (h1 -> y < h2 -> y)
	return -1;

    return 0;
}

ck_placed ()
/****************************************************************\
* 								 *
*  Check placement:						 *
*   returns a '1' if all components are placed (and updates the	 *
*   net location info). A '0' is returned otherwise.		 *
* 								 *
\****************************************************************/
{
    register int i, j, xl, yl, xh;
    register struct nlst *p;
    int yh;

    for (i = 0, xl = V.ncp; i < xl; i++)
	if (CP[i].unplaced)
	    return 0;

    for (i = 0; i < V.nnh; i++)	/* update net locations		*/
	if (NH[i].l) {
	    xl = xmax;
	    yl = ymax;
	    xh = 0;
	    yh = 0;
	    for (p = NH[i].lp; p; p = p -> n) {
		j = p -> c -> x;
		if (j > xh) xh = j;
		if (j < xl) xl = j;
		j = p -> c -> y;
		if (j > yh) yh = j;
		if (j < yl) yl = j;
	    }
	    if (!xl)
		err ("ck_placed: invlid hole coordinate", i, xl, yl, xh);
	    NH[i].x1 = xl;
	    NH[i].x2 = xh;
	    NH[i].y1 = yl;
	    NH[i].y2 = yh;
	}

    return 1;
}

CPp_ini (ctx)			/* CP place initialization	 */
    int ctx;
{
    register int i;
    char buf[nmmax + nmmax + 3];

    if (ck_placed ()) {
	active = 0;
	return START;		/* nothing to place		 */
    }

    for (i = 0; i < V.ncp; i++)	/* find something to place	 */
	if (CP[i].unplaced)
	    break;

    cp_id = i;
    cp_x = wx + 256 / cz;
    cp_y = wy + 241 / cz;
    cp_r = 0;

    active = 1;
    draw_cp (cp_x, cp_y, 0, i);

    sprintf (buf, "%s (%s)", CP[cp_id].name, CP[cp_id].ty -> name);
    err_msg (buf);

    return ctx;
}

/*ARGSUSED*/
CPp_exc (x, y, ctx)		/* try some other component	 */
    int x, y, ctx;
{
    if (C_place (&CP[cp_id], cp_x, cp_y, cp_r)) {
	del_cp (cp_x, cp_y, cp_r, cp_id);
	CH_update ();
	return CPp_ini (ctx);
    }

    err_msg ("Invalid place");

    return ctx;
}

CPp_del (x, y, ctx)		/* delete a component		 */
    int x, y, ctx;
{
    register int i, j, k;
    char buf[nmmax + nmmax + 3];

    i = fnd_cmp (x, y);

    if (i < 0) {		/* try to select an other cmp	 */
	k = V.ncp;
	for (i = 0, j = cp_id + 1; i < k; i++)
	    if (CP[(i + j) % k].unplaced)
		break;
	i = (i + j) % k;
	if (i == cp_id)
	    err_msg ("only one CMP left");
	else {
	    del_cp (cp_x, cp_y, cp_r, cp_id);

	    cp_id = i;
	    cp_x = x;
	    cp_y = y;
	    cp_r = 0;

	    draw_cp (x, y, 0, i);

	    sprintf (buf, "%s (%s)", CP[cp_id].name, CP[cp_id].ty -> name);
	    err_msg (buf);
	}}

    else if (!C_unplace (&CP[i]))	/* delete component		 */
	err_msg ("Remove wires first");

    CH_update ();

    return ctx;
}

CPp_plc (x, y, ctx)		/* tennativly place component	 */
    int x, y, ctx;
{
    char    buf[40];

    del_cp (cp_x, cp_y, cp_r, cp_id);
    cp_x = cp_align (x);
    cp_y = cp_align (y);
    draw_cp (cp_x, cp_y, cp_r, cp_id);
    sprintf (buf, "X=%6.3f\" Y=%6.3f\"",
	    ((float) x / rsun) * 0.1, ((float) y / rsun) * 0.1);
    err_msg (buf);

    return ctx;
}

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

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

err (s, e1, e2, e3, e4)			/* error exit			*/
    char s[];
    int e1, e2, e3, e4;
{
    printf ("Error: %s -- exited\n", s);
    strncpy (V.errtxt, s, 80);
    V.err_info[0] = e1;
    V.err_info[1] = e2;
    V.err_info[2] = e3;
    V.err_info[3] = e4;
    if (s[0] != '-') {
	save (1);		/* save state for recovery	 */
	printf ("Data structure saved on 'pcb.ERR'\n");
    };
    finish ();
}

beep()			/* beep on the terminal		 */
{
    if (no_beep)
	return;
    putc (7, stdout);
    fflush (stdout);
}

pin(x, y)			/* enter pin to pcb and AED	 */
    int x, y;
{
    int     i, j, k;
    static int hx[8] = {3, 3, 0,-3,-3,-3, 0, 3};
    static int hy[8] = {0, 3, 3, 3, 0,-3,-3,-3};
    static int bx[12] = {5, 5, 5, 1, 0,-1,-5,-5,-5, 1, 0,-1};
    static int by[12] = {1, 0,-1, 5, 5, 5, 1, 0,-1,-5,-5,-5};
    static int xt[12] = {3, 3, 3, 1, 0,-1,-3,-3,-3, 1, 0,-1};
    static int yt[12] = {1, 0,-1, 3, 3, 3, 1, 0,-1,-3,-3,-3};

    for (i = x - 2; i <= x + 2; ++i)
	for (j = y - 2; j <= y + 2; ++j) {
	    k = pcb[j][i];
	    if ((k & (fb | chb | ishb)) || (!(k & selb) && k & vec) ||
		!(vec & ~k))
		return 1;	/* overlap error		 */
	}

    for (i = 0; i < 8; ++i)	/* special hole distance	 */
	if (pcb[y+hy[i]][x+hx[i]] & (ahb | fb))
	    return (1);		/* too close to hole		 */

    for (i = 0; i < 12; ++i)	/* check for small passages	 */
	if ((pcb[y+by[i]][x+bx[i]] & ahb) &&
	    ((pcb[y+yt[i]][x+xt[i]] & vec) && !(pcb[y+yt[i]][x+xt[i]] & selb)))
	    return (1);

    for (i = x - 1; i <= x + 1; ++i)
	for (j = y - 1; j <= y + 1; ++j)
	    pcb[j][i] = ccc | (ccm & pcb[j][i]);

    if (!batch)
	dot (x, y);		/* update AED 			 */

    for (i = 0; i < 12; ++i)	/* block small passages		 */
	if (pcb[y+by[i]][x+bx[i]] & ahb)
	    pxl (x + xt[i], y + yt[i]);

    return (0);
}

dot (x, y)			/* plot a 3 by 3 rectangle on AED*/

    int  x, y;
{
    int x1, y1, x2, y2;

    x1 = (x - 1 > fx) ? x - 1 : fx;
    x2 = (x < fx + 510) ? x + 1 : fx + 511;
    y1 = (y - 1 > fy) ? y - 1 : fy;
    y2 = (y < fy + 510) ? y + 1 : fy + 511;
    if ((x1 <= x2) && (y1 <= y2))
	rect (x1, y1, x2, y2);
}

dpin (x, y)		/* dot on pcb and AED (delete pin)	 */
    int x, y;
{
    int     i, j, s, t;
    static int  xt[12] = {3, 3, 3, 1, 0, -1, -3, -3, -3, 1, 0, -1};
    static int  yt[12] = {1, 0, -1, 3, 3, 3, 1, 0, -1, -3, -3, -3};

    s = (~ccm & ahb) ? pcb[y][x] & selb : 0;  /* select prot ?	 */

    for (i = 0; i < 12; ++i)/* remove guard zones		 */
	if (pcb[y + yt[i]][x + xt[i]] & ahb) {
	    t = ccc | (ccm & pcb[y + yt[i]][x + xt[i]]);
	    pcb[y + yt[i]][x + xt[i]] = (s && t & vec) ? t | s : t;
	    if (!batch)
		point (x + xt[i], y + yt[i]);
	}

    for (i = x - 1; i <= x + 1; ++i)
	for (j = y - 1; j <= y + 1; ++j) {
	    t = ccc | (ccm & pcb[j][i]);
	    pcb[j][i] = (t & vec) ? t | s : t;
	}

    if (!batch)
	dot (x, y);		/* update AED 			 */

    return 0;	/* this 0 is used, even if lint does not think so  :-) */
}

ck_pin (x, y)			/* check possibe via hole position */
    int x, y;
/*******************************************************************\
* 								    *
*  A 1 is returned if it is possible to insert a via-hole at <x,y>  *
* 								    *
\*******************************************************************/
{
    int     i, j, k;
    static int hx[8] = {3, 3, 0,-3,-3,-3, 0, 3};
    static int hy[8] = {0, 3, 3, 3, 0,-3,-3,-3};
    static int bx[12] = {5, 5, 5, 1, 0,-1,-5,-5,-5, 1, 0,-1};
    static int by[12] = {1, 0,-1, 5, 5, 5, 1, 0,-1,-5,-5,-5};
    static int xt[12] = {3, 3, 3, 1, 0,-1,-3,-3,-3, 1, 0,-1};
    static int yt[12] = {1, 0,-1, 3, 3, 3, 1, 0,-1,-3,-3,-3};

    for (i = x - 2; i <= x + 2; ++i)
	for (j = y - 2; j <= y + 2; ++j) {
	    k = pcb[j][i];
	    if ((k & (fb | chb | ishb)) || ((k & vec) && !(k & selb)) ||
		!(vec & ~k))
		return 0; 	/* overlap error		 */
	}

    for (i = 0; i < 8; ++i)	/* special hole distance	 */
	if (pcb[y+hy[i]][x+hx[i]] & (ahb | fb))
	    return (0);		/* too close to hole		 */

    for (i = 0; i < 12; ++i)	/* check for small passages	 */
	if ((pcb[y+by[i]][x+bx[i]] & ahb) &&
	    ((pcb[y+yt[i]][x+xt[i]] & vec) && !(pcb[y+yt[i]][x+xt[i]] & selb)))
	    return (0);

    return (1);			/* good place for a hole	 */
}

plt(x1, y1, x2, y2)			/* Plot a line		*/
    int x1, y1, x2, y2;
{
    int     dx, dy, n;

    if ((x1 != x2) && (y1 != y2) && (abs (x1 - x2) != abs (y1 - y2)))
	err ("invalid slope", x1, y1, x2, y2);

    if (!batch)
	plts (x1, y1, x2, y2);

    dx = (x1 < x2) - (x2 < x1);
    dy = (y1 < y2) - (y2 < y1);

    n = abs (x1 - x2);
    if (!n)
	n = abs (y2 - y1);

    while (n >= 0) {
	pcb[y1][x1] = ccc | (ccm & pcb[y1][x1]);
	x1 += dx;
	y1 += dy;
	n--;
    };
};

plts (x1, y1, x2, y2)		/* plot a line on the AED	 */
    int x1, y1, x2, y2;
{
    int     t;

    if (batch)
	return;

    if (y1 > y2) {		/* order y for y-band clipping	 */
	t = x1;
	x1 = x2;
	x2 = t;
	t = y1;
	y1 = y2;
	y2 = t;
    };
    t = ((x1 < x2) - (x2 < x1));

    if (y1 < fy) {
	if (y2 < fy)
	    return;
	x1 += (fy - y1) * t;
	y1 = fy;
    };

    if (y2 > (fy + 511)) {
	if (y1 > (fy + 511))
	    return;
	x2 -= (y2 - (fy + 511)) * t;
	y2 = fy + 511;
    };

    if (x1 > x2) {		/* order x for x-band clipping	 */
	t = x1;
	x1 = x2;
	x2 = t;
	t = y1;
	y1 = y2;
	y2 = t;
    };
    t = (y1 < y2) - (y2 < y1);

    if (x1 < fx) {
	if (x2 < fx)
	    return;
	y1 += (fx - x1) * t;
	x1 = fx;
    };

    if (x2 > (fx + 511)) {
	if (x1 > (fx + 511))
	    return;
	y2 -= (x2 - (fx + 511)) * t;
	x2 = fx + 511;
    };

    if (x1 <= x2)
	plts1 (x1, y1, x2, y2);
    else
	plts1 (x2, y2, x1, y1);
}

plts1 (x1, y1, x2, y2)		/* plot line on aed		 */
    int x1, y1, x2, y2;
{
    int     t;

    if ((x1 & 0xfffffe00) != (x2 & 0xfffffe00)) {
	t = (y2 > y1) - (y2 < y1);
	x1 &= 511;
	plts1 (0, y1 + (512 - x1) * t, x2 & 511, y2);
	x2 = 511;
	y2 = y1 + (511 - x1) * t;
    };

    if (y2 < y1) {	/* this could be optimized with more thinking */
	t = y1;
	y1 = y2;
	y2 = t;
	t = x1;
	x1 = x2;
	x2 = t;
    };

    if ((y1 & 0xfffffe00) != (y2 & 0xfffffe00)) {
	t = (x2 > x1) - (x2 < x1);
	y1 &= 511;
	plts1 (x1 + (512 - y1) * t, 0, x2, y2 & 511);
	y2 = 511;
	x2 = x1 + (511 - y1) * t;
    };

    move (x1, y1);
    draw (x2, y2);
}

menu (s, n)			/* menu function select		 */
    char *s[];
    int n;
/*********************************************************************\
* 								      *
* The <n> strings will be displayed on the screen. If the cursor      *
* is clicked (any key) on a string, the coresponding number <0..n-1>  *
* is returned. Otherwise, a -1 will be returned.		      *
* 								      *
\*********************************************************************/
{
    int     i, j, x, y;

    if (cz > 2)			/* No menu on large zooms	 */
	zoom (2);
    msg_off ();

    j = (cz == 1) ? 13 : 8;	/* line spaceing		 */

    color (resb, resb);

    for (i = 0; i < n; i++)
	atext (wx + 20 / cz, wy + 462 / cz - (i + 1) * j, s[i], 2 - cz);

    i = getcur (&x, &y);
    if (i < 0)
	err ("menu: couldn't read cursor", i, x, y, 0);

    color (0, resb);
    rect (wx + 20 / cz, wy + 452 / cz - n * j, wx + 300 / cz, wy + 462 / cz);

    if (x >= wx + 20 / cz  && x < wx + 160 &&
	y <= wy + 462 / cz && y > wy + 462 / cz - n * j) {
	msg_on ();
	return ((wy + 462 / cz - y) / j);}
    else {
	err_msg ("Nothing selected");
	return (-1);
    }
}

clp_plt (x0, y0, x1, y1, xl, yl, xh, yh)	/* clip plot	 */
    int x0, y0, x1, y1, xl, yl, xh, yh;
{
    float   a, b, c;
    int     t;

    if (batch)			/* redundant			 */
	return;

    if (xh < xl || yh < yl ||
	    ((x0 < xl && x1 < xl) || (x0 > xh && x1 > xh)) ||
	    ((y0 < yl && y1 < yl) || (y0 > yh && y1 > yh)))
	return;			/* nothing to plot		 */

    if (x0 == x1 && y0 == x1) {	/* just one point		 */
	point (x0, x1);
	return;
    }

    a = y0 - y1;		/* get vector equation		 */
    b = x1 - x0;
    c = y0 * x1 - x0 * y1;

    if (x0 > x1) {		/* insure x0 <= x1		 */
	t = x0;
	x0 = x1;
	x1 = t;
	t = y0;
	y0 = y1;
	y1 = t;
    }

    if (x0 < xl) {		/* xl - clip			 */
	x0 = xl;
	y0 = (b == 0.0) ? y0 : (c - a * (float) xl) / b;
    }

    if (x1 > xh) {		/* xh - clip			 */
	x1 = xh;
	y1 = (b == 0.0) ? y1 : (c - a * (float) xh) / b;
    }

    if (y0 > y1) {		/* insure y0 <= y1		 */
	t = x0;
	x0 = x1;
	x1 = t;
	t = y0;
	y0 = y1;
	y1 = t;
    }

    if (y0 > yh || y1 < yl)	/* out of area ?		 */
	return;

    if (y0 < yl) {		/* yl - clip			 */
	y0 = yl;
	x0 = (a == 0.0) ? x0 : (c - b * (float) yl) / a;
    }

    if (y1 > yh) {		/* yh - clip			 */
	y1 = yh;
	x1 = (a == 0.0) ? x1 : (c - b * (float) yh) / a;
    }

    if (x0 == x1 && y0 == x1)	/* draw result			 */
	point (x0, x1);
    else {
	move (x0, y0);
	draw (x1, y1);
    }
}

aed_plt (x0, y0, x1, y1)	/* plot on aed within window	 */
    int x0, y0, x1, y1;
{
    int     xl, yl, xh, yh;
    static int  msk = 0xfffffe00;

    xl = wx;
    xh = wx + 511 / cz;
    yl = wy;
    yh = wy + 482 / cz;

    if ((xl&msk) != (xh&msk)) {	/* need to split x		 */
	if ((yl&msk) != (yh&msk)) {/* need to split y		 */
	    clp_plt (x0, y0, x1, y1, xl, yl, (xl&msk) + 511, (yl&msk) + 511);
	    clp_plt (x0, y0, x1, y1, (xl&msk) + 512, yl, xh, (yl&msk) + 511);
	    clp_plt (x0, y0, x1, y1, xl, (yl&msk) + 512, (xl&msk) + 511, yh);
	    clp_plt (x0, y0, x1, y1, (xl&msk) + 512, (yl&msk) + 512, xh, yh);}
	else {
	    clp_plt (x0, y0, x1, y1, xl, yl, (xl&msk) + 511, yh);
	    clp_plt (x0, y0, x1, y1, (xl&msk) + 512, yl, xh, yh);
	}}
    else {
	if ((yl&msk) != (yh&msk)) {/* need to split y */
	    clp_plt (x0, y0, x1, y1, xl, yl, xh, (yl&msk) + 511);
	    clp_plt (x0, y0, x1, y1, xl, (yl&msk) + 512, xh, yh);}
	else
	    clp_plt (x0, y0, x1, y1, xl, yl, xh, yh);
    }
}


chg_color ()
/************************************************\
* 						 *
*  Change color: interactive changing of colors	 *
* 						 *
\************************************************/
{
    register int    i, j, bs, bl, x, y;
    int             ix, iy;
    char            *ln[ncolors + 1];
    struct color_tab t;

    ln[0] = "flip sides";
    for (i = 0; i < ncolors; i++)
	ln[i + 1] = Color_tab[i].name;

    if (0 <= (i = menu (ln, ncolors + 1))) {	/* change it	 */

        if (!i) {			/* just flip s1b/s2b	 */
	    t = Color_tab[CT_s1_n];
	    Color_tab[CT_s1_n] = Color_tab[CT_s2_n];
	    Color_tab[CT_s2_n] = t;
	    t = Color_tab[CT_s1_s];
	    Color_tab[CT_s1_s] = Color_tab[CT_s2_s];
	    Color_tab[CT_s2_s] = t;
	    ldcmp ();
	    return;}
        else
	    i--;

	j = (cz == 1) ? 13 : 8;	/* line spaceing		 */
	x = wx + 20 / cz;	/* x-start point		 */
	y = wy + 462 / cz;	/* y-start point		 */
	bs = wx + 128 / cz;	/* bar start			 */
	bl = (cz == 1) ? 255 : 127;	/* bar length		 */

 	msg_off ();
	color (resb, resb);

	draw_bar (x, y, "Red", Color_tab[i].r, bs, bl, j);
	draw_bar (x, y - j, "Green", Color_tab[i].g, bs, bl, j);
	draw_bar (x, y - j * 2, "Blue", Color_tab[i].b, bs, bl, j);

	while (getcur (&ix, &iy) < 4) {	/* change it		 */
	    if (ix < bs || ix > (bs + bl))
		break;
	    ix = (ix - bs) * cz;
	    iy = (iy - (y - 2 * j)) / j;
	    if (iy < 0 || iy > 2)
		break;
	    switch (iy) {
		case 0: 	/* blue				 */
		    Color_tab[i].b = ix;
		    new_bar (y - 2 * j, ix, bs, bl, j - 3);
		    break;
		case 1: 	/* Green			 */
		    Color_tab[i].g = ix;
		    new_bar (y - j, ix, bs, bl, j - 3);
		    break;
		case 2: 	/* red				 */
		    Color_tab[i].r = ix;
		    new_bar (y, ix, bs, bl, j - 3);
		    break;
	    }
	    ldcmp ();
	}

	color (0, resb);	/* clean it			 */
	rect (x, y - 2 * j, x + 384 / cz, y + j);
	msg_on ();
    }
}

draw_bar (x, y, s, v, bs, bl, dy)	/* draw a value bar	 */
    int x, y, v, bs, bl, dy;
    char *s;
{
    atext (x, y, s, 2 - cz);
    new_bar (y, v, bs, bl, dy - 3);
}

new_bar (y, v, bs, bl, dy)		/* plain bar		 */
    int y, v, bs, bl, dy;
{
    color (resb, resb);
    rect (bs, y, bs + bl, y + dy);
    v /= cz;
    if (v < (bl - 1) && v >= 0) {/* the value (v) should be in [0,255] */
	color (0, resb);
	rect (bs + v + 1, y + 1, bs + bl - 1, y + dy - 1);
	color (resb, resb);
    }
}

struct nlst *deq_NL ()		/* alocate a NL element		 */
{
    register struct nlst *p;

    if (V.enll) {		/* recycle old ones		 */
	p = V.enll;
	V.enll = p -> n;}
    else {
	if (V.nnl >= nlmax)
	    err ("Net list space too small: increase 'nlmax'", nlmax, 0, 0,0);
	p = &NL[V.nnl++];
    }

    return p;
}

	
!E!O!F!
#
# type    sh /usru0/agn/pcb/distr/../usenet/part7   to unpack this archive.
#
echo extracting pwide.c...
cat >pwide.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	Wide wire support stuff					*
*								*
*	(c) 1985	A. Nowatzyk				*
*								*
\***************************************************************/

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

extern char uc_tab[];			/* see pwork: ck_rdnb		 */
extern int pdr[8];			/* offset direction table	 */
extern int sp[9][2];			/* search pattern		 */
extern char drc_tab1[256];		/* drc decision table		 */

static char **pnt_lst = 0;		/* point list			 */
static int pnt_max = xmax;		/* max number of points		 */
static int pnt_cnt;			/* point count			 */

static int side;			/* side to work on		 */

fnd_pnt (x, y)
    int x, y;
/**************************************************************************\
* 									   *
*   find points: (similar to fnd_seg of pplow.c)			   *
*     <x,y> must point to a part of a trace on side "side". fnd_pnt dumps  *
*     the pointer to all bits of that segment on the segment list. The	   *
*     segment is terminated by either the center of a hole, the center	   *
*     of a 'Y' or the last point of a floating end. The terminating	   *
*     point *is* added to the segment list.				   *
* 									   *
\**************************************************************************/
{
    register int i;

    if (!pnt_lst) {		/* alloacte point list	 */
	pnt_lst = (char **) malloc (sizeof (char *) * pnt_max);
    }
    pnt_cnt = 0;		/* reset point list counter	 */

    if (!(pcb[y][x] & side))
	return;			/* no start point !!		 */

    for (i = 0; i <= 8; i++)	/* find direction		 */
	if (pcb[y + dr[i][1]][x + dr[i][0]] & side)
	   break;

    if (i > 7)
	return;			/* start on single point ??	 */

				/* scan one way			 */
    pnt_scan (&pcb[y][x], i, side);
				/* scan the other way		 */
    pnt_scan (&pcb[y + dr[i][1]][x + dr[i][0]], (i + 4) & 7, side);
}

pnt_scan (p, d, s)
    char *p;
    int d, s;
/****************************************************************\
* 								 *
*  Point scan:							 *
*    <p> points to the start point. <d> is the direction of the	 *
*    next point. The next point will be added to the list. Scan	 *
*    stops if that point was a terminal, that is the center of	 *
*    a hole, a 'Y' or an floating end.				 *
* 								 *
\****************************************************************/
{
    register char *pp;
    register int i, j = d, ss = ~s, k, l;
    int m;

    pp = p + pdr[j];

    do {

        if (pnt_cnt >= pnt_max) {	/* need more space	 */
	    pnt_max += 10 + pnt_max / 2;
	    pnt_lst = (char **) realloc (pnt_lst, sizeof (char *) * pnt_max);
	}

	pnt_lst[pnt_cnt++] = pp;	/* add point		 */
	
	i = 0;
        if (*(pp        + 1) & ~ss) i++;
        if (*(pp + xmax + 1) & ~ss) i++;
        if (*(pp + xmax    ) & ~ss) i++;
        if (*(pp + xmax - 1) & ~ss) i++;
        if (*(pp        - 1) & ~ss) i++;
        if (*(pp - xmax - 1) & ~ss) i++;
        if (*(pp - xmax    ) & ~ss) i++;
        if (*(pp - xmax + 1) & ~ss) i++;

	if (i > 2) {		/* check for a real Y		 */
	    for (m = 0; m < 8; m++)
		if (*(pp + pdr[m]) & ~ss) {
		    k = 0;
		    for (l = 0; l < 8; l++)
			if (*(pp + pdr[m] + pdr[l]) & ~ss)
			    k |= 1 << l;
		    i -= uc_tab[k];
		}
	}

        if (i != 2) break;	/* floating or Y terminal point	 */

        if (*pp & ahb &&	/* hole terminal point check	 */
	    *(pp        + 1) & ahb &&
	    *(pp + xmax + 1) & ahb &&
	    *(pp + xmax    ) & ahb &&
	    *(pp + xmax - 1) & ahb &&
	    *(pp        - 1) & ahb &&
	    *(pp - xmax - 1) & ahb &&
	    *(pp - xmax    ) & ahb &&
	    *(pp - xmax + 1) & ahb    ) break;

        for (i = 6; i < 11; i++)	/* find new direction	 */
	    if (*(pp + pdr[(j + i) & 7]) & ~ss)
		break;
	pp += pdr[j = (j + i) & 7];

    } while (i < 11);
}

expand (n)			/* widen wire by n		 */
    int n;
{
    static int wt5[12] = 
	{2, xmax + 2, 2 * xmax + 1, 2 * xmax, 2 * xmax - 1, xmax - 2,
	 -2, -2 - xmax, -1 - 2 * xmax, -2 * xmax, 1 - 2 * xmax, 2 - xmax};
    static int *wt[2] = {pdr, wt5};
    static int wl[2] = {8, 12};
    register int i, j, k, t;
    register char *p;

    if (n < 0 || n > 1)
	return;			/* you may want to add 2, 3...	 */

    t = ~side;			/* DRC test			 */

    for (i = 0; i < pnt_cnt; i++)
	for (j = 0; j < wl[n]; j++) {
	    p = pnt_lst[i] + wt[n][j];	/* new candidate	 */
	    if (*p & side)
		continue;		/* already taken	 */

	    for (k = 0; k < 8; k++) 	/* check DRC		 */
		if (drc_tab1[*(p + pdr[k]) & 0xff] & ~t)
		    break;

	    if (k >= 8)			/* ok			 */
		pxl (((int) p - (int) pcb) % xmax,
		     ((int) p - (int) pcb) / xmax);
	}
}

wide_wire (ctx)			/* wide wire function		 */
    int ctx;
{
    struct nlhd *get_net (), *net;
    register int i, j;
    int x, y;
    static char *mtext[] = {
	"13 mil (default)",
	"38 mil",
	"63 mil"
    };

    err_msg ("Point to wire");
    getcur (&x, &y);

    for (i = 0; i < 9; i++)	/* look for wire		 */
	if (pcb[y + sp[i][1]][x + sp[i][0]] & vec)
	    break;

    if (i >= 9) {
	err_msg ("No wire found");
	return ctx;
    }

    x += sp[i][0];		/* update wire pointer		 */
    y += sp[i][1];
    side = pcb[y][x] & vec;
    if (side == vec)
	side = top_side;

    for (i = 0, j = 0; i < 8; i++)
	if (pcb[y + dr[i][1]][x + dr[i][0]] & side)
	    j++;
    if (j > 2) {
	err_msg ("no expand on expanded wire");
	return ctx;
    }

    switch (menu (mtext, 3)) {
	case 1:
	    i = 1;		/* 2 raster units + line width	 */
	    break;
	case 2:
	    i = 2;		/* 4 raster units + line width	 */
	    break;
	default:
	    err_msg ("No change made");
	    return ctx;
    }

    net = get_net (x, y, side);	/* find net			 */

    if (V.cnet != net) {	/* select it			 */
	if (V.cnet)
	    deseln (V.cnet);
	selnet (net);
    }

    fnd_pnt (x, y);		/* find the stuff		 */

    color (selb | side, selb | side);	/* set up color		 */
    for (j = 0; j < i; j++)
	expand (j);		/* here we go			 */

    for (i = 0; i < pnt_cnt; i++)
	if (*pnt_lst[i] & ahb) {	/* clean up holes	 */
	    x = ((int) pnt_lst[i] - (int) pcb) % xmax;
	    y = ((int) pnt_lst[i] - (int) pcb) / xmax;
	    ckgp (x, y, s1b);
	    ckgp (x, y, s2b);
	}

    return net_sel (START);
}
!E!O!F!