[net.sources] PCB part 9 of 10

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

#
# type    sh /usru0/agn/pcb/distr/../usenet/part9   to unpack this archive.
#
echo extracting pupdate.c...
cat >pupdate.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	Reverse Engineering and Patch Department		*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/

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

extern rot_m[4][4];		/* rotation matrix (in pplace)	 */

FILE *fwantread (), *fwantwrite ();

extern float scalef;		/* scale factor			 */
static int brutal;		/* =1 remove old stuff		 */

P_list ()			/* list internal structures	 */
{
     static char *mtext[] = {
	"Type file",
	"Component file",
	"Netlist" };

    switch (menu (mtext, 3)) {
	case 0:
	    TY_list ();
	    break;
	case 1:
	    CP_list ();
	    break;
	case 2:
	    NL_list ();
	    break;
    }
}

/*ARGSUSED*/
P_update (ctx)			/* update internal structures	 */
     int ctx;
{
    static char *mtext[] = {
	"Type file",
	"Component file",
	"Netupdate" };

    if (V.cnet)
	deseln (V.cnet);

    switch (menu (mtext, 3)) {
	case 0:
	    TY_update ();
	    break;
	case 1:
	    CP_update ();
	    break;
	case 2:
	    NL_update ();
	    break;
    }

    return net_sel (START);
}

TY_list ()			/* list type file		 */
{
    FILE *opf, *fwantwrite ();
    static char *ptype[] = { "GND", "Vcc", "Vee", "Vtt" };
    char fname[80];
    register int i, j, k;
    register struct pin *pin;
    float cf = 1.0 / rsun;

    opf = fwantwrite (".", "test.ty", fname, "Type def. output file:", 1);
    if (!opf) {
	err_msg ("File open problem");
	return;
    }
    Ferr_msg ("Busy: Listing types");

    fputs ("*types:\n", opf);

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

	if (!strcmp (TY[i].name, DELETED))
	    continue;

	fprintf (opf, "%s:\n", TY[i].name);
	if (TY[i].cif) {		/* external cif-symbol	 */
	    j = TY[i].cif - 1;
	    fprintf (opf, "EXTcif: %d\n", CIF[j].symn);
	    fprintf (opf, "Box: %.3f,%.3f\n",
		(float) TY[i].x * cf, (float) TY[i].y * cf);
	    do {
		if (CIF[j].blk)
		    fprintf (opf, "Block: %.3f,%.3f %.3f,%.3f\n",
			(float) CIF[j].xl * cf, (float) CIF[j].yl * cf,
			(float) CIF[j].xh * cf, (float) CIF[j].yh * cf );}
	    while (CIF[j++].flg);
	}
	for (pin = TY[i].p, j = 1; TY[i].np >= j; pin++, j++) {
	    if (k = pin -> p)
		fprintf (opf, "%.3f,%.3f\t%s\n",
		    (float) (pin -> x) * cf, (float) (pin -> y) * cf,
		    ptype[--k]);
	    else
		fprintf (opf, "%.3f,%.3f\tpin%d\n",
		    (float) (pin -> x) * cf, (float) (pin -> y) * cf, j);
	}
	fputs ("\n", opf);
    }
    fclose (opf);
    err_msg ("Done");
    beep ();
}

CP_list ()			/* list component file		 */
{
    FILE *opf, *fwantwrite ();
    char fname[80];
    register int i;
    float cf = 1.0 / rsun;

    opf = fwantwrite (".", "test.cp", fname, "Component output file:", 1);
    if (!opf) {
	err_msg ("File open problem");
	return;
    }
    Ferr_msg ("Busy: Listing components");

    fputs ("*components:\n", opf);

    for (i = 0; i < V.ncp; i++) {

	if (!strcmp (CP[i].name, DELETED))
	    continue;

	if (CP[i].unplaced)
	    fprintf (opf, "%s\t%s\t\t; ** unplaced **\n",
		CP[i].name, CP[i].ty -> name);
	else
	    fprintf (opf, "%s\t%s\t%.3f,%.3f\t%d\n",
		CP[i].name, CP[i].ty -> name, (float) CP[i].x * cf,
		 (float) CP[i].y * cf, CP[i].r);
    }

    fclose (opf);
    err_msg ("Done");
    beep ();
}

static int nl_type;		/* 0: Multiwire   1: DP		 */
static FILE *opf;

NL_list ()			/* list netlist			 */
{
    FILE *fwantwrite ();
    char fname[80];
    register int i;

    if (!placed) {
	err_msg ("Place components first");
	return;
    }

    opf = fwantwrite (".", "test.nl", fname, "Netlist output file:", 1);
    if (!opf) {
	err_msg ("File open problem");
	return;
    }
    Ferr_msg ("Busy: Printing Netlist");

    nl_type = NH[0].name[0] != '#';	/* decide on format	 */

    if (nl_type)
	fputs ("DPnetlist:\n", opf);
    else
	fputs ("Cnetlist:\n", opf);

    pnt_net (&V.GND, 1);		/* print special nets	 */
    pnt_net (&V.VCC, 1);
    pnt_net (&V.VEE, 1);
    pnt_net (&V.VTT, 1);

    for (i = 0; i < V.nnh; i++)		/* print normal nets	 */
	pnt_net (&NH[i], 0);

    fclose (opf);
    err_msg ("Done");
    beep ();
}

pnt_net (net, sp)		/* print a net			 */
    struct nlhd *net;
    int sp;
{
    register int i;
    register struct nlst *p;
    static int nc;		/* net counter for MW-format	 */

    if (!(net -> l))		/* skip empty nets		 */
	return;

    nc++;
    if (sp)			/* reset net counter		 */
	nc = 0;

    for (p = net -> lp, i = 0; p; p = p -> n, i++) {/* scan net	 */

	if (!(i & 7)) {		/* denote net			 */

	    if (nl_type) {	/* DP-type names		 */
		if (sp) {
		    if (i)
			fputc ('\n', opf);
		    fprintf (opf, "!%s\\", net -> name);}
		else if (!i)
		    fprintf (opf, "%s\\", net -> name);}

	    else {		/* Multi-wire names		 */
		if (i)
		    fputc ('\n', opf);
		if (sp)
		    fprintf (opf, "C%s\t", net -> name);
		else
		    fprintf (opf, "%d\t", nc);
	    }
	}

	fprintf (opf, " %s-%d", CP[p -> c -> cpi].name, p -> c -> pn + 1);
    }

    fputc ('\n', opf);
}

static struct type new_ty;	/* temporary place for a type def	 */
static struct pin *new_pin = 0;
static struct cif *new_cif = 0;
static int npn_max = 100, ncf_max = 50, lcnt, cif_cnt;
static FILE *inp;

TY_update ()
/**************************************************************************\
* 									   *
*  Update type file:							   *
*   The stored type definitions are compared those supplied by the	   *
*   file. Updates will be made only if the particular type is not in use.  *
* 									   *
\**************************************************************************/
{
    char    fname[80], *flgs, buf[80];
    register int i;
    float getfloat ();

    inp = fwantread (".", "test.ty", fname, "New type definition file:");
    if (!inp) {
        err_msg ("Open failed");
	return;
    }

    scalef = getfloat ("Scale factor for pin coordinates", 0.01, 100.0, 1.0);
    brutal = getbool ("Brutal update", 0);

    fgets (buf, inp_lnl, inp);
    if (strncmp (buf, "*types:", 7)) {
	printf ("Type-def file doesn't start with '*types:'");
	err_msg ("Format error");
	beep ();
	fclose (inp);
	return;
    }

    flgs = (char *) malloc (sizeof (char) * tymax);
    for (i = 0; i < V.nty; flgs[i++] = 0);

    lcnt = 1;			/* reset line counter		 */
    Ferr_msg ("Busy: type update");

    while (i = get_ty ()) {
	if (i < 0)
	    printf ("Skipping defective type definition\n");
	else {
	    for (i = 0; i < V.nty; i++)	/* try to find old def	 */
		if (!strncmp (TY[i].name, new_ty.name, nmmax))
		    break;

	    if (i >= V.nty) {
		printf ("Adding '%s'\n", new_ty.name);
		add_TY ();	/* add new type			 */
		flgs[V.nty - 1] = 1;}
	    else {
		if (flgs[i]) {
		    printf ("Line%d: '%s' multiply defined\n",
			lcnt, new_ty.name);
		    continue;
		}
		flgs[i] = 1;	/*  this entry is referenced	 */
		if (neq_TY (&TY[i])) {
		    if (replace_TY (&TY[i]))
			printf ("New definition for '%s' loaded\n",
			    new_ty.name);
		    else
			printf ("Cannot update '%s': in use\n",
			    new_ty.name);
		}
	    }
	}
    }

    for (i = 0; i <V.nty; i++)
	if (!flgs[i] && strcmp (DELETED, TY[i].name)) {
	    strncpy (buf, TY[i].name, nmmax);
	    if (del_TY (&TY[i]))
		printf ("Type '%s' deleted\n", buf);
	    else
		printf ("Cannot delete '%s': in use\n", buf);
	}		

    free (flgs);		/* clean up & exit		 */
    fclose (inp);
    err_msg ("Done");
    beep ();
}

get_ty ()			/* get a new type		 */
{
    char    buf[inp_lnl], nm[nmmax + 2], ga[nmmax + 2];
    register int j, k, ix, iy, error = 0;
    int i;
    float   x, y, x1, y1;
    static char pln[4][4] = {"GND", "VCC", "VEE", "VBB"};

    if(!fgets (buf, inp_lnl, inp))
	return 0;		/* no more types		 */

    rms (buf);
    lcnt++;			/* count lines for error msg	 */

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

    new_ty.x = 0;
    new_ty.y = 0;
    new_ty.np = 0;
    new_ty.cif = 0;
    new_ty.p = nil;

    cif_cnt = 0;

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

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

	    if (j != 1 || i < ex_cifL || i > ex_cifH || new_ty.cif) {
		printf ("Line %d: illegal 'EXTcif'\n", lcnt);
		error = 1;}
	    else {
		if (!new_cif) 	/* need to allocate cif tab	 */
		    new_cif = (struct cif *) malloc
				(sizeof (struct cif) * ncf_max);
		else if (cif_cnt >= ncf_max) {	/* too small	 */
		    ncf_max += 10 + ncf_max / 2;
		    new_cif = (struct cif *) realloc
				(new_cif, sizeof (struct cif) * ncf_max);
		}

		new_cif[cif_cnt].symn = i;
		new_cif[cif_cnt].flg = 0;
		new_cif[cif_cnt].blk = 0;
		new_ty.cif = 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", lcnt);
		error = 1;}
	    else {
		ix = x * rsun * scalef + 0.5;
		iy = y * rsun * scalef + 0.5;
		if (new_ty.x < ix) new_ty.x = ix;
		if (new_ty.y < iy) new_ty.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 || !new_ty.cif ||
		ix > new_ty.x || iy > new_ty.y) {
		printf ("Line %d: invalid 'Block' statement\n", lcnt);
		error = 1;}
	    else {
		if (new_cif[cif_cnt].blk) {	/* need additional record */
		    new_cif[cif_cnt].flg = 1;
		    if (cif_cnt >= ncf_max) {
			ncf_max += 10 + ncf_max / 2;
			new_cif = (struct cif *) realloc
				(new_cif, sizeof (struct cif) * ncf_max);
		    }
		    new_cif[++cif_cnt].flg = 0;
		    new_cif[cif_cnt].symn = new_cif[0].symn;
		}
		new_cif[cif_cnt].blk = 1;
		new_cif[cif_cnt].xh = ix;
		new_cif[cif_cnt].yh = iy;
		new_cif[cif_cnt].xl = x * rsun * scalef + 0.5;
		new_cif[cif_cnt].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;		/* end of one definition	 */

	    k = 0;		/* default type			 */
	    switch (j) {
		case 1: 
		    printf ("Line %d: missing y - line ignored\n", lcnt);
		    error = 1;
		    break;
		case 4: 
		    printf ("Line %d: grabage '%s..' ignored\n", lcnt, ga);
		    error = 1;
		    break;
		case 3: 
		    for (k = 0; k < 4; ++k)
			if (!strncmp (pln[k], nm, nmmax))
			    break;
		    k = (k + 1) % 5;
		case 2:
		    if (!new_pin)
			new_pin = (struct pin *) malloc (
					sizeof (struct pin) * npn_max);
		    else if (new_ty.np >= npn_max) {
			npn_max += 10 + npn_max / 2;
			new_pin = (struct pin *) realloc (new_pin,
					sizeof (struct pin) * npn_max);
		    }

		    new_ty.p = new_pin;
		    ix = x * rsun * scalef + 0.5;
		    iy = y * rsun * scalef + 0.5;
		    if (new_ty.x < ix) new_ty.x = ix;
		    if (new_ty.y < iy) new_ty.y = iy;
		    new_pin[new_ty.np].x = ix;
		    new_pin[new_ty.np].y = iy;
		    new_pin[new_ty.np++].p = k;
	    }
	}
    }

    if (new_ty.y > new_ty.x)
	printf ("Warning for '%s': y>x (text is aligned to the x-axis)\n",
		 new_ty.name);

    return error ? -1 : 1;
}

add_TY ()			/* add new type definition	 */
{
    register int i;

    if (V.ncif + cif_cnt >= cifmax)
	err ("EXTcif table too small: increase 'cifmax'", cifmax, 0, 0, 0);
    if (V.npn + new_ty.np > pnmax)
	err ("Pin table too small: increase 'pnmax'", pnmax, 0, 0, 0);
    if (V.nty > tymax)
	err ("Type table too small: increase 'tymax'", tymax, 0, 0, 0);

    new_ty.p = &PN[V.npn];	/* adjust pointer and index	 */

    if (new_ty.cif)
	new_ty.cif = V.ncif + 1;

    TY[V.nty++] = new_ty;	/* enter type			 */

    for (i = 0; i < new_ty.np; i++)	/* copy pins		 */
	PN[V.npn++] = new_pin[i];

    if (new_ty.cif) {		/* copy cif records		 */
	for (i = 0; i <= cif_cnt; i++)
	    CIF[V.ncif++] = new_cif[i];
    }
}

neq_TY (old)
    struct type *old;
/************************************************************************\
* 									 *
*  .NE. types:								 *
*   This function comapres 2 type definitions and returns a '1' if they	 *
*   differ. The primary reason of difference is printed.		 *
* 									 *
*   Note: the second type is hardwired to 'new_ty'			 *
* 									 *
\************************************************************************/
{
    register int i, j;

    if (new_ty.np != old -> np) {
	printf ("Type '%s' - number of pins: old=%d new=%d\n",
	    new_ty.name, old -> np, new_ty.np);
	return 1;
    }

    for (i = 0; i < new_ty.np; i++) {
	if (new_pin[i].x != (old -> p)[i].x ||
	    new_pin[i].y != (old -> p)[i].y   ) {
	    printf ("Type '%s' - pin%d has new position\n", new_ty.name, ++i);
	    return 1;
	}
	if (new_pin[i].p != (old -> p)[i].p) {
	    printf ("Type '%s' - pin%d has new type\n", new_ty.name, ++i);
	    return 1;
	}
    }

    if (!new_ty.cif != !old -> cif) {
	printf ("Type '%s' - type: old=%s new=%s\n", new_ty.name,
	    old -> cif ? "EXTcif" : "normal",
	    new_ty.cif ? "EXTcif" : "normal");
	return 1;
    }

    if (new_ty.cif) {
	i = 0; 
	j = old -> cif - 1;
	do {
	    if (new_cif[i].symn != CIF[j].symn) {
		printf ("Type '%s' - CIF number: old=%d new=%d\n",
		    new_ty.name, CIF[j].symn, new_cif[i].symn);
		return 1;
	    }
	    if (new_cif[i].blk != CIF[j].blk) {
		printf ("Type '%s' - different number of blocks\n",
		    new_ty.name);
		return 1;
	    }
	    if (new_cif[i].blk && (
		new_cif[i].xl != CIF[j].xl ||
		new_cif[i].xh != CIF[j].xh ||
		new_cif[i].yl != CIF[j].yl ||
		new_cif[i].yh != CIF[j].yh    )) {
		printf ("Type '%s' - different block dimensions\n",
		    new_ty.name);
		return 1;
	    }
	    j++;}
        while (new_cif[i++].flg);
    }

    return 0;			/* they match			 */
}

replace_TY (old)
    struct type *old;
/**************************************************************************\
* 									   *
*  Replace a type definition:						   *
*   The old type definition <old> is replaced by the new one in "new_ty".  *
*   A '1' is returned if the operation succeeds. A returned '0' indicates  *
*   that the type old type is in use and that no change was made.	   *
* 									   *
\**************************************************************************/
{
    register int i, j, new_p = 0, new_c = 0;
    register struct pin *p;

    for (i = 0; i < V.ncp; i++)
	if (CP[i].ty == old) {		/* is in use!		 */
	    if (brutal) {
		printf ("Deleting component '%s'\n", CP[i].name);
		del_CP (&CP[i]);}
	    else
	        return 0;
	}

    if (old -> np < new_ty.np)
	new_p = 1;			/* re-allocate pins	 */

    j = 0;				/* count old CIF records */
    if (old -> cif) {
	i = old -> cif - 1;
	do j++;
	while (CIF[i++].flg);
    }

    if (cif_cnt > j || !old -> cif)
	new_c = 1;			/* re-allocate cif stuff */

    if (new_c && V.ncif + cif_cnt > cifmax)
	err ("EXTcif table too small: increase 'cifmax'", cifmax, 0, 0, 0);
    if (new_p && V.npn + new_ty.np > pnmax)
	err ("Pin table too small: increase 'pnmax'", pnmax, 0, 0, 0);

    new_ty.p = new_p ? &PN[V.npn] : old -> p;
				/* adjust pointer and index	 */
    if (new_ty.cif)
	new_ty.cif = new_c ? V.ncif + 1 : old -> cif;

    *old = new_ty;		/* enter type			 */

    if (new_p) {		/* copy pins			 */
	for (i = 0; i < new_ty.np; i++)
	    PN[V.npn++] = new_pin[i];}
    else {
	for (i = 0, p = new_ty.p; i < new_ty.np; i++)
	    *(p++) = new_pin[i];
    }

    if (new_ty.cif) {		/* copy cif records		 */
	for (i = 0, j = new_ty.cif - 1; i <= cif_cnt; i++)
	    CIF[j++] = new_cif[i];
	if (new_c)
	    V.ncif = j;
    }

    return 1;
}    

del_TY (old)
    struct type *old;
/*************************************************************\
* 							      *
*  Delete a type definition:				      *
*   The type definition will be made inaccessable (the input  *
*   filter 'rms' does not pass lower case characters. The     *
*   space is not freed! A returned '0' indicates that the     *
*   delete failed because the Type definition is in use.      *
* 							      *
\*************************************************************/
{
    register int i;

    for (i = 0; i < V.ncp; i++)
	if (CP[i].ty == old)		/* is in use!		 */
	    return 0;

    strcpy (old -> name, DELETED);	/* Note: lower case letters	*/

    return 1;
}

static struct comp new_cp;

CP_update ()			/* update component file	 */
{
    char    buf[80], *flgs;
    float   getfloat ();
    register int i;

    inp = fwantread (".", "test.cp", buf, "Component definition file:");
    if (!inp) {
        err_msg ("open failed");
	return;
    }

    fgets (buf, inp_lnl, inp);
    if (strncmp (buf, "*components:", 12)) {
	err_msg ("Format error");
	printf ("Component-def file doesn't start with '*components:'\n");
	beep ();
	fclose (inp);
	return;
    }

    scalef = getfloat ("Scale factor for componnet coordinates",
			0.01, 100.0, 1.0);
    brutal = getbool ("Brutal update", 0);

    flgs = (char *) malloc (sizeof (char) * cpmax);
    for (i = 0; i < V.ncp; flgs[i++] = 0);

    lcnt = 1;			/* reset line counter		 */

    Ferr_msg ("Busy: updating components");

    while (i = get_CP ()) {
	if (i < 0) {
	    printf ("Defect component skipped\n");
	    continue;
	}
	for (i = 0; i < V.ncp; i++)
	    if (!strncmp (CP[i].name, new_cp.name, nmmax))
		break;
	if (i >= V.ncp) {	/* add new component		 */
	    printf ("Adding '%s'\n", new_cp.name);
	    add_CP ();
	    flgs[V.ncp - 1] = 1;}
	else {
	    if (flgs[i]) {
		printf ("Line %d: '%s' multiple defined\n",
		    lcnt, new_cp.name);
		continue;
	    }
	    flgs[i] = 1;	/* flag reference		 */

	    if (neq_CP (&CP[i])) {
		if (replace_CP (&CP[i]))
		    printf ("New definition for '%s' loaded\n", new_cp.name);
		else
		    printf ("Cannot update '%s': in use\n", new_cp.name);
	    }
	}
    }

    for (i = 0; i <V.ncp; i++)
	if (!flgs[i] && strcmp (CP[i].name, DELETED)) {
	    strncpy (buf, CP[i].name, nmmax);
	    if (del_CP (&CP[i]))
		printf ("Component '%s' deleted\n", buf);
	    else
		printf ("Cannot delete '%s': in use\n", buf);
	}		

    placed = 0;			/* revaluate net location	 */

    free (flgs);		/* clean up & exit		 */
    fclose (inp);
    err_msg ("Done");
    beep ();
}

get_CP ()
/*********************************************************************\
* 								      *
*  Get a new component						      *
*   A returned '-1' indicates a some trouble, '1' success and '0' EOF *
* 								      *
\*********************************************************************/
{
    char    buf[inp_lnl], t[nmmax + 2];
    float   x, y;
    register int i, j;
    int r;

    if (!fgets (buf, inp_lnl, inp))
	return 0;		/* done				*/

    rms (buf);
    lcnt++;			/* count lines			 */

    j = sscanf (buf, "%s %s %f %f %d", new_cp.name, t, &x, &y, &r);

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

    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", lcnt, t);
	return -1;
    }
	
    new_cp.ty = &TY[i];
    new_cp.unplaced = 1;	/* not yet placed		 */

    if (5 == j) {		/* explicily placed component	 */
	if ((r < 0) || (r > 3)) {
	    printf ("Line %d error: invalid rotation - line ignored\n",lcnt);
	    return -1;
	}
	new_cp.x = rsun * x * scalef + 0.5;
	new_cp.y = rsun * y * scalef + 0.5;
	new_cp.r = r;
        new_cp.unplaced = 0;	/* a wild assumption ...	 */
    }

    return 1;
}

add_CP ()
/**********************************************************************\
* 								       *
*  Try to add a new component					       *
*   The only error condition is lack of table space. If the componnet  *
*   does not fit, it will handled as unplaced.			       *
* 								       *
\**********************************************************************/
{
    register int i;

    if (V.ncp >= cpmax)
	err ("Component table too small: increase 'cpmax'", cpmax, 0, 0, 0);
    if (V.nch + new_cp.ty -> np > chmax)
	err ("Component hole table too small: increase 'chmax'", chmax,0,0,0);

    for (i = new_cp.ty -> 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;
    }

    CP[V.ncp++] = new_cp;	/* insert component		 */

    if (!new_cp.unplaced) {	/* try to make it happen	 */
	CP[V.ncp - 1].unplaced = 1;
	i = new_cp.r;
	if (!C_place (&CP[V.ncp - 1], new_cp.x, new_cp.y, i))
	    printf ("Line %d: cannot place '%s' - kept as unplaced\n",
		lcnt, new_cp.name);
    }

    CH_update ();
}

neq_CP (old)
   struct comp *old;
/************************************************************************\
* 									 *
*  .NE. new component							 *
*    a '1' is returned if the new componet "new_cp" differs from <old>.	 *
*    The first difference is printed.					 *
* 									 *
\************************************************************************/
{
    if (new_cp.ty != old -> ty) {
	printf ("Component '%s' - type difference: old='%s' new='%s'\n",
	    new_cp.name, old -> ty -> name, new_cp.ty -> name);
	return 1;
    }

    if (!new_cp.unplaced && old -> unplaced) {
	printf ("Component '%s' - status difference: old is unplaced\n",
	    new_cp.name);
	return 1;
    }

    if (!new_cp.unplaced && (
	new_cp.x != old -> x ||
	new_cp.y != old -> y ||
	new_cp.r != old -> r   )) {
	printf ("Component '%s' - different position\n", new_cp.name);
	return 1;
    }

    return 0;			/* they match			 */
}

replace_CP (old)
    struct comp *old;
/**************************************************************************\
* 									   *
*  Try to replace a component						   *
*   If the componnet has connections to any net, the replace attempt will  *
*   have no effect and a '0' is returned. A '1' indicates a successfull	   *
*   replacement, but the new component may be 'unplaced'		   *
* 									   *
\**************************************************************************/
{
    register int i, j, own, cc;
    register struct hole *hp, *hp1;
    struct nlhd *net;

    own = ((int) old - (int) CP) / sizeof (struct comp); /* get own index */
    for (i = V.nch, hp = CH; i; i--, hp++)	/* 'use' check	 */
	if (hp -> n && hp -> cpi == own) {
	    if (brutal) {
		net = hp -> n -> nlp;
		printf ("Deleting net '%s'\n", net -> name);
		del_NH (net);}
	    else
	        return 0;	/* component is referenced	 */
	}

    /***** ready to replace it				     *****/

    if (!(old -> unplaced)) {	/* un-place component first	 */
	if (!C_unplace (old))
	    err ("replace_CP: unplace failed with no nets", own, 0, 0, 0);
    }

    cc = V.nch + new_cp.ty -> np - old -> ty -> np; 
				/* expected new hole count	 */
    if (cc > chmax)
	err ("Hole table too small: increase 'chmax'", chmax, 0, 0, cc);

    for (i = new_cp.ty -> np, j = V.nch, hp = CH; i && j; j--, hp++)
	if (hp -> cpi == own) {	/* found a pin			 */
	    hp -> x = 0;
	    hp -> y = 0;
	    hp -> pn = --i;
	    hp -> n = nil;	/* x, y and n should not change here */
	}
    if (i) {			/* need to allocate more pins */
	while (i) {
	    CH[V.nch].x = 0;
	    CH[V.nch].y = 0;
	    CH[V.nch].pn = --i;
	    CH[V.nch].cpi = own;
	    CH[V.nch++].n = nil;
	}}
    else if (j) {		/* there may be dangling pins */
	for (hp1 = hp; j; j--, hp++) {
	    if (hp -> cpi != own)
		*(hp1++) = *hp;
	    else
		V.nch--;
	}
    }

    if (cc != V.nch)		/* something went wrong		 */
	err ("remove_CP: inconsistent hole count", cc, V.nch, own, 0);

    *old = new_cp;		/* insert new component		 */

    if (!new_cp.unplaced) {	/* try to make it happen	 */
	old -> unplaced = 1;
	i = new_cp.r;
	if (!C_place (old, new_cp.x, new_cp.y, i))
	    printf ("Line %d: cannot place '%s' - kept as unplaced\n",
		lcnt, new_cp.name);
    }

    CH_update ();

    return 1;			/* success !			 */
}

del_CP (old)
    struct comp *old;
/*******************************************************************\
* 								    *
*  Delete component:						    *
*   The holes for the componen <old> are removed and the CP entry   *
*   is marked as deleted iff <old> is not in use. '1' indicates	    *
*   sucessfull deletion and '0' signals that no delete took place.  *
*   The as in 'del_TY' the space is not freed (so far).		    *
* 								    *
\*******************************************************************/
{
    register int i, j, own, cc;
    register struct hole *hp, *hp1;
    struct nlhd *net;

    own = ((int) old - (int) CP) / sizeof (struct comp); /* get own index */
    for (i = V.nch, hp = CH; i; i--, hp++)	/* 'use' check	 */
	if (hp -> n && hp -> cpi == own) {
	    if (brutal) {
		net = hp -> n -> nlp;
		printf ("Deleting net '%s'\n", net -> name);
		del_NH (net);}
	    else
	        return 0;	/* component is referenced	 */
	}

    /***** ready to delete it				     *****/

    if (!(old -> unplaced)) {	/* un-place component first	 */
	if (!C_unplace (old))
	    err ("del_CP: unplace failed with no nets", own, 0, 0, 0);
    }

    cc = V.nch - old -> ty -> np; /* expected new hole count	 */

    for (j = V.nch, hp1 = hp = CH; j; j--, hp++) {
	if (hp -> cpi != own)
	    *(hp1++) = *hp;
	else
	    V.nch--;
    }

    if (cc != V.nch)		/* something went wrong		 */
	err ("del_CP: inconsistent hole count", cc, V.nch, own, 0);

    strcpy (old -> name, DELETED);	/* make it inaccessable  */
    old -> ty = 0;		/* free types			 */
    old -> unplaced = 0;	/* do not fool place functions	 */

    CH_update ();

    return 1;			/* all set			 */
}

static int mode;		/* =0: Multiwire =1: DP netlist	 */
static struct nlhd new_nh;	/* temprary net list head	 */
static struct hole **new_ht = 0;/* temporary hole table		 */
static int ht_max = 100;	/* max size of new_ht		 */
static int ht_cnt;		/* allocation counter		 */
static struct nlhd *power_n;	/* != 0 : power net processing	 */
static int net_cnt;		/* net counter (MW format)	 */

NL_update ()			/* update netlist		 */
{
    char    buf[80];
    float   getfloat ();
    register int i, err = 0;
    register struct nlst *p, *q;

    inp = fwantread (".", "test.nl", buf, "Netlist file:");
    if (!inp) {
        err_msg ("Open failed");
	return;
    }

    mode = 0;			/* assume 'Multiwire' mode		 */
    fgets (buf, inp_lnl, inp);
    if (strncmp (buf, "Cnetlist:", 9) &&
	(mode = 1, strncmp (buf, "DPnetlist:", 10))) {
	err_msg ("Format error");
	printf ("Component-def file doesn't start with '*components:'\n");
	beep ();
	fclose (inp);
	return;
    }

    for (i = 0; i < V.nnh; NH[i++].ref = 0);	/* clear ref-flags */

    for (p = V.GND.lp; p; p = p -> n)	/* clear GND net	 */
	p -> mk = 0;
    for (p = V.VCC.lp; p; p = p -> n)	/* clear VCC net	 */
	p -> mk = 0;
    for (p = V.VEE.lp; p; p = p -> n)	/* clear VEE net	 */
	p -> mk = 0;
    for (p = V.VTT.lp; p; p = p -> n)	/* clear VTT net	 */
	p -> mk = 0;

    new_nh.x1 = xmax;		/* initialize prototype		 */
    new_nh.y1 = ymax;
    new_nh.x2 = 0;
    new_nh.y2 = 0;
    new_nh.f = 0;
    new_nh.l = 0;
    new_nh.lp = 0;
    new_nh.ref = 1;

    net_cnt = 0;		/* reset MW net counter		 */
    lcnt = 1;			/* reset line counter		 */

    Ferr_msg ("Busy: updating Netlist");

    while (i = get_NH ()) {
	if (i < 0) {
	    printf ("Invalid net: skipped\n");
	    err = 1;		/* prevent delete phase		 */
	    continue;
	}
	i = ident_NH ();	/* identify net			 */
	if (i < 0) { 		/* add new net			 */
	    printf ("Adding net '%s'\n", new_nh.name);
	    add_NH ();}
	else {
	    if (ref_chk ()) {
		printf ("Line %d: '%s' shorted to other net\n",
		    lcnt, new_nh.name);
		continue;
	    }
	    if (neq_NH (&NH[i])) 
		replace_NH ();
	}
    }

    if (err)
	printf ("Not deleting old net because of earlier errors\n");
    else {
	for (i = 0; i <V.nch; i++)
	    if (!NH[i].ref && NH[i].l) {
		printf ("Net '%s' deleted\n", NH[i].name);
		del_NH (&NH[i]);
	    }

	for (q = 0, p = V.GND.lp; p;) {
	    if (!(p -> mk)) {	/* remove node			 */
		printf ("Removing GND connection '%s-%d'\n",
		    CP[p -> c -> cpi].name, p -> c -> pn + 1);
		if (q)
		    q -> n = p -> n;	/* unlink it		 */
		else
		    V.GND.lp = p -> n;
		p -> n = V.enll;
		V.enll = p;
		p -> c -> n = 0;
		V.GND.l--;
		p = (q) ? q : V.GND.lp;}
	    else {
		q = p;
		p = p -> n;
	    }
	}

	for (q = 0, p = V.VCC.lp; p;) {
	    if (!(p -> mk)) {	/* remove node			 */
		printf ("Removing VCC connection '%s-%d'\n",
		    CP[p -> c -> cpi].name, p -> c -> pn + 1);
		if (q)
		    q -> n = p -> n;	/* unlink it		 */
		else
		    V.VCC.lp = p -> n;
		p -> n = V.enll;
		V.enll = p;
		p -> c -> n = 0;
		V.VCC.l--;
		p = (q) ? q : V.VCC.lp;}
	    else {
		q = p;
		p = p -> n;
	    }
	}

	for (q = 0, p = V.VEE.lp; p;) {
	    if (!(p -> mk)) {	/* remove node			 */
		printf ("Removing VEE connection '%s-%d'\n",
		    CP[p -> c -> cpi].name, p -> c -> pn + 1);
		if (q)
		    q -> n = p -> n;	/* unlink it		 */
		else
		    V.VEE.lp = p -> n;
		p -> n = V.enll;
		V.enll = p;
		p -> c -> n = 0;
		V.VEE.l--;
		p = (q) ? q : V.VEE.lp;}
	    else {
		q = p;
		p = p -> n;
	    }
	}

	for (q = 0, p = V.VTT.lp; p;) {
	    if (!(p -> mk)) {	/* remove node			 */
		printf ("Removing VTT connection '%s-%d'\n",
		    CP[p -> c -> cpi].name, p -> c -> pn + 1);
		if (q)
		    q -> n = p -> n;	/* unlink it		 */
		else
		    V.VTT.lp = p -> n;
		p -> n = V.enll;
		V.enll = p;
		p -> c -> n = 0;
		V.VTT.l--;
		p = (q) ? q : V.VTT.lp;}
	    else {
		q = p;
		p = p -> n;
	    }
	}
		
    }

    flush_stat ();
    placed = 0;			/* reevaluate net loactions	 */

    for (i = 0, nettgo = 0; i < V.nnh; i++)
	nettgo += !NH[i].f && NH[i].l;	/* count unfinished nets */
    nets_msg (nettgo);

    fclose (inp);
    err_msg ("Done");
    beep ();
}

get_NH ()
/*************************************************************\
* 							      *
*  Get a net:						      *
*   returns:  1: a correct net was read into "new_NH/new_NL"  *
* 	      0: EOF was encountered			      *
* 	     -1: the net description was in error	      *
* 							      *
\*************************************************************/
{
    char    buf[inp_lnl];
    register int i, j, ntc = 0;
    int k;
    static int preload = 0;

    ht_cnt = 0;			/* reset node count		 */

    do {
	if (!preload) {
	    if (!fgets (buf, inp_lnl, inp))
	        return mode ? 0 : ntc;	/* end of file		 */

	    rms (buf);
	    lcnt++;
	}
	preload = 0;		/* hack for Multiwre cont. records */

	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", lcnt);
		return -1;
	    }

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

	    if (buf[0] == '!') {/* power net (gnd, vcc, vee, vtt) */
		if      (!strncmp ("GND", &buf[1], 3))
		    power_n = &V.GND;
		else if (!strncmp ("VCC", &buf[1], 3)) 
		    power_n = &V.VCC;
		else if (!strncmp ("VTT", &buf[1], 3))
		    power_n = &V.VTT;
		else if (!strncmp ("VEE", &buf[1], 3))
		    power_n = &V.VEE;
	        else {
		    printf ("Line %d error: unknown power net\n", lcnt);
		    return -1;
		}
		strcpy (new_nh.name, power_n -> name); /* for err-msg only */
	    } else {		/* normal net			 */
		power_n = nil;
		buf[j] = 0;
		strncpy (new_nh.name, buf, nmmax);
	    }

	    for (j++; (j < inp_lnl) && (buf[j] != '\0'); ++j)
		if (buf[j] == ' ') {
		    if (add_NL (&buf[j + 1]))
			return -1;	/* some error in net	 */
		}

	    if (!power_n)
	        return 1;	/* net completed		 */

	    continue;		/* hide power-nets		 */
	}
	
	if (buf[0] == 'C') {	/* Multiwire net list processing */
	    j = 3;
	    if (!strncmp ("GND", &buf[1], 3))
		power_n = &V.GND;
	    else if (!strncmp ("VCC", &buf[1], 3)) 
		power_n = &V.VCC;
	    else if (!strncmp ("VTT", &buf[1], 3))
		power_n = &V.VTT;
	    else if (!strncmp ("VEE", &buf[1], 3))
		power_n = &V.VEE;
	    else
		continue;	/* normal comment		 */
	    strcpy (new_nh.name, power_n -> name);
	} else {
	    power_n = nil;
	    if (!sscanf (buf, "%d", &k)) {
		printf ("Line %d error: invalid net number\n", lcnt);
		return - 1;}
	    else if (k == -1)	/* Multiwire end ?		 */
		return 0;
	    else if ((k < net_cnt) || (k <= 0)) {
		printf ("Line %d error: net number %d out of sequence\n",
		    lcnt, k);
		return -1;}
	    else {
		if (k > net_cnt + 1)
		    printf("Line %d warning: net %d missing, next is %d\n",
			 lcnt, net_cnt + 1, k);
		if (k > net_cnt) {	/* start a new net	 */
		    if (ntc) {
			preload = 1;
			return 1;	/* got a net		 */
		    }
		    ntc = 1;
		    sprintf (new_nh.name, "#%d", net_cnt = k);
		}
	    }
	    j = 0;
	}

	for (j++; (j < inp_lnl) && (buf[j] != '\0'); ++j)
	    if (buf[j] == ' ') {
		if (add_NL (&buf[j + 1]))
		    return -1;	/* some error in net		 */
	    }

    } while (1);

    return -1;			/* keep lint happy		 */
}

add_NL (s)			/* add a node to a net list	*/
    char *s;
{
    register int i, j, l, x, y, r;
    int          k, x1, y1;
    struct hole  *hp, *fndh ();
    struct nlst  *p, *deq_NL ();
    struct nlhd  *net;

    for (i = 0; s[i] != '-'; ++i) /* isolate component name	*/
	if ((s[i] == '\0') || (i > nmmax)) {
	    printf ("Line %d error: missing pin number\n", lcnt);
	    return 1;
	}
    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", lcnt);
	return 1;
    }

    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", lcnt,s,k);
	return 1;
    }					/* 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", lcnt, s,k+1);
    s[i] = '*';				/* this is a hack (as usual)	*/

    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 ("add_NL: failed to find hole", x1, y1, x, y);

    if (power_n) {		
/************************************************************************\
* 									 *
*  New power net handler:						 *
* 									 *
*   case a: touching the old & correct powernet -> mark node		 *
*   case b: touching an old & !correct powernet -> move node, mark it	 *
*   case c: touching an old net (!power) -> delete old net, add a power	 *
* 					  node, mark it			 *
*   case d: touching an new net (!power) -> serious error		 *
*   case e: pin is in no net -> add a power node, mark it		 *
* 									 *
\************************************************************************/
	if (hp -> n) {		/* case a-d			 */
	    net = hp -> n -> nlp;

	    if (net == power_n) {			/*** CASE A ***/
		if (hp -> n -> mk) 
		    printf ("Line %d: multiple '%s' connection\n",
			lcnt, power_n -> name);	/* no need to abort */
		hp -> n -> mk = 1;
		return 0;
	    }

	    if (net < &NH[0] || net > &NH[V.nnh - 1]) { /*** CASE B ***/
		if (pcb[y1][x1] & vec)
		    err ("add_NL: power net with trace", x1, y1, lcnt, 0);
		if (hp -> n -> mk) {
		    printf ("Line %d: '%s' to '%s' short\n", lcnt,
			hp -> n -> nlp -> name, power_n -> name);
		    return 1;
		}
		if (net -> lp == hp -> n)	/* first in old list	 */
		    net -> lp = hp -> n -> n;
		else {
		    for (p = net -> lp; p; p = p -> n)
			if (p -> n == hp -> n) { /* found predecessor	 */
			    p -> n = hp -> n -> n;
			    break;
			}
		    if (p)
			err ("add_NL: unlink failed - ptr error",
				 x1, y1, lcnt, 0);
		}
		hp -> n -> n = power_n -> lp;
		power_n -> lp = hp -> n;	/* linked in new net	 */
		hp -> n -> nlp = power_n;
		hp -> n -> mk = 1;
		power_n -> l++;			/* update net length	 */
		net -> l--;
		return 0;
	    }

	    if (hp -> n -> nlp -> ref) {		/*** CASE D ***/
		printf ("Line %d: Error - net '%s' shorted to '%d'\n",
		    lcnt, hp -> n -> nlp -> name, power_n -> name);
		return 1;
	    }

	    del_NH (hp -> n -> nlp);			/*** CASE C ***/
	}

					     /*** CASE E + (C cont) ***/
	p = deq_NL ();		/* get an NL - node		 */

	p -> c = hp;		/* add node to power net	 */
	p -> n = power_n -> lp;
	p -> nlp = power_n;
	power_n -> lp = p;
	p -> mk = 1;
	hp -> n = p;
	power_n -> l++;		/* update net length		 */

	p -> mk = 1;		/* mark it			 */
	return 0;
    }

    if (!new_ht) 		/* need to allocate space	 */
	new_ht = (struct hole **) malloc (sizeof (struct hole *) * ht_max);
    else if (ht_max <= ht_cnt) {
	ht_max += 50;
	new_ht = (struct hole **) realloc (new_ht, 
			sizeof (struct hole *) * ht_max);
    }

    for (i = 0; i < ht_cnt; i++)
	if (new_ht[i] == hp) {
	    printf ("Line %d: multiple node in net\n", lcnt);
	    return 1;
	}

    new_ht[ht_cnt++] = hp;	/* remember hole		 */

    return 0;
}

ident_NH ()
/*********************************************************\
* 							  *
*  Identify the new net:				  *
*   the first match is reported. '-1' indicates no match  *
* 							  *
\*********************************************************/
{
    register int i;

    for (i = 0; i < ht_cnt; i++)
	if (new_ht[i] -> n) 
	   return ((int) (new_ht[i] -> n -> nlp) - (int) NH) /
			 sizeof (struct nlhd);

    return -1;
}

ref_chk ()
/************************************************************************\
* 									 *
*  reference check:							 *
*   a '1' is return if the new net has a node in common with a net that	 *
*   is already referenced. '0' is returned otherwise.			 *
* 									 *
\************************************************************************/
{
    register int i;

    for (i = 0; i < ht_cnt; i++)
	if (new_ht[i] -> n && new_ht[i] -> n -> nlp -> ref)
	   return 1;

    return 0;
}

neq_NH (net)
   struct nlhd *net;
/*************************************************************\
* 							      *
*  .NE. old net:					      *
*   A '1' is return if the new net differs from the old one.  *
* 							      *
\*************************************************************/
{
    register int i;
    register struct nlst *p;

    if (net -> l != ht_cnt)
	return 1;		/* different length	 */

    for (p = net -> lp; p; p = p -> n)
	p -> mk = 0;		/* clear marks of old net */

    for (i = 0; i < ht_cnt; i++) {
	if (!(new_ht[i] -> n) || new_ht[i] -> n -> nlp != net)
	    return 1;		/* referes to different net */
	new_ht[i] -> n -> mk = 1;
    }

    for (p = net -> lp; p; p = p -> n)
	if (!(p -> mk))
	    err ("new_NH: ptr screw up in internal structure",
		((int) net - (int) NH) / sizeof (struct nlhd), lcnt, 0, 0);

    net -> ref = 1;		/* sucessfully referenced */

    return 0;			/* nets match		 */
}

replace_NH ()
/*******************************************\
* 					    *
*  Replace the old net(s) with the new one  *
* 					    *
\*******************************************/
{
    register int i;

    printf ("The new net '%s' replaces", new_nh.name);

    for (i = 0; i < ht_cnt; i++)
	if (new_ht[i] -> n) {	/* delete the old nets	 */
	   printf (" '%s'", new_ht[i] -> n -> nlp -> name);
	   del_NH (new_ht[i] -> n -> nlp);
	}

    printf ("\n");

    add_NH ();
}

add_NH ()		/* add new net			 */
{
    register int i, j;
    register struct nlst *p;

    for (i = 0; i < V.nnh; i++)	/* look for a old header */
	if (!NH[i].l)
	   break;
    if (i >= V.nnh) {	/* not found: add new entry	 */
	if (V.nnh >= nhmax)
	    err ("Net table too small: increase 'nhmax'", nhmax, 0,0,0);
	i = V.nnh++;
    }

    NH[i] = new_nh;	/* copy prototype		 */
    NH[i].l = ht_cnt;

    for (j = 0; j < ht_cnt; j++) {	/* add nodes	 */
	p = deq_NL ();
	p -> n = NH[i].lp;
	NH[i].lp = p;
	p -> c = new_ht[j];
	p -> nlp = &NH[i];
	p -> mk = 0;
	new_ht[j] -> n = p;
    }
}

del_NH (net)		/* delete net			 */
    struct nlhd *net;
{
    register int x, y;
    register struct nlst *p, *q;
    int delh (), delv ();

    if (!(net -> l))
	err ("del_NH: deleting deleted net ???",
	   ((int) net - (int) NH) / sizeof (struct nlhd), lcnt, 0, 0);

    wthf = delh;	/* renmove old geometry		 */
    wtvf = delv;
    for (p = net -> lp; p; p = p -> n) {
	q = p;
	x = p -> c -> x;
	y = p -> c -> y;
	wtrace (x, y, vec);
	ckgp (x, y, s1b);
	ckgp (x, y, s2b);
	p -> c -> n = 0;	/* free holes		 */
    }

    q -> n = V.enll;	/* enter nodes to free list	 */
    V.enll = net -> lp;

    net -> lp = 0;
    net -> ref = 0;
    net -> l = 0;	/* net gone !!			 */
}
!E!O!F!
#
# type    sh /usru0/agn/pcb/distr/../usenet/part9   to unpack this archive.
#
echo extracting patr.c...
cat >patr.c <<'!E!O!F!'
/***************************************************************\
*								*
*	PCB program						*
*								*
*	Auto router section					*
*								*
*	(c) 1985		A. Nowatzyk			*
*								*
\***************************************************************/

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

#define netmax 50		/* max. net length		*/
#define ratio 3			/* ratio for filter		*/
#define pxsb s1b		/* prefere x side bit		*/
#define pysb s2b		/* prefere y side bit		*/
#define lmax 96			/* max length for filter	*/
#define bbox 16			/* bounding box for local route */
#define maxtry1 0		/* limit for N_route (see def)	*/
#define maxtry2 1		/* limit for N_route (see def)	*/
#define maxtry3 3		/* limit for N_route (see def)	*/

#define new_p1 0		/* use sorted segments in pass2 */

struct sntl {			/* sorted net list		 */
    struct nlhd *p;		/* pointer to net		 */
    int c;			/* cost for this net		 */
};

static struct ssegl {		/* sorted segment list		 */
    struct nlhd *p;		/* pointer to net		 */
    int c;			/* cost for this net		 */
    int xs, ys;			/* start coordinates		 */
    int xe, ye;			/* end coordinates		 */
} *SSEGL;

static int sseglc;		/* count of nets		 */


autor()
/*****************************************************************\
* 								  *
*  Auto Router							  *
* 								  *
*  The Auto router uses several phases:				  *
*        1)  use 'filter' no via-holes, 2 direction changes only  *
*        2)  use full router on level 0				  *
*        3)  use full router on level 1				  *
*        4)  use full router on level 2				  *
*        5)  use full router on level 3				  *
*        							  *
* 								  *
\*****************************************************************/
{
    register struct sntl *snl, *s;
    register int i, j, k;
    int netc_key (), seg_key (), segc, netc, max_nl;

    Ferr_msg ("Preparing autoroute");

    snl = (struct sntl *) malloc (V.nnh * sizeof (*snl));


    segc = 0;			/* count segments and nets	 */
    netc = 0;
    max_nl = 0;
    for ((s = snl, j = i = 0); i < V.nnh; i++)/* evaluate nets	 */
	if (NH[i].l > 1 && !(NH[i].f)) {
	    netc++;
	    k = NH[i].l;
	    if (k > max_nl)
		max_nl = k;
	    segc += k - 1;
	    s -> p = &NH[i];
	    s -> c = net_cst (&NH[i]);
	    j++;
	    s++;
	}

    qsort (snl, j, sizeof (*snl), netc_key);/* sort nets		 */

    SSEGL = (struct ssegl *) malloc (sizeof (struct ssegl) * segc);

    printf ("%4d nets with %5d segments needs to be routed\n", netc, segc);

    Ferr_msg ("Autoroute: pass 1");
    netc = segc = 0;
    for ((s = snl, i = 0); i < j; (s++, i++)){/* try routing	 */
	segc += P_route (s -> p);
	netc += s -> p -> f;
    }
    qsort (SSEGL, sseglc, sizeof (struct ssegl), seg_key);

    printf ("\tPass1: %4d nets, %5d segments routed\n", netc, segc);

    Ferr_msg ("Autoroute: pass 2");
    netc = segc = 0;
    set_rtps (0);

#ifdef new_p2
    for (i = 0; i < sseglc; i++)	/* try routing	segments */
	if (!(SSEGL[i].p -> f)) {
	
	    if (V.cnet != SSEGL[i].p) {
		if (V.cnet)
		    deseln (V.cnet);	/* deselect current net	 */
	        selnet (SSEGL[i].p);	/* select net		 */
	    }
	    
	    segc += s_route (SSEGL[i].xs, SSEGL[i].ys,
			     SSEGL[i].xe, SSEGL[i].ye);
 	    netc += SSEGL[i].p -> f = cchk (SSEGL[i].p);
	}

    if (V.cnet)
	deseln (V.cnet);
#else
    for ((s = snl, i = 0); i < j; (s++, i++))/* try routing	 */
	if (!(s -> p -> f)) {
	    segc += N_route (s -> p, 0, 0, 0, V.BSX, V.BSY);
	    netc += s -> p -> f;
	}
#endif
    free (SSEGL);
    printf ("\tPass2: %4d nets, %5d segments routed\n", netc, segc);

    Ferr_msg ("Autoroute: pass 3");
    netc = segc = 0;
    set_rtps (1);
    for ((s = snl, i = 0); i < j; (s++, i++))/* try routing	 */
	if (!(s -> p -> f)) {
	    segc += N_route (s -> p, maxtry1, 0, 0, V.BSX, V.BSY);
	    netc += s -> p -> f;
	}
    printf ("\tPass3: %4d nets, %5d segments routed\n", netc, segc);

    Ferr_msg ("Autoroute: pass 4");
    netc = segc = 0;
    set_rtps (2);
    for ((s = snl, i = 0); i < j; (s++, i++))/* try routing	 */
	if (!(s -> p -> f)) {
	    segc += N_route (s -> p, maxtry2, 0, 0, V.BSX, V.BSY);
	    netc += s -> p -> f;
	}
    printf ("\tPass4: %4d nets, %5d segments routed\n", netc, segc);

    Ferr_msg ("Autoroute: pass 5");
    netc = segc = 0;
    set_rtps (3);
    for ((s = snl, i = 0); i < j; (s++, i++))/* try routing	 */
	if (!(s -> p -> f)) {
	    segc += N_route (s -> p, maxtry3, 0, 0, V.BSX, V.BSY);
	    netc += s -> p -> f;
	}
    printf ("\tPass5: %4d nets, %5d segments routed\n", netc, segc);

    free (snl);			/* free memory			 */

    Ferr_msg ("Saving result");

    save (0);

    Ferr_msg ("Done");
}

netc_key (a, b)			/* sort key for nets		 */
    struct sntl *a, *b;
{
    return ((a -> c > b -> c) - (a -> c < b -> c));
}

seg_key (a, b)			/* sort key for segments	 */
    struct ssegl *a, *b;
{
    return ((a -> c > b -> c) - (a -> c < b -> c));
}

net_cst (net)			/* net cost function		 */
    struct nlhd *net;
/**************************************************************\
* 							       *
*  This function determins the order of rout - attempts. Nets  *
*  with a low cost are routed first.			       *
* 							       *
\**************************************************************/
{
    int     c, dx, dy;

    dx = abs (net -> x1 - net -> x2);
    dy = abs (net -> y1 - net -> y2);

    c = 500 * abs (dx - dy);
    c /= (dx + dy);		/* prefere square nets		 */

    c += net -> l * 100;	/* large nets later		 */

    c += (dx + dy) * 2;		/* long nets later (significat)	 */

    return (c);
}

filter (x1, y1, x2, y2)		/* look for promissing candiates */
    int x1, y1, x2, y2;
/****************************************************************\
* 								 *
*  This code is obsolete, but it is kept because it runs faster	 *
*  for simple cases than the full router in pleer.c		 *
* 								 *
\****************************************************************/
{
    int     i, j;

    i = abs (x1 - x2);
    j = abs (y1 - y2);
    if ((i + j) > lmax)
	return (0);		/* invalid length		 */

    if (i > ratio * j) {
	if (x1 < x2)
	    return (tryx (x1, y1, x2 - x1, y2 - y1, pxsb));
	else
	    return (tryx (x2, y2, x1 - x2, y1 - y2, pxsb));
    }

    if (i * ratio < j) {
	if (y1 < y2)
	    return (tryy (x1, y1, y2 - y1, x2 - x1, pysb));
	else
	    return (tryy (x2, y2, y1 - y2, x1 - x2, pysb));
    }

    return (0);			/* invalid ratio		 */
}

tryx (x, y, l, o, b)		/* try to route a wire (X)	 */
    int x, y, l, o, b;
{
    int i, l1, l2, c1, c2, c3, t;
    char *p, *p1, *p2, *p3;

    t = ahb | b | fb | selb;		/* test bits	 */

    if (o >= 0) {
	p2 = p1 = &pcb[y - 1][x + 2];
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = (-1); i < o + bbox; i++) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = (abs(o-i) > 2) ? l1 - abs(o-i) : l1 - 2; l2 >= 0; l2--)
				/* check space			 */
		if (*(p++) & t) {
		    c1 = 0;
		    break;
		}

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmplx(x, y, --i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    p1 += xmax;
	    if (i > 1) {
		if ((*p3 & t) || (*(++p3) & t) || (*p1 & t) || (*(p1-1) & t))
		    break;
		p1++;
		l1--;
	    }
	}

	p1 = &pcb[y][x + 2];	/* ok, try other side next	 */
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = 0; i > -bbox; i--) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = ((o-i) > 2) ? l1 - (o-i) : l1 - 2; l2 >= 0; l2--)
				/* check space			 */
		if (*(p++) & t) {
		    c1 = 0;
		    break;
		}

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmplx(x, y, ++i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    p1 -= xmax;
	    if (i < -1) {
		if ((*p3 & t) || (*(++p3) & t) || (*p1 & t) || (*(p1-1) & t))
		    break;
		p1++;
		l1--;
	    }
	}}
    else {		/* same thing, but reversed order	 */
	p1 = &pcb[y + 1][x + 2];
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = 1; i > o - bbox; i--) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = (abs(o-i) > 2) ? l1 - abs(o-i) : l1 - 2; l2 >= 0; l2--)
				/* check space			 */
		if (*(p++) & t) {
		    c1 = 0;
		    break;
		}

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmplx(x, y, ++i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    p1 -= xmax;
	    if (i < -1) {
		if ((*p3 & t) || (*(++p3) & t) || (*p1 & t) || (*(p1-1) & t))
		    break;
		p1++;
		l1--;
	    }
	}

	p1 = &pcb[y][x + 2];	/* ok, try other side	 */
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = 0; i < bbox; i++) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = ((i-o) > 2) ? l1 - (i-o) : l1 - 2; l2 >= 0; l2--)
				/* check space			 */
		if (*(p++) & t) {
		    c1 = 0;
		    break;
		}

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmplx(x, y, --i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    p1 += xmax;
	    if (i > 1) {
		if ((*p3 & t) || (*(++p3) & t) || (*p1 & t) || (*(p1-1) & t))
		    break;
		p1++;
		l1--;
	    }
	}
    }

    return (0);				/* no success		 */
}

cmplx (x, y, po, l, o, b)		/* complete try (x)	 */
    int x, y, po, l, o, b;
{
    int i, d, t;
    char *p;

    t = ahb | b | fb | selb;

    d = o - po;			/* get displacement	 */

    if (d) {			/* check last segment	 */
	if (d > 0) {		/* down segment		 */
	    if (d > 1) {	/* deserves attention	 */
		d--;
		p = &pcb[y + o - 3][x + l - 1];
		for (i = d; i > 0; (p -= xmax, i--))
		    if ((*p & t) || (*(--p) & t) ||
			(*(p + 2 * xmax) & t) || (*(p + 3 * xmax) & t))
			return (0);	/* fail		 */
		color (b | selb, b | selb);
		plt (x + l, y + o, x + l - d, y + o - d);
		l -= d + 1; }
	    else {
		color (b | selb, b | selb);
		pxl (x + l, y + o);
		l--;		/* just cheat on length	 */
	    } }
	else {			/* up segment		 */
	    d = (-d);
	    if (d > 1) {	/* need attention	 */
		d--;
		p = &pcb[y + o + 3][x + l - 1];
		for (i = d; i > 0; (p += xmax, i--))
		    if ((*p & t) || (*(--p) & t) ||
			(*(p - 2 * xmax) & t) || (*(p - 3 * xmax) & t))
			return (0);/* fail	 */
		color (b | selb, b | selb);
		plt (x + l, y + o, x + l - d, y + o + d);
		l -= d + 1; }
	    else {
		color (b | selb, b | selb);
		pxl (x + l, y + o);
		l--;		/* cheat on length	 */
	    }
	} }
    else
	color (b | selb, b | selb);


    if (abs (po) > 1) {
	plt (x, y, x + abs (po), y + po);
	plt (x + abs (po) + 1, y + po, x + l, y + po); }
    else {
	if (po)
	    pxl (x, y);
	plt (x + abs (po), y + po, x + l, y + po);
    }

    return (1);			/* success			 */
}

tryy (x, y, l, o, b)		/* try to route a wire (Y)	 */
    int x, y, l, o, b;
{
    int i, l1, l2, c1, c2, c3, t;
    char  *p, *p1, *p2, *p3;

    t = ahb | b | fb | selb;		/* test bits	 */

    if (o >= 0) {
	p2 = p1 = &pcb[y + 2][x - 1];
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = (-1); i < o + bbox; i++) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = (abs(o-i) > 2) ? l1 - abs(o-i) : l1 - 2; l2 >= 0; l2--){
				/* check space			 */
		if (*p & t) {
		    c1 = 0;
		    break;
		}
		p += xmax;
	    }

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmply(x, y, --i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    ++p1;
	    if (i > 1) {
		if ((*p3 & t) || (*(p3 + xmax) & t) ||
		    (*p1 & t) || (*(p1 - xmax) & t))
		    break;
		p1 += xmax;
		l1--;
	    }
	}

	p1 = &pcb[y + 2][x];	/* ok, try other side next	 */
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = 0; i > -bbox; i--) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = ((o-i) > 2) ? l1 - (o-i) : l1 - 2; l2 >= 0; l2--) {
				/* check space			 */
		if (*p & t) {
		    c1 = 0;
		    break;
		}
		p += xmax;
	    }

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmply(x, y, ++i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    --p1;
	    if (i < -1) {
		if ((*p3 & t) || (*(p3 + xmax) & t) ||
		    (*p1 & t) || (*(p1 - xmax) & t))
		    break;
		p1 += xmax;
		l1--;
	    }
	}}
    else {		/* same thing, but reversed order	 */
	p1 = &pcb[y + 2][x + 1];
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = 1; i > o - bbox; i--) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = (abs(o-i) > 2) ? l1 - abs(o-i) : l1 - 2; l2 >= 0; l2--){
				/* check space			 */
		if (*p & t) {
		    c1 = 0;
		    break;
		}
		p += xmax;
	    }

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmply(x, y, ++i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    --p1;
	    if (i < -1) {
		if ((*p3 & t) || (*(p3 + xmax) & t) ||
		    (*p1 & t) || (*(p1 - xmax) & t))
		    break;
		p1 += xmax;
		l1--;
	    }
	}

	p1 = &pcb[y + 2][x];	/* ok, try other side	 */
	l1 = l - 2;
	c2 = c3 = 0;
	for (i = 0; i < bbox; i++) {
	    c1 = 1;		/* assume space for wire	 */
	    p = p1;
	    for (l2 = ((i-o) > 2) ? l1 - (i-o) : l1 - 2; l2 >= 0; l2--) {
				/* check space			 */
		if (*p & t) {
		    c1 = 0;
		    break;
		}
		p += xmax;
	    }

	    if (c1 & c2 & c3) {	/* looks good so far	 */
		if (cmply(x, y, --i, l, o, b))
		    return (1);
		break;
	    }

	    c3 = c2;
            c2 = c1;
	    p3 = p2;
	    p2 = p1;
	    ++p1;
	    if (i > 1) {
		if ((*p3 & t) || (*(p3 + xmax) & t) ||
		    (*p1 & t) || (*(p1 - xmax) & t))
		    break;
		p1 += xmax;
		l1--;
	    }
	}
    }

    return (0);				/* no success		 */
}

cmply (x, y, po, l, o, b)		/* complete try (x)	 */
    int x, y, po, l, o, b;
{
    int i, d, t;
    char *p;

    t = ahb | b | fb | selb;

    d = o - po;			/* get displacement	 */

    if (d) {			/* check last segment	 */
	if (d > 0) {		/* down segment		 */
	    if (d > 1) {	/* deserves attention	 */
		d--;
		p = &pcb[y + l - 1][x + o - 3];
		for (i = d; i > 0; (p--, i--))
		    if ((*p & t) || (*(p -= xmax) & t) ||
			(*(p + 2) & t) || (*(p + 3) & t))
			return (0);/* fail	 */
		color (b | selb, b | selb);
		plt (x + o, y + l, x + o - d, y + l - d);
		l -= d + 1; }
	    else {
		color (b | selb, b | selb);
		pxl (x + o, y + l);
		l--;		/* just cheat on length	 */
	    } }
	else {			/* up segment		 */
	    d = (-d);
	    if (d > 1) {	/* need attention	 */
		d--;
		p = &pcb[y + l - 1][x + o + 3];
		for (i = d; i > 0; (p++, i--))
		    if ((*p & t) || (*(p -= xmax) & t) ||
			(*(p - 2) & t) || (*(p - 3) & t))
			return (0);/* fail		 */
		color (b | selb, b | selb);
		plt (x + o, y + l, x + o + d, y + l - d);
		l -= d + 1; }
	    else {
		color (b | selb, b | selb);
		pxl (x + o, y + l);
		l--;		/* cheat on length	 */
	    }
	} }
    else
	color (b | selb, b | selb);


    if (abs (po) > 1) {
	plt (x, y, x + po, y + abs (po));
	plt (x + po, y + abs (po) + 1, x + po, y + l); }
    else {
	if (po)
	    pxl (x, y);
	plt (x + po, y + abs (po), x + po, y + l);
    }

    return (1);			/* success			 */
}

/***************************************\
* 				        *
*  Local stuff for N_route and P_route  *
* 				        *
\***************************************/

struct htab {			/* hole table			 */
   int x, y;			/* coordinate			 */
   int snn;			/* subnet number		 */
};

struct clst {			/* connection list		 */
    struct htab *s, *d;		/* pointer to holes		 */
    int c;			/* cost (= length) or 0		 */
};

ct_key (a, b)
    struct clst *a, *b;
{
    return ((a -> c > b -> c) - (a -> c < b -> c));
}

static int s1, s2, nh;		/* current subnet (for Nr_cup)	 */
static struct htab *htp;	/* hole table pointer		 */

Nr_cup (x, y)			/* dumb update function		 */
    int x, y;
{
    int i;
    struct htab *h;

    if (pcb[y][x] & ishb)
	return (0);		/* don't care			 */

    for ((h = htp, i = 0); i < nh; (h++, i++))
	if (h -> x == x && h -> y == y)
	    h -> snn = s1;

    return (0);
}

N_route (net, max, xl, yl, xh, yh)
    struct nlhd *net;
    int max;
    int xl, yl, xh, yh;
/*******************************************************************\
* 								    *
*  Net-route: This routine tries to route an entire net. A minimal  *
*  spanning tree - approach is used, but if this does not succeed,  *
*  all possible routes are tried. This may take some time for long  *
*  nets. <max> is a limit on the number of attempts to connect 2    *
*  subnets.							    *
*  N_route updates the connectivity flag in the net-list header.    *
*  The number of successfully routed segments is returned.	    *
* 								    *
*  <x/y-h/l> defines a subarea for net parts.			    *
* 								    *
\*******************************************************************/
{
    int    i, j, k, l, ct_key (), Nr_cup (), no_seg;
    struct htab *h1, *h2;
    struct clst *c0, *c1, *c2, *clp;
    struct nlst *p;

    if (V.cnet)
	deseln (V.cnet);	/* deselect current net		 */

    if (net -> l < 2)
	return (0);		/* trivial nets always succeed	 */

    if (selnet (net)) {		/* select net			 */
	deseln (net);
	return (0);		/* net is already done		 */
    }

    no_seg = 0;

#ifdef debug
    if(net == testbp) {
	Ferr_msg ("Break");
	i = 0;			/* set breakpoint here		 */
    }
#endif

    nh = net -> l;		/* (max) number of holes in net	 */
    htp = (struct htab *) malloc (nh * sizeof (*htp));
    clp = (struct clst *) malloc (nh * (nh - 1) * sizeof (*clp) / 2);

    nh = 0;			/* count hole in area of interest */
    for (h1 = htp, p = net -> lp; p; p = p -> n) {
				/* scan holes of net		 */
	h1 -> x = p -> c -> x;
	h1 -> y = p -> c -> y;
	if (h1 -> x >= xl && h1 -> x <= xh &&
	    h1 -> y >= yl && h1 -> y <= yh    ) {
	    h1 -> snn = p -> mk;
	    h1++;
	    nh++;
	}
    }

    if (nh < 2) {		/* nothing to do		 */
	free (htp);
	free (clp);
        deseln (net);
	return 0;
    }

    k = 0;			/* number of possible connections*/
    c0 = clp;
    for ((i = 1, h1 = htp); i < nh; (i++, h1++))
	for ((j = i + 1, h2 = htp + i); j <= nh; (j++, h2++))
	    if (h1 -> snn != h2 -> snn) {

				/* pre-select segment orientation */
		if (abs (h1 -> x - h2 -> x) > abs (h1 -> y - h2 -> y)) {
		    if (h1 -> x > h2 -> x) {
			c0 -> d = h1;
			c0 -> s = h2;}
		    else {
		        c0 -> s = h1;
		        c0 -> d = h2;
		    }}
		else {
		    if (h1 -> y > h2 -> y) {
			c0 -> d = h1;
			c0 -> s = h2;}
		    else {
		        c0 -> s = h1;
		        c0 -> d = h2;
		    }
		}

		c0 -> c = abs (h1 -> x - h2 -> x) + abs (h1 -> y - h2 -> y);
		c0++;
		k++;
	    }

    qsort (clp, k, sizeof (*clp), ct_key);

#ifdef debug
    if (ttt) {
	c0 = clp;
	for (i = 0; i < k; (c0++, i++))
	printf ("%2d: s=%3d,%3d (%3d) d=%3d,%3d (%3d) c=%d\n", i,
	        c0 -> s -> x, c0 -> s -> y, c0 -> s -> snn,
		c0 -> d -> x, c0 -> d -> y, c0 -> d -> snn, c0 -> c);
    }
#endif

    for ((i = 0, c0 = clp); i < k; i++)
	(c0++) -> c = 0;	/* re-use cost as retry count	 */

    for ((i = 0, c0 = clp); i < k; (c0++, i++)) {
				/* try to connect the subnets	 */
	if (c0 -> c > max)	/* max. try count exceeded ?	 */
	    continue;

	s1 = c0 -> s -> snn;
	s2 = c0 -> d -> snn;

	if ((s1 != s2) &&	/* try to join 			 */
	    s_route (c0 -> s -> x, c0 -> s -> y, c0 -> d -> x, c0 -> d -> y)){
#ifdef debug
		if (ttt) printf("connected subnet %d to %d\n", s1, s2);
#endif
	    no_seg++;
	    wtvf = nil;		/* update conectivity information*/
	    wthf = Nr_cup;
	    wtrace (c0 -> s -> x, c0 -> s -> y, vec);

	    c1 = c2 = c0 + 1;
	    l = k;
	    for (j = i + 1; j < k; (c1++, j++)) {
		if (s1 != c1 -> s -> snn || s1 != c1 -> d -> snn) {
				/* viable connection */
		    c2 -> s = c1 -> s;
		    c2 -> d = c1 -> d;
		    c2 -> c = c1 -> c;
		    c2++;}
		else
		    l--;
	    }
	    k = l;}
	else {
#ifdef debug
	    if (ttt)
		printf ("failed to connect %d to %d\n", s1, s2);
#endif
	    c1 = c0 + 1;
	    for (j = i + 1; j < k; (c1++, j++))
		if ((s1 == c1 -> s -> snn && s2 == c1 -> d -> snn) ||
		    (s2 == c1 -> s -> snn && s1 == c1 -> d -> snn))
		    (c1 -> c)++;
	}
#ifdef debug
	if (ttt) {
	    c1 = c0 +1;
	    Ferr_msg ("test");
	    for(l = i + 1; l < k; (c1++, l++))
		printf ("%2d: s=%3d,%3d (%3d) d=%3d,%3d (%3d) c=%d\n", l,
		        c1 -> s -> x, c1 -> s -> y, c1 -> s -> snn,
			c1 -> d -> x, c1 -> d -> y, c1 -> d -> snn, c1 -> c);
	}
#endif
    }

    j = htp -> snn;
    h1 = htp + 1;
    for (i = 1; i < nh;(h1++, i++))/* more than one subnet left? */
	if (h1 -> snn != j)
	    break;

			/* net done ?			 */
    net -> f = (i >= nh && nh == net -> l) || cchk (net);

    deseln (net);
    free (clp);			/* free memory			 */
    free (htp);
    return (no_seg);
}

P_route (net)
    struct nlhd *net;
/*********************************************************************\
* 								      *
*  Primitive-route: This routine tries to route the *trivial* parts   *
*  of a net. A minimal spanning tree approch is used. This code	      *
*  should run on empty nets only. It is intended to be used in	      *
*  a pre-routing phase of the auto-router. Multiple connections	      *
*  may result on a partially completed net. This routine is	      *
*  faster than N_route.						      *
* 								      *
*  The parts of the MST that are not routed are saved to the tot_mst  *
*  structure. You understand that this side-effect is used	      *
*  by 'autor', so do not call P_route elsewhere.		      *
* 								      *
\*********************************************************************/
{
    int    i, j, k, l, ct_key (), no_seg;
    struct htab *h1, *h2;
    struct clst *c0, *c1, *c2, *clp;
    struct nlst *p;
    int dx, dy;
    int ttc = 0;		/* test count (check MST)	 */

    if (V.cnet)
	deseln (V.cnet);	/* deselect current net		 */

    if (net -> l < 2)
	return (0);		/* trivial nets always succeed	 */
    no_seg = 0;

    if (selnet (net)) {		/* select net			 */
	deseln (net);
	return (0);		/* net is already done		 */
    }

    nh = net -> l;		/* number of holes in net	 */
    htp = (struct htab *) malloc (nh * sizeof (*htp));
    clp = (struct clst *) malloc (nh * (nh - 1) * sizeof (*clp) / 2);

    i = 0;			/* count subnets		 */
    for ((h1 = htp, p = net -> lp); p; (h1++, p = p -> n)) {
				/* scan holes of net		 */
	h1 -> x = p -> c -> x;
	h1 -> y = p -> c -> y;
	h1 -> snn = p -> mk;
    }

    k = 0;			/* number of possible connections*/
    c0 = clp;
    for ((i = 1, h1 = htp); i < nh; (i++, h1++))
	for ((j = i + 1, h2 = htp + i); j <= nh; (j++, h2++)) {

				/* pre-select segment orientation */
		if (abs (h1 -> x - h2 -> x) > abs (h1 -> y - h2 -> y)) {
		    if (h1 -> x > h2 -> x) {
			c0 -> d = h1;
			c0 -> s = h2;}
		    else {
		        c0 -> s = h1;
		        c0 -> d = h2;
		    }}
		else {
		    if (h1 -> y > h2 -> y) {
			c0 -> d = h1;
			c0 -> s = h2;}
		    else {
		        c0 -> s = h1;
		        c0 -> d = h2;
		    }
		}
				/* get cost (length) of this segment */
		c0 -> c = abs (h1 -> x - h2 -> x) + abs (h1 -> y - h2 -> y);
		c0++;
		k++;
	}

    qsort (clp, k, sizeof (*clp), ct_key);

    for ((i = 0, c0 = clp); i < k; (c0++, i++)) {
				/* try to connect the subnets	 */
	s1 = c0 -> s -> snn;
	s2 = c0 -> d -> snn;

	if (s1 != s2) {		/* try connection		 */

	    ttc++;		/* count MST edges		 */

	    if (filter (c0 -> s -> x, c0 -> s -> y,
			c0 -> d -> x, c0 -> d -> y ))
		no_seg++;
	    else {		/* add segments to SSEGL	 */
		SSEGL[sseglc].p = net;

/************************************************\
* 						 *
*  Segment list cost function: small cost first	 *
* 						 *
\************************************************/
		dx = abs (c0 -> s -> x - c0 -> d -> x);
		dy = abs (c0 -> s -> y - c0 -> d -> y);
		SSEGL[sseglc].c = c0 -> c * 2 +	     /* long segments later */
		   (100 * abs (dx - dy)) / abs (dx + dy);  /* square bonus  */

		SSEGL[sseglc].xs = c0 -> s -> x;
		SSEGL[sseglc].ys = c0 -> s -> y;
		SSEGL[sseglc].xe = c0 -> d -> x;
		SSEGL[sseglc].ye = c0 -> d -> y;
		sseglc++;
	    }

	    for ((j = 0, h1 = htp); j < nh; (j++, h1++))
		if (h1 -> snn == s2)
		    h1 -> snn = s1;	/* subnet s2 is gone	 */
	    c0 -> d -> snn = s1;
	    c1 = c2 = c0 + 1;
	    l = k;
	    for (j = i + 1; j < k; (c1++, j++)) {
		if (s1 != c1 -> s -> snn || s1 != c1 -> d -> snn) {
				/* viable connection */
		    c2 -> s = c1 -> s;
		    c2 -> d = c1 -> d;
		    c2++;}
		else
		    l--;
	    }
	    k = l;
	}
    }

    net -> f = cchk (net);	/* net done ?			 */

    if(ttc > (net->l -1))
	err("P_route: not MST", ttc, net -> l,
	    (int) (net - NH) / sizeof(NH[0]), 0);

    free (clp);			/* free memory			 */
    free (htp);
    deseln (net);
    return (no_seg);
}
!E!O!F!