Skip to content
Extraits de code Groupes Projets
Sélectionner une révision Git
  • 707e92c1846b66125e39b37a51e3acf54e2f0415
  • master par défaut protégée
  • convert-to-dlang
  • clear-warnings
  • update-structs
  • unittests
  • bjarne-stroustrup
  • 5.67.0
8 résultats

log.c

Blame
  • log.c 363,08 Kio
    /* "LOG", the circuit editing and simulation system,
       "DigLOG", the digital simulator for LOG.
       Copyright (C) 1985, 1990 David Gillespie.
       Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.
    
       "AnaLOG", the analog simulator for LOG.
       Copyright (C) 1985, 1990 John Lazzaro.
       Author's address: lazzaro@csvax.caltech.edu; 256-80 Caltech.
    
       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation (any version).
    
       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.
    
       You should have received a copy of the GNU General Public License
       along with this program; see the file COPYING.  If not, write to
       the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       */
    
    /*
       Logic Simulator   Version 4.1
       For HP 9836C
    
    
       Copyright (c)  1985
    
       David Gillespie
       */
    
    
    #include <unistd.h>
    #include <time.h>
    
    #define LOAD_SEARCH    /* Use the search path in load command. */
    
    #include <p2c/p2c.h>
    
    #include "logdef.h"
    #include <p2c/sysglobals.h>
    #include <p2c/sysdevs.h>
    #include <p2c/rnd.h>
    
    /*homeless orphans*/
    
    #include <p2c/misc.h>
    #include "help.h"
    #include <p2c/newci.h>
    #include <p2c/filepack.h>
    #include <p2c/citinfomod.h>
    #include <p2c/iodecl.h>
    #include <p2c/general_1.h>
    #include <p2c/general_2.h>
    #include <p2c/general_3.h>
    #include <p2c/fs.h>
    #include <p2c/mylib.h>
    #include "logfont.h"
    #include "logstuff.h"
    #include "swap.h"
    #include <p2c/newkbd.h>
    #include <p2c/strings.h>
    #include <p2c/newasm.h>
    #include <p2c/newcrt.h>
    
    extern char *GetChipmunkPath();
    char *my_strdup();
    #undef strdup
    #define strdup my_strdup
    #define newci_findprocedure2  findprocedure
    extern int findprocedure (char *name, void (**start)());
    
    
    #define debuglog        false
    #define debugprint      true
    
    #ifndef LOGLIB
    
    #define LOGLIB          "/LIB/LOG"
    #endif
    
    #define gridcen         25   /* Center of "grid" used while drawing gates */
    
    #define memtolerance    20000   /* Minimum "safe" amount of free memory */
    
    #define charheight      8   /* Height of text characters */
    
    #define tapdelay        30  /* How long to wait before a "tap" becomes a "press" */
    #define taptolerance    5   /* How far you can move before a "tap" becomes a "press" */
    #define knobwait        25   /* How long to wait for the knob during scroll */
    
    #define deffastmin      2   /* Simulator delay for good response (csecs) */
    #define deffastmax      50   /* Simulator delay for fast simulation */
    #define deffastrate     35   /* Centiseconds per increase in fastspeed */
    
    #define frytime         50   /* How long a frying object fries, in csecs */
    
    #define chrplain        128
    #define chrinverse      129
    #define chrunderl       132
    
    #define chrgreen        136
    #define chryellow       137
    #define chrblack        138
    #define chrred          139
    #define chrcyan         140
    #define chrwhite        141
    #define chrblue         142
    #define chrpurple       143
    
    #define EXEC            "\003"   /* ASCII code of EXECUTE key */
    #define CTRLD           "\253"   /* Control-D */
    
    
    #define maxmaxkinds     255   /* Maximum number of gates in catalog */
    
    #define maxgatesfiles   15
    #define defmaxsignal    500   /* Maximum number of TO/FROM nodes */
    #define defhtmaxcount   500   /* Maximum number of history timesteps */
    
    #define origin          16384   /* Origin of grid coordinate system */
    
    #define topmessagepos   2   /* Position of first message */
    
    #define maxrots         8   /* Number of gate orientations */
    
    #define hscrollspd      2   /* Knob-scrolling speed */
    #define vscrollspd      2
    #define hfastscrollspd  10   /* Menu-box-scrolling speed */
    #define vfastscrollspd  10
    
    #define watchdogtime    500   /* Time limit for CLR I/O "watchdog" timer */
    
    #define refrdelay       70   /* Delay before refreshing screen */
    
    #define baselinewidth   80
    #define kindgroupmaxsize  40   /* Stuff about gate slots in menu area */
    
    #define kindgroupspacing  (gridcen * 2)
    
    #define maxsafescale    (gridcen / log_scale0)
    
    #define menux1          1
    #define menux2          48
    #define menux3          (-69)
    #define menux4          (-27)
    
    #define pigsfly         false   /*  */
    
    #define gattrrecsize    (sizeof(log_gattrrec) + ((sizeof(log_gattrrec)) & 1))
    #define kattrrecsize    (sizeof(log_kattrrec) + ((sizeof(log_kattrrec)) & 1))
    
    #define histleft        40
    #define histvscale      6
    /*(histdown div 24) * 2*/
    #define histdivision    30
    
    #define histsweeptype   1
    #define histtrigsig     2
    #define histstarttime   3
    #define histstoptime    4
    #define histfullaction  5
    #define histminstep     6
    #define histmaxstep     7
    #define histmaxcount    8
    #define histcurcount    9
    #define histalignsigs   10
    #define histfirsttime   11
    #define histcurtime     12
    #define histsecdiv      13
    #define histcurtstep    14
    
    #define histsweep_contin  0
    #define histsweep_onreset  1
    #define histsweep_trig  2
    #define histsweep_manual  3
    
    #define rablistsize     23   /* Size of Rabbit State Machine */
    #define rabtabsize      10   /* Maximum number of rabbits on screen */
    #define rabmussize      32   /* Length of rabbit theme music */
    #define rabdelay        30000   /* Time to wait for rabbit: 5 Minutes */
    
    #define NAMEGAP         (3 * gg.scale) /* signallabel horizontal offset */
    
    
    typedef struct descrec {
    	long ptr;
    	uchar numvects, numpins, numpnums, lblsize, simtype, procsize;
    	/* log_kflags */ short flag;
    	schar xx1, yy1, xx2, yy2;
    } descrec;
    
    typedef struct ovectorrec {
    	schar x1, y1, x2, y2;
    } ovectorrec;
    
    typedef union filerec {
    	uchar b[256];
    	schar sb[256];
    	char c[256];
    	short sh[128];
    	long i[64];
    	log_pac8 ix[32];
    	ovectorrec vec[64];
    	log_pinrec pin[64];
    	log_pnumrec pnum[64];
    	descrec desc[16];
    	log_pac4 c4[64];
    } filerec;
    
    typedef struct filerecfilerec {
    	FILE *f;
    	FILEBUFNC(f,filerec);
    } filerecfilerec;
    
    typedef struct rablistrec {
    	short x, y, next;
    } rablistrec;   /* Rabbit mode state descriptor */
    
    typedef rablistrec rablisttype[rablistsize + 1];
    
    typedef struct rabmusrec {
    	short note, time;
    } rabmusrec;   /* Rabbit music descriptor */
    
    typedef rabmusrec rabmustype[rabmussize];
    
    typedef short kindgrouptype[kindgroupmaxsize];
    typedef log_gattrrec *kindattrtype[kindgroupmaxsize];
    
    typedef uchar loadedgatesarray[(log_million + 7) / 8];
    typedef char indexarray[log_million][9];
    typedef short ioffsetarray[log_million];
    typedef uchar igrouparray[log_million];
    /* Index to gate library */
    
    typedef struct logmenurec {
    	char name[17];
    	char cmd[33];
    	int *bool_;
    } logmenurec;   /* Pop-up menu options */
    
    typedef logmenurec logmenutype[8];
    
    
    
    /* Pointer to node-combination record */
    /* Pointer to temporary solder */
    /* Pointer to configuration record */
    /* Pointer to macro key record */
    /* Pointer to box in catalog page */
    /* Pointer to library string record */
    
    
    typedef struct cnrec {
    	log_nrec *n, **np;
    	int done;
    	struct cnrec *next;
    } cnrec;   /* Delayed Combinenodes record */
    
    
    typedef struct blobrec {
    	log_hwrec *hw;
    	log_vwrec *vw;
    	short x, y;
    	struct blobrec *next;
    } blobrec;
    
    
    typedef struct cnfrec {
    	char tool[17];
    	struct cnfrec *next;
    	char s[256];   /*not fully allocated*/
    } cnfrec;   /* Tool configuration record */
    
    
    typedef struct macrorec {
    	char key;
    	struct macrorec *next;
    	char name[33];
    } macrorec;   /* Macro key */
    
    
    typedef struct catboxrec {
    	short pos, count;
    	struct catboxrec *next;
    } catboxrec;   /* yow */
    
    
    typedef struct librstrrec {
    	char name[9];
    	char *str;
    	struct librstrrec *left, *right;
    } librstrrec;
    
    
    typedef struct baseptrs {
    	log_grec *gcopy;
    	log_srec *scopy;
    	log_hwrec *hwcopy;
    	log_vwrec *vwcopy;
    	log_lrec *lcopy;
    	log_brec *bcopy;
    	short x1copy, y1copy, x2copy, y2copy, dxcopy, dycopy, pgnum;
    	int valid;
    } baseptrs;
    
    
    
    /* 0*/
    /* If the pen is in "this" sector, */
    /* 1*/
    /*   switch to "this" state.       */
    /* 2*/
    /* 3*/
    /* 4*/
    /* 5*/
    /* 6*/
    /* 7*/
    /* 8*/
    /* 9*/
    /*10*/
    /*11*/
    /*12*/
    /*13*/
    /*14*/
    /*15*/
    /*16*/
    /*17*/
    /*18*/
    /*19*/
    /*20*/
    /*21*/
    /*22*/
    /*23*/
    
    static const rablisttype rablist = {
    	{ 0, 0, 1 },
    	{ 0, 4, 2 },
    	{ 0, 3, 3 },
    	{ 0, 2, 4 },
    	{ 0, 1, 5 },
    	{ 0, 0, 6 },
    	{ 1, 0, 7 },
    	{ 2, 0, 8 },
    	{ 3, 0, 9 },
    	{ 4, 0, 10 },
    	{ 4, 1, 11 },
    	{ 4, 2, -12 },
    	{ 3, 2, 13 },
    	{ 2, 2, 14 },
    	{ 1, 2, 15 },
    	{ 2, 2, -18 },
    	{ 0, 2, 17 },
    	{ 1, 2, 15 },
    	{ 3, 2, -20 },
    	{ 2, 3, -20 },
    	{ 3, 3, 21 },
    	{ 4, 3, -23 },
    	{ 3, 4, -23 },
    	{ 4, 4, 42 }
    };
    
    static const rabmustype discomadness = {
    	{ 3, 46 },
    	{ 0, 8 },
    	{ 4, 10 },
    	{ 0, 15 },
    	{ 4, 12 },
    	{ 0, 2 },
    	{ 5, 35 },
    	{ 0, 6 },
    	{ 4, 35 },
    	{ 0, 6 },
    	{ 5, 8 },
    	{ 0, 17 },
    	{ 5, 12 },
    	{ 0, 2 },
    	{ 6, 35 },
    	{ 0, 6 },
    	{ 5, 35 },
    	{ 0, 6 },
    	{ 6, 8 },
    	{ 0, 17 },
    	{ 6, 12 },
    	{ 0, 2 },
    	{ 8, 35 },
    	{ 0, 6 },
    	{ 3, 35 },
    	{ 0, 6 },
    	{ 4, 8 },
    	{ 0, 16 },
    	{ 4, 12 },
    	{ 0, 3 },
    	{ 5, 50 },
    	{ 0, 0 }
    };
    
    #define maxeditmodes    4
    
    
    static log_action_t gg;   /* External global variables */
    
    static short cursx, cursy;   /* Current position of cursor */
    static short cursx1, cursy1;   /* Wire starting point */
    static short cursx2, cursy2;   /* Wire ending point */
    static short chairx, chairy;   /* Current position of crosshair */
    
    static int cursorflag;   /* Cursor is displayed */
    static int prevcursorflag;
    /* Cursor was displayed before operation began */
    static int chairflag;   /* Crosshair is on screen */
    static int chairflag2;   /* Crosshair will be on screen */
    static int rbandflag;   /* Rubber-band wire is on screen */
    static int rabbits, rabflag;   /* Rabbit mode */
    static int avoidrabbits;
    
    static short txacross, txdown, across, down, baseline, line1, line2,
    			 kindgroupbase, kindgroupleft, kindgroupright, kindgroupstart,
    			 kindgroupsize, histdown;
    
    static int entrycapslock;   /* Capslock status on entry */
    static int oldcapslock;   /* Previous capslock status */
    
    static int signalcaps;   /* Capslock flag for signal-name entry */
    static int labelcaps;   /* Capslock flag for label entry */
    
    static char (*index_)[9];   /* Index into gate library */
    static short *indexoffset;   /* Offset of each gate */
    static uchar *indexfile;   /* File number of each gate */
    static uchar *indexgroup;   /* Group number of each gate */
    static uchar *loadedgates;   /* Tells whether a gate is in the catalog */
    static log_krec *kind[maxmaxkinds];   /* Kind of gate in each catalog space */
    static kindgrouptype kindgroup;   /* Kind of gate in each menu-area space */
    static kindgrouptype kindsig;
    static kindattrtype kindattr;
    static na_strlist_t *gatefilenames;
    static short maxkinds, catwidth;
    static catboxrec *catboxes;
    static librstrrec *librstrs;
    
    static char *gatesname[maxgatesfiles];
    static char *loghelpname, *lognewsname;   /* Names of system files */
    
    static long temp1, temp2, temp3, temp4;   /* For use by main program */
    static char tempch;
    
    static short zoom;   /* Zooming level */
    static int ospointflag;   /* Starting point was touched */
    
    static long xoff0, yoff0;   /* Old XOFF, YOFF */
    
    static short curwcolor;   /* Current VLSI wire color */
    static char cureditmode;   /* Current editing (gate-tapping) mode */
    static short curlistgroup;   /* Current group in library list */
    
    static int vlsimode[log_maxpages];   /* Page contains VLSI circuits */
    static long xoffp[log_maxpages], yoffp[log_maxpages];
    /* XOFF, YOFF for non-current pages */
    static short gatecount[log_maxpages];   /* Highest used gate-ID number */
    static char *curfilename[log_maxpages];   /* Name of last-loaded file */
    static long realcurpage;
    
    static log_nrec *freenode;   /* Node "free" list */
    static log_grec *freegate;   /* Gate "free" list */
    
    static baseptrs copybuf;   /* Del/Copy/Paste buffer */
    
    static long htcount;   /* Number of timesteps in list */
    static short hncount;   /* Number of names in list */
    static short hnocount;   /* Old number of names in list */
    static short histtrig;   /* Number of signal which triggers history */
    static na_strlist_t *histlbl;
    static short histnumattrs;
    static log_kattrrec *histkattr;
    static log_gattrrec *histgattr;
    static short histgridmode, histgridwhich;
    static log_hnrec *histgridhn;
    static double histvalrange, histdivsacross;
    static int histonscreen;   /* Leading edge of trace is visible */
    static int histreset;   /* Clear the history memory */
    static double histtime;   /* Current time for history mode */
    
    static int probeflag;   /* Has the probe been checked? */
    
    static log_nrec *nodeconflictbase;   /* Node conflict list */
    static log_grec *gateconflictbase;   /* Gate conflict list */
    
    static cnfrec *cnfbase;   /* List of tool configuration lines */
    static na_strlist_t *colorbase;   /* List of configured colors */
    static macrorec *macrobase;   /* List of macro keys */
    static na_strlist_t *thingstodo, *nexttodo;   /* List of delayed commands */
    static na_strlist_t *messages;   /* List of delayed messages */
    static na_strlist_t *commandlist;   /* List of tool-activation commands */
    
    static char modename[9];   /* Word in 'mode' area of menu */
    static int modeflag;   /* Mode area contains a word */
    static long modetime;   /* Time (in minutes) in mode display */
    static log_krec *modeprobekind;
    
    static nk_keytransinfo *curkeytrans;   /* Current keyboard definitions */
    
    static enum {
    	normal, grid, delete__, copy_, paste, boxcursor
    } cursortype, oldcursortype;
    /* Type of cursor */
    
    /*  menupicture, errorpicture : m_picturevar;              { Various saved images */
    static short bottomcount;   /* How many nested BEGINBOTTOMs */
    
    static uchar rcolormap[16], gcolormap[16], bcolormap[16];
    
    static short gategreen, gateyellow, gatered, gateorange, gateblack, gatewhite;
    
    static short defineboxcolor, definebackcolor, definetextcolor, catboxcolor;
    
    static short messagepos;   /* Position of next message */
    static short messageright;   /* Maximum width of messages */
    
    static long fastsavetime;
    
    static long watchdog, rabtime;   /* Miscellaneous timers */
    
    static log_tool *simtype_ignore;   /* Non-simulated type */
    static log_tool *simtype_common;   /* Common-pin type */
    
    static double status_oldtime, status_oldtstep;
    static long status_oldmem;
    
    static rablistrec rabtable[rabtabsize];   /* Positions of rabbits */
    static short rabstate;   /* Rabbit recognizer state */
    
    static long helpptr;   /* Help descriptor */
    
    static int popup_grid;   /* Pop-up menus */
    static logmenurec *popupmenus[4];
    
    static filerecfilerec *libf1[maxgatesfiles];   /* Library files */
    static short libfstart[maxgatesfiles];
    /* First descriptor record in LIBF1 */
    static short libptr;   /* Most recently replaced catalog item */
    static short idxsize;   /* Number of gates in library */
    static char *librgroupnames[9];
    
    static short refrtimer, refrtimer0;   /* Time until screen is refreshed */
    
    static long tabletaddr;
    
    static char *dumpfname, *tracefname;
    static FILE *dumpfile, *tracefile;
    
    static long programmark;
    
    static char pushedbackkey, realkey;
    
    extern long EXCP_LINE;   /* Line number of last error */
    static long excpline;
    
    static short conflictdelay;
    
    static int eightcolors;   /* Has only 8 colors */
    static int onescreen;   /* Has only one screen */
    static int doingcnffunction;   /* This is an ACT_CNF, not an ACT_FUNC */
    static int justonecommand;   /* LOG -R mode, so exit after first cmd */
    static int displaynews;   /* LOGNEWS has not yet been displayed */
    static int immedscroll;   /* Don't need to defer 'REFR' function */
    static int tempverbose;   /* Verbose mode temporarily on */
    static int commandfound;   /* Function name was acknowledged */
    static int cursorhide;   /* Cursor is hidden */
    static int reportnowait;   /* Don't wait for key on bug reports */
    static int firsttraining;   /* Training used for first time */
    static int training;   /* Training mode for Help command */
    static int snapflag;   /* Snap-to-grid cursor */
    static int showsolder;   /* Display solder points */
    static int briefprobe;   /* Temporary probe mode */
    static int conflictenbl;   /* Conflict checking enabled */
    static int conflictstop;   /* Conflict stopping mode */
    static int anyconflicts;   /* Any active, reported conflicts? */
    static int steppingoff;   /* Single-step is turning simulation off */
    static int suppressdots;   /* Temporarily suppressing red dots */
    static int glowsolder;   /* Display solder dots in Glow mode */
    static int vlsi;   /* Current page is VLSI mode */
    
    
    extern void m_saveclip ();
    
    extern void nc_cursor_on ();
    
    extern void nc_cursor_off ();
    
    
    static char *ioresult_message(char *Result, long iores)
    {
    	char s[81];
    
    	misc_getioerrmsg(s, iores);   /* MISC */
    	return strcpy(Result, s);
    }
    
    
    /*==================  WORKING  ===================*/
    /*=                                              =*/
    /*=  Reserved for future use.                    =*/
    /*=                                              =*/
    /*================================================*/
    
    static void working()
    {
    }
    
    /*===================  ALERT  ====================*/
    /*=                                              =*/
    /*=  Produce an audible alert from the keyboard. =*/
    /*=  Used to attract attention to keyboard.      =*/
    /*=                                              =*/
    /*================================================*/
    
    static void alert()
    {
    	if (!gg.quiet)
    		BEEPER(17, 10);
    }
    
    
    /*==================  WARNING  ===================*/
    /*=                                              =*/
    /*=  Produce an audible alert from the keyboard. =*/
    /*=  This one generally signifies an error.      =*/
    /*=                                              =*/
    /*================================================*/
    
    static void warning()
    {
    	if (!gg.quiet)
    		BEEPER(4, 10);
    }
    
    
    static void clearshowalpha ();
    
    /*===================  REPORT  ===================*/
    /*=                                              =*/
    /*=  Report an internal error.                   =*/
    /*=                                              =*/
    /*================================================*/
    
    static void message (char *msg);
    
    
    static void report(short num, char *s)
    {
    	char ch;
    	char STR2[256];
    
    	if (reportnowait)
    	{
    		sprintf(STR2, "Internal error %d in %s", num, s);
    		message(STR2);
    		return;
    	}
    	BEEPER(4, 15);
    	clearshowalpha();
    	nk_gotoxy(0, txdown - 1);
    	printf("\215--> Internal error %d in %s\210\n", num, s);
    	if (gg.traceflag)
    		fprintf(tracefile, "--> Internal error %d in %s\n", num, s);
    	m_alpha_on();
    	printf("    Press any key to continue.");
    	ch = nk_getkey();
    	if (ch == 'N' || ch == 'n')
    		reportnowait = true;
    	putchar('\n');
    }
    
    
    /*==================  SETMODE  ===================*/
    /*=                                              =*/
    /*=  Draw a word in the "mode" location of       =*/
    /*=     the menu area.                           =*/
    /*=                                              =*/
    /*================================================*/
    
    static void refreditmode ();
    
    static void log_setmode(const char *s)
    {
    	time_t h;
    	char *cp;
    
    	remcursor();
    	clipoff();
    	m_color((long)gg.color.backgr);
    	if (gg.showpage > 0)
    		drawstr2(across + menux3, line2, modename);
    	refreditmode();   /*may have been trashed by previous mode name*/
    	if (*s != '\0')
    	{
    		strcpy(modename, s);
    		modeflag = true;
    		m_color((long)gg.color.selword);
    	}
    	else
    	{
    		if (gg.probekind != NULL)
    		{
    			strcpy(modename, gg.probekind->name);
    			m_color((long)gg.color.selword);
    		}
    		else
    		{
    			time(&h);
    			cp = ctime(&h);
    			sprintf(modename, "%.5s", cp + 11);
    			modetime = timers_sysclock() / 6000;
    			if (!strcmp(modename, "00:00"))
    				strcpy(modename, "__@/ ");
    			m_color((long)gg.color.menuword);
    		}
    		modeflag = false;
    		modeprobekind = gg.probekind;
    	}
    	if (gg.showpage > 0)
    		drawstr2(across + menux3, line2, modename);
    }
    
    
    static void dounits(char *s, double *r)
    {
    	char ch;
    
    	if (*s == '\0')
    		return;
    	ch = s[0];
    	if (ch >= 'a')
    		ch -= 32;
    	if (ch == 'F')
    	{
    		*r *= 1e-15;
    		return;
    	}
    	if (ch == 'P')
    	{
    		*r *= 1e-12;
    		return;
    	}
    	if (ch == 'N')
    	{
    		*r *= 1e-9;
    		return;
    	}
    	if (ch == 'U')
    	{
    		*r *= 1e-6;
    		return;
    	}
    	if (ch == 'K')
    	{
    		*r *= 1e3;
    		return;
    	}
    	if (ch == 'G')
    	{
    		*r *= 1e9;
    		return;
    	}
    	if (ch == 'T')
    	{
    		*r *= 1e12;
    		return;
    	}
    	if (ch != 'M')
    		return;
    	if (strlen(s) >= 3 && (s[1] == 'E' || s[1] == 'e') &&
    			(s[2] == 'G' || s[2] == 'g'))
    		*r *= 1e6;
    	else
    		*r *= 1e-3;
    }
    
    
    static void readreal(char *s_, double *r)
    {
    	char s[256];
    	long i;
    	char *STR1;
    	char STR2[256];
    
    	strcpy(s, s_);
    	if (!(*s != '\0' &&
    				(s[0] == '.' || s[0] == '+' || s[0] == '-' || isdigit(s[0]))))
    		return;
    	*r = strtod(s, &STR1);
    	i = STR1 - s + 1;
    	strcpy_overlap(s, s + i - 1);
    	strcpy(STR2, strltrim(s));
    	strcpy(s, STR2);
    	dounits(s, r);
    }
    
    
    static void strwordx(char *buf, char *wrd)
    {
    	size_t i;
    	char STR1[256];
    	char STR2[256];
    
    	strcpy(STR1, strltrim(strrtrim(strcpy(STR2, buf))));
    	strcpy(buf, STR1);
    	if (*buf != '"')
    	{
    		strword(buf, wrd);
    		return;
    	}
    	i = strposc(buf, '"', 2L);
    	if (i == 0)
    		i = strlen(buf) + 1;
    	strpart(wrd, buf, 2, i - 1);
    	strcpy_overlap(buf, buf + i);
    }
    
    
    static void getword(char *buf, char *wrd)
    {
    	char STR1[256];
    	char STR2[256];
    
    	strcpy(STR1, strltrim(strrtrim(strcpy(STR2, buf))));
    	strcpy(buf, STR1);
    	if (*buf == '"')
    		strwordx(buf, wrd);
    	else
    	{
    		strwordx(buf, wrd);
    		strupper(wrd, wrd);
    	}
    }
    
    
    static long getint(char *s, long def)
    {
    	char w[10];
    	long i, j, sign;
    	int valid;
    	long FORLIM;
    
    	getword(s, w);
    	if (*w == '-')
    	{
    		strcpy_overlap(w, w + 1);
    		sign = -1;
    	}
    	else
    	{
    		sign = 1;
    	}
    	j = 0;
    	valid = true;
    	FORLIM = strlen(w);
    	for (i = 0; i < FORLIM; i++)
    	{
    		if (w[i] < '0' || w[i] > '9')
    			valid = false;
    		else
    			j = j * 10 + w[i] - 48;
    	}
    
    	if (*w != '\0' && valid)
    		return (j * sign);
    	else
    		return def;
    }
    
    
    static void pgetint(char *buf, long *i, long def)
    {
    	*i = getint(buf, def);
    }
    
    
    static double getreal(char *s, double def)
    {
    	char w[81];
    	double r;
    
    	getword(s, w);
    	r = def;
    	TRY(try1);
    	readreal(w, &r);
    	RECOVER(try1);
    	if (P_escapecode == -20)
    		_Escape(P_escapecode);
    	r = def;
    	ENDTRY(try1);
    	return r;
    }
    
    static void pgetreal(char *buf, double *r, double def)
    {
    	*r = getreal(buf, def);
    }
    
    
    static void getbool(char *buf, int *b)
    {
    	char w[17];
    
    	getword(buf, w);
    	if (!strcmp(w, "ON") || !strcmp(w, "YES") || !strcmp(w, "Y") ||
    			!strcmp(w, "RABBITS"))
    	{   /*avoid*/
    		*b = true;
    		return;
    	}
    	if (!strcmp(w, "OFF") || !strcmp(w, "NO") || !strcmp(w, "N"))
    	{
    		*b = false;
    		return;
    	}
    
    	if (!strcmp(w, "?"))
    		tempverbose = true;
    	else if (*w == '\0')
    		*b = !*b;
    }
    
    
    /*=================  SORTSHINTS  =================*/
    /*=                                              =*/
    /*=  Put two shortint variables into increasing  =*/
    /*=     numerical order.                         =*/
    /*=                                              =*/
    /*================================================*/
    
    static void sortshints(short *x, short *y)
    {
    	short temp;
    
    	if (*x <= *y)
    		return;
    	temp = *x;
    	*x = *y;
    	*y = temp;
    }
    
    
    /*=================  TESTPROBE  ==================*/
    /*=                                              =*/
    /*=  Find which wire, pin, or gate the Probe     =*/
    /*=     is touching and set PROBENODE or         =*/
    /*=     PROBEGATE to its address.                =*/
    /*=                                              =*/
    /*================================================*/
    
    static void unprobe()
    {
    	gg.probenode = NULL;
    	gg.probegate = NULL;
    	gg.probepin = 0;
    	gg.probesimtype = NULL;
    	gg.probekind = NULL;
    	gg.probehwire = NULL;
    	gg.probevwire = NULL;
    	probeflag = false;
    }
    
    
    static log_krec *peninkind(short xx, short yy)
    {
    	log_krec *Result;
    	short i;
    
    	Result = NULL;
    	if (!(P_ibetween((long)kindgroupleft, (long)xx, kindgroupright - 1L) &&
    				P_ibetween((long)baseline, (long)yy, (long)down)))
    		return Result;
    	i = kindgroup[(xx - kindgroupleft) / kindgroupspacing];
    	if (i > 0)
    		return (kind[(i & (log_kindoffset - 1)) - 1]);
    	return Result;
    }
    
    
    static void testprobe(short xx, short yy)
    {
    	log_grec *g;
    	log_krec *k;
    	short i, x, y;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	short FORLIM;
    
    	x = (xx + gg.hscale + gg.xoff) / gg.scale;
    	y = (yy + gg.hscale + gg.yoff) / gg.scale;
    	unprobe();
    	if (gg.showpage > 0 && !gg.invisible && !gg.showconflicts)
    	{
    		if (gg.incircuit)
    		{
    			g = gg.gbase[gg.curpage - 1];
    			while (g != NULL && gg.probegate == NULL)
    			{
    				k = g->kind;
    				if (g->x >= x - k->bbmax && g->x <= x + k->bbmax &&
    						g->y >= y - k->bbmax && g->y <= y + k->bbmax)
    				{
    					if (insidegate(g, x, y))
    					{
    						gg.probegate = g;
    					}
    					else if (g->kind->simtype->simtype >= 8)
    					{
    						FORLIM = g->kind->numpins;
    						for (i = 1; i <= FORLIM; i++) {
    							if (x == g->pinpos[i - 1].x && y == g->pinpos[i - 1].y)
    							{
    								gg.probegate = g;
    								gg.probenode = g->pin[i - 1];
    								gg.probepin = i;
    							}
    						}
    					}
    				}
    				g = g->next;
    			}
    			hw = gg.hwbase[gg.curpage - 1];
    			while (hw != NULL && gg.probenode == NULL)
    			{
    				if (hw->x1 <= x && x <= hw->x2 && hw->y == y)
    				{
    					gg.probehwire = hw;
    					gg.probenode = hw->node;
    				}
    				hw = hw->next;
    			}
    			vw = gg.vwbase[gg.curpage - 1];
    			while (vw != NULL && gg.probenode == NULL)
    			{
    				if (vw->y1 <= y && y <= vw->y2 && vw->x == x)
    				{
    					gg.probevwire = vw;
    					gg.probenode = vw->node;
    				}
    				vw = vw->next;
    			}
    		}
    		else
    		{
    			gg.probekind = peninkind(xx, yy);
    		}
    	}
    	if (gg.probegate != NULL)
    		gg.probekind = gg.probegate->kind;
    	if (gg.probenode != NULL)
    		gg.probesimtype = gg.probenode->simtype;
    	else if (gg.probekind != NULL)
    		gg.probesimtype = gg.probekind->simtype;
    }
    
    
    static void checkprobe(short xx, short yy)
    {
    	short x, y;
    
    	x = (xx + gg.hscale + gg.xoff) / gg.scale;
    	y = (yy + gg.hscale + gg.yoff) / gg.scale;
    	if (gg.probegate != NULL &&
    			(gg.probegate->x < x - gg.probekind->bbmax ||
    			 gg.probegate->x > x + gg.probekind->bbmax ||
    			 gg.probegate->y < y - gg.probekind->bbmax ||
    			 gg.probegate->y > y + gg.probekind->bbmax))
    	{
    		unprobe();
    		return;
    	}
    
    	if (gg.probekind != NULL && gg.probegate == NULL &&
    			peninkind(xx, yy) != gg.probekind)
    	{
    		unprobe();
    		return;
    	}
    
    	if (gg.probehwire != NULL &&
    			(gg.probehwire->x1 > x || x > gg.probehwire->x2 ||
    			 gg.probehwire->y != y))
    		unprobe();
    	else if (gg.probevwire != NULL &&
    			(gg.probevwire->y1 > y || y > gg.probevwire->y2 ||
    			 gg.probevwire->x != x))
    		unprobe();
    }
    
    
    static void stamp(long *i)
    {
    	gg.curstamp++;
    	*i = gg.curstamp;
    }
    
    
    static void send_general(log_tool *sim, char *act)
    {
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	strcpy(gg.genfunc, act);
    	calltool(sim, act_general);
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static void send_gennode(log_nrec *n, char *act)
    {
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	strcpy(gg.genfunc, act);
    	calltoolnode(n, act_gennode);
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static void send_genkind(log_krec *k, char *act)
    {
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	strcpy(gg.genfunc, act);
    	calltoolkind(k, act_genkind);
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static void send_gengate(log_grec *g, char *act)
    {
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	strcpy(gg.genfunc, act);
    	calltoolgate(g, act_gengate);
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static void send_all(char *act)
    {
    	log_tool *tp;
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	tp = gg.toolbase;
    	while (tp != NULL)
    	{
    		if (tp->ready && tp->simulator)
    		{
    			strcpy(gg.genfunc, act);
    			calltool(tp, act_general);
    		}
    		tp = tp->next;
    	}
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static void send_allnodes(char *act)
    {
    	log_tool *tp;
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	tp = gg.toolbase;
    	while (tp != NULL)
    	{
    		if (tp->ready && tp->simulator)
    		{
    			strcpy(gg.genfunc, act);
    			gg.actnode = NULL;
    			calltool(tp, act_gennode);
    		}
    		tp = tp->next;
    	}
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static void send_allkinds(char *act)
    {
    	log_tool *tp;
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	tp = gg.toolbase;
    	while (tp != NULL)
    	{
    		if (tp->ready && tp->simulator)
    		{
    			strcpy(gg.genfunc, act);
    			gg.actkind = NULL;
    			calltool(tp, act_genkind);
    		}
    		tp = tp->next;
    	}
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static void send_allgates(char *act)
    {
    	log_tool *tp;
    	char savefunc[17];
    
    	strcpy(savefunc, gg.genfunc);
    	tp = gg.toolbase;
    	while (tp != NULL)
    	{
    		if (tp->ready && tp->simulator)
    		{
    			strcpy(gg.genfunc, act);
    			gg.actgate = NULL;
    			calltool(tp, act_gengate);
    		}
    		tp = tp->next;
    	}
    	strcpy(gg.genfunc, savefunc);
    }
    
    
    static long glowcol(log_nrec *n, long def)
    {
    	gg.actx = def;
    	calltoolnode(n, act_glowcol);
    	return (gg.actx);
    }
    
    
    static void resetmessages()
    {
    	short opos;
    
    	opos = messagepos;
    	messagepos = topmessagepos;
    	messageright = 0;
    	if (messagepos != opos)
    	{
    		calltools(act_clearmsg);
    		stamp(&gg.msgstamp);
    	}
    }
    
    
    /*====================  PEN  =====================*/
    /*=                                              =*/
    /*=  Find the position of the pen.  Returns:     =*/
    /*=     D, D0 if the pen is/was down;            =*/
    /*=     N, N0 if the pen is/was near;            =*/
    /*=     DN, UP if the pen is pressed/released;   =*/
    /*=     NR if pen remains near;                  =*/
    /*=     OFFSCREEN if pen is off the screen edge; =*/
    /*=     PX, PY, PX0, PY0 = new/old position;     =*/
    /*=     FX, FY = position in grid coordinates;   =*/
    /*=     MENUBOX = menu box number (0-15);        =*/
    /*=                                              =*/
    /*=  Also draws the cursor, runs logic probe,    =*/
    /*=     and handles Rabbit mode.                 =*/
    /*=                                              =*/
    /*================================================*/
    
    static void show_events()
    {
    	/*zEMBED
    	  char buf[30];
    	  extern int m_events_received;
    	  static int old_events, old_serial, old_time;
    	  int serial, time = timers_sysclock() / 200;
    	  sprintf(buf, "%d", m_events_received);
    	  m_color(log_red);
    	  if (m_events_received > old_events)
    	  drawstr2(5, 20, buf);
    	  old_events = m_events_received;
    	  sprintf(buf, "%d", serial = XNextRequest(m_display));
    	  if (serial > old_serial && time != old_time)
    	  drawstr2(5, 29, buf),
    	  old_serial = serial + 2,
    	  old_time = time;
    	  */
    }
    
    
    /*==================  POLLKBD2  ==================*/
    /*=                                              =*/
    /*=  Return TRUE if a key has been pressed       =*/
    /*=     (via keyboard or menu boxes).            =*/
    /*=                                              =*/
    /*================================================*/
    
    static int pollkbd2()
    {
    	return (nk_keybufsize() != 0 || pushedbackkey != '\0');
    }
    
    
    static void pen()
    {
    
    #define ALERTNESS 2 /* Time to get bored (in cs) */
    #define DOZETIME  5 /* Time to sleep after nodding off */
    
    	long x, y;
    	short i, rx, ry, cred;
    	/* static int pollkbd2(void); */
    	static int oldx, oldy;
    	static long awake;
    	long now;
    	char rval, gval, bval;
    
    
    	/* the following section improves idling behavior       */
    	/* contributed by Nick Bailey (een6njb@sun.leeds.ac.uk) */
    
    	/* Keep on your toes if s/he's still twitching about! */
    	now = timers_sysclock();
    	if (gg.t.x!=oldx || gg.t.y!=oldy || pollkbd2() || gg.busyflag)
    	{
    		awake = now;
    		oldx = gg.t.x; oldy = gg.t.y;
    	}
    	/* Be friendly when not running something important */
    	if (now-awake > (unsigned long)ALERTNESS)
    		microsleep((unsigned long)10000*DOZETIME);
    
    	/* end of idling-improvement section */
    
    	TRY(try3);
    	gg.t0 = gg.t;
    	m_readpen(&gg.t);
    	show_events();
    	gg.stillnear = (gg.stillnear && gg.t.near_);
    	gg.incircuit = (gg.t.y < baseline && gg.showpage > 0);
    	RECOVER(try3);
    	if (P_escapecode == -20)
    		_Escape(P_escapecode);
    	printf("Graphics tablet error\n");
    	m_init_pen(tabletaddr);
    	m_alpha_on();
    	ENDTRY(try3);
    	if (snapflag && gg.incircuit)
    	{
    		gg.t.x = (gg.t.x + gg.hscale + gg.xoff) / gg.scale * gg.scale - gg.xoff;
    		gg.t.y = (gg.t.y + gg.hscale + gg.yoff) / gg.scale * gg.scale - gg.yoff;
    	}
    
    	if (gg.t.x < 0)
    		gg.t.x = 0;
    	else if (gg.t.x > across)
    		gg.t.x = across;
    
    	if (gg.t.y < 0)
    		gg.t.y = 0;
    	else if (gg.t.y > down)
    		gg.t.y = down;
    
    	if (gg.t.near_ && !gg.t.depressed)
    	{
    		rx = gg.t.x * 5 / across;
    		ry = gg.t.y * 5 / down;
    		if (rx != rablist[rabstate].x || ry != rablist[rabstate].y)
    		{
    			i = abs(rablist[rabstate].next) - 1;
    			do
    			{
    				i++;
    			} while ((rablist[i].x != rx || rablist[i].y != ry) &&
    					rablist[i].next < 0);
    			if (rablist[i].x == rx && rablist[i].y == ry)
    			{
    				if (i == rablistsize)
    				{
    					remcursor();
    					rabbits = !rabbits;
    					if (rabbits && !gg.quiet)
    					{
    						i = 1;
    						x = timers_sysclock();
    						do
    						{
    							y = discomadness[i - 1].time;
    							BEEPER(discomadness[i - 1].note, (int)y);
    							do
    							{
    							} while (timers_sysclock() <= x + y);
    							/* nothing */
    							i++;
    							x = timers_sysclock();
    						} while (y != 0);
    					}
    					rabstate = 0;
    				} else
    					rabstate = i;
    			} else
    				rabstate = 0;
    		}
    	}
    	else
    	{
    		rabstate = 0;
    	}
    
    	if (gg.probemode)
    	{
    		if (cursx != gg.t.x || cursy != gg.t.y)
    		{
    			if (gg.probesimtype != NULL)
    				checkprobe((int)gg.t.x, (int)gg.t.y);
    			probeflag = false;
    			drawcursor((int)gg.t.x, (int)gg.t.y);
    		}
    		else
    		{
    			if (!cursorflag)
    				drawcursor((int)gg.t.x, (int)gg.t.y);
    			if (!probeflag)
    			{
    				testprobe((int)gg.t.x, (int)gg.t.y);
    				probeflag = true;
    			}
    		}
    
    		if (!gg.t.near_ && briefprobe)
    		{
    			remcursor();
    			gg.probemode = false;
    		}
    	}
    	else
    	{
    		briefprobe = false;
    		if (gg.probesimtype != NULL)
    			unprobe();
    		if (gg.t.near_)
    			drawcursor((int)gg.t.x, (int)gg.t.y);
    		else
    			remcursor();
    	}
    	cred = gg.color.conflict;
    	if (anyconflicts && (cred == log_cred || cred == log_cred8) &&
    			(rcolormap[cred] == 255 || gcolormap[cred] == 255 ||
    			 bcolormap[cred] == 255))
    	{
    		x = timers_sysclock() * 6 % 137 + 119;
    		rval = (char)(x * rcolormap[cred] / 255);
    		gval = (char)(x * gcolormap[cred] / 255);
    		bval = (char)(x * bcolormap[cred] / 255);
    		m_vsetcolors((long)cred, 1L, (unsigned char *) &rval,
    				(unsigned char *) &gval, (unsigned char *) &bval);
    	}
    
    	if (gg.t.moving)
    	{
    		gg.fastspeed = gg.fastmin;
    		fastsavetime = timers_sysclock();
    	}
    	else if (gg.fastspeed < gg.fastmax &&
    			timers_sysclock() > fastsavetime + gg.fastrate)
    	{
    		gg.fastspeed++;
    		fastsavetime = timers_sysclock();
    	}
    	gg.gridx = (gg.t.x + gg.hscale + gg.xoff) / gg.scale;
    	gg.gridy = (gg.t.y + gg.hscale + gg.yoff) / gg.scale;
    }
    
    
    /*=================  JUSTTAP  ====================*/
    /*=                                              =*/
    /*=  Return TRUE if pen was tapped.  Return      =*/
    /*=     FALSE if pen was held and/or moved.      =*/
    /*=                                              =*/
    /*================================================*/
    
    static int justtap()
    {
    	long t0;
    	short tx, ty;
    
    	t0 = timers_sysclock() + tapdelay;
    	tx = gg.t.x;
    	ty = gg.t.y;
    	do
    	{
    		pen();
    	} while (gg.t.depressed && labs(gg.t.x - tx) <= taptolerance &&
    			labs(gg.t.y - ty) <= taptolerance && timers_sysclock() <= t0);
    	return (!gg.t.depressed);
    }
    
    
    /*==================  TESTKEY2  ==================*/
    /*=                                              =*/
    /*=  Return the most recently pressed key.       =*/
    /*=                                              =*/
    /*================================================*/
    
    static char testkey2()
    {
    	if (pushedbackkey != '\0')
    		return pushedbackkey;
    	else if (pollkbd2())
    		return (nk_testkey(0));
    	else
    		return ' ';
    }
    
    
    /*==================  INKEY2  ====================*/
    /*=                                              =*/
    /*=  Return a keystroke.  Key is removed from    =*/
    /*=     the buffer.                              =*/
    /*=                                              =*/
    /*================================================*/
    
    static char inkey2()
    {
    	char ch;
    
    	do
    	{
    	} while (!pollkbd2());
    	if (pushedbackkey != '\0')
    	{
    		realkey = pushedbackkey;
    		pushedbackkey = '\0';
    	}
    	else
    	{
    		realkey = nk_getkey();
    	}
    	ch = realkey;
    	if ((ch & 255) >= 168 && (ch & 255) <= 239 && nk_capslock)
    	{
    		if ((ch & 255) <= 193)
    		{
    			ch += 46;
    		} else if ((ch & 255) >= 214)
    		{
    			ch -= 46;
    		}
    	}
    	gg.fastspeed = gg.fastmin;
    	return ch;
    }
    
    
    static void inkey3(char *ch)
    {
    	*ch = inkey2();
    }
    
    
    static char inkey4()
    {
    	/* undo CAPSLOCK key */
    	char ch;
    
    	ch = inkey2();
    	if (!nk_capslock)
    		return ch;
    	if (isupper(ch))
    		ch += 32;
    	else if (islower(ch))
    		ch -= 32;
    	return ch;
    }
    
    
    static void ungetkey2(char ch)
    {
    	pushedbackkey = ch;
    }
    
    
    /*===============  WAITFORKEY  ===================*/
    /*=                                              =*/
    /*=  Wait until a key is pressed (but ignore it) =*/
    /*=                                              =*/
    /*================================================*/
    
    static void waitforkey()
    {
    	char ch;
    
    	while (pollkbd2())
    		ch = inkey2();
    	do
    	{
    		pen();
    	} while (!(pollkbd2() || (gg.t.dn && gg.t.off)));
    	if (pollkbd2())
    		ch = inkey2();
    }
    
    
    /*===================  INBOX  ====================*/
    /*=                                              =*/
    /*=  Return TRUE if cursor is inside a certain   =*/
    /*=     rectangular area (screen coordinates).   =*/
    /*=                                              =*/
    /*================================================*/
    
    static int inbox(short x, short y, short x1, short y1)
    {
    	return (gg.t.x >= x && gg.t.y >= y && gg.t.x <= x + x1 && gg.t.y <= y + y1);
    }
    
    
    #define spacing         10
    
    static void message(char *msg)
    {
    	na_strlist_t *l1;
    
    	if (!gg.initdone)
    	{
    		l1 = strlist_append(&messages, msg);
    		l1->value = (na_long)0;
    		return;
    	}
    
    	if (messagepos + spacing >= baseline)
    	{
    		uerase(0, 0, messageright, messagepos);
    		resetmessages();
    		refreshsoon();
    	}
    
    	messageright = P_imax2((long)messageright,
    			m_strwidth(logfont_lfont, msg) + 3);
    	m_color((long)gg.color.message);
    	m_drawstr(2L, (long)messagepos, logfont_lfont, msg);
    	messagepos += spacing;
    }
    
    #undef spacing
    
    
    static void vmessage(char *msg)
    {
    	na_strlist_t *l1;
    
    	if (gg.initdone)
    	{
    		if (gg.verbose || tempverbose)
    			message(msg);
    	}
    	else
    	{
    		l1 = strlist_append(&messages, msg);
    		if (tempverbose)
    			l1->value = (na_long)0;
    		else
    			l1->value = (na_long)1;
    	}
    	tempverbose = false;
    }
    
    
    static void vmessageflag(char *msg, int b)
    {
    	char STR1[256];
    
    	if (b)
    	{
    		sprintf(STR1, "%sON", msg);
    		vmessage(STR1);
    	}
    	else
    	{
    		sprintf(STR1, "%sOFF", msg);
    		vmessage(STR1);
    	}
    }
    
    static void tracemessage(char *msg)
    {
    	if (!gg.traceflag)
    		return;
    	if (!gg.traceopen)
    	{
    		if (*tracefname == '\0')
    		{
    			do
    			{
    				sprintf(tracefname, "/tmp/%.10s%03ld",
    						/* P_citinfo->username, P_rand(&gg.rndseed, 1000L)); */
    					cuserid(NULL), P_rand(&gg.rndseed, 1000L));
    
    			} while (access(tracefname, F_OK) == 0);
    		}
    		if (tracefile != NULL)
    			tracefile = freopen(tracefname, "a", tracefile);
    		else
    			tracefile = fopen(tracefname, "a");
    		if (tracefile == NULL)
    			_EscIO(FileNotFound);
    		gg.traceopen = true;
    	}
    	fprintf(tracefile, "%s\n", msg);
    }
    
    
    static void dumpmessage(char *msg)
    {
    	if (*dumpfname == '\0')
    		return;
    	if (!gg.dumpopen) {
    		if (dumpfile != NULL)
    			dumpfile = freopen(dumpfname, "a", dumpfile);
    		else
    			dumpfile = fopen(dumpfname, "a");
    		if (dumpfile == NULL)
    			_EscIO(FileNotFound);
    		gg.dumpopen = true;
    	}
    	fprintf(dumpfile, "%s\n", msg);
    }
    
    
    static void closedump()
    {
    	if (gg.dumpopen)
    	{
    		TRY(try4);
    		if (dumpfile != NULL)
    			fclose(dumpfile);
    		dumpfile = NULL;
    		RECOVER(try4);
    		if (P_escapecode == -20)
    			_Escape(P_escapecode);
    		ENDTRY(try4);
    	}
    	gg.dumpopen = false;
    }
    
    
    static void closetrace()
    {
    	if (gg.traceopen)
    	{
    		TRY(try5);
    		if (tracefile != NULL)
    			fclose(tracefile);
    		tracefile = NULL;
    		RECOVER(try5);
    		if (P_escapecode == -20)
    			_Escape(P_escapecode);
    		ENDTRY(try5);
    	}
    	gg.traceopen = false;
    }
    
    
    static void setdumpname(char *name_)
    {
    	char name[256];
    
    	strcpy(name, name_);
    	newci_fixfname(name, "text", "");
    	closedump();
    	strcpy(dumpfname, name);
    }
    
    
    static void settracename(char *name_)
    {
    	char name[256];
    
    	strcpy(name, name_);
    	newci_fixfname(name, "text", "");
    	closetrace();
    	strcpy(tracefname, name);
    	if (gg.traceflag)
    		tracemessage("Trace mode ON");
    }
    
    
    static void closedumpfiles()
    {
    	closedump();
    	closetrace();
    }
    
    
    /*=================  BEGINERROR  =================*/
    /*=                                              =*/
    /*=  Clear the menu area for an error message.   =*/
    /*=                                              =*/
    /*================================================*/
    
    static void beginerror()
    {
    	beginbottom();
    	strlist_empty(&thingstodo);
    	warning();
    }
    
    
    /*==================  ENDERROR  ==================*/
    /*=                                              =*/
    /*=  Clean up after displaying an error message. =*/
    /*=                                              =*/
    /*================================================*/
    
    static void enderror()
    {
    	printf("  Press any key to continue.");
    	m_alpha_on();
    	waitforkey();
    	endbottom();
    }
    
    
    static void reportnodeconflict(log_nrec *n)
    {
    	if (n->conflict || !conflictenbl)
    		return;
    	if (!n->oconflict)
    	{
    		n->confnext = nodeconflictbase;
    		nodeconflictbase = n;
    		n->conflict1 = (3L - conflictdelay) & 1;
    		n->conflict2 = ((3L - conflictdelay) / 2) & 1;
    	}
    	n->conflict = true;
    }
    
    
    static void reportgateconflict(log_grec *g)
    {
    	if (g->conflict || !conflictenbl)
    		return;
    	if (!g->oconflict)
    	{
    		g->confnext = gateconflictbase;
    		gateconflictbase = g;
    		g->conflict1 = (3L - conflictdelay) & 1;
    		g->conflict2 = ((3L - conflictdelay) / 2) & 1;
    	}
    	g->conflict = true;
    }
    
    
    static void drawhistdivisions(short x1, short x2)
    {
    	short x, y;
    
    	m_color((long)gg.color.division);
    	x = histleft;
    	while (x <= x2)
    	{
    		if (x >= x1)
    		{
    			y = histdown;
    			while (y >= 0)
    			{
    				m_drawpoint((long)x, (long)y);
    				y -= histdivision;
    			}
    		}
    		x += histdivision;
    	}
    }
    
    
    static void historypointx(log_htrec *ht, short *x)
    {
    	gg.actval = (ht->time - histgattr[histfirsttime - 1].UU.r) /
    		histgattr[histsecdiv - 1].UU.r;
    	if (gg.actval > histdivsacross)
    	{
    		*x = across * 2;
    		return;
    	}
    	if (gg.actval < 0)
    		*x = -across;
    	else
    		*x = histleft + (long)floor(gg.actval * histdivision + 0.5);
    }
    
    
    static void historyvaluey(log_hnrec *hn, double value, double *outval, short *y)
    {
    	gg.actval = value;
    	gg.actx = hn->sig;
    	gg.actgattr = hn->attr;
    	gg.acty = gg.color.chart;
    	calltoolnode(gg.signaltab[gg.actx - 1].np, act_histval);
    	*outval = gg.actval;
    	if (gg.actval < -histvalrange)
    		gg.actval = -histvalrange;
    	else if (gg.actval > histvalrange)
    		gg.actval = histvalrange;
    	*y = hn->y - (long)floor(gg.actval * histdivision + 0.5);
    }  /*also returns in gg.acty*/
    
    
    static void historypointy(log_hnrec *hn, log_htrec *ht, short *y)
    {
    	double r;
    
    	historyvaluey(hn, na_srtor(ht->val[hn->num - 1]), &r, y);
    }
    
    
    static void getnodeval(log_nrec *n, double *val, char *opts)
    {
    	gg.actval = 0.0;
    	strcpy(gg.actstr, opts);
    	calltoolnode(n, act_nodeval);
    	*val = gg.actval;
    }
    
    
    /*===================  PASS  =====================*/
    /*=                                              =*/
    /*=  Make one simulation pass through the        =*/
    /*=     circuit.                                 =*/
    /*=                                              =*/
    /*=  For each page, call the simulator(s) and    =*/
    /*=     do other simulation-related chores.      =*/
    /*=                                              =*/
    /*================================================*/
    
    static void pass()
    {
    	log_grec *g, *g1, *g2;
    	log_nrec *n, *n1, *n2;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_srec *s;
    	log_tool *st, *mintimetool;
    	log_htrec *ht;
    	log_hnrec *hn;
    	long i1;
    	short histsweep, hx1, hx2, hy1, hy2;
    	int havetime, hadconflicts;
    	double mintime, dtime;
    	int flag, flag2;
    	log_gattrrec *WITH;
    	log_hwrec *WITH1;
    	log_vwrec *WITH2;
    	log_srec *WITH3;
    
    	watchdog = timers_sysclock();
    	gg.busyflag = false;
    	gg.oldsimstate = gg.simstate;
    	gg.oldsimstatetool = gg.simstatetool;
    	gg.simstate = simst_null;
    	gg.simstatetool = NULL;
    	if (!gg.pwrflag)
    		gg.fastspeed = gg.fastmin;
    	if (gg.showpage > 0 && !modeflag &&
    			(timers_sysclock() / 6000 != modetime || gg.probekind != modeprobekind))
    		log_setmode("");
    
    	if (gg.showpage > 0 || bottomcount > 0)
    	{
    		clipon();
    	}
    	else if (gg.showpage == log_page_history)
    	{
    		if (bottomcount == 0)
    			m_clip((long)histleft, 0L, (long)across, (long)histdown);
    		else
    			m_clip((long)histleft, 0L, (long)across, baseline - 1L);
    	}
    	histsweep = histgattr[histsweeptype - 1].UU.nv;
    	if (gg.resetflag)
    	{
    		stamp(&gg.resetstamp);
    		gg.time = 0.0;
    		gg.singlestepcount = 0;
    		histreset = true;
    		if (histsweep == histsweep_contin ||
    				(histsweep == histsweep_onreset &&
    				 (histgattr[histstarttime - 1].blnk ||
    				  histgattr[histstarttime - 1].UU.r == 0)))
    			gg.histactive = true;
    		st = gg.toolbase;
    		while (st != NULL)
    		{
    			if (st->simulator)
    				st->deltatime = 0.0;
    			st = st->next;
    		}
    	}
    
    	if (!gg.histactive && (histsweep == histsweep_trig) && (histtrig != 0))
    	{
    		gg.actflag = false;
    		gg.actx = histtrig;
    		calltoolnode(gg.signaltab[gg.actx - 1].np, act_trigger);
    		if (gg.actflag)
    		{
    			histreset = true;
    			gg.histactive = true;
    		}
    	}
    
    	if (histreset || hncount != hnocount)
    	{
    		if (gg.htbase != NULL)
    		{
    			if (gg.showpage == log_page_history && gg.htbase != gg.htlast)
    			{
    				historypointx(gg.htbase, &hx1);
    				historypointx(gg.htlast, &hx2);
    				if (hx1 < histleft)
    					hx1 = histleft;
    				if (hx2 > across)
    					hx2 = across;
    				if (hx1 <= hx2)
    				{
    					m_color((long)gg.color.backgr);
    					m_fillrect((long)hx1, 0L, (long)hx2, (long)histdown);
    					drawhistdivisions(hx1, hx2);
    				}
    			}
    			while (gg.htbase != NULL)
    			{
    				ht = gg.htbase->next;
    				Free(gg.htbase);
    				gg.htbase = ht;
    			}
    			gg.htlast = NULL;
    		}
    		htcount = 0;
    		WITH = &histgattr[histminstep - 1];
    		if (WITH->blnk)
    			histtime = gg.time;
    		else
    			histtime = gg.time - WITH->UU.r;
    	}
    	if (gg.histactive && !histgattr[histmaxstep - 1].blnk)
    	{
    		mintime = histgattr[histmaxstep - 1].UU.r;
    		havetime = (mintime > 0);
    		mintimetool = NULL;
    	}
    	else
    	{
    		havetime = false;
    	}
    	st = gg.toolbase;
    	while (st != NULL)
    	{
    		if (st->simulator)
    		{
    			st->nexttstep = -1.0;
    			calltool(st, act_pass);
    			if (st->nexttstep >= 0.0)
    			{
    				dtime = st->nexttstep - st->deltatime;
    				if (dtime < 0.0)
    				{
    					st->deltatime = st->nexttstep * 0.999999999;
    					dtime = st->nexttstep - st->deltatime;
    				}
    				if (!havetime || dtime < mintime)
    				{
    					mintime = dtime;
    					mintimetool = st;
    				}
    				havetime = true;
    			}
    		}
    		st = st->next;
    	}
    
    	if (gg.histactive && gg.pwrflag &&
    			htcount >= histgattr[histmaxcount - 1].UU.U73.i1 &&
    			histgattr[histsweeptype - 1].UU.nv != histsweep_contin)
    	{
    		m_saveclip();
    		m_noclip();
    		vmessage("Warning: scope memory is 100% full");
    		switch (histgattr[histfullaction - 1].UU.nv)
    		{
    
    			case 0:
    				gg.histactive = false;
    				break;
    
    			case 1:
    				gg.pwrflag = false;
    				vmessage("Simulation is OFF (scope full)");
    				break;
    		}
    		m_unclip();
    	}
    
    	if (gg.pwrflag)
    	{
    		gg.simstatetool = mintimetool;
    		if (havetime)
    		{
    			if (mintime > 0)
    			{
    				gg.simstate = simst_running;
    				if (histsweep == histsweep_onreset)
    				{
    					flag = (gg.time >= histgattr[histstarttime - 1].UU.r);
    					flag2 = (gg.time >= histgattr[histstoptime - 1].UU.r);
    				}
    				gg.time += mintime;
    				gg.prevtimestep = mintime;
    				if (histsweep == histsweep_onreset)
    				{
    					if (!histgattr[histstarttime - 1].blnk && !flag &&
    							gg.time >= histgattr[histstarttime - 1].UU.r)
    						gg.histactive = true;
    					if (!histgattr[histstoptime - 1].blnk && !flag2 &&
    							gg.time >= histgattr[histstoptime - 1].UU.r)
    						gg.histactive = false;
    				}
    				st = gg.toolbase;
    				while (st != NULL)
    				{
    					if (st->simulator) {
    						if (st->nexttstep > 0.0)
    						{
    							gg.actflag = (st->nexttstep - st->deltatime == mintime);
    							if (gg.actflag)
    								st->deltatime = 0.0;
    							else
    								st->deltatime += mintime;
    							calltool(st, act_tstep);
    						}
    					}
    					st = st->next;
    				}
    				if (gg.histactive && hncount > 0 &&
    						(histgattr[histminstep - 1].blnk ||
    						 gg.time - histtime >= histgattr[histminstep - 1].UU.r))
    				{
    					if (htcount >= histgattr[histmaxcount - 1].UU.U73.i1)
    					{
    						if (gg.showpage == log_page_history)
    							historypointx(gg.htbase, &hx1);
    						while (htcount >= histgattr[histmaxcount - 1].UU.U73.i1)
    						{
    							ht = gg.htbase->next;
    							Free(gg.htbase);
    							gg.htbase = ht;
    							htcount--;
    						}
    						if (gg.showpage == log_page_history)
    						{
    							if (gg.htbase != NULL)
    								historypointx(gg.htbase, &hx2);
    							else
    								hx2 = across;
    							if (hx2 >= hx1)
    							{
    								m_color((long)gg.color.backgr);
    								m_fillrect((long)hx1, 0L, (long)hx2, (long)histdown);
    								drawhistdivisions(hx1, hx2);
    							}
    						}
    					}
    					if (gg.htbase == NULL)
    					{
    						histgattr[histfirsttime - 1].UU.r = gg.time;
    						histgattr[histfirsttime - 1].changed = true;
    						histonscreen = false;
    					}
    
    					ht = (log_htrec *)Malloc(sizeof(log_htrec) -
    							log_million * sizeof(void *) +
    							hncount * sizeof(void *));
    
    					ht->next = NULL;
    					ht->time = gg.time;
    					hn = gg.hnbase;
    					i1 = 0;
    					while (hn != NULL)
    					{
    						gg.actval = 0.0;
    						gg.actx = hn->sig;
    						gg.actgattr = hn->attr;
    						calltoolnode(gg.signaltab[gg.actx - 1].np, act_history);
    						i1++;
    						ht->val[i1 - 1] = na_rtosr(gg.actval);
    						hn = hn->next;
    					}
    
    					if (gg.showpage == log_page_history && gg.htlast != NULL)
    					{
    						historypointx(gg.htlast, &hx1);
    						historypointx(ht, &hx2);
    						hn = gg.hnbase;
    						while (hn != NULL)
    						{
    							historypointy(hn, gg.htlast, &hy1);
    							historypointy(hn, ht, &hy2);
    							if ((unsigned long)gg.acty <= 15)
    							{
    								m_color(gg.acty);
    								m_drawline((long)hx1, (long)hy1, (long)hx2, (long)hy2);
    							}
    							hn = hn->next;
    						}
    					}
    
    					if (gg.htlast == NULL)
    						gg.htbase = ht;
    					else
    						gg.htlast->next = ht;
    
    					gg.htlast = ht;
    					htcount++;
    					histtime = gg.time;
    					if (histsweep != histsweep_contin)
    					{
    						i1 = histgattr[histmaxcount - 1].UU.U73.i1;
    						if (htcount >= i1 * 9 / 10)
    						{
    							if (htcount == i1 * 9 / 10)
    							{
    								m_noclip();
    								vmessage("Warning: scope memory is 90% full");
    							}
    							if (htcount == i1 * 19 / 20)
    							{
    								m_noclip();
    								vmessage("Warning: scope memory is 95% full");
    							}
    						}
    					}
    				}
    			}
    			else
    				gg.simstate = simst_notready;
    		}
    		else
    			gg.simstate = simst_notactive;
    
    		if (gg.glowmode && gg.showpage > 0 && !gg.invisible && !gg.showconflicts)
    		{
    			flag = false;
    			hw = gg.hwbase[gg.curpage - 1];
    			while (hw != NULL)
    			{
    				WITH1 = hw;
    				if ((!WITH1->node->conflict1 || !WITH1->node->conflict2) &&
    						WITH1->node->changed && hw != gg.movinghw)
    				{
    					hidecursor_hook();
    					m_color(glowcol(hw->node,
    								(long)gg.color.wire[hw->wcolr - log_wcol_normal]));
    					hline(WITH1->x1, WITH1->x2, WITH1->y);
    					flag = true;
    				}
    				hw = WITH1->next;
    			}
    			vw = gg.vwbase[gg.curpage - 1];
    			while (vw != NULL)
    			{
    				WITH2 = vw;
    				if ((!WITH2->node->conflict1 || !WITH2->node->conflict2) &&
    						WITH2->node->changed && vw != gg.movingvw)
    				{
    					hidecursor_hook();
    					m_color(glowcol(vw->node,
    								(long)gg.color.wire[vw->wcolr - log_wcol_normal]));
    					vline(WITH2->x, WITH2->y1, WITH2->y2);
    					flag = true;
    				}
    				vw = WITH2->next;
    			}
    			if (glowsolder)
    			{
    				s = gg.sbase[gg.curpage - 1];
    				while (s != NULL)
    				{
    					WITH3 = s;
    					n = WITH3->hwire->node;
    					if ((!n->conflict1 || !n->conflict2) && n->changed &&
    							WITH3->hwire != gg.movinghw && WITH3->vwire != gg.movingvw)
    					{
    						hidecursor_hook();
    						drawsolderc(WITH3->x, WITH3->y,
    								(int)glowcol(n, (long)gg.color.solder));
    						flag = true;
    					}
    					s = WITH3->next;
    				}
    			}
    			if (flag)
    			{
    				n = gg.nbase;
    				while (n != NULL)
    				{
    					n->changed = false;
    					n = n->next;
    				}
    				unhidecursor_hook();
    			}
    		}  /*if gg.glowmode*/
    	}
    	else
    		gg.simstate = simst_off;
    	hadconflicts = anyconflicts;
    	anyconflicts = false;
    	n = nodeconflictbase;
    	n1 = NULL;
    	while (n != NULL)
    	{
    		n2 = n->confnext;
    		if (n->conflict)
    		{
    			flag2 = (n->conflict1 && n->conflict2);
    			if (gg.simstate == simst_running && !flag2 && n->oconflict)
    			{
    				n->conflict1 = !n->conflict1;
    				if (!n->conflict1)
    					n->conflict2 = true;
    			}
    			if (n->conflict1 && n->conflict2)
    			{
    				anyconflicts = true;
    				if ((gg.refrflag || !flag2 || !n->oconflict) && gg.showpage > 0)
    					drawnodec(n, gg.color.conflict);
    			}
    			n->oconflict = true;
    		}
    		else
    		{
    			if (gg.showpage > 0)
    				drawnode(n);
    			if (n1 == NULL)
    				nodeconflictbase = n2;
    			else
    				n1->confnext = n2;
    			n->oconflict = false;
    			n->conflict1 = false;
    			n->conflict2 = false;
    			n = n1;
    		}
    		n1 = n;
    		n = n2;
    	}
    	g = gateconflictbase;
    	g1 = NULL;
    	while (g != NULL)
    	{
    		g2 = g->confnext;
    		if (g->conflict)
    		{
    			flag2 = (g->conflict1 && g->conflict2);
    			if (gg.simstate == simst_running && !flag2 && g->oconflict)
    			{
    				g->conflict1 = !g->conflict1;
    				if (!g->conflict1)
    					g->conflict2 = true;
    			}
    			if (g->conflict2 && g->conflict2)
    			{
    				anyconflicts = true;
    				if ((gg.refrflag || !flag2 || !g->oconflict) && gg.showpage > 0)
    					drawgatexc(g, gg.color.conflict);
    			}
    			g->oconflict = true;
    		}
    		else
    		{
    			if (gg.showpage > 0)
    				drawgatex(g);
    			if (g1 == NULL)
    				gateconflictbase = g2;
    			else
    				g1->confnext = g2;
    			g->oconflict = false;
    			g->conflict1 = false;
    			g->conflict2 = false;
    			g = g1;
    		}
    		g1 = g;
    		g = g2;
    	}
    	/* clipoff; */
    	if (gg.showpage > 0 && bottomcount == 0)
    		refrbaseline(false);
    	gg.baselinecolor = gg.color.baseline;
    	gg.resetflag = false;
    	histreset = false;
    	hnocount = hncount;
    	if (gg.singlestepcount > 0 && gg.simstate == simst_running)
    	{
    		gg.singlestepcount--;
    		if (gg.singlestepcount == 0) {
    			gg.pwrflag = false;
    			if (steppingoff)
    				vmessage("Simulation is OFF (single-step)");
    			steppingoff = false;
    		}
    	}
    	if (conflictstop && anyconflicts && !hadconflicts)
    	{
    		gg.pwrflag = false;
    		vmessage("Simulation is OFF (conflict occurred)");
    	}
    	gg.refrflag = false;
    }
    
    
    static void clearconflicts(log_tool *tool)
    {
    	log_grec *g;
    	log_nrec *n;
    
    	n = nodeconflictbase;
    	while (n != NULL)
    	{
    		if (n->simtype == tool)
    			n->conflict = false;
    		n = n->confnext;
    	}
    	g = gateconflictbase;
    	while (g != NULL)
    	{
    		if (g->kind->simtype == tool)
    			g->conflict = false;
    		g = g->confnext;
    	}
    }
    
    
    static short getsignal (int d, char *n);
    
    
    static void newattrs(log_gattrrec **gattr, short numattrs, log_kattrrec *kattr)
    {
    	short i;
    
    	*gattr = (log_gattrrec *)Malloc(numattrs * gattrrecsize);
    	for (i = 0; i < numattrs; i++)
    	{
    		switch (kattr[i].dtype)
    		{
    
    			case 'R':
    			case 'U':
    			case 'F':
    				(*gattr)[i].UU.r = kattr[i].UU.U82.r;
    				break;
    
    			case 'I':
    			case 'H':
    				(*gattr)[i].UU.U73.i1 = kattr[i].UU.U73.i1;
    				break;
    
    			case 'C':
    				(*gattr)[i].UU.c = (char *)Malloc(kattr[i].prec + 1L);
    				strcpy((*gattr)[i].UU.c, kattr[i].UU.c);
    				break;
    
    			case 'A':
    				(*gattr)[i].UU.sp = strdup(kattr[i].UU.sp);
    				break;
    
    			case 'B':
    				(*gattr)[i].UU.b = kattr[i].UU.b;
    				break;
    
    			case 'V':
    				(*gattr)[i].UU.nv = kattr[i].UU.U86.dv;
    				break;
    		}
    
    		(*gattr)[i].blnk = kattr[i].blnk;
    		(*gattr)[i].changed = false;
    	}
    }
    
    
    static void disposeattrs(log_gattrrec **gattr, short numattrs, log_kattrrec *kattr)
    {
    	short i;
    
    	for (i = 0; i < numattrs; i++)
    	{
    		switch (kattr[i].dtype)
    		{
    
    			case 'C':
    				Free((*gattr)[i].UU.c);
    				break;
    
    			case 'A':
    				strdispose(&(*gattr)[i].UU.sp);
    				break;
    		}
    	}
    	Free(*gattr);
    }
    
    
    static void copyattrs(log_gattrrec **gattr, log_gattrrec *oldattr, short numattrs, log_kattrrec *kattr)
    {
    	short i;
    
    	*gattr = (log_gattrrec *)Malloc(numattrs * gattrrecsize);
    	for (i = 0; i < numattrs; i++)
    	{
    		(*gattr)[i] = oldattr[i];
    		switch (kattr[i].dtype)
    		{
    
    			case 'C':
    				(*gattr)[i].UU.c = (char *)Malloc(kattr[i].prec + 1L);
    				strcpy((*gattr)[i].UU.c, oldattr[i].UU.c);
    				break;
    
    			case 'A':
    				(*gattr)[i].UU.sp = strdup(oldattr[i].UU.sp);
    				break;
    		}
    	}
    }
    
    
    /*===================  NEWBOX  ===================*/
    /*=                                              =*/
    /*=  Create a Box.                               =*/
    /*=                                              =*/
    /*================================================*/
    
    static void linkbox(log_brec *b)
    {
    	b->next = gg.bbase[gg.curpage - 1];
    	gg.bbase[gg.curpage - 1] = b;
    	stamp(&gg.boxstamp);
    }
    
    static void newbox(log_brec **b)
    {
    	*b = (log_brec *)Malloc(sizeof(log_brec));
    	(*b)->temp = (na_long)0;
    	linkbox(*b);
    }
    
    /*=================  DISPBOX  ====================*/
    /*=                                              =*/
    /*=  Dispose of a dashed box.                    =*/
    /*=                                              =*/
    /*================================================*/
    
    static void unlinkbox(log_brec *b)
    {
    	log_brec *b1;
    
    	b1 = gg.bbase[gg.curpage - 1];
    	while (b1 != NULL && b1->next != b)
    		b1 = b1->next;
    	if (b1 == NULL)
    		gg.bbase[gg.curpage - 1] = b->next;
    	else
    		b1->next = b->next;
    	chpageplace((int)gg.curpage, b->x1, b->y1, b->x2, b->y2);
    	stamp(&gg.boxstamp);
    }
    
    
    static void dispbox(log_brec **b)
    {
    	unlinkbox(*b);
    	Free(*b);
    }
    
    
    static void defsimulator(log_action_t *act)
    {
    	switch (act->action)
    	{
    
    		case act_init:
    			act->acttool->simulator = true;
    			act->acttool->ready = true;
    			break;
    
    		default:
    			break;
    	}
    }
    
    
    static log_tool *findsimtype(uchar st)
    {
    	char simname[17];
    	log_tool *stp;
    	int rdy;
    
    	sprintf(simname, "%d", st);
    	stp = findtool(simname);
    	if (gg.traceflag)
    		fprintf(tracefile, "Findsimtype of %d gets %ld\n", st, (long)stp);
    	if (!stp->ready || !stp->simulator)
    	{
    		rdy = stp->ready;
    		if (rdy)
    			calltool(stp, act_exit);
    		stp->proc = defsimulator;
    		gg.action = act_init;
    		gg.acttool = stp;
    		defsimulator(&gg);
    		stp->nexttstep = 0.0;
    		stp->nnumattrs = 0;
    		stp->nattr = NULL;
    		stp->hnumattrs = 0;
    		stp->hattr = NULL;
    		beginerror();
    		if (rdy)
    			printf("Tool %d is not a simulator!\n", st);
    		else
    			printf("No program loaded for gate-simulation type %d\n", st);
    		enderror();
    	}
    	stp->keep = true;
    	stp->simtype = st;
    	if (!strcmp(stp->shortname, simname))
    		sprintf(stp->shortname, "Type %s", simname);
    	return stp;
    }
    
    
    static void dumpconflicts()
    {
    	/*no longer needed (I hope!)*/
    	log_grec *g;
    	log_nrec *n;
    
    	n = nodeconflictbase;
    	g = gateconflictbase;
    	printf("\f");
    	if (n != NULL || g != NULL)
    	{
    		printf("Conflicts:\n");
    		while (n != NULL)
    		{
    			printf("   Conflict node %ld  c=%c  delay=%d  oc=%c\n",
    					(long)n, n->conflict ? 'T' : 'F',
    					3 - n->conflict - n->conflict2 * 2, n->oconflict ? 'T' : 'F');
    			n = n->confnext;
    		}
    		while (g != NULL)
    		{
    			printf("   Conflict gate %ld  c=%c  delay=%d  oc=%c\n",
    					(long)g, g->conflict ? 'T' : 'F',
    					3 - g->conflict - g->conflict2 * 2, g->oconflict ? 'T' : 'F');
    			g = g->confnext;
    		}
    	}
    	else
    	{
    		printf("No conflicts registered.\n");
    	}
    	m_alpha_on();
    }
    
    
    static void purgesignaltab()
    {
    	short i, pg;
    	log_nrec *n1;
    	log_hnrec *hn;
    	log_grec *g;
    	short FORLIM;
    	log_sigrec *WITH;
    
    	FORLIM = gg.maxsignal;
    	for (i = 0; i < FORLIM; i++)
    		gg.signaltab[i].f = gg.signaltab[i].keep;
    
    	FORLIM = gg.numpages;
    	for (pg = 0; pg < FORLIM; pg++)
    	{
    		g = gg.gbase[pg];
    		while (g != NULL)
    		{
    			if (g->sig != 0)
    				gg.signaltab[g->sig - 1].f = true;
    			g = g->next;
    		}
    	}
    
    	if (copybuf.valid)
    	{
    		g = copybuf.gcopy;
    		while (g != NULL)
    		{
    			if (g->sig != 0)
    				gg.signaltab[g->sig - 1].f = true;
    			g = g->next;
    		}
    	}
    
    	if (histtrig != 0)
    		gg.signaltab[histtrig - 1].f = true;
    
    	hn = gg.hnbase;
    	while (hn != NULL)
    	{
    		gg.signaltab[hn->sig - 1].f = true;
    		hn = hn->next;
    	}
    
    	FORLIM = kindgroupsize;
    	for (i = 0; i < FORLIM; i++)
    	{
    		if (kindsig[i] != 0)
    			gg.signaltab[kindsig[i] - 1].f = true;
    	}
    
    	g = gg.neargate;
    	if (g != NULL && g->sig != 0)
    		gg.signaltab[g->sig - 1].f = true;
    
    	gg.lastsignal = 0;
    	FORLIM = gg.maxsignal;
    	for (i = 1; i <= FORLIM; i++)
    	{
    		if (!gg.signaltab[i - 1].f)
    		{
    			if (gg.signaltab[i -1].name && gg.signaltab[i - 1].np)
    			{
    				WITH = &gg.signaltab[i - 1];
    				if (WITH->name != NULL)
    					strdispose(&WITH->name);
    				n1 = gg.signaltab[i - 1].np;
    				if (n1 && nodeexists(n1))
    					unrefnode(&gg.signaltab[i - 1].np);
    				gg.signaltab[i - 1].np = NULL;
    			}
    		}
    		else
    		{
    			gg.lastsignal = i;
    		}
    	}
    }
    
    
    /*=================  GARBAGECOLL  ================*/
    /*=                                              =*/
    /*=  Check each node and get rid of ones that    =*/
    /*=  are no longer used.                         =*/
    /*=                                              =*/
    /*================================================*/
    
    static void garbagecoll()
    {
    	log_nrec *n, *n1;
    	log_grec *g;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	short i, pg, FORLIM, FORLIM1;
    
    	working();
    	n = gg.nbase;
    	while (n != NULL)
    	{
    		if (!n->keep)
    			n->ref = 0;
    		n = n->next;
    	}
    	FORLIM = gg.numpages;
    	for (pg = 0; pg < FORLIM; pg++)
    	{
    		hw = gg.hwbase[pg];
    		while (hw != NULL)
    		{
    			hw->node->ref++;
    			hw = hw->next;
    		}
    		vw = gg.vwbase[pg];
    		while (vw != NULL)
    		{
    			vw->node->ref++;
    			vw = vw->next;
    		}
    		g = gg.gbase[pg];
    		while (g != NULL)
    		{
    			FORLIM1 = g->kind->numpins;
    			for (i = 0; i < FORLIM1; i++)
    				g->pin[i]->ref++;
    			g = g->next;
    		}
    	}
    	FORLIM = gg.lastsignal;
    	for (i = 0; i < FORLIM; i++)
    	{
    		if (gg.signaltab[i].np != NULL)
    			gg.signaltab[i].np->ref++;
    	}
    	callsimtools(act_refnodes);
    	working();
    	purgesignaltab();
    	n = gg.nbase;
    	while (n != NULL)
    	{
    		n1 = n->next;
    		if (n->ref == 0 && !n->keep)
    			disposenode(&n);
    		n = n1;
    	}
    }
    
    
    /*=================  GETTOFROM  ==================*/
    /*=                                              =*/
    /*=  Find the number associated with a signal    =*/
    /*=     name.  If it doesn't exist, create it.   =*/
    /*=     If not enough room, issue an error and   =*/
    /*=     return zero.                             =*/
    /*=                                              =*/
    /*================================================*/
    
    static short getsignal(int d, char *n_)
    {
    	char n[256];
    	short i;
    	char STR1[256], STR2[256];
    	short FORLIM;
    	log_sigrec *WITH;
    
    	strcpy(n, n_);
    	strcpy(STR1, strltrim(strrtrim(strcpy(STR2, n))));
    	strcpy(n, STR1);
    	if (*n == '\0')
    	{
    		i = d;
    	}
    	else
    	{
    		i = 1;
    		while (i <= gg.lastsignal &&
    				(gg.signaltab[i - 1].name == NULL ||
    				 strcmp(gg.signaltab[i - 1].name, n)))
    			i++;
    		if (i > gg.lastsignal)
    		{
    			stamp(&gg.sigstamp);
    			i = 1;
    			while (i <= gg.maxsignal && gg.signaltab[i - 1].name != NULL)
    				i++;
    			if (i > gg.maxsignal)
    			{
    				beginerror();
    				printf("Only %d distinct signal names are allowed!\n", gg.maxsignal);
    				enderror();
    				i = 0;
    			}
    			if (i != 0)
    			{
    				WITH = &gg.signaltab[i - 1];
    				WITH->name = strdup(n);
    				WITH->keep = false;
    				newnoderef(&WITH->np, 0, 1L);
    				WITH->temp = (na_long)0;
    			}
    		}
    	}
    	if (i > gg.lastsignal)
    		gg.lastsignal = i;
    	return i;
    }
    
    
    static void getsigname(char *name, log_sigrec **sig)
    {
    	short i;
    
    	i = getsignal(0, name);
    	if (i != 0)
    	{
    		*sig = &gg.signaltab[i - 1];
    		(*sig)->keep = true;
    	}
    	else
    	{
    		*sig = NULL;
    	}
    }
    
    
    /*==================  SETSCALE  ==================*/
    /*=                                              =*/
    /*=  Set the scaling (zoom) factor.              =*/
    /*=                                              =*/
    /*================================================*/
    
    static void setscale(short s)
    {
    	zoom = s;
    	gg.scale = zoomscales[s + 2];
    	gg.hscale = gg.scale / 2;
    }
    
    
    static void setupregion(log_regrec **r, short pagenum)
    {
    	log_regrec *r2;
    
    	if (pagenum < 1 || pagenum > gg.numpages)
    	{
    		if (*r != NULL)
    		{
    			if (*r == gg.pageregions[(*r)->pagenum - 1])
    				gg.pageregions[(*r)->pagenum - 1] = (*r)->next;
    			else
    			{
    				r2 = gg.pageregions[(*r)->pagenum - 1];
    				while (r2 != NULL && r2->next != *r)
    					r2 = r2->next;
    				if (r2 != NULL)
    					r2->next = (*r)->next;
    			}
    			Free(*r);
    		}
    		while (gg.numpages > gg.curpage && pagenull((int)gg.numpages))
    			gg.numpages--;
    		return;
    	}
    	*r = (log_regrec *)Malloc(sizeof(log_regrec));
    	(*r)->pagenum = pagenum;
    	(*r)->x1 = -32768L;
    	(*r)->y1 = -32768L;
    	(*r)->x2 = 32767;
    	(*r)->y2 = 32767;
    	stamp(&(*r)->regstamp);
    	(*r)->info = (na_long)0;
    	(*r)->next = gg.pageregions[pagenum - 1];
    	gg.pageregions[pagenum - 1] = *r;
    }
    
    
    /*=================  COLORNAME  ==================*/
    /*=                                              =*/
    /*=  Return a string containing the name of      =*/
    /*=     VLSI wire color C.                       =*/
    /*=                                              =*/
    /*================================================*/
    
    static char *colorname(char *Result, short c)
    {
    	if (c == log_wcol_normal)
    		return strcpy(Result, "U");
    	else if (c == log_wcol_green)
    		return strcpy(Result, "G");
    	else if (c == log_wcol_red)
    		return strcpy(Result, "R");
    	else if (c == log_wcol_blue)
    		return strcpy(Result, "B");
    	else if (c == log_wcol_yellow)
    		return strcpy(Result, "Y");
    	else {
    		sprintf(Result, "%02d", c);
    		return Result;
    	}
    }
    
    
    /*===================  GETHELP  ==================*/
    /*=                                              =*/
    /*=  Display program Help information.           =*/
    /*=                                              =*/
    /*================================================*/
    
    static void gethelp(char *s)
    {
    	char cmdline[256];
    	char *pager;
    
    	vmessage("Starting an xterm for help");
    
    	pager = getenv("PAGER");
    	if (!pager)
    		pager = "more";
    
    	if (*m_display_name == '\0')
    		sprintf(cmdline, "xterm -e %s %s & \n", pager, loghelpname);
    	else
    		sprintf(cmdline, "xterm -display %s -e %s %s & \n",
    				m_display_name, pager, loghelpname);
    
    	system(cmdline);
    }
    
    
    /*==================  READLNPASS  ================*/
    /*=                                              =*/
    /*=  Simulate READLN, but keep the circuit       =*/
    /*=     running by calling PASS.                 =*/
    /*=                                              =*/
    /*================================================*/
    
    static void readlnpass(char *s, short mode)
    {
    	uchar ch;
    	short i, xleft, oxleft;
    	long x, y;
    	int redraw, starting;
    	char STR1[256];
    
    	m_alpha_on();
    	if (mode != 3)   /*mode 0: normal*/
    		*s = '\0';
    	/*mode 2: exit on knob up/dn*/
    	nk_getxy(&x, &y);   /*mode 3: 2 + keep default*/
    	oxleft = 1;
    	xleft = 1;
    	i = 1;
    	starting = true;
    	redraw = true;
    	do
    	{
    		xleft = P_imax2(1L, x + i - txacross + 1);
    		if (redraw || xleft != oxleft)
    		{
    			hidecursor();
    			nk_gotoxy((int)x, (int)y);
    			printf("%s\t", strsub(STR1, s, xleft, (int)(txacross - x)));
    			hidecursor();
    			oxleft = xleft;
    			redraw = false;
    		}
    		nk_gotoxy((int)(x + i - xleft), (int)y);
    		nc_cursor_on();
    		if (!pollkbd2())
    		{
    			do
    			{
    				pass();
    				pen();
    			} while (!(pollkbd2() || gg.t.dn));
    		}
    		nc_cursor_off();
    		if (gg.t.dn)
    			ch = '\015';
    		else
    			ch = inkey2();
    		if (ch == '\b' && i > 1)
    			i--;
    		else if (ch == '\034' && i <= strlen(s))
    			i++;
    		else if (ch == '\007' && i > 1)
    		{
    			i--;
    			strcpy_overlap(s + i - 1, s + i);
    			redraw = true;
    		}
    		else if (ch == '\177')
    		{
    			*s = '\0';
    			i = 1;
    			redraw = true;
    		}
    		else if (ch >= ' ' && ch != 250 && ch != 251 && strlen(s) < 255)
    		{
    			if (starting)
    				*s = '\0';
    			sprintf(STR1, "%c%s", ch, s + i - 1);
    			strcpy(s + i - 1, STR1);
    			i++;
    			redraw = true;
    		}
    		if ((unsigned)mode < 32 && ((1L << mode) & 0xc) != 0 && ch < 32 &&
    				((1L << ch) & 0x80000400L) != 0) {
    			ungetkey2(ch);
    			ch = '\015';
    		}
    		starting = false;
    	} while (ch >= 32 || ((1L << ch) & 0x2008) == 0);
    	remcursor();
    	sprintf(STR1, "%c", ch);
    	if (!strcmp(STR1, EXEC))
    	{
    		*s = '\0';
    		nk_gotoxy((int)x, (int)y);
    		putchar('\t');
    	}
    	if (gg.t.dn)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    }
    
    static void dofunction ();
    
    static void assertfunc (char *name);
    
    static void clearfunc()
    {
    	if (doingcnffunction)
    		*gg.func = '\0';
    	else
    		assertfunc("");
    }
    
    static void refrfunc()
    {
    	if (gg.initdone && !doingcnffunction)
    		assertfunc("REFR");
    	else
    		clearfunc();
    }
    
    static void zoomto(short z)
    {
    	short s0, i, FORLIM;
    
    	if (-2 > z || z > 2 || z == zoom)
    	{
    		clearfunc();
    		return;
    	}
    	s0 = gg.scale;
    	setscale(z);
    	xoff0 += (gg.xoff + across / 2) * gg.scale / s0 - across / 2 - gg.xoff;
    	yoff0 += (gg.yoff + baseline / 2) * gg.scale / s0 - baseline / 2 - gg.yoff;
    	FORLIM = gg.numpages;
    	for (i = 0; i < FORLIM; i++)
    	{
    		xoffp[i] = (xoffp[i] + across / 2) * gg.scale / s0 - across / 2;
    		yoffp[i] = (yoffp[i] + baseline / 2) * gg.scale / s0 - baseline / 2;
    	}
    	refrfunc();
    }
    
    
    static void scroll()
    {
    	char ch, TEMP;
    
    	if (strcmp(gg.func, "REFR"))
    		return;
    	remcursor();
    	gg.xoff += xoff0;
    	gg.yoff += yoff0;
    	refrscreen1();
    	xoff0 = 0;
    	yoff0 = 0;
    	TEMP = nk_testkey(0);
    	if ((uchar)TEMP < 32 && ((1L << TEMP) & 0x90000500L) != 0)
    		ch = inkey2();
    	restorecursor();
    	gg.startpoint = false;
    	clearfunc();
    }
    
    
    static void doimmedcnffunction()
    {
    	char STR1[256], STR2[256];
    
    	if (*gg.func == '\0')
    		return;
    	if (!strcmp(gg.func, "SNAP"))
    	{
    		getbool(gg.funcarg, &snapflag);
    		vmessageflag("Snap-to-grid is ", snapflag);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "GLOW"))
    	{
    		getbool(gg.funcarg, &gg.glowmode);
    		refrfunc();
    		vmessageflag("Glow mode is ", gg.glowmode);
    		return;
    	}
    	if (!strcmp(gg.func, "AUTOWINDOW"))
    	{
    		getbool(gg.funcarg, &m_autoraise);
    		refrfunc();
    		vmessageflag("AUTOWINDOW mode is ", m_autoraise);
    		return;
    	}
    	if (!strcmp(gg.func, "GLOWSOLDER"))
    	{
    		getbool(gg.funcarg, &glowsolder);
    		refrfunc();
    		vmessageflag("Glowing solder mode is ", glowsolder);
    		return;
    	}
    	if (!strcmp(gg.func, "PROBE"))
    	{
    		if (gg.initdone)
    			remcursor();
    		getbool(gg.funcarg, &gg.probemode);
    		briefprobe = false;
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "DOTS"))
    	{
    		getbool(gg.funcarg, &gg.dotsvisible);
    		refrfunc();
    		if (gg.dotsvisible)
    			vmessage("Dots are now visible");
    		else
    			vmessage("Dots are now hidden");
    		return;
    	}
    	if (!strcmp(gg.func, "ONOFF") || !strcmp(gg.func, "SIM") ||
    			!strcmp(gg.func, "POWER"))
    	{
    		getbool(gg.funcarg, &gg.pwrflag);
    		vmessageflag("Simulation is ", gg.pwrflag);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "ON"))
    	{
    		gg.pwrflag = true;
    		vmessageflag("Simulation is ", gg.pwrflag);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "OFF"))
    	{
    		gg.pwrflag = false;
    		vmessageflag("Simulation is ", gg.pwrflag);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "INVISIBLE"))
    	{
    		getbool(gg.funcarg, &gg.invisible);
    		refrfunc();
    		vmessageflag("Invisible mode is ", gg.invisible);
    		return;
    	}
    	if (!strcmp(gg.func, "INVLABEL"))
    	{
    		getbool(gg.funcarg, &gg.textinvisible);
    		refrfunc();
    		vmessageflag("Invisible-labels mode is ", gg.textinvisible);
    		return;
    	}
    	if (!strcmp(gg.func, "INVPINNUM"))
    	{
    		getbool(gg.funcarg, &gg.pnuminvisible);
    		refrfunc();
    		vmessageflag("Invisible-pin-number mode is ", gg.pnuminvisible);
    		return;
    	}
    	if (!strcmp(gg.func, "SHOWCONFLICTS"))
    	{
    		getbool(gg.funcarg, &gg.showconflicts);
    		refrfunc();
    		if (gg.showconflicts)
    			vmessage("Conflicts are highlighted");
    		else
    			vmessage("Conflicts are not highlighted");
    		return;
    	}
    	if (!strcmp(gg.func, "QUIET"))
    	{
    		getbool(gg.funcarg, &gg.quiet);
    		vmessageflag("Quiet mode is ", gg.quiet);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "CONFLICT"))
    	{
    		if (*gg.funcarg != '\0' && isdigit(gg.funcarg[0]))
    		{
    			conflictenbl = true;
    			conflictdelay = getint(gg.funcarg, 1L);
    			if (conflictdelay > 3)   /*from 0 to 3*/
    				conflictdelay = 3;
    		}
    		else
    			getbool(gg.funcarg, &conflictenbl);
    		if (conflictenbl)
    		{
    			sprintf(STR2, "Conflicts are enabled with delay %d", conflictdelay);
    			vmessage(STR2);
    		}
    		else
    			vmessage("Conflicts are disabled");
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "CSTOP"))
    	{
    		getbool(gg.funcarg, &conflictstop);
    		vmessageflag("Conflict-stopping is ", conflictstop);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "RESPONSE"))
    	{
    		gg.fastmin = getint(gg.funcarg, gg.fastmin);
    		gg.fastmax = getint(gg.funcarg, gg.fastmax);
    		gg.fastrate = getint(gg.funcarg, gg.fastrate);
    		if (gg.fastmax < gg.fastmin)
    			gg.fastmax = gg.fastmin;
    		if (gg.fastspeed < gg.fastmin)
    			gg.fastspeed = gg.fastmin;
    		else if (gg.fastspeed > gg.fastmax)
    			gg.fastspeed = gg.fastmax;
    		if (gg.fastrate < 1)
    			gg.fastrate = 1;
    		sprintf(STR1, "Response: min=%ld, max=%ld, rate=%ld",
    				gg.fastmin, gg.fastmax, gg.fastrate);
    		vmessage(STR1);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "VERBOSE"))
    	{
    		getbool(gg.funcarg, &gg.verbose);
    		if (gg.verbose)
    			message("Verbose mode is ON");
    		else
    			message("Verbose mode is OFF");
    		clearfunc();
    		return;
    	}
    	if (strcmp(gg.func, "AVOID"))
    		return;
    	if (gg.initdone)
    		remcursor();
    	getbool(gg.funcarg, &avoidrabbits);
    	if (avoidrabbits)
    		vmessage("Avoiding rabbits");
    	else
    		vmessage("Not avoiding rabbits");
    	clearfunc();
    }
    
    
    static void doimmedfunction()
    {
    	log_tool *tp;
    	char cmd[256];
    	na_strlist_t *l1;
    
    	if (*gg.func != '\0')
    	{
    		l1 = strlist_find(commandlist, gg.func);
    		if (l1 != NULL) {
    			if (*(char *)l1->value != '\0')
    			{
    				tp = findtool((char *)l1->value);
    				if (tp->ready)
    					strlist_delete(&commandlist, &l1);
    			}
    		}
    		doingcnffunction = false;
    		strcpy(cmd, gg.func);
    		tp = gg.toolbase;
    		while (tp != NULL && !strcmp(gg.func, cmd))
    		{
    			if (tp->ready)
    				calltool(tp, act_immed);
    			tp = tp->next;
    		}
    		doimmedcnffunction();
    	}
    	if (*gg.func == '\0')
    		return;
    	if (!strcmp(gg.func, "HELP"))
    	{
    		gethelp(gg.funcarg);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "RESET"))
    	{
    		gg.resetflag = true;
    		vmessage("Resetting simulation");
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "TRACE"))
    	{
    		getbool(gg.funcarg, &gg.traceflag);
    		vmessageflag("Trace mode ", gg.traceflag);
    		if (gg.traceflag)
    			tracemessage("Trace mode ON");
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "DUMPFILE"))
    	{
    		setdumpname(gg.funcarg);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "TRACEFILE"))
    	{
    		settracename(gg.funcarg);
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "CLOSEFILES"))
    	{
    		closedumpfiles();
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "DUMP"))
    	{
    		dumpnodes();
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "HOME"))
    	{
    		zoomto(0);
    		refrfunc();
    		xoff0 = origin - gg.xoff;
    		yoff0 = origin - gg.yoff;
    		setscale(0);
    		refrfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "ZOOMDN"))
    	{
    		zoomto(zoom - 1);
    		return;
    	}
    	if (!strcmp(gg.func, "ZOOMUP"))
    	{
    		zoomto(zoom + 1);
    		return;
    	}
    	if (!strcmp(gg.func, "GRID"))
    	{
    		remcursor();
    		if (cursortype == grid)
    			cursortype = normal;
    		else
    			cursortype = grid;
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "EXAMINE"))
    	{
    		clearfunc();
    		remcursor();
    		gg.probemode = true;
    		briefprobe = true;
    		return;
    	}
    	if (!strcmp(gg.func, "ARROW"))
    	{
    		remcursor();
    		cursortype = normal;
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "ALTPOSN"))
    	{
    		xoff0 = xoffp[gg.curpage - 1] - gg.xoff;
    		yoff0 = yoffp[gg.curpage - 1] - gg.yoff;
    		xoffp[gg.curpage - 1] = gg.xoff;
    		yoffp[gg.curpage - 1] = gg.yoff;
    		refrfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "PAGE"))
    	{
    		if (!strcmp(gg.funcarg, "+"))
    		{
    			if (gg.curpage < log_maxpages)
    				newpage((int)(gg.curpage + 1));
    		}
    		else if (!strcmp(gg.funcarg, "-"))
    		{
    			if (gg.curpage > 1)
    				newpage((int)(gg.curpage - 1));
    		}
    		else if (strlen(gg.funcarg) == 1 && gg.funcarg[0] >= '1' &&
    				gg.funcarg[0] <= '9')
    			newpage(gg.funcarg[0] - 48);
    		refrfunc();
    		return;
    	}
    	if (strcmp(gg.func, "DO"))
    	{
    		if (immedscroll)
    			scroll();
    		return;
    	}
    	if (*gg.funcarg != '\0')
    	{
    		assertfunc(gg.funcarg);
    		return;
    	}
    	beginbottom();
    	m_alpha_on();
    	printf("Do: ");
    	readlnpass(cmd, 0);
    	endbottom();
    	assertfunc(cmd);
    }
    
    
    static void assertfunc(char *name_)
    {
    	char name[256];
    	char cmd[17];
    
    	strcpy(name, name_);
    	remcursor();
    	commandfound = true;
    	while (*name == ':')
    		strcpy_overlap(name, name + 1);
    	getword(name, cmd);
    	doingcnffunction = false;
    	if (!strcmp(gg.func, cmd))
    	{
    		*gg.func = '\0';
    		return;
    	}
    	strcpy(gg.func, cmd);
    	strcpy(gg.funcarg, name);
    	if (briefprobe)
    	{
    		remcursor();
    		gg.probemode = false;
    	}
    	doimmedfunction();
    }
    
    
    /*===================  TRYKBD  ===================*/
    /*=                                              =*/
    /*=  Check the keyboard for macros.              =*/
    /*=                                              =*/
    /*================================================*/
    
    static void trykbd()
    {
    	long t;
    	int moving;
    	char ch;
    	macrorec *mp;
    	na_strlist_t *todo;
    	char TEMP;
    
    	if (gg.t.near_ && !gg.t0.near_ && gg.showpage >= 0)
    	{
    		m_graphics_on();
    		m_alpha_off();
    	}
    	if (thingstodo != NULL)
    	{
    		if (nexttodo == NULL)
    			todo = thingstodo;
    		else
    			todo = nexttodo;
    		nexttodo = todo->next;
    		assertfunc(todo->s);
    		if (nexttodo == NULL)
    			strlist_empty(&thingstodo);
    		return;
    	}
    	if (!pollkbd2())
    		return;
    	norabbits();
    	rabtime = timers_sysclock();
    	ch = inkey4();
    	switch (ch)
    	{
    
    		case '\003':
    			assertfunc("ABORT");
    			break;
    
    		case '\b':
    		case '\034':   /* Scroll horizontally */
    			do
    			{
    				m_graphics_on();
    				m_colormode((long)m_xor);
    				m_color((long)gg.color.scroll);
    				m_drawline(xoff0 - 1, 0L, xoff0 - 1, baseline - 1L);
    				m_drawline(xoff0 + across + 1, 0L, xoff0 + across + 1, baseline - 1L);
    				if (ch == '\b')
    					xoff0 -= gg.scale * hscrollspd;
    				if (ch == '\034')
    					xoff0 += gg.scale * hscrollspd;
    				m_drawline(xoff0 - 1, 0L, xoff0 - 1, baseline - 1L);
    				m_drawline(xoff0 + across + 1, 0L, xoff0 + across + 1, baseline - 1L);
    				m_colormode((long)m_normal);
    				t = timers_sysclock() + knobwait;
    				do {
    				} while (timers_sysclock() <= t && testkey2() == ' ');
    				TEMP = testkey2();
    				moving = ((uchar)TEMP < 32 && ((1L << TEMP) & 0x10000100L) != 0);
    				if (moving)
    					ch = inkey2();
    			} while (moving && labs(xoff0) <= across - 10);
    			refrfunc();
    			break;
    
    		case '\n':
    		case '\037':   /* Scroll vertically */
    			do
    			{
    				m_graphics_on();
    				m_colormode((long)m_xor);
    				m_color((long)gg.color.scroll);
    				if (yoff0 < baseline)
    					m_drawline(0L, yoff0 - 1, (long)across, yoff0 - 1);
    				if (yoff0 < 0)
    					m_drawline(0L, yoff0 + baseline, (long)across, yoff0 + baseline);
    				if (ch == '\n')
    					yoff0 += gg.scale * vscrollspd;
    				if (ch == '\037')
    					yoff0 -= gg.scale * vscrollspd;
    				if (yoff0 < baseline)
    					m_drawline(0L, yoff0 - 1, (long)across, yoff0 - 1);
    				if (yoff0 < 0)
    					m_drawline(0L, yoff0 + baseline, (long)across, yoff0 + baseline);
    				m_colormode((long)m_normal);
    				t = timers_sysclock() + knobwait;
    				do
    				{
    				} while (timers_sysclock() <= t && testkey2() == ' ');
    				TEMP = testkey2();
    				moving = ((uchar)TEMP < 32 && ((1L << TEMP) & 0x80000400L) != 0);
    				if (moving)
    					ch = inkey2();
    			} while (moving && labs(yoff0) <= baseline - 10);
    			refrfunc();
    			break;
    
    		default:
    			mp = macrobase;
    			while (mp != NULL && mp->key != ch)
    				mp = mp->next;
    			if (mp != NULL)
    				assertfunc(mp->name);
    			break;
    	}
    }
    
    
    static void trykbdscroll()
    {
    	immedscroll = true;
    	trykbd();
    	immedscroll = false;
    	scroll();
    }
    
    /* Local variables for wantsolder: */
    struct LOC_wantsolder
    {
    	int hasred, hasgreen, hasyellow, hasblue;
    } ;
    
    static void markcolor(log_hwrec **hw, struct LOC_wantsolder *LINK)
    {
    	if (*hw == NULL)
    		return;
    	switch ((*hw)->wcolr)
    	{
    
    		case log_wcol_red:
    			LINK->hasred = true;
    			break;
    
    		case log_wcol_green:
    			LINK->hasgreen = true;
    			break;
    
    		case log_wcol_yellow:
    			LINK->hasyellow = true;
    			break;
    
    		case log_wcol_blue:
    			LINK->hasblue = true;
    			break;
    	}
    }
    
    
    static void confirmsimtype(log_nrec *n)
    {
    	log_grec *g;
    	short i, pg;
    	int found;
    	log_hnrec *hn;
    	short FORLIM, FORLIM1;
    
    	if (gg.traceflag)
    		fprintf(tracefile, "Confirm simtype of %ld\n", (long)n);
    	if (n == NULL || n->simtype->simtype < 8)
    		return;
    	found = false;
    	FORLIM = gg.numpages;
    	for (pg = 0; pg < FORLIM; pg++)
    	{
    		g = gg.gbase[pg];
    		while (g != NULL && !found)
    		{
    			FORLIM1 = g->kind->numpins;
    			for (i = 0; i < FORLIM1; i++)
    			{
    				if (g->pin[i] == n)
    				{
    					if (g->kind->pin[i].s >= 8)
    						found = true;
    				}
    			}
    			g = g->next;
    		}
    	}
    
    	if (found)
    		return;
    
    	if (gg.traceflag)
    		fprintf(tracefile, "Deleting simtype of %ld\n", (long)n);
    	calltoolnode(n, act_disposenode);
    	disposeattrs(&n->attr, n->simtype->nnumattrs, n->simtype->nattr);
    	hn = gg.hnbase;
    	while (hn != NULL)
    	{
    		if (gg.signaltab[hn->sig - 1].np == n)
    			disposeattrs(&hn->attr, n->simtype->hnumattrs, n->simtype->hattr);
    		hn = hn->next;
    	}
    	n->simtype = simtype_ignore;
    }
    
    
    static void scancn (cnrec *cn, struct LOC_checkcombine *LINK);
    
    /* Local variables for scancn: */
    struct LOC_scancn {
    	struct LOC_checkcombine *LINK;
    } ;
    
    static void scan(log_nrec **n, struct LOC_scancn *LINK)
    {
    	cnrec *cn;
    
    	if (!LINK->LINK->good)
    		return;
    	if (*n != NULL)
    		checknode(*n, LINK->LINK);
    	cn = *LINK->LINK->cnbase;
    	while (cn != NULL && LINK->LINK->good)
    	{
    		if ((cn->n == *n && *n != NULL) || cn->np == n)
    			scancn(cn, LINK->LINK);
    		cn = cn->next;
    	}
    }
    
    static void scancn(cnrec *cn, struct LOC_checkcombine *LINK)
    {
    	struct LOC_scancn V;
    
    	V.LINK = LINK;
    	if (cn->done)
    		return;
    	cn->done = true;
    	scan(&cn->n, &V);
    	scan(cn->np, &V);
    }
    
    static void frysolder(short x, short y)
    {
    	long t0;
    
    	remcursor();
    	clipon();
    	t0 = timers_sysclock();
    	while (labs(timers_sysclock() - t0) < frytime)
    	{
    		drawsolderc(x, y, gg.color.conflict);
    		drawsolderc(x, y, gg.color.backgr);
    	}
    	clipoff();
    	refreshsoon();
    }
    
    
    static void addblobs(blobrec **blbase, short x1, short y1, short x2, short y2)
    {
    	blobrec *blp;
    	log_srec *s;
    
    	s = gg.sbase[gg.curpage - 1];
    	while (s != NULL)
    	{
    		if (P_ibetween((long)x1, (long)s->x, (long)x2) &&
    				P_ibetween((long)y1, (long)s->y, (long)y2))
    		{
    			blp = (blobrec *)Malloc(sizeof(blobrec));
    			blp->x = s->x;
    			blp->y = s->y;
    			blp->next = *blbase;
    			*blbase = blp;
    		}
    		s = s->next;
    	}
    }
    
    
    static void doblobs(blobrec *blp)
    {
    	log_hwrec *hw;
    	log_vwrec *vw;
    	short x, y;
    
    	while (blp != NULL)
    	{
    		if (blp->x != -32768L)
    		{
    			x = blp->x;
    			y = blp->y;
    			hw = gg.hwbase[gg.curpage - 1];
    			while (hw != NULL && (hw->y != y || hw->x1 > x || hw->x2 < x))
    				hw = hw->next;
    			vw = gg.vwbase[gg.curpage - 1];
    			while (vw != NULL && (vw->x != x || vw->y1 > y || vw->y2 < y))
    				vw = vw->next;
    			if (hw != NULL && vw != NULL && hw->node != vw->node)
    			{
    				if (trycombinenodes(&hw->node, &vw->node)) {
    					clipon();
    					addsolder(x, y, hw, NULL, vw, NULL);
    					clipoff();
    				}
    			}
    		}
    		blp = blp->next;
    	}
    }
    
    
    static void dispblobs(blobrec **blbase)
    {
    	blobrec *blp;
    
    	while (*blbase != NULL)
    	{
    		blp = *blbase;
    		*blbase = blp->next;
    		Free(blp);
    	}
    }
    
    
    /*=================  CLEARBUF  ===================*/
    /*=                                              =*/
    /*=  Clear a copy buffer.                        =*/
    /*=                                              =*/
    /*================================================*/
    
    static void initbuf(baseptrs *bases)
    {
    	bases->gcopy = NULL;
    	bases->scopy = NULL;
    	bases->hwcopy = NULL;
    	bases->vwcopy = NULL;
    	bases->lcopy = NULL;
    	bases->bcopy = NULL;
    	bases->pgnum = 0;
    	bases->valid = false;
    }
    
    
    static void clearbuf(baseptrs *bases)
    {
    	log_grec *g;
    	log_srec *s;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_lrec *l;
    	log_brec *b;
    
    	while (bases->gcopy != NULL)
    	{
    		g = bases->gcopy->next;
    		disposegate(&bases->gcopy);
    		bases->gcopy = g;
    	}
    
    	while (bases->scopy != NULL)
    	{
    		s = bases->scopy->next;
    		Free(bases->scopy);
    		bases->scopy = s;
    	}
    
    	while (bases->hwcopy != NULL)
    	{
    		hw = bases->hwcopy->next;
    		Free(bases->hwcopy);
    		bases->hwcopy = hw;
    	}
    
    	while (bases->vwcopy != NULL)
    	{
    		vw = bases->vwcopy->next;
    		Free(bases->vwcopy);
    		bases->vwcopy = vw;
    	}
    
    	while (bases->lcopy != NULL)
    	{
    		l = bases->lcopy->next;
    		Free(bases->lcopy);
    		bases->lcopy = l;
    	}
    
    	while (bases->bcopy != NULL)
    	{
    		b = bases->bcopy->next;
    		Free(bases->bcopy);
    		bases->bcopy = b;
    	}
    
    	bases->pgnum = 0;
    	bases->valid = false;
    }
    
    
    static int bufempty(baseptrs *bases)
    {
    	return (bases->gcopy == NULL && bases->scopy == NULL &&
    			bases->hwcopy == NULL && bases->vwcopy == NULL &&
    			bases->lcopy == NULL && bases->bcopy == NULL);
    }
    
    
    static int bufissmall(baseptrs *bases)
    {
    	return ((bases->gcopy == NULL || bases->gcopy->next == NULL ||
    				bases->gcopy->next->next == NULL ||
    				bases->gcopy->next->next->next == NULL) &&
    			(bases->hwcopy == NULL || bases->hwcopy->next == NULL ||
    			 bases->hwcopy->next->next == NULL ||
    			 bases->hwcopy->next->next->next == NULL) &&
    			(bases->vwcopy == NULL || bases->vwcopy->next == NULL ||
    			 bases->vwcopy->next->next == NULL ||
    			 bases->vwcopy->next->next->next == NULL) &&
    			(bases->lcopy == NULL || bases->lcopy->next == NULL ||
    			 bases->lcopy->next->next == NULL) &&
    			(bases->bcopy == NULL || bases->bcopy->next == NULL ||
    			 bases->bcopy->next->next == NULL));
    }
    
    
    /*==================  CUTCOPY  ===================*/
    /*=                                              =*/
    /*=  Cut or Copy all gates/wires/solder points   =*/
    /*=     in a rectangular area.  Previous         =*/
    /*=     contents of Copy buffer are lost.        =*/
    /*=                                              =*/
    /*================================================*/
    
    static void cutcopy(baseptrs *bases, short x1, short y1, short x2, short y2, int cut, int tap)
    {
    	log_grec *g, *g1, *g2;
    	log_hwrec *hw, *hw1, *hw2;
    	log_vwrec *vw, *vw1, *vw2;
    	log_srec *s, *s2;
    	log_lrec *l, *l1, *l2;
    	log_brec *b, *b1, *b2;
    	short xx1, yy1, xx2, yy2, anchorx, anchory;
    	int found;
    	blobrec *blbase;
    
    	clearbuf(bases);
    	anchorx = x2;
    	anchory = y2;
    	if (tap)
    	{
    		x2 = x1;
    		y2 = y1;
    		closergate(x1, y1);
    		if (gg.nearlabel == NULL && gg.nearbox == NULL && gg.neargate == NULL)
    		{
    			closerwire(x1, y1);
    			if (gg.nearhw != NULL)
    			{
    				gg.nearvw = NULL;
    				x1 = gg.nearhw->x1;
    				x2 = gg.nearhw->x2;
    				y1 = gg.nearhw->y;
    				y2 = gg.nearhw->y;
    			}
    			else if (gg.nearvw != NULL)
    			{
    				x1 = gg.nearvw->x;
    				x2 = gg.nearvw->x;
    				y1 = gg.nearvw->y1;
    				y2 = gg.nearvw->y2;
    			}
    		}
    		else
    		{
    			gg.nearhw = NULL;
    			gg.nearvw = NULL;
    		}
    	}
    	bases->x1copy = x1;
    	bases->y1copy = y1;
    	bases->x2copy = x2;
    	bases->y2copy = y2;
    	bases->dxcopy = x1 - x2;
    	bases->dycopy = y1 - y2;
    	sortshints(&x1, &x2);
    	sortshints(&y1, &y2);
    	bases->pgnum = gg.curpage;
    	g = gg.gbase[gg.curpage - 1];
    	while (g != NULL)
    	{
    		g1 = g->next;
    		if (tap)
    			found = (g == gg.neargate);
    		else
    			found = (x1 <= g->x && g->x <= x2 && y1 <= g->y && g->y <= y2);
    
    		if (found)
    		{
    			copygate(g, &g2);
    			g2->next = bases->gcopy;
    			bases->gcopy = g2;
    			g2->x = g->x - anchorx;
    			g2->y = g->y - anchory;
    			if (cut)
    				delgate(g);
    		}
    		g = g1;
    	}
    	s = gg.sbase[gg.curpage - 1];
    	while (s != NULL)
    	{
    		if (tap)
    			found = ((s->hwire == gg.nearhw && s->hwire != NULL) ||
    					(s->vwire == gg.nearvw && s->vwire != NULL));
    		else
    			found = (x1 <= s->x && s->x <= x2 && y1 <= s->y && s->y <= y2);
    
    		if (found &&
    				(s->hwire == NULL || (s->hwire->x1 != s->x && s->hwire->x2 != s->x)) &&
    				(s->vwire == NULL || (s->vwire->y1 != s->y && s->vwire->y2 != s->y))) {
    			s2 = (log_srec *)Malloc(sizeof(log_srec));
    			s2->next = bases->scopy;
    			bases->scopy = s2;
    			s2->x = s->x - anchorx;
    			s2->y = s->y - anchory;
    		}
    		s = s->next;
    	}
    	hw = gg.hwbase[gg.curpage - 1];
    	while (hw != NULL)
    	{
    		hw1 = hw->next;
    		xx1 = hw->x1;
    		xx2 = hw->x2;
    		yy1 = hw->y;
    		if (tap)
    			found = (hw == gg.nearhw);
    		else
    			found = (x1 <= xx2 && xx1 <= x2 && y1 <= yy1 && yy1 <= y2);
    		if (found)
    		{
    			hw2 = (log_hwrec *)Malloc(sizeof(log_hwrec));
    			hw2->x1 = P_imax2((long)xx1, (long)x1) - anchorx;
    			hw2->x2 = P_imin2((long)xx2, (long)x2) - anchorx;
    			hw2->y = yy1 - anchory;
    			hw2->wcolr = hw->wcolr;
    
    			if (hw2->x1 == hw2->x2)
    			{
    				Free(hw2);
    			}
    			else
    			{
    				hw2->next = bases->hwcopy;
    				bases->hwcopy = hw2;
    				if (cut)
    				{
    					blbase = NULL;
    					if (xx1 < x1)
    						addblobs(&blbase, xx1, yy1, x1, yy1);
    					if (xx2 > x2)
    						addblobs(&blbase, x2, yy1, xx2, yy1);
    					delhwire(hw);
    					if (xx1 < x1)
    						addhwire(xx1, x1, yy1, hw2->wcolr);
    					if (xx2 > x2)
    						addhwire(x2, xx2, yy1, hw2->wcolr);
    					doblobs(blbase);
    					dispblobs(&blbase);
    				}
    			}
    		}
    		hw = hw1;
    	}
    	vw = gg.vwbase[gg.curpage - 1];
    	while (vw != NULL)
    	{
    		vw1 = vw->next;
    		xx1 = vw->x;
    		yy1 = vw->y1;
    		yy2 = vw->y2;
    		if (tap)
    			found = (vw == gg.nearvw);
    		else
    			found = (y1 <= yy2 && yy1 <= y2 && x1 <= xx1 && xx1 <= x2);
    
    		if (found)
    		{
    			vw2 = (log_vwrec *)Malloc(sizeof(log_vwrec));
    			vw2->x = xx1 - anchorx;
    			vw2->y1 = P_imax2((long)yy1, (long)y1) - anchory;
    			vw2->y2 = P_imin2((long)yy2, (long)y2) - anchory;
    			vw2->wcolr = vw->wcolr;
    			if (vw2->y1 == vw2->y2)
    			{
    				Free(vw2);
    			}
    			else
    			{
    				vw2->next = bases->vwcopy;
    				bases->vwcopy = vw2;
    				if (cut)
    				{
    					blbase = NULL;
    					if (yy1 < y1)
    						addblobs(&blbase, xx1, y1, xx1, yy1);
    					if (yy2 > y2)
    						addblobs(&blbase, xx1, yy2, xx1, y2);
    					delvwire(vw);
    					if (yy1 < y1)
    						addvwire(xx1, yy1, y1, vw2->wcolr);
    					if (yy2 > y2)
    						addvwire(xx1, y2, yy2, vw2->wcolr);
    					doblobs(blbase);
    					dispblobs(&blbase);
    				}
    			}
    		}
    		vw = vw1;
    	}
    	l = gg.lbase[gg.curpage - 1];
    	while (l != NULL)
    	{
    		l1 = l->next;
    		if (tap)
    		{
    			found = (l == gg.nearlabel);
    		}
    		else
    		{
    			found = (x1 <= l->x + m_strwidth(logfont_lfont, l->name) / gg.scale &&
    					l->x <= x2 && y1 <= l->y + 2 && l->y <= y2);
    		}
    
    		if (found)
    		{
    			l2 = (log_lrec *)Malloc(sizeof(log_lrec));
    			l2->next = bases->lcopy;
    			bases->lcopy = l2;
    			l2->x = l->x - anchorx;
    			l2->y = l->y - anchory;
    			strcpy(l2->name, l->name);
    			if (cut)
    			{
    				eralabel(l);
    				displabel(&l);
    			}
    		}
    		l = l1;
    	}
    	b = gg.bbase[gg.curpage - 1];
    	while (b != NULL)
    	{
    		b1 = b->next;
    		if (tap)
    			found = (b == gg.nearbox);
    		else
    			found = (x1 <= b->x1 && b->x2 <= x2 && y1 <= b->y1 && b->y2 <= y2);
    
    		if (found)
    		{
    			b2 = (log_brec *)Malloc(sizeof(log_brec));
    			b2->next = bases->bcopy;
    			bases->bcopy = b2;
    			b2->x1 = b->x1 - anchorx;
    			b2->y1 = b->y1 - anchory;
    			b2->x2 = b->x2 - anchorx;
    			b2->y2 = b->y2 - anchory;
    			if (cut)
    			{
    				drawboxc(b, gg.color.backgr);
    				dispbox(&b);
    			}
    		}
    		b = b1;
    	}
    	bases->valid = true;
    	if (pageempty((int)gg.curpage) && curfilename[gg.curpage - 1] != NULL)
    		Free(curfilename[gg.curpage - 1]);
    }
    
    
    static void checkabort()
    {
    	if (!gg.stillnear || (gg.t.dn && !gg.incircuit) || *gg.func != '\0')
    		_Escape(5);
    }
    
    
    static void waitnear()
    {
    	do
    	{
    		gg.stillnear = true;
    		pass();
    		trykbdscroll();
    		pen();
    	} while (!(gg.stillnear || *gg.func != '\0'));
    	checkabort();
    }
    
    
    static void getfirstpoint()
    {
    	checkabort();
    	do
    	{
    		pass();
    		trykbdscroll();
    		pen();
    		checkabort();
    	} while (!gg.t.dn);
    	gg.posx = gg.gridx;
    	gg.posy = gg.gridy;
    }
    
    
    static int getrectangle(short *x1, short *y1, short *x2, short *y2, int first)
    {
    	int flag;
    	long time;
    
    	if (first)
    		getfirstpoint();
    	*x1 = gg.posx;
    	*y1 = gg.posy;
    	time = timers_sysclock();
    	do
    	{
    		pen();
    		*x2 = gg.gridx;
    		*y2 = gg.gridy;
    		m_colormode((long)m_xor);
    		m_color((long)gg.color.select);
    		flag = gg.incircuit;
    		if (flag)
    			rect(*x1, *y1, *x2, *y2);
    		m_colormode((long)m_normal);
    		do
    		{
    			pass();
    			trykbd();
    			pen();
    		} while (gg.gridx == *x2 && gg.gridy == *y2 && gg.t.depressed &&
    				*gg.func == '\0');
    		m_colormode((long)m_xor);
    		m_color((long)gg.color.select);
    		if (flag)
    			rect(*x1, *y1, *x2, *y2);
    		m_colormode((long)m_normal);
    		scroll();
    		gg.stillnear = true;
    		checkabort();
    	} while (gg.t.depressed);
    	remcursor();
    	if (!gg.incircuit)
    		_Escape(5);
    	return (abs(*x1 - *x2) < 2 && abs(*y1 - *y2) < 2 &&
    			timers_sysclock() - time < tapdelay);
    }
    
    
    /*==================  DELOBJECT  =================*/
    /*=                                              =*/
    /*=  Delete the object touched, or all objects   =*/
    /*=     in a specific area.                      =*/
    /*=                                              =*/
    /*================================================*/
    
    static void delcommand()
    {
    	short x1, y1, x2, y2;
    	int flag;
    
    	log_setmode("DEL");
    	clearfunc();
    	cursortype = delete__;
    	waitnear();
    	do
    	{
    		flag = getrectangle(&x1, &y1, &x2, &y2, true);
    		cutcopy(&copybuf, x1, y1, x2, y2, true, flag);
    	} while (true);
    }
    
    
    static int pagembb(short pg, short *x1, short *y1, short *x2, short *y2)
    {
    	short max;
    	log_grec *g;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_lrec *l;
    	log_brec *b;
    
    	*x1 = log_maxshint;
    	*y1 = log_maxshint;
    	*x2 = -log_maxshint;
    	*y2 = -log_maxshint;
    	g = gg.gbase[pg - 1];
    	while (g != NULL)
    	{
    		max = g->kind->bbmax;
    		if (g->x - max < *x1)
    			*x1 = g->x - max;
    		if (g->x + max > *x2)
    			*x2 = g->x + max;
    		if (g->y - max < *y1)
    			*y1 = g->y - max;
    		if (g->y + max > *y2)
    			*y2 = g->y + max;
    		g = g->next;
    	}
    	hw = gg.hwbase[pg - 1];
    	while (hw != NULL)
    	{
    		if (hw->x1 < *x1)
    			*x1 = hw->x1;
    		if (hw->x2 > *x2)
    			*x2 = hw->x2;
    		if (hw->y < *y1)
    			*y1 = hw->y;
    		if (hw->y > *y2)
    			*y2 = hw->y;
    		hw = hw->next;
    	}
    	vw = gg.vwbase[pg - 1];
    	while (vw != NULL)
    	{
    		if (vw->x < *x1)
    			*x1 = vw->x;
    		if (vw->x > *x2)
    			*x2 = vw->x;
    		if (vw->y1 < *y1)
    			*y1 = vw->y1;
    		if (vw->y2 > *y2)
    			*y2 = vw->y2;
    		vw = vw->next;
    	}
    	l = gg.lbase[pg - 1];
    	while (l != NULL)
    	{
    		if (l->x < *x1)
    			*x1 = l->x;
    		max = m_strwidth(logfont_lfont, l->name) / gg.scale;
    		if (l->x + max > *x2)
    			*x2 = l->x + max;
    		if (l->y < *y1)
    			*y1 = l->y;
    		if (l->y + 2 > *y2)
    			*y2 = l->y + 2;
    		l = l->next;
    	}
    	b = gg.bbase[pg - 1];
    	while (b != NULL)
    	{
    		if (b->x1 < *x1)
    			*x1 = b->x1;
    		if (b->x2 > *x2)
    			*x2 = b->x2;
    		if (b->y1 < *y1)
    			*y1 = b->y1;
    		if (b->y2 > *y2)
    			*y2 = b->y2;
    		b = b->next;
    	}
    	(*x1)--;
    	(*y1)--;
    	(*x2)++;
    	(*y2)++;
    	return (*x1 < *x2);
    }
    
    
    static void deleverything()
    {
    	short x1, y1, x2, y2;
    
    	if (pagembb((int)gg.curpage, &x1, &y1, &x2, &y2))
    		cutcopy(&copybuf, x1, y1, x2, y2, true, false);
    }
    
    
    /*================  CHANGEKIND  ==================*/
    /*=                                              =*/
    /*=  Drop a new gate type into one of the slots  =*/
    /*=     in the menu area.                        =*/
    /*=                                              =*/
    /*================================================*/
    
    static void changekind2(short i, short gtype, short sig, log_gattrec *attrs)
    {
    	log_krec *k;
    
    	clipoff();
    	kdrawgatec(i, gg.color.backgr);
    	if (kindattr[i - 1] != NULL)
    	{
    		k = kind[(kindgroup[i - 1] & (log_kindoffset - 1)) - 1];
    		disposeattrs(&kindattr[i - 1], k->numattrs, k->attr);
    		kindattr[i - 1] = NULL;
    	}
    	k = kind[(gtype & (log_kindoffset - 1)) - 1];
    	if (!k->flag.U3.named)
    		sig = 0;
    	kindgroup[i - 1] = gtype;
    	kindsig[i - 1] = sig;
    	if (attrs != NULL)
    		copyattrs(&kindattr[i - 1], attrs, k->numattrs, k->attr);
    	kdrawgatec(i, gg.color.kindgate);
    }
    
    
    static void changekind(short gtype, short sig, log_gattrrec *attrs)
    {
    	short i;
    
    	if (kindgroupleft <= gg.t.x && gg.t.x < kindgroupright)
    	{
    		i = (gg.t.x - kindgroupleft) / kindgroupspacing + 1;
    		changekind2(i, gtype, sig, attrs);
    	}
    }
    
    
    static void showstick(long x1, long y1, long x2, long y2, long mode)
    {
    	m_colormode(mode);
    	m_color((long)gg.color.select);
    	x1 = x1 * gg.scale - gg.xoff;
    	y1 = y1 * gg.scale - gg.yoff;
    	x2 = x2 * gg.scale - gg.xoff;
    	y2 = y2 * gg.scale - gg.yoff;
    	m_drawline(x1, y1, x2, y2);
    	m_drawarrow(x1, y1, x2, y2, 4L, 4L);
    	m_drawarrow(x2, y2, x1, y1, 4L, 4L);
    	m_colormode((long)m_normal);
    }
    
    
    static void yardstick()
    {
    	long x1, y1, x2, y2;
    
    	x1 = gg.posx;
    	y1 = gg.posy;
    	do
    	{
    		x2 = gg.gridx;
    		y2 = gg.gridy;
    		showstick(x1, y1, x2, y2, (long)m_xor);
    		do
    		{
    			pass();
    			trykbd();
    			pen();
    		} while (gg.gridx == x2 && gg.gridy == y2 && gg.t.depressed &&
    				*gg.func == '\0');
    		showstick(x1, y1, x2, y2, (long)m_xor);
    		scroll();
    	} while (gg.t.depressed && *gg.func == '\0');
    	x1 -= x2;
    	y1 -= y2;
    	while (gg.t.near_ && *gg.func == '\0')
    	{
    		remcursor();
    		showstick(x2 + x1, y2 + y1, x2, y2, (long)m_normal);
    		do
    		{
    			x2 = gg.gridx;
    			y2 = gg.gridy;
    			showstick(x2 + x1, y2 + y1, x2, y2, (long)m_xor);
    			do
    			{
    				pass();
    				trykbd();
    				pen();
    			} while (gg.gridx == x2 && gg.gridy == y2 && gg.t.near_ && !gg.t.dn &&
    					*gg.func == '\0');
    			showstick(x2 + x1, y2 + y1, x2, y2, (long)m_xor);
    			scroll();
    		} while (!gg.t.dn && gg.t.near_ && *gg.func == '\0');
    	}
    }
    
    
    static void yardstickcommand()
    {
    	log_setmode("YARD");
    	clearfunc();
    	cursortype = copy_;
    	getfirstpoint();
    	waitnear();
    	yardstick();
    	cursortype = normal;
    	log_setmode("");
    }
    
    
    static void nextkindsig(short i)
    {
    	char buf[256];
    	short j;
    	char STR1[256];
    
    	if (kindsig[i - 1] == 0)
    		return;
    	strcpy(buf, gg.signaltab[kindsig[i - 1] - 1].name);
    	j = strlen(buf);
    	if (!(j > 0 && isdigit(buf[j - 1])))
    		return;
    	while (j > 0 && buf[j - 1] == '9')
    	{
    		buf[j - 1] = '0';
    		j--;
    	}
    
    	if (j > 0 && isdigit(buf[j - 1]))
    	{
    		buf[j - 1]++;
    	}
    	else
    	{
    		sprintf(STR1, "1%s", buf + j);
    		strcpy(buf + j, STR1);
    	}
    	kdrawgatec(i, gg.color.backgr);
    	kindsig[i - 1] = getsignal(0, buf);
    	kdrawgatec(i, gg.color.kindgate);
    }
    
    
    /* Local variables for xorcopybuf: */
    struct LOC_xorcopybuf {
    	long *count, max, time;
    	int aborting;
    } ;
    
    static int abortit(struct LOC_xorcopybuf *LINK)
    {
    	if (LINK->max == LONG_MAX)
    	{
    		if (LINK->aborting || timers_sysclock() - LINK->time <= 10)
    			return LINK->aborting;
    		clipoff();
    		pen();
    		clipon();
    		m_color((long)gg.color.select);
    		if (gg.posx != gg.gridx || gg.posy != gg.gridy || gg.t.dn ||
    				!gg.stillnear || pollkbd2())
    			LINK->aborting = true;
    		return LINK->aborting;
    	}
    	else
    	{
    		return (*LINK->count >= LINK->max);
    	}
    }
    
    
    /*=================  XORCOPYBUF  =================*/
    /*=                                              =*/
    /*=  XOR a picture of gates to be pasted.        =*/
    /*=                                              =*/
    /*================================================*/
    
    static void xorcopybuf(baseptrs *bases, short x, short y, long *count_)
    {
    	struct LOC_xorcopybuf V;
    	log_grec *g;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_brec *b;
    	log_lrec *l;
    
    	V.count = count_;
    	V.max = *V.count;
    	*V.count = 0;
    	V.time = timers_sysclock();
    	V.aborting = false;
    	clipon();
    	m_colormode((long)m_xor);
    	b = bases->bcopy;
    
    	while (b != NULL && !abortit(&V))
    	{
    		drawboxc0(b->x1 + x, b->y1 + y, b->x2 + x, b->y2 + y, gg.color.select);
    		(*V.count)++;
    		b = b->next;
    	}
    	m_color((long)gg.color.select);
    	hw = bases->hwcopy;
    
    	while (hw != NULL && !abortit(&V))
    	{
    		hline(hw->x1 + x, hw->x2 + x, hw->y + y);
    		(*V.count)++;
    		hw = hw->next;
    	}
    	vw = bases->vwcopy;
    
    	while (vw != NULL && !abortit(&V))
    	{
    		vline(vw->x + x, vw->y1 + y, vw->y2 + y);
    		(*V.count)++;
    		vw = vw->next;
    	}
    	g = bases->gcopy;
    
    	while (g != NULL && !abortit(&V))
    	{
    		drawgatec(g->x + x, g->y + y, g->g, gg.color.select);
    		(*V.count)++;
    		g = g->next;
    	}
    	m_color((long)gg.color.select);
    	l = bases->lcopy;
    
    	while (l != NULL && !abortit(&V))
    	{
    		m_drawstr((l->x + x) * gg.scale - gg.xoff,
    				(l->y + y) * gg.scale - gg.yoff + 2, logfont_lfont, l->name);
    		(*V.count)++;
    		l = l->next;
    	}
    	m_colormode((long)m_normal);
    	clipoff();
    }
    
    
    
    /*==================  PASTEBUF  ==================*/
    /*=                                              =*/
    /*=  Paste a group of objects into the page.     =*/
    /*=                                              =*/
    /*================================================*/
    
    static void pastebuf(baseptrs *bases, short x, short y)
    {
    	log_grec *g, *g1;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_srec *s;
    	log_lrec *l, *l1;
    	log_brec *b, *b1;
    
    	clipon();
    	g = bases->gcopy;
    	while (g != NULL)
    	{
    		copygate(g, &g1);
    		g1->x = g->x + x;
    		g1->y = g->y + y;
    		if (connectgate(g1))
    		{
    			drawgatex(g1);
    		}
    		else
    		{
    			frygate(g1);
    			disposegate(&g1);
    			clipon();
    		}
    		g = g->next;
    	}
    	clipoff();
    	hw = bases->hwcopy;
    
    	while (hw != NULL)
    	{
    		addhwire(hw->x1 + x, hw->x2 + x, hw->y + y, hw->wcolr);
    		hw = hw->next;
    	}
    	vw = bases->vwcopy;
    
    	while (vw != NULL)
    	{
    		addvwire(vw->x + x, vw->y1 + y, vw->y2 + y, vw->wcolr);
    		vw = vw->next;
    	}
    	s = bases->scopy;
    
    	while (s != NULL)
    	{
    		closerwire(s->x + x, s->y + y);
    		if (gg.nearhw != NULL && gg.nearvw != NULL)
    		{
    			if (trycombinenodes(&gg.nearvw->node, &gg.nearhw->node))
    			{
    				clipon();
    				addsolder(s->x + x, s->y + y, gg.nearhw, NULL, gg.nearvw, NULL);
    				clipoff();
    			}
    			else
    			{
    				frysolder(s->x + x, s->y + y);
    			}
    		}
    		s = s->next;
    	}
    	l = bases->lcopy;
    
    	while (l != NULL)
    	{
    		l1 = (log_lrec *)Malloc(sizeof(log_lrec));
    		l1->next = gg.lbase[gg.curpage - 1];
    		gg.lbase[gg.curpage - 1] = l1;
    		l1->x = l->x + x;
    		l1->y = l->y + y;
    		strcpy(l1->name, l->name);
    		l1->w = m_strwidth(logfont_lfont, l1->name) / log_scale0;
    		l1->temp = (na_long)0;
    		clipon();
    		m_color((long)gg.color.labeltext);
    		if (!gg.textinvisible)
    		{
    			m_drawstr(l1->x * gg.scale - gg.xoff, l1->y * gg.scale - gg.yoff + 2,
    					logfont_lfont, l1->name);
    		}
    		clipoff();
    		chpageplace((int)gg.curpage, l1->x, l1->y, l1->x + l1->w, l1->y + 2);
    		stamp(&gg.labelstamp);
    		l = l->next;
    	}
    	b = bases->bcopy;
    
    	while (b != NULL)
    	{
    		b1 = (log_brec *)Malloc(sizeof(log_brec));
    		b1->next = gg.bbase[gg.curpage - 1];
    		gg.bbase[gg.curpage - 1] = b1;
    		b1->x1 = b->x1 + x;
    		b1->y1 = b->y1 + y;
    		b1->x2 = b->x2 + x;
    		b1->y2 = b->y2 + y;
    		b1->temp = (na_long)0;
    		clipon();
    		if (!gg.textinvisible)
    			drawboxc(b1, gg.color.dashbox);
    		clipoff();
    		chpageplace((int)gg.curpage, b1->x1, b1->y1, b1->x2, b1->y2);
    		stamp(&gg.boxstamp);
    		b = b->next;
    	}
    }
    
    
    static void xororiginal()
    {
    	remcursor();
    	clipon();
    	m_colormode((long)m_xor);
    	m_color((long)gg.color.dashbox);
    	m_linestyle(1L);
    	rect(copybuf.x1copy, copybuf.y1copy, copybuf.x2copy, copybuf.y2copy);
    	m_linestyle(0L);
    	m_colormode((long)m_normal);
    	clipoff();
    }
    
    
    /*=================  PASTEOBJECT  ================*/
    /*=                                              =*/
    /*=  Enter Paste mode.  When cursor is pressed,  =*/
    /*=     add a copy of all gates/wires in Copy    =*/
    /*=     buffer at the pen position.              =*/
    /*=  If the pen is held still, XOR a picture of  =*/
    /*=     what would be added if pen is pressed.   =*/
    /*=                                              =*/
    /*================================================*/
    
    static void pastecommand(long movemode)
    {
    	short thepage;
    	long max;
    	baseptrs deleted;
    	long time;
    	int smallbuf;
    
    	clearfunc();
    	if (!copybuf.valid)
    		return;
    	log_setmode("PASTE");
    	smallbuf = (bufissmall(&copybuf) && !bufempty(&copybuf));
    	if (smallbuf)
    		cursortype = normal;
    	else
    		cursortype = paste;
    	xororiginal();
    	waitnear();
    	xororiginal();
    	do
    	{
    		do
    		{
    			if (smallbuf)
    			{
    				pen();
    				checkabort();
    				if (!gg.t.dn)
    				{
    					xororiginal();
    					gg.posx = gg.gridx;
    					gg.posy = gg.gridy;
    					max = LONG_MAX;
    					xorcopybuf(&copybuf, gg.posx, gg.posy, &max);
    					while (gg.posx == gg.gridx && gg.posy == gg.gridy && !gg.t.dn &&
    							gg.stillnear && *gg.func == '\0')
    					{
    						pass();
    						trykbd();
    						pen();
    					}
    					xorcopybuf(&copybuf, gg.posx, gg.posy, &max);
    					xororiginal();
    				}
    			}
    			else
    			{
    				xororiginal();
    				time = timers_sysclock();
    				do
    				{
    					gg.posx = gg.gridx;
    					gg.posy = gg.gridy;
    					pass();
    					trykbd();
    					pen();
    					if (gg.posx != gg.gridx || gg.posy != gg.gridy)
    						time = timers_sysclock();
    				} while (!(timers_sysclock() - time > 25 || smallbuf || gg.t.dn) &&
    						gg.stillnear && *gg.func == '\0');
    				xororiginal();
    				scroll();
    				checkabort();
    				if (gg.posx == gg.gridx && gg.posy == gg.gridy && !gg.t.dn)
    				{
    					xororiginal();
    					max = LONG_MAX;
    					xorcopybuf(&copybuf, gg.posx, gg.posy, &max);
    					while (gg.posx == gg.gridx && gg.posy == gg.gridy && !gg.t.dn &&
    							gg.stillnear && *gg.func == '\0')
    					{
    						pass();
    						trykbd();
    						pen();
    					}
    					xorcopybuf(&copybuf, gg.posx, gg.posy, &max);
    					xororiginal();
    				}
    			}
    			scroll();
    			checkabort();
    		} while (!gg.t.dn);
    		remcursor();
    
    		if (movemode >= 1)
    		{
    			if (gg.posx != copybuf.x1copy || gg.posy != copybuf.y1copy ||
    					gg.curpage != copybuf.pgnum)
    			{
    				initbuf(&deleted);
    				thepage = gg.curpage;
    				if (thepage != copybuf.pgnum)
    				{
    					newpage(copybuf.pgnum);
    					refrscreen1();
    				}
    				cutcopy(&deleted, copybuf.x1copy, copybuf.y1copy, copybuf.x2copy,
    						copybuf.y2copy, true, false);
    				if (thepage != copybuf.pgnum)
    				{
    					newpage(thepage);
    					refrscreen1();
    				}
    				clearbuf(&deleted);
    				pastebuf(&copybuf, gg.posx, gg.posy);
    			}
    
    			if (movemode == 2)
    				movemode = 0;
    		}
    		else
    		{
    			pastebuf(&copybuf, gg.posx, gg.posy);
    		}
    		gg.refrflag = true;
    	} while (movemode != 1);
    	cursortype = normal;
    	log_setmode("");
    }
    
    
    static void extract()
    {
    	int okay;
    	short x1, y1, x2, y2;
    
    	okay = pagembb((int)gg.curpage, &x1, &y1, &x2, &y2);
    	if (okay)
    		cutcopy(&copybuf, x1, y1, x2, y2, true, false);
    	if (!strcmp(gg.funcarg, "*"))
    		dumpnodes();
    	if (okay)
    		pastebuf(&copybuf, x2, y2);
    	clearfunc();
    }
    
    /*=================  COPYCOMMAND  ================*/
    /*=                                              =*/
    /*=  Enter Copy mode.                            =*/
    /*=                                              =*/
    /*================================================*/
    
    static void copycommand()
    {
    	short x1, y1, x2, y2;
    	int flag;
    
    	log_setmode("COPY");
    	clearfunc();
    	cursortype = copy_;
    	waitnear();
    	do
    	{
    		flag = getrectangle(&x1, &y1, &x2, &y2, true);
    		cutcopy(&copybuf, x1, y1, x2, y2, false, flag);
    		if (!bufempty(&copybuf))
    			pastecommand(0L);
    	} while (true);
    }
    
    
    /*=================  MOVECOMMAND  ================*/
    /*=                                              =*/
    /*=  Enter Move mode.  Sweep out an area, then   =*/
    /*=     move all objects in that area to a new   =*/
    /*=     position.                                =*/
    /*=                                              =*/
    /*================================================*/
    
    static void movecommand(int waitflag)
    {
    	short x1, y1, x2, y2;
    	int flag;
    
    	log_setmode("MOVE");
    	clearfunc();
    	cursortype = copy_;
    	if (waitflag)
    		waitnear();
    	do
    	{
    		flag = getrectangle(&x1, &y1, &x2, &y2, waitflag);
    		cutcopy(&copybuf, x1, y1, x2, y2, false, flag);
    		if (!bufempty(&copybuf))
    		{
    			if (waitflag)
    				pastecommand(1L);
    			else
    				pastecommand(2L);
    		}
    	} while (waitflag);
    	_Escape(5);
    }
    
    static void OLDmovecommand()
    {
    	short x1, y1, oldpg, stillhere;
    	baseptrs buf;
    	long max;
    
    	log_setmode("MOVE");
    	clearfunc();
    	cursortype = copy_;
    	waitnear();
    	do
    	{
    		gg.posx = gg.gridx;
    		gg.posy = gg.gridy;
    		pass();
    		trykbdscroll();
    		pen();
    	} while (!gg.t.dn && gg.stillnear && *gg.func == '\0');
    
    	while (gg.incircuit && gg.stillnear && *gg.func == '\0')
    	{
    		x1 = gg.posx;
    		y1 = gg.posy;
    		do
    		{
    			pen();
    			x1 = gg.gridx;
    			y1 = gg.gridy;
    			m_colormode((long)m_xor);
    			m_color((long)gg.color.select);
    			rect(gg.posx, gg.posy, x1, y1);
    			m_colormode((long)m_normal);
    			do
    			{
    				pass();
    				trykbd();
    				pen();
    			} while (gg.gridx == x1 && gg.gridy == y1 && gg.t.depressed &&
    					*gg.func == '\0');
    
    			m_colormode((long)m_xor);
    			m_color((long)gg.color.select);
    			rect(gg.posx, gg.posy, x1, y1);
    			m_colormode((long)m_normal);
    			scroll();
    		} while ((gg.t.depressed || abs(x1 - gg.posx) < 2 ||
    					abs(y1 - gg.posy) < 2) && *gg.func == '\0');
    
    		sortshints(&gg.posx, &x1);
    		sortshints(&gg.posy, &y1);
    		remcursor();
    		if (!(gg.incircuit && *gg.func == '\0'))
    			continue;
    		buf.gcopy = NULL;
    		buf.scopy = NULL;
    		buf.hwcopy = NULL;
    		buf.vwcopy = NULL;
    		buf.lcopy = NULL;
    		buf.bcopy = NULL;
    		cutcopy(&buf, gg.posx, gg.posy, x1, y1, false, false);
    		oldpg = gg.curpage;
    		cursortype = paste;
    		clipon();
    		m_color((long)gg.color.dashbox);
    		m_linestyle(1L);
    		rect(buf.x1copy, buf.y1copy, buf.x2copy, buf.y2copy);
    		m_linestyle(0L);
    		clipoff();
    
    		do
    		{
    			stillhere = 50;
    			do
    			{
    				gg.posx = gg.gridx;
    				gg.posy = gg.gridy;
    				pass();
    				trykbd();
    				if (!strcmp(gg.func, "REFR"))
    				{
    					scroll();
    					clipon();
    					m_color((long)gg.color.dashbox);
    					m_linestyle(1L);
    					rect(buf.x1copy, buf.y1copy, buf.x2copy, buf.y2copy);
    					m_linestyle(0L);
    					clipoff();
    				}
    				pen();
    				stillhere--;
    			} while (!(gg.posx != gg.gridx || gg.posy != gg.gridy ||
    						stillhere < 0 ||
    						gg.t.dn) && gg.stillnear && *gg.func == '\0');
    
    			if (gg.posx == gg.gridx && gg.posy == gg.gridy && !gg.t.dn &&
    					gg.stillnear && *gg.func == '\0')
    			{
    				remcursor();
    				max = LONG_MAX;
    				xorcopybuf(&buf, gg.posx, gg.posy, &max);
    				restorecursor();
    				while (gg.posx == gg.gridx && gg.posy == gg.gridy && !gg.t.dn &&
    						gg.stillnear && *gg.func == '\0')
    				{
    					pass();
    					trykbd();
    					pen();
    				}
    				remcursor();
    				xorcopybuf(&buf, gg.posx, gg.posy, &max);
    				restorecursor();
    			}
    		} while (!gg.t.dn && gg.stillnear && *gg.func == '\0');
    
    		remcursor();
    		clipon();
    		m_color((long)gg.color.backgr);
    		rect(buf.x1copy, buf.y1copy, buf.x2copy, buf.y2copy);
    		clipoff();
    
    		if (gg.incircuit && gg.stillnear && *gg.func == '\0')
    			pastebuf(&buf, gg.posx, gg.posy);
    		clearbuf(&buf);
    		refreshsoon();
    	}
    	gg.startpoint = false;
    	log_setmode("");
    	if (gg.t.dn && !gg.incircuit)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    	cursortype = normal;
    }
    
    
    static int near_(short x, short y)
    {
    	return (abs(x - y) < 2);
    }
    
    
    /*================  MOVEOBJECT  ==================*/
    /*=                                              =*/
    /*=  Move a gate, wire, label, or dashed box.    =*/
    /*=                                              =*/
    /*================================================*/
    
    static void moveobject()
    {
    	short gtype, x1, y1, yy, hx1, hx2, hy, vx, vy1, vy2, hc, vc, oldpg, newpg,
    		  oldx1, oldy1, oldx2, oldy2;
    	int fh1, fv1, fh2, fv2, oo;
    	log_srec *s;
    	log_hwrec *hw1;
    	log_vwrec *vw1;
    	blobrec *blbase, *blp;
    
    	closergate(gg.posx, gg.posy);
    	oldpg = gg.curpage;
    	gg.gridx = gg.posx;
    	gg.gridy = gg.posy;
    	if (gg.markers && ((gg.gridx == gg.markerx1 && gg.gridy == gg.markery1) ||
    				(gg.gridx == gg.markerx2 && gg.gridy == gg.markery2)))
    	{
    		remcursor();
    		drawmarkersc(gg.color.backgr);
    		gg.markers = false;
    		stamp(&gg.markerstamp);
    		do
    		{
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			m_colormode((long)m_xor);
    			drawmarkersc(gg.color.marker);
    			m_colormode((long)m_normal);
    			do
    			{
    				pass();
    				trykbd();
    				pen();
    			} while (gg.gridx == gg.posx && gg.gridy == gg.posy && gg.t.depressed &&
    					strcmp(gg.func, "REFR"));
    
    			m_colormode((long)m_xor);
    			drawmarkersc(gg.color.marker);
    			m_colormode((long)m_normal);
    			if (gg.posx == gg.markerx1 && gg.posy == gg.markery1 &&
    					gg.gridx < gg.markerx2 && gg.gridy < gg.markery2 && gg.incircuit)
    			{
    				gg.markerx1 = gg.gridx;
    				gg.markery1 = gg.gridy;
    			}
    			else if (gg.posx == gg.markerx2 && gg.posy == gg.markery2 &&
    					gg.gridx > gg.markerx1 && gg.gridy > gg.markery1 &&
    					gg.incircuit)
    			{
    				gg.markerx2 = gg.gridx;
    				gg.markery2 = gg.gridy;
    			}
    			scroll();
    		} while (gg.t.depressed);
    		stamp(&gg.markerstamp);
    		gg.markers = true;
    		remcursor();
    		drawmarkersc(gg.color.marker);
    		refreshsoon();
    		gg.startpoint = false;
    		return;
    	}
    
    	if (gg.nearlabel != NULL)
    	{
    		remcursor();
    		oldx1 = gg.nearlabel->x;
    		oldy1 = gg.nearlabel->y;
    		oldx2 = oldx1 + gg.nearlabel->w;
    		oldy2 = oldy1 + 2;
    		chpageplace((int)gg.curpage, oldx1, oldy1, oldx2, oldy2);
    		stamp(&gg.labelstamp);
    		clipon();
    		eralabel(gg.nearlabel);
    		clipoff();
    		x1 = gg.nearlabel->x - gg.posx;
    		y1 = gg.nearlabel->y - gg.posy;
    		do
    		{
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			oo = gg.t.off;
    			clipon();
    			xorlabel(gg.posx + x1, gg.posy + y1, gg.nearlabel);
    			clipoff();
    			do
    			{
    				pass();
    				trykbd();
    				pen();
    			} while (gg.gridx == gg.posx && gg.gridy == gg.posy && gg.t.depressed &&
    					strcmp(gg.func, "REFR"));
    			clipon();
    			xorlabel(gg.posx + x1, gg.posy + y1, gg.nearlabel);
    			clipoff();
    			if (!strcmp(gg.func, "REFR"))
    			{
    				scroll();
    				clipon();
    				eralabel(gg.nearlabel);
    				clipoff();
    			}
    		} while (gg.t.depressed);
    		remcursor();
    		chpageplace(oldpg, oldx1, oldy1, oldx2, oldy2);
    		if (gg.incircuit && !oo && !gg.t.off)
    		{
    			gg.posx += x1;
    			gg.posy += y1;
    			gg.nearlabel->x = gg.posx;
    			gg.nearlabel->y = gg.posy;
    			if (gg.curpage != oldpg)
    			{
    				newpg = gg.curpage;
    				gg.curpage = oldpg;
    				unlinklabel(gg.nearlabel);
    				gg.curpage = newpg;
    				linklabel(gg.nearlabel);
    			}
    			m_color((long)gg.color.labeltext);
    			m_drawstr(gg.posx * gg.scale - gg.xoff,
    					gg.posy * gg.scale - gg.yoff + 2, logfont_lfont,
    					gg.nearlabel->name);
    			gg.refrflag = true;
    			chpageplace((int)gg.curpage, gg.nearlabel->x, gg.nearlabel->y,
    					gg.nearlabel->x + gg.nearlabel->w, gg.nearlabel->y + 2);
    		}
    		else
    		{
    			newpg = gg.curpage;
    			gg.curpage = oldpg;
    			displabel(&gg.nearlabel);
    			gg.curpage = newpg;
    		}
    		stamp(&gg.labelstamp);
    		refreshsoon();
    		gg.startpoint = false;
    		return;
    	}
    
    	if (gg.nearbox != NULL)
    	{
    		remcursor();
    		oldx1 = gg.nearbox->x1;
    		oldy1 = gg.nearbox->y1;
    		oldx2 = gg.nearbox->x2;
    		oldy2 = gg.nearbox->y2;
    		chpageplace((int)gg.curpage, oldx1, oldy1, oldx2, oldy2);
    		stamp(&gg.boxstamp);
    		clipon();
    		drawboxc(gg.nearbox, gg.color.backgr);
    		clipoff();
    		hx1 = gg.nearbox->x1;
    		hx2 = gg.nearbox->x2;
    		vy1 = gg.nearbox->y1;
    		vy2 = gg.nearbox->y2;
    		do
    		{
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			oo = gg.t.off;
    			clipon();
    			m_colormode((long)m_xor);
    			drawboxc0(hx1, vy1, hx2, vy2, gg.color.dashbox);
    			m_colormode((long)m_normal);
    			clipoff();
    			do
    			{
    				pass();
    				trykbd();
    				pen();
    			} while (gg.gridx == gg.posx && gg.gridy == gg.posy && gg.t.depressed &&
    					strcmp(gg.func, "REFR"));
    
    			clipon();
    			m_colormode((long)m_xor);
    			drawboxc0(hx1, vy1, hx2, vy2, gg.color.dashbox);
    			m_colormode((long)m_normal);
    			clipoff();
    			if (near_(gg.posx, hx1) && near_(gg.posy, vy1))
    			{
    				hx1 = gg.gridx;
    				vy1 = gg.gridy;
    			}
    			else if (near_(gg.posx, hx1) && near_(gg.posy, vy2))
    			{
    				hx1 = gg.gridx;
    				vy2 = gg.gridy;
    			}
    			else if (near_(gg.posx, hx2) && near_(gg.posy, vy1))
    			{
    				hx2 = gg.gridx;
    				vy1 = gg.gridy;
    			}
    			else if (near_(gg.posx, hx2) && near_(gg.posy, vy2))
    			{
    				hx2 = gg.gridx;
    				vy2 = gg.gridy;
    			}
    			else
    			{
    				hx1 += gg.gridx - gg.posx;
    				hx2 += gg.gridx - gg.posx;
    				vy1 += gg.gridy - gg.posy;
    				vy2 += gg.gridy - gg.posy;
    			}
    
    			if (!strcmp(gg.func, "REFR"))
    			{
    				scroll();
    				clipon();
    				drawboxc(gg.nearbox, gg.color.backgr);
    				clipoff();
    			}
    		} while (gg.t.depressed);
    		remcursor();
    		sortshints(&hx1, &hx2);
    		sortshints(&vy1, &vy2);
    		gg.nearbox->x1 = hx1;
    		gg.nearbox->x2 = hx2;
    		gg.nearbox->y1 = vy1;
    		gg.nearbox->y2 = vy2;
    		chpageplace(oldpg, oldx1, oldy1, oldx2, oldy2);
    		if (gg.incircuit && !oo && !gg.t.off)
    		{
    			if (gg.curpage != oldpg)
    			{
    				newpg = gg.curpage;
    				gg.curpage = oldpg;
    				unlinkbox(gg.nearbox);
    				gg.curpage = newpg;
    				linkbox(gg.nearbox);
    			}
    			clipon();
    			drawboxc(gg.nearbox, gg.color.dashbox);
    			clipoff();
    			chpageplace((int)gg.curpage, gg.nearbox->x1, gg.nearbox->y1,
    					gg.nearbox->x2, gg.nearbox->y2);
    			gg.refrflag = true;
    		}
    		else
    		{
    			newpg = gg.curpage;
    			gg.curpage = oldpg;
    			dispbox(&gg.nearbox);
    			gg.curpage = newpg;
    		}
    		stamp(&gg.boxstamp);
    		refreshsoon();
    		gg.startpoint = false;
    		return;
    	}
    
    	if (gg.neargate != NULL)
    	{
    		gtype = gg.neargate->g;
    		remcursor();
    		clipon();
    		eragate(gg.neargate);
    		clipoff();
    		disconnectgate(gg.neargate);
    		x1 = gg.neargate->x - gg.posx;
    		y1 = gg.neargate->y - gg.posy;
    		do
    		{
    			yy = gg.t.y;
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			oo = gg.t.off;
    			movexorgate(gg.posx + x1, gg.posy + y1, gtype, gg.neargate->sig, yy);
    			do
    			{
    				pass();
    				trykbd();
    				pen();
    			} while (gg.gridx == gg.posx && gg.gridy == gg.posy && gg.t.depressed &&
    					strcmp(gg.func, "REFR"));
    			movexorgate(gg.posx + x1, gg.posy + y1, gtype, gg.neargate->sig, yy);
    			scroll();
    		} while (gg.t.depressed);
    		remcursor();
    
    		if (gg.incircuit && !oo && !gg.t.off)
    		{
    			gg.posx += x1;
    			gg.posy += y1;
    			gg.neargate->x = gg.posx;
    			gg.neargate->y = gg.posy;
    			clipon();
    			drawgatex(gg.neargate);
    			clipoff();
    			if (!connectgate(gg.neargate))
    			{
    				frygate(gg.neargate);
    				disposegate(&gg.neargate);
    			}
    			gg.refrflag = true;
    		}
    		else if (gg.t.y >= baseline)
    		{
    			changekind(gg.neargate->g, gg.neargate->sig, gg.neargate->attr);
    			disposegate(&gg.neargate);
    		}
    		else
    		{
    			disposegate(&gg.neargate);
    		}
    		refreshsoon();
    		gg.startpoint = false;
    		return;
    	}
    	closerwire(gg.posx, gg.posy);
    	if (gg.nearhw == NULL && gg.nearvw == NULL)
    	{
    		gg.startpoint = false;
    		assertfunc("MOVE *");
    		return;
    	}
    	remcursor();
    	clipon();
    	m_color((long)gg.color.backgr);
    	if (gg.nearhw != NULL)
    	{
    		hx1 = gg.nearhw->x1;
    		hx2 = gg.nearhw->x2;
    		hy = gg.nearhw->y;
    		fh1 = (gg.posx == hx1 && gg.posy == hy);
    		fh2 = (gg.posx == hx2 && gg.posy == hy);
    		hline(hx1, hx2, hy);
    		gg.movinghw = gg.nearhw;
    		hc = gg.nearhw->wcolr;
    	}
    
    	if (gg.nearvw != NULL)
    	{
    		vx = gg.nearvw->x;
    		vy1 = gg.nearvw->y1;
    		vy2 = gg.nearvw->y2;
    		fv1 = (gg.posy == vy1 && gg.posx == vx);
    		fv2 = (gg.posy == vy2 && gg.posx == vx);
    		vline(vx, vy1, vy2);
    		gg.movingvw = gg.nearvw;
    		vc = gg.nearvw->wcolr;
    	}
    	blbase = NULL;
    	s = gg.sbase[gg.curpage - 1];
    	while (s != NULL)
    	{
    		if ((gg.nearhw != NULL && (s->hwire == gg.nearhw || s->hwire2 == gg.nearhw)) ||
    				(gg.nearvw != NULL && (s->vwire == gg.nearvw || s->vwire2 == gg.nearvw)))
    		{
    			drawsolderc(s->x, s->y, gg.color.backgr);
    			blp = (blobrec *)Malloc(sizeof(blobrec));
    			if (s->hwire == gg.nearhw)
    				blp->hw = NULL;
    			else
    				blp->hw = s->hwire;
    
    			if (s->vwire == gg.nearvw)
    				blp->vw = NULL;
    			else
    				blp->vw = s->vwire;
    
    			blp->next = blbase;
    			blbase = blp;
    		}
    		s = s->next;
    	}
    	clipoff();
    	do
    	{
    		gg.posx = gg.gridx;
    		gg.posy = gg.gridy;
    		oo = gg.t.off;
    		clipon();
    		m_colormode((long)m_xor);
    		if (gg.nearhw != NULL)
    		{
    			if (fh1)
    			{
    				hx1 = gg.posx;
    				hy = gg.posy;
    			} else if (fh2)
    			{
    				hx2 = gg.posx;
    				hy = gg.posy;
    			}
    			else
    			{
    				if (gg.posx < hx1)
    					hx1 = gg.posx;
    				if (gg.posx > hx2)
    					hx2 = gg.posx;
    				hy = gg.posy;
    			}
    			m_color((long)gg.color.wire[gg.nearhw->wcolr - log_wcol_normal]);
    			hline(hx1, hx2, hy);
    		}
    		if (gg.nearvw != NULL)
    		{
    			if (fv1)
    			{
    				vy1 = gg.posy;
    				vx = gg.posx;
    			}
    			else if (fv2)
    			{
    				vy2 = gg.posy;
    				vx = gg.posx;
    			}
    			else
    			{
    				if (gg.posy < vy1)
    					vy1 = gg.posy;
    				if (gg.posy > vy2)
    					vy2 = gg.posy;
    				vx = gg.posx;
    			}
    			m_color((long)gg.color.wire[gg.nearvw->wcolr - log_wcol_normal]);
    			vline(vx, vy1, vy2);
    		}
    		m_colormode((long)m_normal);
    		clipoff();
    		do
    		{
    			pass();
    			trykbd();
    			pen();
    		} while (gg.gridx == gg.posx && gg.gridy == gg.posy && gg.t.depressed &&
    				strcmp(gg.func, "REFR"));
    		clipon();
    		m_colormode((long)m_xor);
    		if (gg.nearhw != NULL)
    		{
    			m_color((long)gg.color.wire[gg.nearhw->wcolr - log_wcol_normal]);
    			hline(hx1, hx2, hy);
    		}
    
    		if (gg.nearvw != NULL)
    		{
    			m_color((long)gg.color.wire[gg.nearvw->wcolr - log_wcol_normal]);
    			vline(vx, vy1, vy2);
    		}
    
    		m_colormode((long)m_normal);
    		clipoff();
    		scroll();
    	} while (gg.t.depressed);
    	working();
    	gg.movinghw = NULL;
    	gg.movingvw = NULL;
    	remcursor();
    	gg.curpage = oldpg;
    	if (gg.nearhw != NULL)
    	{
    		delhwire(gg.nearhw);
    	}
    	else
    	{
    		hx1 = 0;
    		hx2 = 0;
    	}
    
    	if (gg.nearvw != NULL)
    	{
    		delvwire(gg.nearvw);
    	}
    	else
    	{
    		vy1 = 0;
    		vy2 = 0;
    	}
    
    	gg.curpage = realcurpage;
    	if (gg.incircuit && !oo && !gg.t.off)
    	{
    		blp = blbase;
    		while (blp != NULL)
    		{
    			if (blp->hw != NULL)
    			{
    				hw1 = gg.hwbase[gg.curpage - 1];
    				while (hw1 != NULL &&
    						(hw1->node != blp->hw->node ||
    						 !P_ibetween((long)hw1->x1, (long)vx, (long)hw1->x2) ||
    						 !P_ibetween((long)vy1, (long)hw1->y, (long)vy2)))
    					hw1 = hw1->next;
    
    				if (hw1 != NULL)
    				{
    					blp->x = vx;
    					blp->y = hw1->y;
    				}
    				else
    				{
    					blp->x = -32768L;
    				}
    			}
    			else if (blp->vw != NULL)
    			{
    				vw1 = gg.vwbase[gg.curpage - 1];
    				while (vw1 != NULL &&
    						(vw1->node != blp->vw->node ||
    						 !P_ibetween((long)vw1->y1, (long)hy, (long)vw1->y2) ||
    						 !P_ibetween((long)hx1, (long)vw1->x, (long)hx2)))
    					vw1 = vw1->next;
    
    				if (vw1 != NULL)
    				{
    					blp->x = vw1->x;
    					blp->y = hy;
    				}
    				else
    				{
    					blp->x = -32768L;
    				}
    			}
    			else
    			{
    				blp->x = vx;
    				blp->y = hy;
    			}
    			blp = blp->next;
    		}
    
    		if (hx1 != hx2)
    			addhwire(hx1, hx2, hy, hc);
    		if (vy1 != vy2)
    			addvwire(vx, vy1, vy2, vc);
    		doblobs(blbase);
    	}
    	dispblobs(&blbase);
    	refreshsoon();
    	gg.startpoint = false;
    
    	/*thrown away*/
    	/* move a wire */
    }
    
    
    static void shiftgate(log_grec *g, short dx, short dy)
    {
    	short i, FORLIM;
    	log_pinposrec *WITH;
    
    	g->x += dx;
    	g->y += dy;
    	FORLIM = g->kind->numpins;
    	for (i = 0; i < FORLIM; i++)
    	{
    		WITH = &g->pinpos[i];
    		WITH->x += dx;
    		WITH->y += dy;
    	}
    }
    
    
    static void xorrect(short x1, short y1, short x2, short y2)
    {
    	short y3;
    
    	sortshints(&x1, &x2);
    	sortshints(&y1, &y2);
    	y3 = (y1 + y2) / 2;
    	m_colormode((long)m_xor);
    	m_color((long)gg.color.select);
    	rect(x1, y1, x2, y2);
    	hline(x1, x2, y3);
    	line(x2 - 1, y3 - 1, x2, y3);
    	line(x2 - 1, y3 + 1, x2, y3);
    	m_colormode((long)m_normal);
    }
    
    
    /*==================  OPENHORIZ  =================*/
    /*=                                              =*/
    /*=  Open space horizontally.                    =*/
    /*=                                              =*/
    /*================================================*/
    
    static void openhoriz()
    {
    	log_grec *g;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_srec *s;
    	log_lrec *l;
    	log_brec *b;
    	short x1, y1;
    	int flag;
    
    	log_setmode("OPNH");
    	clearfunc();
    	cursortype = copy_;
    	waitnear();
    	do
    	{
    		do
    		{
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			pass();
    			trykbdscroll();
    			pen();
    		} while (!gg.t.dn && gg.stillnear && *gg.func == '\0');
    
    		if (gg.incircuit && gg.stillnear && *gg.func == '\0')
    		{
    			x1 = gg.posx;
    			y1 = gg.posy;
    			do
    			{
    				pen();
    				x1 = gg.gridx;
    				y1 = gg.gridy;
    				xorrect(gg.posx, gg.posy, x1, y1);
    				do
    				{
    					pass();
    					trykbd();
    					pen();
    				} while (gg.gridx == x1 && gg.gridy == y1 && gg.t.depressed &&
    						*gg.func == '\0');
    				xorrect(gg.posx, gg.posy, x1, y1);
    				scroll();
    			} while ((gg.t.depressed || x1 == gg.posx || y1 == gg.posy) &&
    					*gg.func == '\0');
    			sortshints(&gg.posx, &x1);
    			sortshints(&gg.posy, &y1);
    			remcursor();
    
    			if (gg.incircuit && *gg.func == '\0')
    			{
    				chpage((int)gg.curpage);
    				vw = gg.vwbase[gg.curpage - 1];
    				flag = false;
    				while (vw != NULL)
    				{
    					if (vw->x > gg.posx &&
    							((vw->y1 < gg.posy && gg.posy < vw->y2) ||
    							 (vw->y1 < y1 && y1 < vw->y2)))
    						flag = true;
    					vw = vw->next;
    				}
    
    				if (!flag)
    				{
    					g = gg.gbase[gg.curpage - 1];
    					while (g != NULL)
    					{
    						if (gg.posy <= g->y && g->y <= y1 && g->x >= gg.posx)
    							shiftgate(g, x1 - gg.posx, 0);
    						g = g->next;
    					}
    					s = gg.sbase[gg.curpage - 1];
    
    					while (s != NULL)
    					{
    						if (!vlsi && gg.posy <= s->vwire->y2 && s->vwire->y1 <= y1 &&
    								s->vwire->x > gg.posx)
    							s->x += x1 - gg.posx;
    						s = s->next;
    					}
    					hw = gg.hwbase[gg.curpage - 1];
    
    					while (hw != NULL)
    					{
    						if (gg.posy <= hw->y && hw->y <= y1)
    						{
    							if (hw->x1 > gg.posx)
    								hw->x1 += x1 - gg.posx;
    							if (hw->x2 >= gg.posx)
    								hw->x2 += x1 - gg.posx;
    						}
    						hw = hw->next;
    					}
    					vw = gg.vwbase[gg.curpage - 1];
    
    					while (vw != NULL)
    					{
    						if (gg.posy <= vw->y2 && vw->y1 <= y1 && vw->x > gg.posx)
    							vw->x += x1 - gg.posx;
    						vw = vw->next;
    					}
    					b = gg.bbase[gg.curpage - 1];
    
    					while (b != NULL)
    					{
    						if (gg.posy <= b->y1 && b->y2 <= y1)
    						{
    							if (b->x1 >= gg.posx)
    								b->x1 += x1 - gg.posx;
    							if (b->x2 >= gg.posx)
    								b->x2 += x1 - gg.posx;
    						}
    						b = b->next;
    					}
    					l = gg.lbase[gg.curpage - 1];
    
    					while (l != NULL)
    					{
    						if (gg.posy <= l->y && l->y <= y1 && l->x >= gg.posx)
    							l->x += x1 - gg.posx;
    						l = l->next;
    					}
    					refrfunc();
    					scroll();
    				}
    				else
    				{
    					beginerror();
    					printf("Can't Open: Blocked by vertical wires\n");
    					enderror();
    				}
    			}
    		}
    	} while (gg.incircuit && gg.stillnear && *gg.func == '\0');
    	gg.startpoint = false;
    	log_setmode("");
    	if (gg.t.dn && !gg.incircuit)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    	cursortype = normal;
    }
    
    
    static void xorrect_(short x1, short y1, short x2, short y2)
    {
    	short x3;
    
    	sortshints(&x1, &x2);
    	sortshints(&y1, &y2);
    	x3 = (x1 + x2) / 2;
    	m_colormode((long)m_xor);
    	m_color((long)gg.color.select);
    	rect(x1, y1, x2, y2);
    	vline(x3, y1, y2);
    	line(x3 - 1, y2 - 1, x3, y2);
    	line(x3 + 1, y2 - 1, x3, y2);
    	m_colormode((long)m_normal);
    }
    
    
    /*==================  OPENVERT  ==================*/
    /*=                                              =*/
    /*=  Open space vertically.                      =*/
    /*=                                              =*/
    /*================================================*/
    
    static void openvert()
    {
    	log_grec *g;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_srec *s;
    	log_lrec *l;
    	log_brec *b;
    	short x1, y1;
    	int flag;
    
    	log_setmode("OPNV");
    	clearfunc();
    	cursortype = copy_;
    	waitnear();
    	do
    	{
    		do
    		{
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			pass();
    			trykbdscroll();
    			pen();
    		} while (!gg.t.dn && gg.stillnear && *gg.func == '\0');
    
    		if (gg.incircuit && gg.stillnear && *gg.func == '\0')
    		{
    			x1 = gg.posx;
    			y1 = gg.posy;
    			do
    			{
    				x1 = gg.gridx;
    				y1 = gg.gridy;
    				xorrect_(gg.posx, gg.posy, x1, y1);
    				do
    				{
    					pass();
    					trykbd();
    					pen();
    				} while (gg.gridx == x1 && gg.gridy == y1 && gg.t.depressed &&
    						*gg.func == '\0');
    				xorrect_(gg.posx, gg.posy, x1, y1);
    				scroll();
    			} while ((gg.t.depressed || x1 == gg.posx || y1 == gg.posy) &&
    					*gg.func == '\0');
    			sortshints(&gg.posx, &x1);
    			sortshints(&gg.posy, &y1);
    			remcursor();
    			if (gg.incircuit && *gg.func == '\0')
    			{
    				chpage((int)gg.curpage);
    				hw = gg.hwbase[gg.curpage - 1];
    				flag = false;
    
    				while (hw != NULL)
    				{
    					if (hw->y > gg.posy &&
    							((hw->x1 < gg.posx && gg.posx < hw->x2) ||
    							 (hw->x1 < x1 && x1 < hw->x2)))
    						flag = true;
    					hw = hw->next;
    				}
    
    				if (!flag)
    				{
    					g = gg.gbase[gg.curpage - 1];
    					while (g != NULL)
    					{
    						if (gg.posx <= g->x && g->x <= x1 && g->y >= gg.posy)
    							shiftgate(g, 0, y1 - gg.posy);
    						g = g->next;
    					}
    					s = gg.sbase[gg.curpage - 1];
    
    					while (s != NULL)
    					{
    						if (!vlsi && gg.posx <= s->hwire->x2 && s->hwire->x1 <= x1 &&
    								s->hwire->y > gg.posy)
    							s->y += y1 - gg.posy;
    						s = s->next;
    					}
    					vw = gg.vwbase[gg.curpage - 1];
    
    					while (vw != NULL)
    					{
    						if (gg.posx <= vw->x && vw->x <= x1)
    						{
    							if (vw->y1 > gg.posy)
    								vw->y1 += y1 - gg.posy;
    							if (vw->y2 >= gg.posy)
    								vw->y2 += y1 - gg.posy;
    						}
    						vw = vw->next;
    					}
    					hw = gg.hwbase[gg.curpage - 1];
    
    					while (hw != NULL)
    					{
    						if (gg.posx <= hw->x2 && hw->x1 <= x1 && hw->y > gg.posy)
    							hw->y += y1 - gg.posy;
    						hw = hw->next;
    					}
    
    					b = gg.bbase[gg.curpage - 1];
    					while (b != NULL)
    					{
    						if (gg.posx <= b->x1 && b->x2 <= x1)
    						{
    							if (b->y1 >= gg.posy)
    								b->y1 += y1 - gg.posy;
    							if (b->y2 >= gg.posy)
    								b->y2 += y1 - gg.posy;
    						}
    						b = b->next;
    					}
    					l = gg.lbase[gg.curpage - 1];
    					while (l != NULL)
    					{
    						if (gg.posx <= l->x && l->x <= x1 && l->y >= gg.posy)
    							l->y += y1 - gg.posy;
    						l = l->next;
    					}
    					refrfunc();
    					scroll();
    				}
    				else
    				{
    					beginerror();
    					printf("Can't Open: Blocked by horizontal wires\n");
    					enderror();
    				}
    			}
    		}
    	} while (gg.incircuit && gg.stillnear && *gg.func == '\0');
    	gg.startpoint = false;
    	log_setmode("");
    	if (gg.t.dn && !gg.incircuit)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    	cursortype = normal;
    }
    
    static void xorrect__(short x1, short y1, short x2, short y2)
    {
    	short y3;
    
    	sortshints(&x1, &x2);
    	sortshints(&y1, &y2);
    	y3 = (y1 + y2) / 2;
    	m_colormode((long)m_xor);
    	m_color((long)gg.color.select);
    	rect(x1, y1, x2, y2);
    	hline(x1, x2, y3);
    	line(x1 + 1, y3 - 1, x1, y3);
    	line(x1 + 1, y3 + 1, x1, y3);
    	m_colormode((long)m_normal);
    }
    
    
    /*==================  CLOSEHORIZ  ================*/
    /*=                                              =*/
    /*=  Close space horizontally.                   =*/
    /*=                                              =*/
    /*================================================*/
    
    static void closehoriz()
    {
    	log_grec *g, *g1;
    	log_hwrec *hw, *hw1;
    	log_vwrec *vw, *vw1;
    	log_srec *s, *s1;
    	log_lrec *l, *l1;
    	log_brec *b, *b1;
    	short x1, y1;
    	int flag;
    
    	log_setmode("CLSH");
    	clearfunc();
    	cursortype = copy_;
    	waitnear();
    	do
    	{
    		do
    		{
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			pass();
    			trykbdscroll();
    			pen();
    		} while (!gg.t.dn && gg.stillnear && *gg.func == '\0');
    		
    		if (gg.incircuit && gg.stillnear && *gg.func == '\0')
    		{
    			x1 = gg.posx;
    			y1 = gg.posy;
    			do
    			{
    				x1 = gg.gridx;
    				y1 = gg.gridy;
    				xorrect__(gg.posx, gg.posy, x1, y1);
    				do
    				{
    					pass();
    					trykbd();
    					pen();
    				} while (gg.gridx == x1 && gg.gridy == y1 && gg.t.depressed &&
    						*gg.func == '\0');
    				xorrect__(gg.posx, gg.posy, x1, y1);
    				scroll();
    			} while ((gg.t.depressed || x1 == gg.posx || y1 == gg.posy) &&
    					*gg.func == '\0');
    			sortshints(&gg.posx, &x1);
    			sortshints(&gg.posy, &y1);
    			remcursor();
    			if (gg.incircuit && *gg.func == '\0')
    			{
    				chpage((int)gg.curpage);
    				vw = gg.vwbase[gg.curpage - 1];
    				flag = false;
    				while (vw != NULL)
    				{
    					if (vw->x >= gg.posx &&
    							((vw->y1 < gg.posy && gg.posy < vw->y2) ||
    							 (vw->y1 < y1 && y1 < vw->y2)))
    						flag = true;
    					vw = vw->next;
    				}
    				
    				if (!flag)
    				{
    					g = gg.gbase[gg.curpage - 1];
    					while (g != NULL)
    					{
    						g1 = g->next;
    						if (gg.posy <= g->y && g->y <= y1 && g->x >= gg.posx)
    						{
    							if (g->x <= x1)
    								delgate(g);
    							else
    								shiftgate(g, gg.posx - x1, 0);
    						}
    						g = g1;
    					}
    					s = gg.sbase[gg.curpage - 1];
    					
    					while (s != NULL)
    					{
    						s1 = s->next;
    						if (!vlsi && gg.posy <= s->vwire->y2 && s->vwire->y1 <= y1 &&
    								s->vwire->x >= gg.posx)
    						{
    							if (s->vwire->x > x1)
    								s->x += gg.posx - x1;
    						}
    						s = s1;
    					}
    					hw = gg.hwbase[gg.curpage - 1];
    					
    					while (hw != NULL)
    					{
    						hw1 = hw->next;
    						if (gg.posy <= hw->y && hw->y <= y1 && hw->x2 >= gg.posx) {
    							if (hw->x1 >= gg.posx && hw->x2 < x1)
    								delhwire(hw);
    						}
    						hw = hw1;
    					}
    					vw = gg.vwbase[gg.curpage - 1];
    					
    					while (vw != NULL)
    					{
    						vw1 = vw->next;
    						if (gg.posy <= vw->y2 && vw->y1 <= y1 && vw->x >= gg.posx &&
    								vw->x <= x1)
    							delvwire(vw);
    						vw = vw1;
    					}
    					hw = gg.hwbase[gg.curpage - 1];
    					
    					while (hw != NULL)
    					{
    						if (gg.posy <= hw->y && hw->y <= y1 && hw->x2 >= gg.posx)
    						{
    							if (hw->x1 >= gg.posx)
    							{
    								if (hw->x1 < x1)
    								{
    									hw->x1 = gg.posx;
    								}
    								else
    								{
    									hw->x1 += gg.posx - x1;
    									hw->x2 += gg.posx - x1;
    								}
    							}
    							else if (hw->x2 >= x1)
    							{
    								hw->x2 += gg.posx - x1;
    							}
    							else if (hw->x2 >= gg.posx)
    							{
    								hw->x2 = gg.posx;
    							}
    						}
    						hw = hw->next;
    					}
    					vw = gg.vwbase[gg.curpage - 1];
    					
    					while (vw != NULL)
    					{
    						if (gg.posy <= vw->y2 && vw->y1 <= y1 && vw->x >= gg.posx)
    							vw->x += gg.posx - x1;
    						vw = vw->next;
    					}
    					b = gg.bbase[gg.curpage - 1];
    
    					while (b != NULL)
    					{
    						b1 = b->next;
    						if (gg.posy <= b->y1 && b->y2 <= y1)
    						{
    							if (b->x1 >= x1)
    							{
    								b->x1 += gg.posx - x1;
    								b->x2 += gg.posx - x1;
    							}
    							else if (b->x1 >= gg.posx)
    							{
    								if (b->x2 < x1)
    								{
    									dispbox(&b);
    								}
    								else
    								{
    									b->x1 = gg.posx;
    									b->x2 += gg.posx - x1;
    								}
    							}
    							else if (b->x2 >= x1)
    							{
    								b->x2 += gg.posx - x1;
    							}
    							else if (b->x2 >= gg.posx)
    							{
    								b->x2 = gg.posx;
    							}
    						}
    						b = b1;
    					}
    					l = gg.lbase[gg.curpage - 1];
    
    					while (l != NULL)
    					{
    						l1 = l->next;
    						if (gg.posy <= l->y && l->y <= y1 && l->x >= gg.posx)
    						{
    							if (l->x + strlen(gg.nearlabel->name) * 7 / gg.scale <= x1)
    								displabel(&l);
    							else
    								l->x += gg.posx - x1;
    						}
    						l = l1;
    					}
    					refrfunc();
    					scroll();
    				}
    				else
    				{
    					beginerror();
    					printf("Can't Close: Blocked by vertical wires\n");
    					enderror();
    				}
    			}
    		}
    	} while (gg.incircuit && gg.stillnear && *gg.func == '\0');
    	gg.startpoint = false;
    	log_setmode("");
    	if (gg.t.dn && !gg.incircuit)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    	cursortype = normal;
    }
    
    
    static void xorrect___(short x1, short y1, short x2, short y2)
    {
    	short x3;
    
    	sortshints(&x1, &x2);
    	sortshints(&y1, &y2);
    	x3 = (x1 + x2) / 2;
    	m_colormode((long)m_xor);
    	m_color((long)gg.color.select);
    	rect(x1, y1, x2, y2);
    	vline(x3, y1, y2);
    	line(x3 - 1, y1 + 1, x3, y1);
    	line(x3 + 1, y1 + 1, x3, y1);
    	m_colormode((long)m_normal);
    }
    
    
    /*==================  CLOSEVERT  =================*/
    /*=                                              =*/
    /*=  Close space vertically.                     =*/
    /*=                                              =*/
    /*================================================*/
    
    static void closevert()
    {
    	log_grec *g, *g1;
    	log_hwrec *hw, *hw1;
    	log_vwrec *vw, *vw1;
    	log_srec *s, *s1;
    	log_lrec *l, *l1;
    	log_brec *b, *b1;
    	short x1, y1;
    	int flag;
    
    	log_setmode("CLSV");
    	clearfunc();
    	cursortype = copy_;
    	waitnear();
    	do
    	{
    		do
    		{
    			gg.posx = gg.gridx;
    			gg.posy = gg.gridy;
    			pass();
    			trykbdscroll();
    			pen();
    		} while (!gg.t.dn && gg.stillnear && *gg.func == '\0');
    		
    		if (gg.incircuit && gg.stillnear && *gg.func == '\0')
    		{
    			x1 = gg.posx;
    			y1 = gg.posy;
    			do
    			{
    				x1 = gg.gridx;
    				y1 = gg.gridy;
    				xorrect___(gg.posx, gg.posy, x1, y1);
    				do
    				{
    					pass();
    					trykbd();
    					pen();
    				} while (gg.gridx == x1 && gg.gridy == y1 && gg.t.depressed &&
    						*gg.func == '\0');
    				xorrect___(gg.posx, gg.posy, x1, y1);
    				scroll();
    			} while ((gg.t.depressed || x1 == gg.posx || y1 == gg.posy) &&
    					*gg.func == '\0');
    			sortshints(&gg.posx, &x1);
    			sortshints(&gg.posy, &y1);
    			remcursor();
    			if (gg.incircuit && *gg.func == '\0')
    			{
    				chpage((int)gg.curpage);
    				hw = gg.hwbase[gg.curpage - 1];
    				flag = false;
    				while (hw != NULL)
    				{
    					if (hw->y >= gg.posy &&
    							((hw->x1 < gg.posx && gg.posx < hw->x2) ||
    							 (hw->x1 < x1 && x1 < hw->x2)))
    						flag = true;
    					hw = hw->next;
    				}
    				
    				if (!flag)
    				{
    					g = gg.gbase[gg.curpage - 1];
    					while (g != NULL)
    					{
    						g1 = g->next;
    						if (gg.posx <= g->x && g->x <= x1 && g->y >= gg.posy)
    						{
    							if (g->y <= y1)
    								delgate(g);
    							else
    								shiftgate(g, 0, gg.posy - y1);
    						}
    						g = g1;
    					}
    					s = gg.sbase[gg.curpage - 1];
    					
    					while (s != NULL)
    					{
    						s1 = s->next;
    						if (!vlsi && gg.posx <= s->hwire->x2 && s->hwire->x1 <= x1 &&
    								s->hwire->y >= gg.posy)
    						{
    							if (s->hwire->y > y1)
    								s->y += gg.posy - y1;
    						}
    						s = s1;
    					}
    					vw = gg.vwbase[gg.curpage - 1];
    					
    					while (vw != NULL)
    					{
    						vw1 = vw->next;
    						if (gg.posx <= vw->x && vw->x <= x1 && vw->y2 >= gg.posy)
    						{
    							if (vw->y1 >= gg.posy && vw->y2 < y1)
    								delvwire(vw);
    						}
    						vw = vw1;
    					}
    					hw = gg.hwbase[gg.curpage - 1];
    					
    					while (hw != NULL)
    					{
    						hw1 = hw->next;
    						if (gg.posx <= hw->x2 && hw->x1 <= x1 && hw->y >= gg.posy &&
    								hw->y <= y1)
    							delhwire(hw);
    						hw = hw1;
    					}
    					vw = gg.vwbase[gg.curpage - 1];
    					
    					while (vw != NULL)
    					{
    						if (gg.posx <= vw->x && vw->x <= x1 && vw->y2 >= gg.posy)
    						{
    							if (vw->y1 >= gg.posy)
    							{
    								if (vw->y1 < y1)
    								{
    									vw->y1 = gg.posy;
    								}
    								else
    								{
    									vw->y1 += gg.posy - y1;
    									vw->y2 += gg.posy - y1;
    								}
    							}
    							else if (vw->y2 >= y1)
    							{
    								vw->y2 += gg.posy - y1;
    							}
    							else if (vw->y2 >= gg.posy)
    							{
    								vw->y2 = gg.posy;
    							}
    						}
    						vw = vw->next;
    					}
    					hw = gg.hwbase[gg.curpage - 1];
    					
    					while (hw != NULL)
    					{
    						if (gg.posx <= hw->x2 && hw->x1 <= x1 && hw->y >= gg.posy)
    							hw->y += gg.posy - y1;
    						hw = hw->next;
    					}
    					b = gg.bbase[gg.curpage - 1];
    					
    					while (b != NULL)
    					{
    						b1 = b->next;
    						if (gg.posx <= b->x1 && b->x2 <= x1)
    						{
    							if (b->y1 >= y1)
    							{
    								b->y1 += gg.posy - y1;
    								b->y2 += gg.posy - y1;
    							}
    							else if (b->y1 >= gg.posy)
    							{
    								if (b->y2 < y1)
    								{
    									dispbox(&b);
    								}
    								else
    								{
    									b->y1 = gg.posy;
    									b->y2 += gg.posy - y1;
    								}
    							}
    							else if (b->y2 >= y1)
    							{
    								b->y2 += gg.posy - y1;
    							}
    							else if (b->y2 >= gg.posy)
    							{
    								b->y2 = gg.posy;
    							}
    						}
    						b = b1;
    					}
    					l = gg.lbase[gg.curpage - 1];
    
    					while (l != NULL)
    					{
    						l1 = l->next;
    						if (gg.posx <= l->x && l->y >= gg.posy &&
    								l->x + strlen(gg.nearlabel->name) * 7 / gg.scale <= x1)
    						{
    							if (l->y <= y1)
    								displabel(&l);
    							else
    								l->y += gg.posy - y1;
    						}
    						l = l1;
    					}
    					refrfunc();
    					scroll();
    				}
    				else
    				{
    					beginerror();
    					printf("Can't Close: Blocked by horizontal wires\n");
    					enderror();
    				}
    			}
    		}
    	} while (gg.incircuit && gg.stillnear && *gg.func == '\0');
    	gg.startpoint = false;
    	log_setmode("");
    	if (gg.t.dn && !gg.incircuit)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    	cursortype = normal;
    }
    
    
    static void centercommand()
    {
    	log_grec *g;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_srec *s;
    	log_lrec *l;
    	log_brec *b;
    	short dx, dy, x1, y1, x2, y2;
    
    	if (pagembb((int)gg.curpage, &x1, &y1, &x2, &y2))
    	{
    		dx = (origin + across / 2) / log_scale0 - (x2 + x1) / 2;
    		dy = (origin + baseline / 2) / log_scale0 - (y2 + y1) / 2;
    		g = gg.gbase[gg.curpage - 1];
    		while (g != NULL)
    		{
    			shiftgate(g, dx, dy);
    			g = g->next;
    		}
    		hw = gg.hwbase[gg.curpage - 1];
    		
    		while (hw != NULL)
    		{
    			hw->x1 += dx;
    			hw->x2 += dx;
    			hw->y += dy;
    			hw = hw->next;
    		}
    		vw = gg.vwbase[gg.curpage - 1];
    
    		while (vw != NULL)
    		{
    			vw->x += dx;
    			vw->y1 += dy;
    			vw->y2 += dy;
    			vw = vw->next;
    		}
    		s = gg.sbase[gg.curpage - 1];
    
    		while (s != NULL)
    		{
    			s->x += dx;
    			s->y += dy;
    			s = s->next;
    		}
    		l = gg.lbase[gg.curpage - 1];
    
    		while (l != NULL)
    		{
    			l->x += dx;
    			l->y += dy;
    			l = l->next;
    		}
    		b = gg.bbase[gg.curpage - 1];
    
    		while (b != NULL)
    		{
    			b->x1 += dx;
    			b->x2 += dx;
    			b->y1 += dy;
    			b->y2 += dy;
    			b = b->next;
    		}
    	}
    	xoff0 = origin - gg.xoff;
    	yoff0 = origin - gg.yoff;
    	setscale(0);
    	refrfunc();
    }
    
    
    /*================  COMPARESTR  ==================*/
    /*=                                              =*/
    /*=  Compare string S with template string T.    =*/
    /*=  T allows wildcards:                         =*/
    /*=     % matches any character in S.            =*/
    /*=     * matches zero or more characters in S.  =*/
    /*=     ? and = are equivalent to *.             =*/
    /*=     ; precedes group number(s).              =*/
    /*=                                              =*/
    /*================================================*/
    
    static int comparestr(char *s_, short g, char *t_)
    {
    	int Result;
    	char s[9], t[9];
    	char ch;
    	short i;
    	int match;
    	short FORLIM;
    
    	strcpy(s, s_);
    	strcpy(t, t_);
    	if (*t == '\0' || !strcmp(s, t))
    	{
    		return (strcmp(s, t) == 0);
    	}
    	else
    	{
    		ch = t[0];
    		if (ch == '*' || ch == '?' || ch == '=')
    		{
    			strcpy_overlap(t, t + 1);
    			do
    			{
    				match = comparestr(s, g, t);
    				if (!match && *s != '\0')
    					strcpy_overlap(s, s + 1);
    			} while (!(match || *s == '\0'));
    			return (match || comparestr(s, g, t));
    		}
    		else if (ch == ';')
    		{
    			Result = false;
    			if (*s != '\0')
    				return Result;
    			FORLIM = strlen(t);
    			for (i = 1; i < FORLIM; i++)
    			{
    				if (t[i] == g + 48)
    					Result = true;
    			}
    			return Result;
    		}
    		else if (*s != '\0' && (ch == '%' || ch == s[0]))
    		{
    			strcpy_overlap(s, s + 1);
    			strcpy_overlap(t, t + 1);
    			return (comparestr(s, g, t));
    		}
    		else
    		{
    			return false;
    		}
    	}
    	return Result;
    }
    
    
    #define maxvars         16
    
    
    /* Local variables for readlibrary_at: */
    struct LOC_readlibrary_at {
    	short p, f;
    	long dist;
    } ;
    
    static void readint(struct LOC_readlibrary_at *LINK)
    {
    	if (LINK->p >= 64)
    	{
    		GET(libf1[LINK->f - 1]->f, filerec);
    		LINK->p = 0;
    	}
    }
    
    static long readnum(struct LOC_readlibrary_at *LINK)
    {
    	long Result;
    
    	if (LINK->p >= 256)
    	{
    		GET(libf1[LINK->f - 1]->f, filerec);
    		LINK->p = 0;
    	}
    	Result = GETFBUF(libf1[LINK->f - 1]->f, filerec).b[LINK->p];
    	LINK->p++;
    	LINK->dist++;
    	return Result;
    }
    
    static long readcoord(struct LOC_readlibrary_at *LINK)
    {
    	long i;
    
    	i = readnum(LINK);
    	if (i < 128)
    		return i;
    	else if (i == 128)
    		return 0;
    	else
    		return (i - 256);
    }
    
    static void bound(log_krec *k, long x, long y, struct LOC_readlibrary_at *LINK)
    {
    	if (x < k->bbx1)
    		k->bbx1 = x;
    	if (x > k->bbx2)
    		k->bbx2 = x;
    	if (y < k->bby1)
    		k->bby1 = y;
    	if (y > k->bby2)
    		k->bby2 = y;
    }
    
    static long uncompress(long i, struct LOC_readlibrary_at *LINK)
    {
    	if (i < 0)
    		i += 256;
    	if (i == 0)
    		return 0;
    	else
    		return (na_po2(i / 16) * ((i & 15) + 16) * 4);
    }
    
    
    static descrec *readdesc(char *rec)
    {
    	unsigned short i,j1,j2,s1,s2;
    	static descrec d;
    	d.ptr = getintsw(rec);
    	d.numvects = rec[4];
    	d.numpins = rec[5];
    	d.numpnums= rec[6];
    	d.lblsize = rec[7];
    	d.simtype = rec[8];
    	d.procsize= rec[9];
    	d.flag = getshortsw(&(rec[10]));
    
    	if (!bigendian)
    	{
    		/* d.flag.i = reverse(d.flag.i); */
    		d.flag = reverse(d.flag);
    	}
    	d.xx1= rec[12];
    	d.yy1= rec[13];
    	d.xx2= rec[14];
    	d.yy2= rec[15];
    	return &d;
    }
    
    
    static log_pnumrec readpnum(char *rec)
    {
    	static log_pnumrec p;
    
    	p.x = rec[0];
    	p.y = rec[1];
    	p.num = getshortsw(&(rec[2]));
    	return p;
    }
    
    
    /*==================  READLIBRARY  ===============*/
    /*=                                              =*/
    /*=  Read gate(s) named from library and enter   =*/
    /*=     into the catalog.  If catalog is full,   =*/
    /*=     attempt to replace a gate-kind which is  =*/
    /*=     no longer used.                          =*/
    /*=                                              =*/
    /*================================================*/
    
    static short readlibrary_at(char *n_, short where, int loadit)
    {
    	struct LOC_readlibrary_at V;
    	short Result;
    	char n[9];
    	short i, i0, i00, j, j0, j00, j000, count;
    	long j1;
    	na_strlist_t *l2;
    	log_grec *g;
    	char buf[256];
    	char ch, ch2, curcol;
    	int found, flag;
    	log_vectorrec *tempvects;
    	char STR1[256];
    	short FORLIM, FORLIM1;
    	long TEMP;
    	log_krec *WITH;
    	descrec *WITH1;
    	log_vectorrec *WITH2;
    	long FORLIM2;
    
    	strcpy(n, n_);
    	working();
    	strcpy(n, strrtrim(strcpy(STR1, strltrim(n))));
    	found = false;
    	count = 0;
    	FORLIM = idxsize;
    	for (i0 = 1; i0 <= FORLIM; i0++)
    	{
    		if (comparestr(index_[i0 - 1], indexgroup[i0 - 1], n))
    		{
    			found = true;
    			if (P_getbits_UB(loadedgates, i0 - 1, 0, 3))
    			{
    				i = 0;
    				FORLIM1 = maxkinds;
    				for (j = 1; j <= FORLIM1; j++)
    				{
    					if (kind[j - 1] != NULL && kind[j - 1]->code == i0)
    						i = j;
    				}
    				goto _L1;
    			}
    
    			if (!loadit)
    			{
    				count++;
    				goto _L1;
    			}
    			i = where;
    			while (i <= maxkinds && kind[i - 1] != NULL)
    				i++;
    			if (i > maxkinds)
    			{
    				i = 1;
    				while (i <= maxkinds && kind[i - 1] != NULL)
    					i++;
    			}
    			
    			/* garbagge collection */
    			if (i > maxkinds)
    			{
    				i = libptr;
    				do
    				{
    					if (i >= maxkinds)
    						i = 0;
    					i++;
    					flag = false;
    					FORLIM1 = gg.numpages;
    					for (j = 0; j < FORLIM1; j++)
    					{
    						g = gg.gbase[j];
    						while (g != NULL)
    						{
    							flag = (flag || (g->g & (log_kindoffset - 1)) == i);
    							g = g->next;
    						}
    					}
    					FORLIM1 = kindgroupsize;
    					for (j = 0; j < FORLIM1; j++)
    						flag = (flag || (kindgroup[j] & (log_kindoffset - 1)) == i);
    				} while (flag && i != libptr);
    
    				if (flag)
    				{
    					beginerror();
    					printf("Maximum of %d gate types are in use.\n", maxkinds);
    					enderror();
    					i = 0;
    					goto _L1;
    				}
    				libptr = i;
    				clipoff();
    				if (gg.showpage == log_page_cat)
    				{
    					udrawgatec((int)(((i - 1) % catwidth * 2 + 1) * gridcen),
    							(int)(((i - 1) / catwidth * 2 + 1) * gridcen), i,
    							gg.color.backgr);
    				}
    				TEMP = kind[i - 1]->code - 1;
    				P_clrbits_B(loadedgates, TEMP, 0, 3);
    				WITH = kind[i - 1];
    				calltoolkind(kind[i - 1], act_disposekind);
    				if (WITH->proc != NULL)
    					Free(WITH->proc);
    				if (WITH->lbl != NULL)
    					strlist_empty(&WITH->lbl);
    				if (WITH->attr != NULL)
    					Free(WITH->attr);
    				if (WITH->vector != NULL)
    					Free(WITH->vector);
    				if (WITH->pin != NULL)
    					Free(WITH->pin);
    				if (WITH->pnum != NULL)
    					Free(WITH->pnum);
    				Free(kind[i - 1]);
    				kind[i - 1] = NULL;
    			}
    			V.f = indexfile[i0 - 1];
    			TRY(try15);
    			i00 = indexoffset[i0 - 1];
    			fseek(libf1[V.f - 1]->f,
    					(libfstart[V.f - 1] + (i00 - 1L) / 16 - 1) * sizeof(filerec),
    					0);
    			SETUPBUF(libf1[V.f - 1]->f, filerec);
    			GET(libf1[V.f - 1]->f, filerec);
    			WITH1 = readdesc((char*) &GETFBUF(libf1[V.f - 1]->f, filerec).b[16*((i00 - 1) &
    						15)]);
    			kind[i - 1] = (log_krec *)Malloc(sizeof(log_krec));
    			kind[i - 1]->simtype = findsimtype(WITH1->simtype);
    			kind[i - 1]->numvects = WITH1->numvects;
    			kind[i - 1]->numpins = WITH1->numpins;
    			kind[i - 1]->flag.i = WITH1->flag;
    			if (kind[i - 1]->flag.U3.expanded)
    			{
    				kind[i - 1]->bigprocsize = uncompress((long)WITH1->procsize, &V);
    				kind[i - 1]->biglblsize = uncompress((long)WITH1->lblsize, &V);
    				kind[i - 1]->numpnums = 0;
    				kind[i - 1]->bigvectsize = uncompress((long)WITH1->numpnums, &V);
    			}
    			else
    			{
    				kind[i - 1]->bigprocsize = WITH1->procsize * 4;
    				kind[i - 1]->biglblsize = WITH1->lblsize * 4;
    				kind[i - 1]->numpnums = WITH1->numpnums;
    			}
    			kind[i - 1]->x1 = WITH1->xx1;
    			kind[i - 1]->y1 = WITH1->yy1;
    			kind[i - 1]->x2 = WITH1->xx2;
    			kind[i - 1]->y2 = WITH1->yy2;
    			j1 = WITH1->ptr;
    			fseek(libf1[V.f - 1]->f, j1 / 64 * sizeof(filerec), 0);
    			SETUPBUF(libf1[V.f - 1]->f, filerec);
    			GET(libf1[V.f - 1]->f, filerec);
    			WITH = kind[i - 1];
    			WITH->code = i0;
    			strcpy(WITH->name, index_[i0 - 1]);
    			WITH->proc = NULL;
    			WITH->lbl = NULL;
    			WITH->attr = NULL;
    			WITH->vector = NULL;
    			WITH->pin = NULL;
    			WITH->pinnames = NULL;
    			WITH->pnum = NULL;
    			WITH->info = (na_long)0;
    			V.p = j1 & 63;
    			WITH->bbx1 = -log_scale0;
    			WITH->bby1 = -log_scale0;
    			WITH->bbx2 = log_scale0;
    			WITH->bby2 = log_scale0;
    			bound(kind[i - 1], (long)WITH->x1, (long)WITH->y1, &V);
    			bound(kind[i - 1], (long)WITH->x2, (long)WITH->y2, &V);
    			
    			if (WITH->numvects != 0)
    			{
    				if (WITH->flag.U3.expanded)
    				{
    					tempvects = (log_vectorrec *)
    						Malloc(WITH->numvects * sizeof(log_vectorrec) * 2);
    					j = 0;
    					curcol = '1';
    					V.dist = 0;
    					V.p *= 4;
    					FORLIM1 = WITH->numvects;
    					for (j0 = 1; j0 <= FORLIM1; j0++)
    					{
    						ch = (char)readnum(&V);
    						if (ch >= '1' && ch <= '7')
    						{
    							do
    							{
    								ch2 = ch;
    								ch = (char)readnum(&V);
    							} while (ch >= '1' && ch <= '7');
    							
    							if (ch2 != curcol)
    							{
    								j++;
    								tempvects[j - 1].vkind = ch2;
    								tempvects[j - 1].numcoords = 0;
    								curcol = ch2;
    							}
    						}
    						j++;
    						WITH2 = &tempvects[j - 1];
    						WITH2->vkind = ch;
    						switch (ch)
    						{
    
    							case 'v':
    							case 'C':
    							case 'e':
    							case 'E':
    								WITH2->x1 = readcoord(&V);
    								WITH2->y1 = readcoord(&V);
    								WITH2->UU.U99.x2 = readcoord(&V);
    								WITH2->UU.U99.y2 = readcoord(&V);
    								WITH2->numcoords = 2;
    								bound(kind[i - 1], (long)WITH2->x1, (long)WITH2->y1, &V);
    								bound(kind[i - 1], (long)WITH2->UU.U99.x2,
    										(long)WITH2->UU.U99.y2, &V);
    								break;
    
    							case 'r':
    								WITH2->x1 = readcoord(&V);
    								WITH2->y1 = readcoord(&V);
    								WITH2->UU.U99.x2 = readcoord(&V);
    								WITH2->UU.U99.y2 = readcoord(&V);
    								WITH2->UU.U98.num = readcoord(&V);
    								WITH2->numcoords = 2;
    								bound(kind[i - 1], (long)WITH2->x1, (long)WITH2->y1, &V);
    								bound(kind[i - 1], (long)WITH2->UU.U99.x2,
    										(long)WITH2->UU.U99.y2, &V);
    								break;
    
    							case 'F':
    							case 'c':
    								WITH2->x1 = readcoord(&V);
    								WITH2->y1 = readcoord(&V);
    								WITH2->UU.U99.x2 = readcoord(&V);
    								WITH2->UU.U99.y2 = readcoord(&V);
    								WITH2->UU.U99.x3 = readcoord(&V);
    								WITH2->UU.U99.y3 = readcoord(&V);
    								WITH2->UU.U99.x4 = readcoord(&V);
    								WITH2->UU.U99.y4 = readcoord(&V);
    								WITH2->numcoords = 4;
    								bound(kind[i - 1], (long)WITH2->x1, (long)WITH2->y1, &V);
    								bound(kind[i - 1], (long)WITH2->UU.U99.x2,
    										(long)WITH2->UU.U99.y2, &V);
    								bound(kind[i - 1], (long)WITH2->UU.U99.x3,
    										(long)WITH2->UU.U99.y3, &V);
    								bound(kind[i - 1], (long)WITH2->UU.U99.x4,
    										(long)WITH2->UU.U99.y4, &V);
    								break;
    
    							case 'p':
    								WITH2->UU.U98.num = readnum(&V);
    								WITH2->x1 = readcoord(&V);
    								WITH2->y1 = readcoord(&V);
    								WITH2->numcoords = 1;
    								bound(kind[i - 1], (long)WITH2->x1, (long)WITH2->y1, &V);
    								break;
    
    							case 'b':
    								WITH2->UU.U98.num = readnum(&V);
    								WITH2->x1 = readcoord(&V);
    								WITH2->y1 = readcoord(&V);
    								WITH2->UU.U99.x2 = readcoord(&V);
    								WITH2->UU.U99.y2 = readcoord(&V);
    								WITH2->numcoords = 2;
    								bound(kind[i - 1], (long)WITH2->x1, (long)WITH2->y1, &V);
    								bound(kind[i - 1], (long)WITH2->UU.U99.x2,
    										(long)WITH2->UU.U99.y2, &V);
    								break;
    
    							case 't':
    								WITH2->UU.U116.tsize = readnum(&V);
    								WITH2->UU.U116.torg = readnum(&V) - 1;
    								WITH2->x1 = readcoord(&V);
    								WITH2->y1 = readcoord(&V);
    								WITH2->numcoords = 1;
    								bound(kind[i - 1], (long)WITH2->x1, (long)WITH2->y1, &V);
    								j000 = readnum(&V);
    								buf[j000] = '\0';
    								for (j00 = 0; j00 < j000; j00++)
    									buf[j00] = (char)readnum(&V);
    								WITH2->UU.U116.sp = strdup(buf);
    								break;
    
    							default:
    								j--;
    								break;
    						}
    					}
    					WITH->numvects = j;
    					WITH->vector = (log_vectorrec *)
    						Malloc(WITH->numvects * sizeof(log_vectorrec));
    					memmove((void *)WITH->vector, (void *)tempvects,
    							WITH->numvects * sizeof(log_vectorrec));
    					while (V.dist < WITH->bigvectsize)
    						j0 = readnum(&V);
    					V.p /= 4;
    					Free(tempvects);
    				}
    				else
    				{
    					WITH->vector = (log_vectorrec *)
    						Malloc(WITH->numvects * sizeof(log_vectorrec));
    					FORLIM1 = WITH->numvects;
    					for (j = 0; j < FORLIM1; j++)
    					{
    						readint(&V);
    						WITH->vector[j].vkind = 'v';
    						WITH->vector[j].numcoords = 2;
    						WITH->vector[j].x1 = GETFBUF(libf1[V.f - 1]->f, filerec).vec[V.p].x1;
    						WITH->vector[j].y1 = GETFBUF(libf1[V.f - 1]->f, filerec).vec[V.p].y1;
    						WITH->vector[j].UU.U99.x2 =
    							GETFBUF(libf1[V.f - 1]->f, filerec).vec[V.p].x2;
    						WITH->vector[j].UU.U99.y2 =
    							GETFBUF(libf1[V.f - 1]->f, filerec).vec[V.p].y2;
    						bound(kind[i - 1], (long)WITH->vector[j].x1,
    								(long)WITH->vector[j].y1, &V);
    						bound(kind[i - 1], (long)WITH->vector[j].UU.U99.x2,
    								(long)WITH->vector[j].UU.U99.y2, &V);
    						V.p++;
    					}
    				}
    			}
    
    			if (WITH->numpins != 0)
    			{
    				WITH->pin = (log_pinrec *)Malloc(WITH->numpins * sizeof(log_pinrec));
    				WITH->pinnames = (na_strlist_t **)
    					Malloc(WITH->numpins * sizeof(na_strlist_t *));
    				FORLIM1 = WITH->numpins;
    				for (j = 0; j < FORLIM1; j++)
    				{
    					readint(&V);
    					WITH->pin[j].x = GETFBUF(libf1[V.f - 1]->f, filerec).pin[V.p].x /
    						log_scale0;
    					WITH->pin[j].y = GETFBUF(libf1[V.f - 1]->f, filerec).pin[V.p].y /
    						log_scale0;
    					WITH->pin[j].s = GETFBUF(libf1[V.f - 1]->f, filerec).pin[V.p].s;
    					WITH->pin[j].c = GETFBUF(libf1[V.f - 1]->f, filerec).pin[V.p].c;
    					bound(kind[i - 1], (long)(WITH->pin[j].x * log_scale0),
    							(long)(WITH->pin[j].y * log_scale0), &V);
    					WITH->pinnames[j] = NULL;
    					V.p++;
    				}
    			}
    			
    			if (WITH->numpnums != 0)
    			{
    				WITH->pnum = (log_pnumrec *)Malloc(WITH->numpnums *
    						sizeof(log_pnumrec));
    				FORLIM1 = WITH->numpnums;
    				for (j = 0; j < FORLIM1; j++)
    				{
    					readint(&V);
    					WITH->pnum[j] = readpnum((char *) &GETFBUF(libf1[V.f - 1]->f, filerec).b
    							[4*V.p]);
    					bound(kind[i - 1], (long)WITH->pnum[j].x, (long)WITH->pnum[j].y,
    							&V);
    					V.p++;
    				}
    			}
    			WITH->numattrs = 0;
    			if (WITH->biglblsize != 0)
    			{
    				strlist_init(&WITH->lbl);
    				*buf = '\0';
    				ch = '\001';
    				FORLIM2 = WITH->biglblsize / 4;
    				for (j1 = 1; j1 <= FORLIM2; j1++)
    				{
    					readint(&V);
    					for (j = 0; j <= 3; j++)
    					{
    						if (ch != '\0')
    						{
    							ch = GETFBUF(libf1[V.f - 1]->f, filerec).c4[V.p][j];
    							if (ch == '\001')
    							{
    								if (*buf == '\002')
    								{
    									j0 = 0;
    									while (*buf != '\0')
    									{
    										if (buf[0] == '\002')
    											j0++;
    										strcpy_overlap(buf, buf + 1);
    										j00 = strposc(buf, '\002', 1L);
    										if (j00 == 0)
    											j00 = strlen(buf) + 1;
    										j000 = strposc(buf, '\003', 1L);
    										if (j000 == 0)
    											j000 = strlen(buf) + 1;
    										j00 = P_imin2((long)j00, (long)j000);
    										if (j00 > 1) {
    											if (j0 <= WITH->numpins)
    											{
    												sprintf(STR1, "%.*s", j00 - 1, buf);
    												l2 = strlist_append(&WITH->pinnames[j0 - 1], STR1);
    												l2->value = (na_long)((long)j0);
    											}
    										}
    										strcpy_overlap(buf, buf + j00 - 1);
    									}
    								}
    								else
    								{
    									l2 = strlist_append(&WITH->lbl, buf);
    								}
    								*buf = '\0';
    							}
    							else if (ch != '\0')
    							{
    								sprintf(buf + strlen(buf), "%c", ch);
    							}
    						}
    					}
    					V.p++;
    				}
    				parselabel(&WITH->lbl, &j, &WITH->attr);
    				WITH->numattrs = j;
    			}
    			if (WITH->bigprocsize != 0) {
    				WITH->proc = (uchar *)Malloc(WITH->bigprocsize);
    				FORLIM2 = WITH->bigprocsize / 4;
    				for (j1 = 1; j1 <= FORLIM2; j1++) {
    					readint(&V);
    					for (j0 = 0; j0 <= 3; j0++)
    						WITH->proc[j1 * 4 + j0 - 4] = GETFBUF(libf1[V.f - 1]->f,
    								filerec).c[V.p * 4 + j0];
    					V.p++;
    				}
    			}
    			else
    			{
    				WITH->proc = (uchar *)Malloc(4L);
    				WITH->proc[0] = '\0';
    			}
    			WITH->bbx1 = -((log_scale0 - WITH->bbx1 - 1) / log_scale0);
    			WITH->bby1 = -((log_scale0 - WITH->bby1 - 1) / log_scale0);
    			WITH->bbx2 = (log_scale0 + WITH->bbx2 - 1) / log_scale0;
    			WITH->bby2 = (log_scale0 + WITH->bby2 - 1) / log_scale0;
    			WITH->bbmax = P_imax2(P_imax2((long)(-WITH->bbx1), (long)WITH->bbx2),
    					P_imax2((long)(-WITH->bby1), (long)WITH->bby2));
    			calltoolkind(kind[i - 1], act_newkind);
    			P_putbits_UB(loadedgates, i0 - 1, 1, 0, 3);
    			RECOVER(try15);
    			kind[i - 1] = NULL;
    			
    			if (P_escapecode == -20)
    			{
    				_Escape(P_escapecode);
    			}
    			else
    			{
    				if (P_escapecode != 0)
    				{
    					beginerror();
    					printf("%d/%d/%ld: ", P_escapecode, i, EXCP_LINE);
    					printf("Unable to read file \"%s\"\n", gatesname[V.f - 1]);
    					enderror();
    				}
    				i = 0;
    				goto _L1;
    			}
    
    			ENDTRY(try15);
    			clipoff();
    			if (gg.showpage == log_page_cat)
    			{
    				udrawgatec((int)(((i - 1) % catwidth * 2 + 1) * gridcen),
    						(int)(((i - 1) / catwidth * 2 + 1) * gridcen), i,
    						gg.color.catgate);
    			}
    _L1:
    			Result = i;
    		}
    	}
    
    	if (!loadit)
    		return count;
    	if (found)
    		return Result;
    	beginerror();
    	printf("Can't find gate \"%s\"\n", n);
    	enderror();
    	Result = 0;
    	if (!gg.initdone)
    		_Escape(0);
    	return Result;
    }
    
    #undef maxvars
    
    
    static short readlibrary(char *n)
    {
    	return (readlibrary_at(n, 1, true));
    }
    
    
    static void getgate(char *name, short *gtype)
    {
    	*gtype = readlibrary(name);
    }
    
    
    static void getgategroup(na_strlist_t *grp)
    {
    	na_strlist_t *l1;
    	short pos, i, count;
    	int done;
    	catboxrec *cb;
    
    	l1 = grp;
    	count = 0;
    	while (l1 != NULL)
    	{
    		count += readlibrary_at(l1->s, 1, false);
    		l1 = l1->next;
    	}
    	
    	if (count != 0)
    	{
    		if (count > maxkinds)
    			count = maxkinds;
    		pos = 0;
    		do
    		{
    			pos++;
    			if (count > catwidth)
    			{
    				done = ((pos - 1) % catwidth == 0);
    			}
    			else
    			{
    				done = ((pos - 1) / catwidth == (pos + count - 2) / catwidth);
    			}
    
    			for (i = pos - 1; i <= pos + count - 2; i++)
    			{
    				if (kind[i] != NULL)
    					done = false;
    			}
    		} while (!(done || pos + count > maxkinds));
    		
    		if (done)
    		{
    			if (count <= catwidth)
    			{
    				cb = (catboxrec *)Malloc(sizeof(catboxrec));
    				cb->pos = pos;
    				cb->count = count;
    				cb->next = catboxes;
    				catboxes = cb;
    			}
    		}
    		else
    		{
    			pos = 1;
    		}
    	}
    	else
    	{
    		pos = 1;
    	}
    	l1 = grp;
    	while (l1 != NULL)
    	{
    		i = readlibrary_at(l1->s, pos, true);
    		l1 = l1->next;
    	}
    	strlist_empty(&grp);
    }
    
    
    #define nummap          "0.,+123-456*789/.()^"
    
    
    static void showpinname(log_grec *g, short i, short c, char *name)
    {
    	short j, j2, x, y, w, y0, y1, y2;
    	int small;
    	char buf[256];
    	short FORLIM;
    
    	if (zoom < 2)
    	{
    		*buf = '\0';
    		small = true;
    		FORLIM = strlen(name);
    		for (j = 0; j < FORLIM; j++)
    		{
    			j2 = strposc(nummap, name[j], 1L);
    			if (j2 > 0)
    				sprintf(buf + strlen(buf), "%c", j2 + 127);
    			else if (isupper(name[j]))
    				sprintf(buf + strlen(buf), "%c", name[j] + 103);
    			else
    				small = false;
    		}
    	}
    	else
    	{
    		small = false;
    	}
    
    	if (small)
    	{
    		y0 = -5;
    		y1 = -3;
    		y2 = 3;
    	}
    	else
    	{
    		y0 = -3;
    		y1 = -4;
    		y2 = 4;
    		strcpy(buf, name);
    	}
    	x = g->pinpos[i - 1].x * gg.scale - gg.xoff;
    	y = g->pinpos[i - 1].y * gg.scale - gg.yoff;
    	w = m_strwidth(logfont_lfont, buf);
    	m_color((long)c);
    	if (c == gg.color.backgr)
    		m_fillrect(x - w / 2L - 1, (long)(y + y1), x + w / 2L + 1, (long)(y + y2));
    	else
    		m_centerstr((long)x, (long)(y + y0), logfont_lfont, buf);
    }
    
    #undef nummap
    
    
    #define spc             12
    #define xdiff           30
    #define ydiff           20
    #define border          3
    
    
    
    static void showgateinfo(na_strlist_t *info, log_grec *g)
    {
    	na_strlist_t *l1;
    	long width, height, i;
    	short gx, gy, gx1, gy1, gx2, gy2, mx, my, y, z;
    	log_krec *WITH;
    
    	width = 10;
    	height = 0;
    	l1 = info;
    	while (l1 != NULL)
    	{
    		i = m_strwidth(logfont_lfont, l1->s);
    		if (i > width)
    			width = i;
    		height += spc;
    		l1 = l1->next;
    	}
    	width += border * 2;
    	height += border * 2 - 1;
    	mx = -1;
    	if (g != NULL)
    	{
    		gx = g->x * gg.scale - gg.xoff;
    		gy = g->y * gg.scale - gg.yoff;
    		z = g->rot;
    		WITH = g->kind;
    		gx1 = gx + (WITH->x1 * log_rotxx[z] + WITH->y1 * log_rotyx[z]) *
    			gg.scale / log_scale0;
    		gx2 = gx + (WITH->x2 * log_rotxx[z] + WITH->y2 * log_rotyx[z]) *
    			gg.scale / log_scale0;
    		sortshints(&gx1, &gx2);
    		gy1 = gy + (WITH->x1 * log_rotxy[z] + WITH->y1 * log_rotyy[z]) *
    			gg.scale / log_scale0;
    		gy2 = gy + (WITH->x2 * log_rotxy[z] + WITH->y2 * log_rotyy[z]) *
    			gg.scale / log_scale0;
    		sortshints(&gy1, &gy2);
    		gx1 -= 2;
    		gx2 += 2;
    		gy1 -= 2;
    		gy2 += 2;
    		if (gx2 + xdiff + width < across)
    			mx = gx2 + xdiff;
    		else if (gx1 - xdiff - width > 0)
    			mx = gx1 - xdiff - width;
    		else if (gx < across / 2)
    			mx = across - width;
    		else
    			mx = 0;
    		
    		if (gy2 + ydiff + height < baseline)
    			my = gy2 + ydiff;
    		else if (gy1 - ydiff - height > 0)
    			my = gy1 - ydiff - height;
    		else if (gy < baseline / 2)
    			my = baseline - height;
    		else
    			my = 0;
    
    		if (false)
    		{
    			if (gx < across / 3)
    				mx = (gx2 + across - width) / 2;
    			else if (gx > across * 2 / 3 || (gy >= baseline / 3 && gy <= baseline))
    				mx = (gx1 - width) / 2;
    			else
    				mx = (across - width) / 2;
    			mx = P_imax2(P_imin2((long)mx, across - width), 0L);
    			if (gy < baseline / 3)
    				my = (gy2 + baseline - height) / 2;
    			else if (gy > baseline * 2 / 3 || (gx >= across / 3 && gx <= across))
    				my = (gy1 - height) / 2;
    			else
    				my = (baseline - height) / 2;
    			my = P_imax2(P_imin2((long)my, baseline - height), 0L);
    		}
    
    		m_color((long)defineboxcolor);
    		m_linestyle(2L);
    		if (mx < gx1 || my < gy1)
    			m_drawline((long)gx1, (long)gy1, (long)mx, (long)my);
    		if (mx + width > gx2 || my < gy1)
    			m_drawline((long)gx2, (long)gy1, mx + width, (long)my);
    		if (mx < gx1 || my + height > gy2)
    			m_drawline((long)gx1, (long)gy2, (long)mx, my + height);
    		if (mx + width > gx2 || my + height > gy2)
    			m_drawline((long)gx2, (long)gy2, mx + width, my + height);
    		m_linestyle(0L);
    	}
    
    	if (mx < 0)
    	{
    		mx = P_imax2(across * 3L / 5 - width / 2, 0L);
    		my = P_imax2(baseline * 3L / 5 - height / 2, 0L);
    	}
    	m_color((long)definebackcolor);
    	m_fillrect((long)mx, (long)my, mx + width, my + height);
    	m_color((long)defineboxcolor);
    	m_drawrect((long)mx, (long)my, mx + width, my + height);
    	m_color((long)gg.color.selword);
    	y = my + border;
    	l1 = info;
    	while (l1 != NULL)
    	{
    		m_drawstr((long)(mx + border), (long)y, logfont_lfont, l1->s);
    		y += spc;
    		m_color((long)definetextcolor);
    		l1 = l1->next;
    	}
    	strlist_empty(&info);
    }
    
    #undef spc
    #undef xdiff
    #undef ydiff
    #undef border
    
    
    static void showgatedef(log_krec *k, log_grec *g)
    {
    	na_strlist_t *l1;
    	char STR1[42];
    
    	gg.actstrlist = NULL;
    	if (g != NULL)
    	{
    		send_gengate(g, "DUMPKIND");
    		gg.actflag = false;
    		send_gengate(g, "SHOWPINS");
    	}
    	
    	if (gg.actstrlist == NULL)
    		send_genkind(k, "DUMPKIND");
    	
    	if (gg.actstrlist == NULL)
    	{
    		sprintf(STR1, "No definition available for gate %s", k->name);
    		l1 = strlist_append(&gg.actstrlist, STR1);
    	}
    	showgateinfo(gg.actstrlist, g);
    }
    
    
    static void gatedefinitioncommand()
    {
    	long i;
    	char STR1[256];
    
    	if (*gg.funcarg == '\0')
    	{
    		clearfunc();
    		do
    		{
    			do
    			{
    				beginbottom();
    				m_alpha_on();
    				nk_gotoxy(0, txdown - 1);
    				printf("Select a gate to view its simulator definition.");
    				do
    				{
    					pass();
    					trykbd();
    					pen();
    					m_alpha_on();
    				} while (!(gg.t.dn || *gg.func != '\0'));
    				endbottom();
    				scroll();
    			} while (!(gg.t.dn || *gg.func != '\0'));
    			if (*gg.func == '\0')
    			{
    				closergate(gg.gridx, gg.gridy);
    				if (gg.neargate != NULL)
    					showgatedef(gg.neargate->kind, gg.neargate);
    			}
    			else
    			{
    				gg.neargate = NULL;
    			}
    		} while (gg.neargate != NULL);
    		return;
    	}
    	i = readlibrary(strupper(STR1, gg.funcarg));
    	clearfunc();
    	if (i != 0)
    		showgatedef(kind[i - 1], NULL);
    }
    
    
    /*================  LISTLIBRARY  =================*/
    /*=                                              =*/
    /*=  List the gates available in the library.    =*/
    /*=     + or space bar displays next page;       =*/
    /*=     - displays previous page;                =*/
    /*=     anything else returns to Instructions.   =*/
    /*=                                              =*/
    /*================================================*/
    
    static char *strreverse(char *Result, char *s)
    {
    	long i;
    	char s2[256];
    
    	*s2 = '\0';
    	for (i = strlen(s) - 1; i >= 0; i--)
    		sprintf(s2 + strlen(s2), "%c", s[i]);
    	return strcpy(Result, s2);
    }
    
    
    static librstrrec *findlibrstr(char *name_)
    {
    	char name[9];
    	librstrrec *lsp;
    	char STR1[256];
    
    	strcpy(name, name_);
    	lsp = librstrs;
    	strcpy(name, strreverse(STR1, name));
    	while (lsp != NULL && strcmp(lsp->name, name))
    	{
    		if (strcmp(name, lsp->name) < 0)
    			lsp = lsp->left;
    		else
    			lsp = lsp->right;
    	}
    	return lsp;
    }
    
    
    #define maxmaxi         12
    #define maxmaxj         45
    #define huge_           30000
    
    
    /* Local variables for listlibrary: */
    struct LOC_listlibrary {
    	short maxi, maxj;
    	short karr[maxmaxi + 1][maxmaxj];
    } ;
    
    static short kfunc(short *i, short *j, struct LOC_listlibrary *LINK)
    {
    	/* K for Kludge */
    	*i = (gg.t.ax - 2) / 10;
    	*j = gg.t.ay - 1;
    	if (!gg.t.near_)
    	{
    		return -1;
    	}
    	else if (*j <= 0 || (unsigned)(*i) > LINK->maxi)
    	{
    		return -2;
    	}
    	else if (*j > LINK->maxj)
    	{
    		if (*i < 1)
    			return -3;
    		else if (*i < 3)
    			return -4;
    		else
    			return -2;
    	}
    	else if (LINK->karr[*i][*j - 1] == 0)
    	{
    		return (huge_ + *j * 8 + *i);
    	}
    	else
    	{
    		return (LINK->karr[*i][*j - 1]);
    	}
    }
    
    
    static void listlibrary()
    {
    	struct LOC_listlibrary V;
    	short i, j, ii, jj, k, nn0, nn;
    	librstrrec *lsp;
    	char ch;
    	int exitflag;
    	char STR1[256];
    	short FORLIM, FORLIM1;
    
    	V.maxi = P_imin2((txacross - 9L) / 10, (long)maxmaxi);
    	V.maxj = P_imin2(txdown - 3L, (long)maxmaxj);
    	nn0 = 1;
    	exitflag = false;
    	do
    	{
    		clearshowalpha();
    		printf("Listing of gates ");
    		if (librgroupnames[curlistgroup] != NULL &&
    				strlen(librgroupnames[curlistgroup]) <= txacross - 26)
    			fputs(strcjust(STR1, librgroupnames[curlistgroup], txacross - 26L),
    					stdout);
    		else
    			printf("%*c", txacross - 26, ' ');
    		
    		printf("Group%2d\n", curlistgroup);
    		FORLIM = V.maxi;
    		for (i = 0; i <= FORLIM; i++)
    		{
    			FORLIM1 = V.maxj;
    			for (j = 0; j < FORLIM1; j++)
    				V.karr[i][j] = 0;
    		}
    		i = 0;
    		j = 1;
    		nn = nn0;
    		do
    		{
    			if (indexgroup[nn - 1] == curlistgroup)
    			{
    				V.karr[i][j - 1] = nn;
    				nk_gotoxy(i * 10 + 2, j + 1);
    				if (P_getbits_UB(loadedgates, nn - 1, 0, 3))
    					putchar(chryellow);
    				printf("%s%c", index_[nn - 1], chrgreen);
    				j++;
    				if (j > V.maxj)
    				{
    					j = 1;
    					i++;
    				}
    			}
    			nn++;
    		} while (i <= V.maxi && nn <= idxsize);
    		nk_gotoxy(0, txdown);
    		printf("+ for next group, - for last group, space bar to quit.");
    		do
    		{
    			k = kfunc(&i, &j, &V);
    			lsp = NULL;
    			if (k > 0)
    			{
    				if (k < huge_)
    				{
    					lsp = findlibrstr(index_[k - 1]);
    					if (lsp != NULL)
    					{
    						nk_gotoxy(0, txdown - 1);
    						printf("%.*s", txacross, lsp->str);
    					}
    				}
    				nk_gotoxy(i * 10 + 2, j + 1);
    				if (k < huge_)
    				{
    					if (P_getbits_UB(loadedgates, k - 1, 0, 3))
    						putchar(chryellow);
    					printf("%c%s%c%c", chrinverse, index_[k - 1], chrgreen, chrplain);
    				}
    			}
    			else
    			{
    				switch (k)
    				{
    
    					case -1:
    						/* blank case */
    						break;
    
    					case -2:
    						nk_gotoxy(49, txdown);
    						printf("%cquit%c.", chrinverse, chrplain);
    						break;
    
    					case -3:
    						nk_gotoxy(0, txdown);
    						printf("%c+%c", chrinverse, chrplain);
    						break;
    
    					case -4:
    						nk_gotoxy(18, txdown);
    						printf("%c-%c", chrinverse, chrplain);
    						break;
    				}
    			}
    
    			if (gg.t.near_ && gg.t.inalpha)
    				nk_gotoxy(gg.t.ax, gg.t.ay);
    			else
    				noblink();
    			
    			do
    			{
    				pass();
    				pen();
    			} while (!(pollkbd2() || gg.t.dn || k != kfunc(&ii, &jj, &V)));
    			
    			remcursor();
    			if (k > 0)
    			{
    				if (k < huge_)
    				{
    					if (lsp != NULL)
    					{
    						nk_gotoxy(0, txdown - 1);
    						putchar('\t');
    					}
    					nk_gotoxy(i * 10 + 2, j + 1);
    					if (P_getbits_UB(loadedgates, k - 1, 0, 3))
    						putchar(chryellow);
    					printf("%s%c", index_[k - 1], chrgreen);
    				}
    			}
    			else
    			{
    				switch (k)
    				{
    
    					case -1:
    						/* blank case */
    						break;
    
    					case -2:
    						nk_gotoxy(49, txdown);
    						printf("quit.");
    						break;
    
    					case -3:
    						nk_gotoxy(0, txdown);
    						putchar('+');
    						break;
    
    					case -4:
    						nk_gotoxy(18, txdown);
    						putchar('-');
    						break;
    				}
    			}
    		} while (!(pollkbd2() || gg.t.dn));
    		ch = '\0';
    		if (pollkbd2())
    			ch = inkey2();
    
    		if (gg.t.dn)
    		{
    			if (k >= huge_)
    			{
    				ch = '\003';
    			}
    			else if (k > 0)
    			{
    				if (readlibrary(index_[k - 1]) != 0)
    				{
    					remcursor();
    					nk_gotoxy(i * 10 + 2, j + 1);
    					printf("%c%s%c", chryellow, index_[k - 1], chrgreen);
    				}
    			}
    			else
    			{
    				switch (k)
    				{
    
    					case -1:
    					case -2:
    						ch = '\003';
    						break;
    
    					case -3:
    						ch = '+';
    						break;
    
    					case -4:
    						ch = '-';
    						break;
    				}
    			}
    		}
    		if (ch >= '0' && ch <= '8')
    		{
    			curlistgroup = ch - 48;
    		}
    		else if (ch == '\b' || ch == '-')
    		{
    			curlistgroup = (curlistgroup + 8) % 9;
    		}
    		else if (ch == '\034' || ch == '+')
    		{
    			curlistgroup = (curlistgroup + 1) % 9;
    		}
    		else if (ch == '\003' || ch == '\015' || ch == 'Q' || ch == 'q' ||
    				(ch & 255) == 171 || ch == ' ')
    		{
    			exitflag = true;
    		}
    	} while (!exitflag);
    	clearscreen();
    	m_graphics_on();
    	clearalpha();
    }
    
    #undef maxmaxi
    #undef maxmaxj
    #undef huge_
    
    
    /*=================  GATECATALOG  ================*/
    /*=                                              =*/
    /*=  Process CAT menu item.  Display catalog,    =*/
    /*=     call ADDGATE if a gate is touched.       =*/
    /*=                                              =*/
    /*================================================*/
    
    static void gatecatalog(int librmode)
    {
    	short x, y, x0, y0, x00, y00, w, x1, y1;
    	char nm[9];
    	/*  pic : m_picturevar;  */
    	uchar ch;
    	log_krec *k;
    	char bot1[256], bot2[256], bot3[256];
    	na_strlist_t *lp;
    	int flag, oo, done, botflag, refrflag;
    	long bottime;
    	librstrrec *lsp;
    
    	clearfunc();
    	done = false;
    	do
    	{
    		refrflag = false;
    		if (librmode)
    		{
    			if (ch >= '0' && ch <= '8')
    				curlistgroup = ch - 48;
    			listlibrary();
    			librmode = false;
    		}
    		else
    		{
    			showcatalog();
    			m_color((long)gg.color.selword);
    			drawstr2(10, down - 27, "LIBR");
    			drawstr2(across - 32, down - 27, "LIBR");
    			clearalpha();
    			pen();
    			do
    			{
    				ch = '\0';
    				x0 = gg.t.x / (gridcen * 2);
    				y0 = gg.t.y / (gridcen * 2);
    				*bot1 = '\0';
    				*bot2 = '\0';
    				*bot3 = '\0';
    				botflag = false;
    				if ((unsigned)x0 < catwidth && y0 >= 0 &&
    						y0 * catwidth + x0 < maxkinds &&
    						gg.t.near_ && kind[y0 * catwidth + x0] != NULL)
    				{
    					flag = true;
    					nm[8] = '\0';
    					k = kind[y0 * catwidth + x0];
    					strrtrim(strcpy(nm, k->name));
    					w = m_strwidth(logfont_lfont, nm);
    					x00 = (x0 * 2 + 1) * gridcen - w / 2;
    					y00 = (y0 + 1) * gridcen * 2 + 2;
    					remcursor();
    					/*  m_getcpicture(imax(x00-2,0), y00-2, x00+w+4, y00+10, pic);
    						m_color(gg.color.backgr);
    						m_fillrect(x00-2, y00-2, x00+w+4, y00+10);
    						m_color(gg.color.selword);
    						m_centerstr((x0*2+1)*gridcen, y00, logfont_lfont, nm);*/
    					m_colormode((long)m_xor);
    					m_color((long)gg.color.selword);
    					m_centerstr((x0 * 2L + 1) * gridcen, (long)y00, logfont_lfont, nm);
    					m_colormode((long)m_normal);
    					lp = k->lbl;
    					
    					while (lp != NULL && lp->kind != '\0')
    						lp = lp->next;
    
    					while (lp != NULL && *bot3 == '\0')
    					{
    						if (*bot1 == '\0')
    							strcpy(bot1, lp->s);
    						else if (*bot2 == '\0')
    							strcpy(bot2, lp->s);
    						else if (*bot3 == '\0')
    							strcpy(bot3, lp->s);
    						lp = lp->next;
    					}
    					
    					if (*bot1 == '\0')
    					{
    						lsp = findlibrstr(k->name);
    						if (lsp != NULL)
    							strcpy(bot1, lsp->str);
    					}
    					bottime = timers_sysclock();
    				}
    				else
    				{
    					flag = false;
    				}
    				
    				do
    				{
    					x = gg.t.x;
    					y = gg.t.y;
    					pass();
    					pen();
    					if (*bot1 != '\0' && !botflag)
    					{
    						if (labs(x - gg.t.x) > 10 || labs(y - gg.t.y) > 10)
    						{
    							bottime = timers_sysclock();
    						}
    						else if (timers_sysclock() > bottime + 10)
    						{
    							m_color((long)gg.color.selword);
    							m_centerstr(across / 2L, down - 27L, NULL, bot1);
    							if (*bot2 != '\0')
    								m_centerstr(across / 2L, down - 17L, NULL, bot2);
    							if (*bot3 != '\0')
    								m_centerstr(across / 2L, down - 7L, NULL, bot3);
    							botflag = true;
    						}
    					}
    					if (pollkbd2())
    						ch = inkey2();
    					x1 = gg.t.x / (gridcen * 2);
    					y1 = gg.t.y / (gridcen * 2);
    				} while (!gg.t.dn && gg.t.near_ && x0 == x1 && y0 == y1 && ch == '\0');
    				if (flag)
    				{
    					remcursor();
    					/*  m_putcpicture(imax(x00-2,0), y00-2, pic);
    						m_disposepicture(pic);  */
    					m_colormode((long)m_xor);
    					m_color((long)gg.color.selword);
    					m_centerstr((x0 * 2L + 1) * gridcen, (long)y00, logfont_lfont, nm);
    					m_colormode((long)m_normal);
    					m_color((long)gg.color.backgr);
    
    					if (botflag)
    					{
    						m_centerstr(across / 2L, down - 27L, NULL, bot1);
    						if (*bot2 != '\0')
    							m_centerstr(across / 2L, down - 17L, NULL, bot2);
    						if (*bot3 != '\0')
    							m_centerstr(across / 2L, down - 7L, NULL, bot3);
    					}
    				}
    
    				if (gg.t.dn)
    				{
    					if ((x < 40 || x >= across - 37) && y >= down - 32)
    						librmode = true;
    					else
    						done = true;
    				}
    				
    				if (ch == 251 || ch == 250 || ch == ' ')
    				{
    					refrflag = true;
    				}
    				else if (ch == '\003' || ch == 171 || ch == 'Q' || ch == 'q')
    				{
    					done = true;
    				}
    				else if ((ch >= '0' && ch <= '8') || ch == 'L' || ch == 'l')
    				{
    					librmode = true;
    				}
    				else if (ch == 'D' || ch == 'd')
    				{
    					if ((unsigned)x0 < catwidth && y0 >= 0 &&
    							y0 * catwidth + x0 < maxkinds &&
    							gg.t.near_ && kind[y0 * catwidth + x0] != NULL)
    						showgatedef(kind[y0 * catwidth + x0], NULL);
    				}
    			} while (!(done || librmode || refrflag));
    			oo = gg.t.off;
    			pen();
    			pen();
    			if (done && gg.t.depressed && !oo && !gg.t.off && flag)
    			{
    				refrscreen();
    				addgate(y0 * catwidth + x0 + 1, 0, NULL);
    			}
    		}
    	} while (!done);
    }
    
    
    /*==================  VLSIMODE  ==================*/
    /*=                                              =*/
    /*=  Turn VLSI mode on or off.                   =*/
    /*=                                              =*/
    /*================================================*/
    
    static void setvlsimode(int flag)
    {
    	if (flag)
    	{
    		beginerror();
    		printf("VLSI mode not supported in version %s\n", log_version);
    		enderror();
    		flag = false;
    	}
    
    	/*$if false$
    	  var
    	  i, j : log_shortint;
    	  begin
    	  remcursor;
    	  if flag and (ptrans = nil) then
    	  begin
    
    i := readlibrary('P');
    if i <> 0 then
    j := readlibrary('N');
    if (i = 0) or (j = 0) then
    flag := false
    else
    begin
    new(ptrans);
    ptrans^.g := i;
    ptrans^.info.proc := kind[ptrans^.g]^.proc;
    ptrans^.numpins := kind[ptrans^.g]^.numpins;
    for i := 1 to ptrans^.numpins do
    ptrans^.pin^[i] := nullnode;
    new(ntrans);
    ntrans^.g := j;
    ntrans^.info.proc := kind[ntrans^.g]^.proc;
    ntrans^.numpins := kind[ntrans^.g]^.numpins;
    for i := 1 to ntrans^.numpins do
    ntrans^.pin^[i] := nullnode;
    end;
    end;
    $end$*/
    
    	if (flag)
    		curwcolor = log_wcol_blue;
    	else
    		curwcolor = log_wcol_normal;
    	vlsi = flag;
    	vlsimode[gg.curpage - 1] = vlsi;
    }
    
    
    /*==================  REALSTR  ===================*/
    /*=                                              =*/
    /*=  Convert a real number to a string.          =*/
    /*=                                              =*/
    /*================================================*/
    
    static char *realstr(char *Result, double r, short p)
    {
    	long i, j;
    	char s[81];
    
    	s[80] = '\0';
    	if ((fabs(r) < 1e-2 || fabs(r) >= 1e6) && r != 0)
    	{
    		sprintf(s, "% .13E", r);
    		i = strlen(s) + 1;
    		s[i - 1] = '\0';
    		i = strposc(s, 'E', 1L) - 1;
    		j = strposc(s, '.', 1L);
    		while (s[i - 1] == '0' || (p != 0 && i > j + p))
    		{
    			strcpy_overlap(s + i - 1, s + i);
    			i--;
    		}
    		if (s[i - 1] == '.')
    		{
    			strcpy_overlap(s + i - 1, s + i);
    			i--;
    		}
    		while (strlen(s) > i + 3 && s[i + 2] == '0')
    			strcpy_overlap(s + i + 2, s + i + 3);
    		if (s[i + 1] == '+')
    			strcpy_overlap(s + i + 1, s + i + 2);
    		return strcpy(Result, strltrim(s));
    	}
    
    	if (p == 0)
    	{
    		sprintf(s, "%30.9f", r);
    		i = strlen(s) + 1;
    		do
    		{
    			i--;
    		} while (s[i - 1] == '0');
    		
    		if (s[i - 1] == '.')
    			i--;
    		s[i] = '\0';
    		return strcpy(Result, strltrim(s));
    	}
    	sprintf(s, "%25.*f", p, r);
    	i = strlen(s) + 1;
    	s[i - 1] = '\0';
    	/* zfprintf(stdout, "realstr:%lf p: %d s:  %s\n", r, p, s); **MDG** */
    	return strcpy(Result, strltrim(s));
    }
    
    
    /*=================  REALUNIT  ===================*/
    /*=                                              =*/
    /*=  Convert a unitted real number to a string.  =*/
    /*=                                              =*/
    /*================================================*/
    
    static char *realunit(char *Result, double r, short p, char *u, int mu)
    {
    	char s[81], STR1[81];
    	char STR2[162];
    
    	/* zfprintf(stdout, "Realunit r: %le\n ", r);  ***MDG** */
    	*s = '\0';
    	if (r == 0 || fabs(r) >= 1.0e15 || fabs(r) < 1.0e-16)
    	{
    		*s = '\0';
    	}
    	else if (fabs(r) >= 1e12)
    	{
    		strcpy(s, "T");
    		r /= 1e12;
    	}
    	else if (fabs(r) >= 1e9)
    	{
    		strcpy(s, "G");
    		r /= 1e9;
    	}
    	else if (fabs(r) >= 1e6)
    	{
    		strcpy(s, "Meg");
    		r /= 1e6;
    	}
    	else if (fabs(r) >= 1e3)
    	{
    		strcpy(s, "K");
    		r /= 1e3;
    	}
    	else if (fabs(r) >= 0.1)
    	{
    		*s = '\0';
    	}
    	else if (fabs(r) >= 1e-3)
    	{
    		strcpy(s, "m");
    		r *= 1e3;
    	}
    	else if (fabs(r) >= 1e-6)
    	{
    		strcpy(s, "u");
    		r *= 1e6;
    	}
    	else if (fabs(r) >= 1e-9)
    	{
    		strcpy(s, "n");
    		r *= 1e9;
    	}
    	else if (fabs(r) >= 1e-12)
    	{
    		strcpy(s, "p");
    		r *= 1e12;
    	}
    	else
    	{
    		strcpy(s, "f");
    		r *= 1e15;
    	}
    	
    	sprintf(s, "%s%s", realstr(STR1, r, p), strcpy(STR2, s));
    	sprintf(Result, "%s%s", s, u);
    	/* zfprintf(stdout, "realunit Result: %s\n", Result); ***MDG** */
    	return Result;
    }
    
    /* was static void, cause gcc problems in some releases */
    extern void prealunit(double r, short p, char *u, char *s)
    {
    	realunit(s, r, p, u, false);
    }
    
    /* was static void, cause gcc problems in some releases */
    extern void prealunit2(double r, short p, char *u, char *s)
    {
    	realunit(s, r, p, u, true);
    }
    
    
    /* Local variables for editattrs: */
    struct LOC_editattrs {
    	log_gattrrec *gattr;
    	short numattrs;
    	log_kattrrec *kattr;
    	na_strlist_t *lbl;
    	char name[256];
    	void (*chproc) ();
    	log_tool *tool;
    	log_grec *gate;
    	log_nrec *node;
    	short acty, p, ybase;
    } ;
    
    static void drawlabelline(long i, struct LOC_editattrs *LINK)
    {
    	long j;
    	na_strlist_t *l1;
    	long FORLIM;
    
    	l1 = LINK->lbl;
    	while (l1 != NULL && l1->kind != '\0')
    		l1 = l1->next;
    	FORLIM = i + LINK->ybase;
    	for (j = 1; j <= FORLIM; j++)
    	{
    		if (l1 != NULL)
    			l1 = l1->next;
    	}
    	
    	if (l1 != NULL)
    		nc_putStr(0, (int)i, l1->s);
    }
    
    static void eraselabelline(longi, struct LOC_editattrs *LINK)
    {
    	remcursor();
    	nk_gotoxy(0, (int)i);
    	putchar('\t');
    }
    
    static void drawlabel(struct LOC_editattrs *LINK)
    {
    	short i, FORLIM;
    
    	remcursor();
    	nc_putStr(txacross - strlen(LINK->name), 0, LINK->name);
    	FORLIM = txdown;
    	for (i = 0; i <= FORLIM; i++)
    		drawlabelline((long)i, LINK);
    }
    
    static void drawvalue(short i, int highlight, struct LOC_editattrs *LINK)
    {
    	na_strlist_t *l1;
    	log_kattrrec *WITH;
    	char STR1[81];
    	char STR4[256];
    
    	WITH = &LINK->kattr[i - 1];
    	if (WITH->y < LINK->ybase || WITH->y > LINK->ybase + txdown)
    		return;
    	remcursor();
    	nk_gotoxy(WITH->x, WITH->y - LINK->ybase);
    	if (highlight)
    		putchar(129);
    	 * Note: WRITE statement contains color/attribute characters [203] */
    	if (!LINK->gattr[i - 1].blnk)
    	{
    		switch (WITH->dtype)
    		{
    
    			case 'R':
    				fputs(realstr(STR1, LINK->gattr[i - 1].UU.r, WITH->prec), stdout);
    				break;
    
    			case 'U':
    				fputs(realunit(STR1, LINK->gattr[i - 1].UU.r, WITH->prec,
    							WITH->UU.U82.u, false), stdout);
    				break;
    
    			case 'F':
    				printf("%s%s",
    						realstr(STR1, LINK->gattr[i - 1].UU.r, WITH->prec),
    						WITH->UU.U82.u);
    				break;
    
    			case 'I':
    				printf("%*ld", WITH->prec, LINK->gattr[i - 1].UU.U73.i1);
    				break;
    
    			case 'H':
    				fputs(strhex(STR4, LINK->gattr[i - 1].UU.U73.i1, (long)WITH->prec),
    						stdout);
    				break;
    
    			case 'C':
    				printf("%.*s", txacross - WITH->x + 1, LINK->gattr[i - 1].UU.c);
    				break;
    
    			case 'A':
    				printf("%.*s", txacross - WITH->x + 1, LINK->gattr[i - 1].UU.sp);
    				break;
    
    			case 'B':
    				if (WITH->prec == 1)
    				{
    					if (LINK->gattr[i - 1].UU.b)
    						printf("Yes");
    					else
    						printf("No");
    				}
    				else
    				{
    					if (LINK->gattr[i - 1].UU.b)
    						printf("True");
    					else
    						printf("False");
    				}
    				break;
    
    			case 'V':
    				l1 = WITH->UU.U86.v;
    				while (l1 != NULL && (long)l1->value != LINK->gattr[i - 1].UU.nv)
    					l1 = l1->next;
    				if (l1 != NULL)
    					fputs(l1->s, stdout);
    				else
    					printf("(value not found)");
    				break;
    		}
    	}
    	if (WITH->x == XPOS)
    		putchar(' ');
    	LINK->gattr[i - 1].x2 = XPOS - 1;   /*from CRT*/
    	/*prob. no longer used*/
    	printf("\t\200");
    	LINK->gattr[i - 1].changed = false;
    }
    
    static void maskvalues(struct LOC_editattrs *LINK)
    {
    	short i, FORLIM;
    
    	FORLIM = LINK->numattrs;
    	for (i = 0; i < FORLIM; i++)
    	{
    		if (LINK->kattr[i].vra != 0 &&
    				LINK->kattr[i].vr != LINK->gattr[LINK->kattr[i].vra - 1].UU.nv)
    		{
    			if (!LINK->gattr[i].supr)
    				eraselabelline((long)LINK->kattr[i].y, LINK);
    			LINK->gattr[i].supr = true;
    		}
    		else
    		{
    			if (LINK->gattr[i].supr)
    			{
    				drawlabelline((long)LINK->kattr[i].y, LINK);
    				drawvalue(i + 1, false, LINK);
    			}
    			LINK->gattr[i].supr = false;
    		}
    	}
    }
    
    static double cleanup(double r, double r1, struct LOC_editattrs *LINK)
    {
    	long i;
    	char s[81];
    	char *STR1;
    
    	if (fabs(r) * 2 < r1)
    	{
    		return 0.0;
    	}
    	else if (fabs(r) < 1e9 && r >= 1e-5)
    	{
    		sprintf(s, "%20.0f", r / r1);
    		i = strlen(s) + 1;
    		s[i - 1] = '\0';
    		r = strtod(s, &STR1);
    		i = STR1 - s + 1;
    		return (r * r1);
    	}
    	else
    	{
    		return r;
    	}
    }
    
    static double scrnincr(short p, struct LOC_editattrs *LINK)
    {
    	long i;
    	double r1;
    	char s[81];
    	log_kattrrec *WITH;
    
    	WITH = &LINK->kattr[p - 1];
    	switch (WITH->dtype)
    	{
    
    		case 'R':
    			realstr(s, LINK->gattr[p - 1].UU.r, WITH->prec);
    			break;
    
    		case 'U':
    			realunit(s, LINK->gattr[p - 1].UU.r, WITH->prec, "", false);
    			break;
    
    		case 'F':
    			realstr(s, LINK->gattr[p - 1].UU.r, WITH->prec);
    			break;
    	}
    	strcat(s, " ");
    	i = 0;
    	do
    	{
    		i++;
    		if (s[i - 1] == '-')
    			s[i - 1] = '+';
    		else if (isdigit(s[i - 1]))
    			s[i - 1] = '0';
    	} while (s[i - 1] == '.' || s[i - 1] == '+' || s[i - 1] == '0');
    	
    	if (i > 1)
    		s[i - 2] = '1';
    	r1 = 0.0;
    	readreal(s, &r1);
    	return r1;
    }
    
    static void callconfig(void (*proc) (), struct LOC_editattrs *LINK)
    {
    	gg.actx = LINK->p;
    	gg.acty = LINK->acty;
    	gg.acttool = LINK->tool;
    	gg.actgate = LINK->gate;
    	gg.actnode = LINK->node;
    	gg.actgattr = LINK->gattr;
    	gg.actkattr = LINK->kattr;
    	(*proc)();
    }
    
    static int tryconfig(struct LOC_editattrs *LINK)
    {
    	gg.actflag = true;
    	callconfig(LINK->chproc, LINK);
    	return (gg.actflag);
    }
    
    
    static void editattrs(log_gattrrec *gattr_, short numattrs_, log_kattrrec *kattr_, na_strlist_t *lbl_, char *name_,
    		void (*proc) (), void (*chproc_) (), void (*relproc) (), long *attrstamp)
    {
    	struct LOC_editattrs V;
    	short i, i1, p0, olday, ytotal;
    	na_strlist_t *l1;
    	long j, j1, savei;
    	double r1, saver;
    	char ch;
    	char buf[256], savebuf[256];
    	int exitflag, saveb, saveb2, touched, understood;
    	short FORLIM;
    	log_gattrrec *WITH;
    	char STR1[256];
    	char *STR2;
    	char STR3[256];
    
    	V.gattr = gattr_;
    	V.numattrs = numattrs_;
    	V.kattr = kattr_;
    	V.lbl = lbl_;
    	strcpy(V.name, name_);
    	V.chproc = chproc_;
    	if (V.lbl == NULL)
    		return;
    	V.tool = gg.acttool;
    	V.gate = gg.actgate;
    	V.node = gg.actnode;
    	V.acty = gg.acty;
    	clearshowalpha();
    	V.ybase = 0;
    	ytotal = 0;
    	l1 = V.lbl;
    	while (l1 != NULL)
    	{
    		if (l1->kind == '\0')
    			ytotal++;
    		l1 = l1->next;
    	}
    	drawlabel(&V);
    	gg.actflag = true;
    	callconfig(proc, &V);
    	FORLIM = V.numattrs;
    	for (i = 0; i < FORLIM; i++)
    	{
    		WITH = &V.gattr[i];
    		touched = false;
    		WITH->supr = false;
    	}
    	maskvalues(&V);
    	FORLIM = V.numattrs;
    	for (i = 1; i <= FORLIM; i++)
    	{
    		if (!V.gattr[i - 1].supr)
    			drawvalue(i, false, &V);
    	}
    	showalpha();
    	if (V.numattrs == 0)
    	{
    		do
    		{
    			noblink();
    			do
    			{
    				pass();
    				pen();
    			} while (!(pollkbd2() || gg.t.dn));
    			
    			if (pollkbd2())
    				ch = inkey2();
    			else
    				ch = '\015';
    		} while (ch != '\003' && ch != '\015' && ch != ' ');
    	}
    	else
    	{
    		V.p = 1;
    		olday = -1;
    		exitflag = false;
    		do
    		{
    			noblink();
    			if (V.kattr[V.p - 1].y <= V.ybase ||
    					V.kattr[V.p - 1].y >= V.ybase + txdown)
    			{
    				i1 = V.ybase;
    				if (V.kattr[V.p - 1].y <= V.ybase)
    				{
    					V.ybase = V.kattr[V.p - 1].y - 1;
    					if (V.p == 1)
    						V.ybase = P_imax2(0L, (long)(V.kattr[V.p - 1].y - txdown));
    				}
    				else
    				{
    					V.ybase = V.kattr[V.p - 1].y - txdown + 1;
    					if (V.p == V.numattrs)
    						V.ybase = P_imin2(ytotal - txdown - 1L, (long)V.kattr[V.p - 1].y);
    				}
    				
    				if (abs(V.ybase - i1) < txdown)
    					nc_scrollXY(0, V.ybase - i1);
    				else
    					clearshowalpha();
    				
    				drawlabel(&V);
    				FORLIM = V.numattrs;
    				for (i = 0; i < FORLIM; i++)
    					V.gattr[i].supr = false;
    				
    				maskvalues(&V);
    				FORLIM = V.numattrs;
    				for (i = 1; i <= FORLIM; i++)
    				{
    					if (!V.gattr[i - 1].supr)
    						drawvalue(i, i == V.p, &V);
    				}
    			}
    			else
    			{
    				drawvalue(V.p, true, &V);
    			}
    
    			do
    			{
    				ch = '\0';
    				pass();
    				gg.actflag = false;
    				callconfig(proc, &V);
    				FORLIM = V.numattrs;
    				for (i = 1; i <= FORLIM; i++)
    				{
    					if (V.gattr[i - 1].changed)
    					{
    						stamp(attrstamp);
    						if (!V.gattr[i - 1].supr)
    						{
    							drawvalue(i, i == V.p, &V);
    
    							if (V.kattr[i - 1].dtype == 'V')
    								maskvalues(&V);
    							
    							if (V.gattr[V.p - 1].supr)
    								ch = '\037';
    							noblink();
    						}
    					}
    				}
    				pen();
    				/*  if gg.t.near and (gg.t.ay <> olday) then
    					begin
    i := 1;
    while (i <= numattrs) and (kattr^[i].y <> gg.t.ay) do
    i := i + 1;
    if (i <= numattrs) and (not gattr^[i].supr) then
    if i < p then
    ch := #31
    else if i > p then
    ch := #10;
    end;  */
    				if (pollkbd2())
    					ch = inkey2();
    			} while (!(ch != '\0' || gg.t.dn));
    			drawvalue(V.p, false, &V);
    			
    			if (gg.t.dn)
    				ch = '\003';
    			p0 = V.p;
    			understood = true;
    			WITH = &V.gattr[V.p - 1];
    			
    			if (ch == '\003' || ch == ' ')
    			{
    				exitflag = true;
    			}
    			else if ((ch & 255) != 251 && (ch & 255) != 250)
    			{
    				if (ch == '\n')
    				{
    					do
    					{
    						V.p++;
    					} while (V.p <= V.numattrs && V.gattr[V.p - 1].supr);
    					
    					if (V.p > V.numattrs)
    						V.p = p0;
    				}
    				else if (ch == '\037')
    				{
    					do
    					{
    						V.p--;
    					} while (V.p >= 1 && V.gattr[V.p - 1].supr);
    					
    					if (V.p < 1)   /*should never happen!*/
    						V.p = p0;
    				}
    				else if (ch == '\034')
    				{
    					gg.actflag = false;
    					gg.actflag2 = true;
    					callconfig(relproc, &V);
    
    					if (!gg.actflag)
    					{
    						switch (V.kattr[V.p - 1].dtype)
    						{
    
    							case 'R':
    							case 'U':
    							case 'F':
    								if (!WITH->blnk)
    								{
    									r1 = scrnincr(V.p, &V);
    									saver = WITH->UU.r;
    									WITH->UU.r = cleanup(WITH->UU.r + r1, r1, &V);
    									if (tryconfig(&V))
    									{
    										drawvalue(V.p, false, &V);
    										touched = true;
    									}
    									else
    									{
    										WITH->UU.r = saver;
    									}
    								}
    								break;
    
    							case 'I':
    							case 'H':
    								if (!WITH->blnk)
    								{
    									WITH->UU.U73.i1++;
    									if (tryconfig(&V))
    									{
    										drawvalue(V.p, false, &V);
    										touched = true;
    									}
    									else
    									{
    										WITH->UU.U73.i1--;
    									}
    								}
    								break;
    
    							case 'C':
    							case 'A':
    								understood = false;
    								break;
    
    							case 'B':
    								saveb = WITH->UU.b;
    								saveb2 = WITH->blnk;
    								WITH->UU.b = true;
    								WITH->blnk = false;
    								
    								if (!tryconfig(&V))
    								{
    									WITH->UU.b = saveb;
    									WITH->blnk = saveb2;
    								}
    								
    								if (WITH->UU.b != saveb || WITH->blnk != saveb2)
    								{
    									drawvalue(V.p, false, &V);
    									touched = true;
    								}
    								break;
    
    							case 'V':
    								savei = WITH->UU.nv;
    								if (WITH->UU.nv < V.kattr[V.p - 1].UU.U86.nv - 1)
    									WITH->UU.nv++;
    								
    								if (!tryconfig(&V))
    									WITH->UU.nv = savei;
    								
    								if (WITH->UU.nv != savei)
    								{
    									maskvalues(&V);
    									drawvalue(V.p, false, &V);
    									touched = true;
    								}
    								break;
    						}
    					}
    					stamp(attrstamp);
    					chpage((int)gg.curpage);
    				}
    				else if (ch == '\b')
    				{
    					gg.actflag = false;
    					gg.actflag2 = false;
    					callconfig(relproc, &V);
    					if (!gg.actflag)
    					{
    						switch (V.kattr[V.p - 1].dtype)
    						{
    
    							case 'R':
    							case 'U':
    							case 'F':
    								if (!WITH->blnk)
    								{
    									r1 = scrnincr(V.p, &V);
    									saver = WITH->UU.r;
    									WITH->UU.r = cleanup(WITH->UU.r - r1, r1, &V);
    									if (tryconfig(&V))
    									{
    										drawvalue(V.p, false, &V);
    										touched = true;
    									}
    									else
    									{
    										WITH->UU.r = saver;
    									}
    								}
    								break;
    
    							case 'I':
    							case 'H':
    								if (!WITH->blnk)
    								{
    									WITH->UU.U73.i1--;
    									if (tryconfig(&V))
    									{
    										drawvalue(V.p, false, &V);
    										touched = true;
    									}
    									else
    									{
    										WITH->UU.U73.i1++;
    									}
    								}
    								break;
    
    							case 'C':
    							case 'A':
    								understood = false;
    								break;
    
    							case 'B':
    								saveb = WITH->UU.b;
    								saveb2 = WITH->blnk;
    								WITH->UU.b = false;
    								WITH->blnk = false;
    								if (!tryconfig(&V))
    								{
    									WITH->UU.b = saveb;
    									WITH->blnk = saveb2;
    								}
    								
    								if (WITH->UU.b != saveb || WITH->blnk != saveb2)
    								{
    									drawvalue(V.p, false, &V);
    									touched = true;
    								}
    								break;
    
    							case 'V':
    								savei = WITH->UU.nv;
    								if (WITH->UU.nv > 0)
    									WITH->UU.nv--;
    								
    								if (!tryconfig(&V))
    									WITH->UU.nv = savei;
    								
    								if (WITH->UU.nv != savei)
    								{
    									maskvalues(&V);
    									drawvalue(V.p, false, &V);
    									touched = true;
    								}
    								break;
    						}
    					}
    					stamp(attrstamp);
    					chpage((int)gg.curpage);
    				}
    				else
    				{
    					understood = false;
    				}
    			}
    
    			if (!understood)
    			{
    				nk_gotoxy(V.kattr[V.p - 1].x, V.kattr[V.p - 1].y - V.ybase);
    				putchar('\t');
    
    				if (ch == '\015')
    					ungetkey2('\003');
    				else
    					ungetkey2(ch);
    
    				switch (V.kattr[V.p - 1].dtype)
    				{
    
    					case 'R':
    					case 'U':
    					case 'F':
    						readlnpass(buf, 2);
    						strcpy(STR1, strltrim(buf));
    						strcpy(buf, STR1);
    						saveb2 = touched;
    						saveb = WITH->blnk;
    						saver = WITH->UU.r;
    						if (*buf == '\0' ||
    								!(buf[0] == '-' || buf[0] == '+' || buf[0] == '.' ||
    									isdigit(buf[0])))
    						{
    							if (V.kattr[V.p - 1].opt)
    							{
    								WITH->blnk = true;
    							}
    							else
    							{
    								WITH->blnk = false;
    								WITH->UU.r = V.kattr[V.p - 1].UU.U82.r;
    							}
    							touched = true;
    						}
    						else
    						{
    							TRY(try16);
    							readreal(buf, &r1);
    							WITH->UU.r = r1;
    							WITH->blnk = false;
    							touched = true;
    							RECOVER(try16);
    							if (P_escapecode == -20)
    								_Escape(P_escapecode);
    							warning();
    							ENDTRY(try16);
    						}
    						
    						if (!tryconfig(&V))
    						{
    							WITH->UU.r = saver;
    							WITH->blnk = saveb;
    							touched = saveb2;
    						}
    						break;
    
    					case 'I':
    						readlnpass(buf, 2);
    						strcpy(STR1, strltrim(buf));
    						strcpy(buf, STR1);
    						saveb2 = touched;
    						saveb = WITH->blnk;
    						savei = WITH->UU.U73.i1;
    						if (*buf == '\0' ||
    								!(buf[0] == '+' || buf[0] == '-' || isdigit(buf[0])))
    						{
    							if (V.kattr[V.p - 1].opt)
    							{
    								WITH->blnk = true;
    							}
    							else
    							{
    								WITH->blnk = false;
    								WITH->UU.U73.i1 = V.kattr[V.p - 1].UU.U73.i1;
    							}
    							touched = true;
    						}
    						else
    						{
    							TRY(try17);
    							j1 = strtol(buf, &STR2, 10);
    							j = STR2 - buf + 1;
    							WITH->UU.U73.i1 = j1;
    							WITH->blnk = false;
    							touched = true;
    							RECOVER(try17);
    							if (P_escapecode == -20)
    								_Escape(P_escapecode);
    							warning();
    							ENDTRY(try17);
    						}
    
    						if (!tryconfig(&V))
    						{
    							WITH->UU.U73.i1 = savei;
    							WITH->blnk = saveb;
    							touched = saveb2;
    						}
    						break;
    
    					case 'H':
    						readlnpass(buf, 2);
    						strcpy(STR1, strltrim(buf));
    						strcpy(buf, STR1);
    						saveb2 = touched;
    						saveb = WITH->blnk;
    						savei = WITH->UU.U73.i1;
    						if (*buf == '\0' ||
    								!((buf[0] >= 'a' && buf[0] <= 'f') ||
    									(buf[0] >= 'A' && buf[0] <= 'F') || isdigit(buf[0])))
    						{
    							if (V.kattr[V.p - 1].opt)
    							{
    								WITH->blnk = true;
    							}
    							else
    							{
    								WITH->blnk = false;
    								WITH->UU.U73.i1 = V.kattr[V.p - 1].UU.U73.i1;
    							}
    							touched = true;
    						}
    						else
    						{
    							TRY(try18);
    							WITH->UU.U73.i1 = strtol(buf, NULL, 16);
    							WITH->blnk = false;
    							touched = true;
    							RECOVER(try18);
    							if (P_escapecode == -20)
    								_Escape(P_escapecode);
    							warning();
    							ENDTRY(try18);
    						}
    						
    						if (!tryconfig(&V))
    						{
    							WITH->UU.U73.i1 = savei;
    							WITH->blnk = saveb;
    							touched = saveb2;
    						}
    						break;
    
    					case 'C':
    						strcpy(buf, WITH->UU.c);
    						readlnpass(buf, 3);
    						strcpy(savebuf, WITH->UU.c);
    						strcpy(STR1, strltrim(strrtrim(strcpy(STR3, buf))));
    						strcpy(buf, STR1);
    						if (*buf == '\0' && !V.kattr[V.p - 1].opt)
    						{
    							strcpy(buf, V.kattr[V.p - 1].UU.c);
    						}
    						else if (strlen(buf) > V.kattr[V.p - 1].prec)
    						{
    							buf[V.kattr[V.p - 1].prec] = '\0';
    						}
    						strcpy(WITH->UU.c, buf);
    						if (tryconfig(&V))
    							touched = true;
    						else
    							strcpy(WITH->UU.c, savebuf);
    						WITH->blnk = (*WITH->UU.c == '\0');
    						break;
    
    					case 'A':
    						strcpy(buf, WITH->UU.c);
    						readlnpass(buf, 3);
    						strcpy(savebuf, WITH->UU.sp);
    						strcpy(STR1, strltrim(strrtrim(strcpy(STR3, buf))));
    						strcpy(buf, STR1);
    						if (*buf == '\0' && !V.kattr[V.p - 1].opt)
    							strcpy(buf, V.kattr[V.p - 1].UU.sp);
    						strchange(&WITH->UU.sp, buf);
    						if (tryconfig(&V))
    							touched = true;
    						else
    							strchange(&WITH->UU.sp, savebuf);
    						WITH->blnk = (*WITH->UU.sp == '\0');
    						break;
    
    					case 'B':
    						saveb = WITH->blnk;
    						saveb2 = WITH->UU.b;
    						ch = inkey2();
    						if (ch == '1' || ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T')
    						{
    							WITH->UU.b = true;
    							WITH->blnk = false;
    						}
    						else if (ch == '0' || ch == 'n' || ch == 'N' || ch == 'f' || ch == 'F')
    						{
    							WITH->UU.b = false;
    							WITH->blnk = false;
    						}
    						else if ((ch == '\003' || ch == '\015' || ch == 'x' || ch == 'X') && V.kattr[V.p - 1].opt)
    						{
    							WITH->blnk = true;
    						}
    						else if (ch == '\003' || ch == '\015' || ch == 'z' || ch == 'Z')
    						{
    							WITH->UU.b = !WITH->UU.b;
    							WITH->blnk = false;
    						}
    
    						if (tryconfig(&V))
    						{
    							touched = true;
    						}
    						else
    						{
    							WITH->blnk = saveb;
    							WITH->UU.b = saveb2;
    						}
    						break;
    
    					case 'V':
    						readlnpass(buf, 2);
    						savei = WITH->UU.nv;
    						strcpy(STR1, strltrim(strrtrim(strcpy(STR3, buf))));
    						strcpy(buf, STR1);
    						l1 = V.kattr[V.p - 1].UU.U86.v;
    						while (l1 != NULL && strcicmp(l1->s, buf) != 0)
    							l1 = l1->next;
    						
    						if (l1 != NULL)
    							WITH->UU.nv = (long)l1->value;
    						
    						if (tryconfig(&V))
    						{
    							maskvalues(&V);
    							touched = true;
    						}
    						else
    						{
    							WITH->UU.nv = savei;
    						}
    						break;
    				}
    				stamp(attrstamp);
    				chpage((int)gg.curpage);
    				drawvalue(V.p, false, &V);
    			}
    		} while (!exitflag);
    	}
    	m_graphics_on();
    	clearalpha();
    
    	/*ignore*/
    }
    
    
    static void editattrsx(log_fattrrec *gattr, short numattrs, log_kattrrec *kattr, na_strlist *lbl, char *name,
    		void (*proc) (), void (*chproc) (), void (*relproc())
    {
    	long stamp;
    
    	editattrs(gattr, numattrs, kattr, lbl, name, proc, chproc, relproc, &stamp);
    }
    
    
    static void gproc1()
    {
    	calltool(gg.acttool, act_configgate);
    }
    
    
    static void gproc2()
    {
    	calltool(gg.acttool, act_configchgate);
    }
    
    
    static void gproc3()
    {
    	calltool(gg.acttool, act_configrelgate);
    }
    
    
    static void configgate(log_grec *g)
    {
    	void (*TEMP) ();
    	void (*TEMP5) ();
    	void (*TEMP6) ();
    
    	gg.actgate = g;
    	gg.acttool = g->kind->simtype;
    	TEMP = gproc1;
    	TEMP5 = gproc2;
    	TEMP6 = gproc3;
    	editattrs(g->attr, g->kind->numattrs, g->kind->attr, g->kind->lbl,
    			g->kind->name, TEMP, TEMP5, TEMP6, &gg.gattrstamp);
    }
    
    
    static void nproc1()
    {
    	calltool(gg.acttool, act_confignode);
    }
    
    
    static void nproc2()
    {
    	calltool(gg.acttool, act_configchnode);
    }
    
    
    static void nproc3()
    {
    	calltool(gg.acttool, act_configrelnode);
    }
    
    
    static void confignode(log_nrec *n, char *name)
    {
    	void (*TEMP) ();
    	void (*TEMP5) ();
    	void (*TEMP6) ();
    
    	gg.actnode = n;
    	gg.acttool = n->simtype;
    	TEMP = nproc1;
    	TEMP5 = nproc2;
    	TEMP6 = nproc3;
    	editattrs(n->attr, n->simtype->nnumattrs, n->simtype->nattr,
    			n->simtype->nlbl, name, TEMP, TEMP5, TEMP6, &gg.nattrstamp);
    }
    
    
    static void configkind(short i)
    {
    	log_krec *k;
    	log_grec *g;
    
    	if (kindgroup[i - 1] == 0)
    		return;
    	k = kind[(kindgroup[i - 1] & (log_kindoffset - 1)) - 1];
    	newgate(&g, kindgroup[i - 1]);
    	if (kindattr[i - 1] != NULL)
    	{
    		disposeattrs(&g->attr, k->numattrs, k->attr);
    		copyattrs(&g->attr, kindattr[i - 1], k->numattrs, k->attr);
    	}
    	configgate(g);
    	if (kindattr[i - 1] != NULL)
    		disposeattrs(&kindattr[i - 1], k->numattrs, k->attr);
    	copyattrs(&kindattr[i - 1], g->attr, k->numattrs, k->attr);
    	disposegate(&g);
    }
    
    
    /* Local variables for setattr: */
    struct LOC_setattr {
    	log_gattrrec *gattr;
    	log_kattrrec *kattr;
    	short p;
    } ;
    
    static int tryconfig_(struct LOC_setattr *LINK)
    {
    	gg.actflag = true;
    	gg.actx = LINK->p;
    	gg.actgattr = LINK->gattr;
    	gg.actkattr = LINK->kattr;
    	(*gg.acttool->proc)(&gg);
    	return (gg.actflag);
    }
    
    static int setattr(log_gattrrec *gattr_, log_kattrrec *kattr_, short p_, char *buf)
    {
    	struct LOC_setattr V;
    	int touched;
    	long savei;
    	double r1, saver;
    	int saveb, saveb2;
    	char savebuf[256];
    	long j, j1;
    	na_strlist_t *l1;
    	log_gattrrec *WITH;
    	char STR1[256];
    	char *STR2;
    	char STR3[256];
    
    	V.gattr = gattr_;
    	V.kattr = kattr_;
    	V.p = p_;
    	touched = false;
    	WITH = &V.gattr[V.p - 1];
    	switch (V.kattr[V.p - 1].dtype)
    	{
    
    		case 'R':
    		case 'U':
    		case 'F':
    			strcpy(STR1, strltrim(buf));
    			strcpy(buf, STR1);
    			saveb2 = touched;
    			saveb = WITH->blnk;
    			saver = WITH->UU.r;
    			if (*buf == '\0' || !(buf[0] == '-' || buf[0] == '+' || buf[0] == '.' || isdigit(buf[0])))
    			{
    				if (V.kattr[V.p - 1].opt)
    				{
    					WITH->blnk = true;
    				}
    				else
    				{
    					WITH->blnk = false;
    					WITH->UU.r = V.kattr[V.p - 1].UU.U82.r;
    				}
    				touched = true;
    			}
    			else
    			{
    				TRY(try19);
    				readreal(buf, &r1);
    				WITH->UU.r = r1;
    				WITH->blnk = false;
    				touched = true;
    				RECOVER(try19);
    				if (P_escapecode == -20)
    					_Escape(P_escapecode);
    				ENDTRY(try19);
    			}
    			
    			if (!tryconfig_(&V))
    			{
    				WITH->UU.r = saver;
    				WITH->blnk = saveb;
    				touched = saveb2;
    			}
    			break;
    
    		case 'I':
    			strcpy(STR1, strltrim(buf));
    			strcpy(buf, STR1);
    			saveb2 = touched;
    			saveb = WITH->blnk;
    			savei = WITH->UU.U73.i1;
    			if (*buf == '\0' || !(buf[0] == '+' || buf[0] == '-' || isdigit(buf[0])))
    			{
    				if (V.kattr[V.p - 1].opt)
    				{
    					WITH->blnk = true;
    				}
    				else
    				{
    					WITH->blnk = false;
    					WITH->UU.U73.i1 = V.kattr[V.p - 1].UU.U73.i1;
    				}
    				touched = true;
    			}
    			else
    			{
    				TRY(try20);
    				j1 = strtol(buf, &STR2, 10);
    				j = STR2 - buf + 1;
    				WITH->UU.U73.i1 = j1;
    				WITH->blnk = false;
    				touched = true;
    				RECOVER(try20);
    				if (P_escapecode == -20)
    					_Escape(P_escapecode);
    				ENDTRY(try20);
    			}
    			
    			if (!tryconfig_(&V))
    			{
    				WITH->UU.U73.i1 = savei;
    				WITH->blnk = saveb;
    				touched = saveb2;
    			}
    			break;
    
    		case 'H':
    			strcpy(STR1, strltrim(buf));
    			strcpy(buf, STR1);
    			saveb2 = touched;
    			saveb = WITH->blnk;
    			savei = WITH->UU.U73.i1;
    			if (*buf == '\0' ||
    					!((buf[0] >= 'a' && buf[0] <= 'f') || (buf[0] >= 'A' && buf[0] <= 'F') ||
    						isdigit(buf[0])))
    			{
    				if (V.kattr[V.p - 1].opt)
    				{
    					WITH->blnk = true;
    				}
    				else
    				{
    					WITH->blnk = false;
    					WITH->UU.U73.i1 = V.kattr[V.p - 1].UU.U73.i1;
    				}
    				touched = true;
    			}
    			else
    			{
    				TRY(try21);
    				WITH->UU.U73.i1 = strtol(buf, NULL, 16);
    				WITH->blnk = false;
    				touched = true;
    				RECOVER(try21);
    				if (P_escapecode == -20)
    					_Escape(P_escapecode);
    				ENDTRY(try21);
    			}
    			
    			if (!tryconfig_(&V))
    			{
    				WITH->UU.U73.i1 = savei;
    				WITH->blnk = saveb;
    				touched = saveb2;
    			}
    			break;
    
    		case 'C':
    			strcpy(savebuf, WITH->UU.c);
    			strcpy(STR1, strltrim(strrtrim(strcpy(STR3, buf))));
    			strcpy(buf, STR1);
    			if (*buf == '\0' && !V.kattr[V.p - 1].opt)
    			{
    				strcpy(buf, V.kattr[V.p - 1].UU.c);
    			}
    			else if (strlen(buf) > V.kattr[V.p - 1].prec)
    			{
    				buf[V.kattr[V.p - 1].prec] = '\0';
    			}
    			strcpy(WITH->UU.c, buf);
    
    			if (tryconfig_(&V))
    				touched = true;
    			else
    				strcpy(WITH->UU.c, savebuf);
    			WITH->blnk = (*WITH->UU.c == '\0');
    			break;
    
    		case 'A':
    			strcpy(savebuf, WITH->UU.sp);
    			strcpy(STR1, strltrim(strrtrim(strcpy(STR3, buf))));
    			strcpy(buf, STR1);
    			if (*buf == '\0' && !V.kattr[V.p - 1].opt)
    				strcpy(buf, V.kattr[V.p - 1].UU.sp);
    			strchange(&WITH->UU.sp, buf);
    			if (tryconfig_(&V))
    				touched = true;
    			else
    				strchange(&WITH->UU.sp, savebuf);
    			WITH->blnk = (*WITH->UU.sp == '\0');
    			break;
    
    		case 'B':
    			saveb = WITH->blnk;
    			saveb2 = WITH->UU.b;
    			if (*buf == '\0')
    				strcpy(buf, " ");
    			if (buf[0] == '1' || buf[0] == 'y' || buf[0] == 'Y' || buf[0] == 't' || buf[0] == 'T')
    			{
    				WITH->UU.b = true;
    				WITH->blnk = false;
    			}
    			else if (buf[0] == '0' || buf[0] == 'n' || buf[0] == 'N' || buf[0] == 'f' || buf[0] == 'F')
    			{
    				WITH->UU.b = false;
    				WITH->blnk = false;
    			}
    			else if ((buf[0] == 'x' || buf[0] == 'X' || buf[0] == ' ') && V.kattr[V.p - 1].opt)
    			{
    				WITH->blnk = true;
    			}
    			else if (buf[0] == 'z' || buf[0] == 'Z' || buf[0] == ' ')
    			{
    				WITH->UU.b = !WITH->UU.b;
    				WITH->blnk = false;
    			}
    			
    			if (tryconfig_(&V))
    			{
    				touched = true;
    			}
    			else
    			{
    				WITH->blnk = saveb;
    				WITH->UU.b = saveb2;
    			}
    			break;
    
    		case 'V':
    			savei = WITH->UU.nv;
    			strcpy(STR1, strltrim(strrtrim(strcpy(STR3, buf))));
    			strcpy(buf, STR1);
    			l1 = V.kattr[V.p - 1].UU.U86.v;
    			while (l1 != NULL && strcicmp(l1->s, buf) != 0)
    				l1 = l1->next;
    
    			if (l1 != NULL)
    				WITH->UU.nv = (long)l1->value;
    
    			if (tryconfig_(&V))
    				touched = true;
    			else
    				WITH->UU.nv = savei;
    			break;
    	}
    	return touched;
    }
    
    
    static void setgattr(log_grec *g, short num, char *value_)
    {
    	char value[256];
    	log_grec *g1;
    	short pg;
    	log_tool *saveacttool;
    
    	strcpy(value, value_);
    	if (num < 1 || num > g->kind->numattrs)
    		return;
    	saveacttool = gg.acttool;
    	gg.actgate = g;
    	gg.actnode = NULL;
    	gg.acttool = g->kind->simtype;
    	gg.action = act_configchgate;
    	if (setattr(g->attr, g->kind->attr, num, value))
    	{
    		stamp(&gg.gattrstamp);
    		g1 = NULL;
    		pg = gg.numpages + 1;
    		while (pg > 1 && g1 != NULL)
    		{
    			pg--;
    			g1 = gg.gbase[pg - 1];
    			while (g1 != NULL && g1 != g)
    				g1 = g1->next;
    		}
    		if (g1 != NULL)
    			chpage(pg);
    	}
    	gg.acttool = saveacttool;
    }
    
    
    static void setnattr(log_nrec *n, short num, char *value_)
    {
    	char value[256];
    	log_tool *saveacttool;
    
    	strcpy(value, value_);
    	if (num < 1 || num > n->simtype->nnumattrs)
    		return;
    	saveacttool = gg.acttool;
    	gg.actgate = NULL;
    	gg.actnode = n;
    	gg.acttool = n->simtype;
    	gg.action = act_configchnode;
    	if (setattr(n->attr, n->simtype->nattr, num, value))
    		stamp(&gg.nattrstamp);
    	gg.acttool = saveacttool;
    }
    
    
    typedef short flipvec[8];
    typedef flipvec fliparr[4];
    
    
    const fliparr flips = {
    	{ 4, 5, 6, 7, 0, 1, 2, 3 },
    	{ 1, 2, 3, 0, 5, 6, 7, 4 },
    	{ 4, 7, 6, 5, 0, 3, 2, 1 },
    	{ 6, 5, 4, 7, 2, 1, 0, 3 }
    };
    
    
    static short doflip(short rot, short mode)
    {
    	return (flips[mode][rot]);
    }
    
    
    /*==================  FLIPGATE  ==================*/
    /*=                                              =*/
    /*=  Flip a gate in the circuit.                 =*/
    /*=                                              =*/
    /*================================================*/
    
    static void flipgate(log_grec *g)
    {
    	short i;
    	log_krec *WITH;
    
    	if (g->kind->flag.U3.noflip)
    	{
    		configgate(g);
    		return;
    	}
    	
    	WITH = g->kind;
    	
    	if (g->kind->flag.U3.toggle)
    		i = 0;
    	else
    		i = cureditmode;
    	
    	switch (i)
    	{
    
    		case 0:
    		case 1:
    		case 2:
    		case 3:
    			remcursor();
    			clipon();
    			eragate(g);
    			disconnectgate(g);
    			g->rot = doflip(g->rot, i);
    			g->g = g->rot * log_kindoffset + (g->g & (log_kindoffset - 1));
    			drawgatex(g);
    			clipoff();
    			if (!connectgate(g))
    			{
    				frygate(g);
    				disposegate(&g);
    			}
    			restorecursor();
    			refreshsoon();
    			break;
    
    		case 4:
    			configgate(g);
    			break;
    	}
    }
    
    
    /*==================  FLIPKIND  ==================*/
    /*=                                              =*/
    /*=  Flip a gate in menu area.                   =*/
    /*=                                              =*/
    /*================================================*/
    
    static void flipkind()
    {
    	short i, z, k;
    
    	remcursor();
    	i = (gg.t.x - kindgroupleft) / kindgroupspacing + 1;
    	k = kindgroup[i - 1] & (log_kindoffset - 1);
    	if (kindgroup[i - 1] != 0 && !kind[k - 1]->flag.U3.noflip)
    	{
    		clipoff();
    		kdrawgatec(i, gg.color.backgr);
    		z = kindgroup[i - 1] / log_kindoffset;
    		if (kind[k - 1]->flag.U3.named)
    		{
    			z = doflip(z, 2);
    		}
    		else
    		{
    			switch (cureditmode)
    			{
    
    				case 1:
    				case 2:
    				case 3:
    					z = doflip(z, cureditmode);
    					break;
    
    				case 4:
    					z = doflip(z, 1);
    					break;
    			}
    		}
    		kindgroup[i - 1] = z * log_kindoffset + k;
    		kdrawgatec(i, gg.color.kindgate);
    	}
    	restorecursor();
    }
    
    /*==============  ADJUSTSIGNAL  ==================*/
    /*=                                              =*/
    /*=  Enter a new name for nameable gate.         =*/
    /*=                                              =*/
    /*================================================*/
    
    static void settofrom(log_grec **g, char *name)
    {
    	if (!(*g)->kind->flag.U3.named)
    		return;
    	disconnectgate(*g);
    	clipon();
    	eragate(*g);
    	clipoff();
    	(*g)->sig = getsignal((*g)->sig, name);
    	if (connectgate(*g))
    	{
    		clipon();
    		drawgatex(*g);
    		clipoff();
    		return;
    	}
    	frygate(*g);
    	disposegate(g);
    	*g = NULL;
    }
    
    
    static void adjustsignal(log_grec *g)
    {
    	char n[256];
    	uchar ch;
    	int savecaps, rightface;
    	char STR1[256], STR2[256];
    
    	alert();
    	savecaps = nk_setcapslock(signalcaps);
    	rightface = (g->kind->flag.U3.nright != (g->rot == 0));
    	gsignallabel(g->x, g->y, g, gg.color.backgr);
    	*n = '\0';
    	do
    	{
    		if (strlen(n) < 256-1)
    			strcat(n, "_");
    		remcursor();
    		m_colormode((long)m_xor);
    		m_color((long)gg.color.signal);
    		if (rightface)
    		{
    			drawstr2((int)(g->x * gg.scale - gg.xoff - m_strwidth(logfont_lfont,
    							strrtrim(strcpy(STR1, n))) + NAMEGAP),
    					(int)(g->y * gg.scale - gg.yoff - 3),
    					strrtrim(strcpy(STR2, n)));
    		}
    		else
    		{
    			drawstr2((int)(g->x * gg.scale - gg.xoff - NAMEGAP),
    					(int)(g->y * gg.scale - gg.yoff - 3),
    					strrtrim(strcpy(STR1, n)));
    		}
    		m_colormode((long)m_normal);
    		if (!pollkbd2())
    		{
    			do
    			{
    				pass();
    				pen();
    			} while (!(pollkbd2() || gg.t.dn));
    		}
    		remcursor();
    		m_colormode((long)m_xor);
    		m_color((long)gg.color.signal);
    		if (rightface)
    		{
    			drawstr2((int)(g->x * gg.scale - gg.xoff - m_strwidth(logfont_lfont,
    							strrtrim(strcpy(STR1, n))) + NAMEGAP),
    					(int)(g->y * gg.scale - gg.yoff - 3),
    					strrtrim(strcpy(STR2, n)));
    		}
    		else
    		{
    			drawstr2((int)(g->x * gg.scale - gg.xoff - NAMEGAP),
    					(int)(g->y * gg.scale - gg.yoff - 3),
    					strrtrim(strcpy(STR1, n)));
    		}
    		m_colormode((long)m_normal);
    		n[strlen(n) - 1] = '\0';
    		if (pollkbd2())
    		{
    			ch = inkey2();
    			if ((strlen(n) < 256-2 && ch > ' ' && ch != 250 && ch != 251)
    					|| (ch == ' ' && *n != '\0'))
    				sprintf(n + strlen(n), "%c", ch);
    
    			if (ch == '\007' && *n != '\0')
    				n[strlen(n) - 1] = '\0';
    		}
    	} while (!((ch < 32 && ((1L << ch) & 0x2008) != 0) || gg.t.dn));
    	remcursor();
    	m_color((long)gg.color.signal);
    	if (rightface)
    	{
    		drawstr2((int)(g->x * gg.scale - gg.xoff - m_strwidth(logfont_lfont,
    						strrtrim(strcpy(STR1, n))) + NAMEGAP),
    				(int)(g->y * gg.scale - gg.yoff - 3), strrtrim(strcpy(STR2, n)));
    	}
    	else
    	{
    		drawstr2((int)(g->x * gg.scale - gg.xoff - NAMEGAP),
    				(int)(g->y * gg.scale - gg.yoff - 3), strrtrim(strcpy(STR1, n)));
    	}
    	settofrom(&g, n);
    	signalcaps = nk_setcapslock(savecaps);
    }
    
    
    static void touchgate(log_grec *g)
    {
    	short xx, yy;
    
    	if (g->kind->flag.U3.named)
    	{
    		adjustsignal(g);
    		return;
    	}
    	xx = gg.gridx - g->x;
    	yy = gg.gridy - g->y;
    	gg.actx = log_irotxx[g->rot] * xx + log_irotyx[g->rot] * yy;
    	gg.acty = log_irotxy[g->rot] * xx + log_irotyy[g->rot] * yy;
    	xx = gg.t.x - g->x * gg.scale + gg.xoff;
    	yy = gg.t.y - g->y * gg.scale + gg.yoff;
    	gg.actx2 = log_irotxx[g->rot] * xx + log_irotyx[g->rot] * yy;
    	gg.acty2 = log_irotxy[g->rot] * xx + log_irotyy[g->rot] * yy;
    	gg.actflag = false;
    	calltoolgate(g, act_touchgate);
    	
    	if (gg.actflag)
    		chpageplace((int)gg.curpage, g->x - g->kind->bbmax, g->y - g->kind->bbmax,
    				g->x + g->kind->bbmax, g->y + g->kind->bbmax);
    	else if (!gg.invisible || g->kind->flag.U3.visible)
    		flipgate(g);
    }
    
    static void unsoldernear()
    {
    	short oldx, oldy1, oldy2, oldcolr;
    	blobrec *blbase;
    
    	oldx = gg.nearvw->x;
    	oldy1 = gg.nearvw->y1;
    	oldy2 = gg.nearvw->y2;
    	oldcolr = gg.nearvw->wcolr;
    	if (gg.nearhw->y == oldy1 || gg.nearhw->y == oldy2 ||
    			gg.nearhw->x1 == oldx || gg.nearhw->x2 == oldx)
    		return;
    	remcursor();
    	blbase = NULL;
    	addblobs(&blbase, oldx, oldy1, oldx, gg.nearhw->y - 1);
    	addblobs(&blbase, oldx, gg.nearhw->y + 1, oldx, oldy2);
    	delvwire(gg.nearvw);
    	addvwire(oldx, oldy1, oldy2, oldcolr);
    	doblobs(blbase);
    	dispblobs(&blbase);
    }
    
    
    static void unsolderwires(log_hwrec *hw, log_vwrec *vw)
    {
    	if (hw == NULL || vw == NULL)
    		return;
    	gg.nearhw = hw;
    	gg.nearvw = vw;
    	unsoldernear();
    }
    
    
    static void soldernear()
    {
    	if (!trycombinenodes(&gg.nearvw->node, &gg.nearhw->node))
    	{
    		frysolder(gg.nearvw->x, gg.nearhw->y);
    		return;
    	}
    	clipon();
    	addsolder(gg.nearvw->x, gg.nearhw->y, gg.nearhw, NULL, gg.nearvw, NULL);
    	clipoff();
    }
    
    
    static void solderat(short x, short y)
    {
    	if (findsolder(x, y) != NULL)
    		return;
    	closerwire(x, y);
    	if (gg.nearhw != NULL && gg.nearvw != NULL && gg.nearhw->x1 != x &&
    			gg.nearhw->x2 != x && gg.nearvw->y1 != y && gg.nearvw->y2 != y)
    		soldernear();
    }
    
    
    static void findattrnum2(short numattrs, log_kattrec *kattr, na_strlist_t *lbl, char *name, char *kinds, short *num)
    {
    	na_strlist_t *l1;
    
    	if (strsubset(name, "0123456789"))
    	{
    		if (*name == '\0')
    			*num = 0;
    		else
    			*num = strtol(name, NULL, 0);
    	}
    	else
    	{
    		l1 = lbl;
    		while (l1 != NULL && l1->kind != '\001')
    			l1 = l1->next;
    
    		if (l1 != NULL)
    			l1 = strlist_find((na_strlist_t *)l1->value, name);
    
    		if (l1 != NULL)
    			*num = (long)l1->value;
    		else
    			*num = 0;
    	}
    
    	if (*num < 1 || *num > numattrs ||
    			(strposc(kinds, kattr[*num - 1].dtype, 1L) == 0 && *kinds != '\0'))
    		*num = 0;
    }
    
    
    static void findattrnum(log_krec *k, char *name, char *kinds, short *num)
    {
    	findattrnum2(k->numattrs, k->attr, k->lbl, name, kinds, num);
    }
    
    
    static void findattrname2(short numattrs, log_kattrrec *kattr, na_strlist_t *lbl, short num, char *name)
    {
    	na_strlist_t *l1;
    
    	if (num < 1 || num > numattrs)
    	{
    		*name = '\0';
    		return;
    	}
    	l1 = lbl;
    	
    	while (l1 != NULL && l1->kind != '\001')
    		l1 = l1->next;
    	
    	if (l1 != NULL)
    	{
    		l1 = (na_strlist_t *)l1->value;
    		while (l1 != NULL && (long)l1->value != num)
    			l1 = l1->next;
    	}
    	
    	if (l1 != NULL)
    		strcpy(name, l1->s);
    	else
    		sprintf(name, "%d", num);
    }
    
    
    static void findattrname(log_krec *k, short num, char *name)
    {
    	findattrname2(k->numattrs, k->attr, k->lbl, num, name);
    }
    
    
    static void findpinnum(log_krec *k, char *name_, short *num)
    {
    	char name[256];
    
    	strcpy(name, name_);
    	if (*name == '#')
    		strcpy_overlap(name, name + 1);
    
    	if (strsubset(name, "0123456789"))
    	{
    		if (*name == '\0')
    		{
    			*num = 0;
    			return;
    		}
    		*num = strtol(name, NULL, 0);
    		if (*num < 1 || *num > k->numpins)
    			*num = 0;
    		return;
    	}
    	*num = 1;
    	while (*num <= k->numpins &&
    			strlist_find(k->pinnames[*num - 1], name) == NULL)
    		(*num)++;
    	if (*num > k->numpins)
    		*num = 0;
    }
    
    
    static void findpinname(log_krec *k, short num, char *name)
    {
    	if (num >= 1 && num <= k->numpins && k->pinnames[num - 1] != NULL)
    	{
    		strcpy(name, k->pinnames[num - 1]->s);
    		return;
    	}
    	
    	if (num == 0)
    		*name = '\0';
    	else
    		sprintf(name, "%d", num);
    }
    
    
    static void findpointmarker(log_krec *k, short num, short *x, short *y)
    {
    	long i;
    
    	i = k->numvects;
    	while (i >= 1 && (k->vector[i - 1].vkind != 'p' || k->vector[i - 1].UU.U98.num != num))
    		i--;
    
    	if (i >= 1)
    	{
    		*x = k->vector[i - 1].x1;
    		*y = k->vector[i - 1].y1;
    	}
    }
    
    
    static void findboxmarker(log_krec *k, short num, short *x1, short *y1, short *x2, short *y2)
    {
    	long i;
    
    	i = k->numvects;
    	while (i >= 1 && (k->vector[i - 1].vkind != 'b' || k->vector[i - 1].UU.U98.num != num))
    		i--;
    
    	if (i < 1)
    		return;
    
    	k->x1 = k->vector[i - 1].x1;
    	k->y1 = k->vector[i - 1].y1;
    	k->x2 = k->vector[i - 1].UU.U99.x2;
    	k->y2 = k->vector[i - 1].UU.U99.y2;
    }
    
    
    static void addlabelat(short x, short y, char *s)
    {
    	log_lrec *l;
    
    	newlabel(&l);
    	strcpy(l->name, s);
    	l->x = x;
    	l->y = y;
    	l->w = m_strwidth(logfont_lfont, s) / log_scale0;
    	chpageplace((int)gg.curpage, x, y, x + l->w, y + 2);
    	remcursor();
    	clipon();
    	m_color((long)gg.color.labeltext);
    	m_drawstr(x * gg.scale - gg.xoff, y * gg.scale - gg.yoff + 2, logfont_lfont, s);
    	clipoff();
    	gg.nearlabel = l;
    }
    
    
    static void addlabel(log_lrec **l, char *s)
    {
    	int conflict;
    	log_lrec *l1;
    	short x, y;
    
    	x = 0;
    	y = baseline - 15;
    	do
    	{
    		fixxy(&x, &y);
    		conflict = false;
    		l1 = gg.lbase[gg.curpage - 1];
    		while (l1 != NULL)
    		{
    			if (l1->y * gg.scale - gg.yoff == y &&
    					labs(l1->x * gg.scale - gg.xoff - x) < 20)
    				conflict = true;
    			l1 = l1->next;
    		}
    
    		if (conflict)
    		{
    			y -= gg.scale * 2;
    			if (y < 10)
    			{
    				y = baseline - 15;
    				x += gg.scale * 20;
    			}
    		}
    	} while (conflict);
    	x = (x + gg.xoff) / gg.scale;
    	y = (y + gg.yoff) / gg.scale;
    	if (x * gg.scale < gg.xoff)
    		x++;
    	addlabelat(x, y, s);
    	*l = gg.nearlabel;
    }
    
    
    #define blinkrate       25
    
    
    /*================  EDITLABEL  ===================*/
    /*=                                              =*/
    /*=  Edit or create a label.                     =*/
    /*=                                              =*/
    /*================================================*/
    
    static void editlabel(log_lrec *l)
    {
    	short i, x1, y1;
    	long j;
    	uchar ch;
    	int savecaps, redraw, touching;
    	char name[log_lablen + 1];
    	char STR1[256];
    
    	m_graphics_on();
    	clearalpha();
    	remcursor();
    	alert();
    	savecaps = nk_setcapslock(labelcaps);
    	touching = (l != NULL && l == gg.nearlabel);
    	if (l == NULL)
    		addlabel(&l, "");
    	x1 = l->x * gg.scale - gg.xoff;
    	y1 = l->y * gg.scale - gg.yoff + 2;
    	i = 1;
    	strcpy(name, l->name);
    	if (touching)
    	{
    		while (i <= strlen(name) &&
    				gg.t.x - x1 > m_strwidth(logfont_lfont,
    					(sprintf(STR1, "%.*s", i, name), STR1)))
    		{
    			i++;
    		}
    	}
    
    	do
    	{
    		do
    		{
    			remcursor();
    			clipon();
    			m_colormode((long)m_xor);
    			m_color((long)gg.color.labeltext);
    			sprintf(STR1, "%.*s", i - 1, name);
    			m_move(x1 + m_strwidth(logfont_lfont, STR1) - 1, y1 + 8L);
    			if (i > strlen(name))
    			{
    				m_drawrel(6L, 0L);
    			}
    			else
    			{
    				sprintf(STR1, "%.1s", name + i - 1);
    				m_drawrel(m_strwidth(logfont_lfont, STR1), 0L);
    			}
    			m_colormode((long)m_normal);
    			clipoff();
    			j = timers_sysclock() + blinkrate;
    			if (!pollkbd2())
    			{
    				do
    				{
    					pass();
    					pen();
    				} while (!(pollkbd2() || gg.t.dn || timers_sysclock() > j));
    			}
    			remcursor();
    			clipon();
    			m_colormode((long)m_xor);
    			m_color((long)gg.color.labeltext);
    			sprintf(STR1, "%.*s", i - 1, name);
    			m_move(x1 + m_strwidth(logfont_lfont, STR1) - 1, y1 + 8L);
    			if (i > strlen(name))
    			{
    				m_drawrel(6L, 0L);
    			}
    			else
    			{
    				sprintf(STR1, "%.1s", name + i - 1);
    				m_drawrel(m_strwidth(logfont_lfont, STR1), 0L);
    			}
    			m_colormode((long)m_normal);
    			clipoff();
    			j = timers_sysclock() + blinkrate;
    			if (!(pollkbd2() || gg.t.dn))
    			{
    				do
    				{
    					pass();
    					pen();
    				} while (!(pollkbd2() || gg.t.dn || timers_sysclock() > j));
    			}
    		} while (!(pollkbd2() || gg.t.dn));
    
    		if (!gg.t.dn)
    		{
    			ch = inkey2();
    			if (ch >= 32 || ((1L << ch) & 0x10002108L) == 0)
    			{
    				remcursor();
    				m_color((long)gg.color.backgr);
    				m_drawstr((long)x1, (long)y1, logfont_lfont, name);
    				redraw = true;
    			}
    			else
    			{
    				redraw = false;
    			}
    			
    			if (ch >= ' ' && ch != 250 && ch != 251 && strlen(name) < log_lablen)
    			{
    				if (i <= strlen(name))
    				{
    					sprintf(STR1, " %s", name + i - 1);
    					strcpy(name + i - 1, STR1);
    				}
    				else
    				{
    					strcat(name, " ");
    				}
    				name[i - 1] = ch;
    				i++;
    			}
    			else if (ch == '\007' && i > 1)
    			{
    				i--;
    				strcpy_overlap(name + i - 1, name + i);
    			}
    			else if (ch == '\030' && i <= strlen(name))
    			{
    				strcpy_overlap(name + i - 1, name + i);
    			}
    			else if (ch == '\b' && i > 1)
    			{
    				i--;
    			}
    			else if (ch == '\034' && i <= strlen(name))
    			{
    				i++;
    			}
    			else if (ch == '\031')
    			{
    				i = 1;
    			}
    			else if (ch == '\032')
    			{
    				i = strlen(name) + 1;
    			}
    			else if (ch == '\n' && strlen(name) < log_lablen)
    			{
    				sprintf(STR1, " %s", name + i - 1);
    				strcpy(name + i - 1, STR1);
    			}
    			else if (ch == '\037' && i <= strlen(name) && strlen(name) > 1)
    			{
    				strcpy_overlap(name + i - 1, name + i);
    			}
    			if (redraw)
    			{
    				remcursor();
    				m_color((long)gg.color.labeltext);
    				m_drawstr((long)x1, (long)y1, logfont_lfont, name);
    			}
    		}
    	} while (!((ch < 32 && ((1L << ch) & 0x2008) != 0) || gg.t.dn));
    
    	if (*name == '\0')
    	{
    		displabel(&l);
    	}
    	else if (strcmp(name, l->name))
    	{
    		strcpy(l->name, name);
    		l->w = m_strwidth(logfont_lfont, l->name) / log_scale0;
    		stamp(&gg.labelstamp);
    		chpageplace((int)gg.curpage, l->x, l->y, l->x + l->w, l->y + 2);
    	}
    	labelcaps = nk_setcapslock(savecaps);
    	gg.t.depressed = false;
    	refreshsoon();
    }
    
    #undef blinkrate
    
    
    /*==================  ADDBOX  ====================*/
    /*=                                              =*/
    /*=  Create a new dashed box.                    =*/
    /*=                                              =*/
    /*================================================*/
    
    static void addboxat(short x1, short y1, short x2, short y2)
    {
    	log_brec *b;
    
    	newbox(&b);
    	sortshints(&x1, &x2);
    	sortshints(&y1, &y2);
    	b->x1 = x1;
    	b->y1 = y1;
    	b->x2 = x2;
    	b->y2 = y2;
    	remcursor();
    	clipon();
    	drawboxc(b, gg.color.dashbox);
    	clipoff();
    	chpageplace((int)gg.curpage, x1, y1, x2, y2);
    	gg.nearbox = b;
    }
    
    
    static void addbox()
    {
    	short x1, y1;
    
    	log_setmode("BOX");
    	clearfunc();
    	cursortype = boxcursor;
    	waitnear();
    	do
    	{
    		do
    		{
    			pass();
    			trykbdscroll();
    			pen();
    		} while (!gg.t.dn && gg.stillnear && *gg.func == '\0');
    		gg.posx = gg.gridx;
    		gg.posy = gg.gridy;
    		if (gg.incircuit && gg.stillnear && *gg.func == '\0')
    		{
    			x1 = gg.posx;
    			y1 = gg.posy;
    			do
    			{
    				pen();
    				x1 = gg.gridx;
    				y1 = gg.gridy;
    				m_colormode((long)m_xor);
    				m_color((long)gg.color.dashbox);
    				m_linestyle(1L);
    				rect(gg.posx, gg.posy, x1, y1);
    				m_linestyle(0L);
    				m_colormode((long)m_normal);
    				do
    				{
    					pass();
    					trykbd();
    					pen();
    				} while (gg.gridx == x1 && gg.gridy == y1 && gg.t.depressed && *gg.func == '\0');
    
    				m_colormode((long)m_xor);
    				m_color((long)gg.color.dashbox);
    				m_linestyle(1L);
    				rect(gg.posx, gg.posy, x1, y1);
    				m_linestyle(0L);
    				m_colormode((long)m_normal);
    				scroll();
    			} while (gg.t.depressed || abs(x1 - gg.posx) < 2 || abs(y1 - gg.posy) < 2);
    			sortshints(&gg.posx, &x1);
    			sortshints(&gg.posy, &y1);
    			remcursor();
    			if (gg.incircuit && *gg.func == '\0')
    				addboxat(gg.posx, gg.posy, x1, y1);
    		}
    	} while (gg.incircuit && gg.stillnear && *gg.func == '\0');
    	gg.startpoint = false;
    	log_setmode("");
    	if (gg.t.dn && !gg.incircuit)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    	cursortype = normal;
    }
    
    
    static void initcolors ();
    
    /* Local variables for doshellescape: */
    struct LOC_doshellescape {
    	long oldc;
    } ;
    
    static void recov(struct LOC_doshellescape *LINK)
    {
    	nk_settransarray(nk_ktsupplied, &curkeytrans);
    	initscreen2();
    
    	if (m_maxcolor != LINK->oldc)
    		initcolormap();
    
    	m_init_pen(tabletaddr);
    	initcolors();
    	refrscreen();
    }
    
    
    static void doshellescape(char *arg)
    {
    	struct LOC_doshellescape V;
    	nk_keytransinfo *ktemp;
    	long i, j;
    	char STR1[256];
    
    	m_graphics_off();
    	m_alpha_on();
    	V.oldc = m_maxcolor;
    	TRY(try22);
    	closedumpfiles();
    	nk_settransarray(nk_ktstandard, &ktemp);
    	m_alpha_off();
    	m_graphics_on();
    	recov(&V);
    	RECOVER(try22);
    	i = P_escapecode;
    	j = P_ioresult;
    	recov(&V);
    	if (i != -20)
    	{
    		beginerror();
    		puts(_ShowEscape(STR1, i, j, "During shell escape"));
    		enderror();
    	}
    	ENDTRY(try22);
    }
    
    static void dumphistory()
    {
    	log_htrec *ht;
    	log_hnrec *hn;
    	short i, FORLIM;
    
    	m_graphics_off();
    	clearalpha();
    	m_alpha_on();
    	hn = gg.hnbase;
    	i = 0;
    	printf("Time               ");
    	while (hn != NULL)
    	{
    		printf("%s%*c", gg.signaltab[hn->sig - 1].name, (int)(15 - strlen(gg.signaltab[hn->sig - 1].name)), ' ');
    		hn = hn->next;
    		i++;
    	}
    	putchar('\n');
    	ht = gg.htbase;
    	while (ht != NULL)
    	{
    		printf("% .5E   ", ht->time);
    		FORLIM = hncount;
    		for (i = 0; i < FORLIM; i++)
    			printf("%12.6f   ", na_srtor(ht->val[i]));
    		putchar('\n');
    		ht = ht->next;
    	}
    	printf("Press any key to continue.\n");
    	waitforkey();
    	gg.showpage = 0;
    }
    
    
    /*================  SHOWHISTORY  =================*/
    /*=                                              =*/
    /*=  Enter History (Scope) display mode.         =*/
    /*=                                              =*/
    /*================================================*/
    
    static void reshuffle()
    {
    	log_hnrec *hn;
    	short i;
    
    	i = 0;
    	hn = gg.hnbase;
    	while (hn != NULL)
    	{
    		i++;
    		hn->num = i;
    		hn = hn->next;
    	}
    	hncount = i;
    	histreset = true;
    }
    
    
    static void histdelsignals()
    {
    	log_hnrec *hn;
    	log_tool *tool;
    
    	while (gg.hnbase != NULL)
    	{
    		tool = gg.signaltab[gg.hnbase->sig - 1].np->simtype;
    		disposeattrs(&gg.hnbase->attr, tool->hnumattrs, tool->hattr);
    		hn = gg.hnbase->next;
    		Free(gg.hnbase);
    		gg.hnbase = hn;
    	}
    	histgridhn = NULL;
    	if (histgridwhich == 2)
    		histgridwhich = 0;
    	reshuffle();
    }
    
    
    #define unit            (histdivision / 2)
    
    
    static void alignsigname(short *y)
    {
    	if (histgattr[histalignsigs - 1].UU.b)
    		*y = histdown - (histdown - *y + unit / 2) / unit * unit;
    }
    
    #undef unit
    
    
    static short histaddsignalpos()
    {
    	log_hnrec *hn;
    	short y;
    
    	y = histdivision / 2;
    	do
    	{
    		hn = gg.hnbase;
    		while (hn != NULL && (hn->y + histvscale < y - histvscale ||
    					hn->y - histvscale > y + histvscale))
    			hn = hn->next;
    		y += histdivision;
    	} while (hn != NULL && y <= histdown);
    	y -= histdivision;
    	alignsigname(&y);
    	return y;
    }
    
    
    static void histaddsignal(log_hnrec **hn, short sig, short y)
    {
    	log_tool *tool;
    
    	*hn = (log_hnrec *)Malloc(sizeof(log_hnrec));
    	(*hn)->y = y;
    	(*hn)->sig = sig;
    	tool = gg.signaltab[sig - 1].np->simtype;
    	newattrs(&(*hn)->attr, tool->hnumattrs, tool->hattr);
    	if (gg.traceflag)
    		fprintf(tracefile, "Histaddsignal: %ld, %d\n",
    				(long)(*hn)->attr, tool->hnumattrs);
    	(*hn)->next = gg.hnbase;
    	gg.hnbase = *hn;
    	reshuffle();
    }
    
    
    static void hnproc1()
    {
    	calltool(gg.acttool, act_confighist);
    }
    
    
    static void hnproc2()
    {
    	calltool(gg.acttool, act_configchhist);
    }
    
    
    static void hnproc3()
    {
    	calltool(gg.acttool, act_configrelhist);
    }
    
    
    static void haproc1()
    {
    	log_gattrrec *WITH;
    
    	WITH = &histgattr[histcurcount - 1];
    	if (WITH->UU.U73.i1 != htcount)
    	{
    		WITH->UU.U73.i1 = htcount;
    		WITH->blnk = false;
    		WITH->changed = true;
    	}
    	WITH = &histgattr[histcurtime - 1];
    	if (WITH->UU.r != gg.time)
    	{
    		WITH->UU.r = gg.time;
    		WITH->blnk = false;
    		WITH->changed = true;
    	}
    	WITH = &histgattr[histcurtstep - 1];
    	if (WITH->UU.r == gg.prevtimestep)
    		return;
    	WITH->UU.r = gg.prevtimestep;
    	WITH->blnk = false;
    	WITH->changed = true;
    }
    
    
    static void haproc2()
    {
    	log_gattrrec *WITH;
    
    	WITH = &histgattr[gg.actx - 1];
    	switch (gg.actx)
    	{
    
    		case histtrigsig:
    			if (!strcmp(WITH->UU.c, "(none)"))
    				histtrig = 0;
    			else
    				histtrig = getsignal(0, WITH->UU.c);
    			break;
    
    		case histstarttime:
    			if (WITH->UU.r <= 0)
    				WITH->blnk = true;
    			
    			if (!WITH->blnk && WITH->UU.r >= histgattr[histstoptime - 1].UU.r)
    			{
    				histgattr[histstoptime - 1].blnk = true;
    				histgattr[histstoptime - 1].changed = true;
    			}
    			break;
    
    		case histstoptime:
    			if (WITH->UU.r < 0)
    				WITH->blnk = true;
    			
    			if (!WITH->blnk && WITH->UU.r <= histgattr[histstarttime - 1].UU.r)
    			{
    				histgattr[histstarttime - 1].blnk = true;
    				histgattr[histstarttime - 1].changed = true;
    			}
    			break;
    
    		case histminstep:
    		case histmaxstep:
    			if (WITH->UU.r <= 0)
    				WITH->blnk = true;
    			break;
    
    		case histsecdiv:
    			if (WITH->UU.r <= 0)
    				gg.actflag = false;
    			break;
    
    		case histmaxcount:
    			if (WITH->UU.U73.i1 < 2)
    				WITH->UU.U73.i1 = 2;
    			break;
    
    		case histcurcount:
    		case histcurtime:
    		case histcurtstep:
    			gg.actflag = false;
    			break;
    	}
    }
    
    
    static void haproc3()
    {
    	/* nothing at all! */
    }
    
    
    #define quit1pos        2
    
    #define configpos       (quit1pos + 44)
    #define triggerpos      (configpos + 63)
    #define resetpos        (triggerpos + 51)
    #define onoffpos        (resetpos + 45)
    #define gridpos         (onoffpos + 26)
    #define gridwpos        (gridpos + 60)
    #define fastpos         (gridwpos + 54)
    #define dumppos         (fastpos + 40)
    #define nextpos         (dumppos + 40)
    
    #define quit2pos        484
    
    #define otherpos        (quit2pos - 50)
    
    #define axiswidth       50
    
    #define xaxispos        (quit1pos + 44)
    #define yaxispos        (xaxispos + axiswidth)
    #define exprpos         (yaxispos + axiswidth + 20)
    #define timepos         (exprpos + 65)
    #define plotpos         (timepos + 80)
    #define next2pos        (plotpos + 50)
    
    #define nummenus        2
    
    
    #define tolerance       15
    
    
    typedef short ararr[log_million];
    
    
    /* Local variables for historycommand: */
    struct LOC_historycommand {
    	int rflag, oldtrigger, oldreset, oldonoff, oldfast;
    	short oldgridmode, oldgridwhich, gridx1, gridy1, gridx2, gridy2, valuey,
    		  whichmenu, vmenu1, vmenu2;
    	int xactive, yactive;
    	char xexpr[256], yexpr[256];
    	double gridval, gridval2, gridtime;
    	char gridstr[81];
    	long stamp;
    } ;
    
    static double valueattime(log_hnrec *hn, double time, struct LOC_historycommand *LINK)
    {
    	log_htrec *ht, *ht0;
    	double v1, v2, alpha;
    
    	ht = gg.htbase;
    	ht0 = NULL;
    	while (ht != NULL && ht->time < time)
    	{
    		ht0 = ht;
    		ht = ht->next;
    	}
    
    	if (ht == NULL || ht0 == NULL)
    	{
    		return 0.0;
    	}
    	else
    	{
    		v1 = na_srtor(ht0->val[hn->num - 1]);
    		v2 = na_srtor(ht->val[hn->num - 1]);
    		alpha = (time - ht0->time) / (ht->time - ht0->time);
    		return (v1 + (v2 - v1) * alpha);
    	}
    }
    
    static log_hnrec *findtrace(short x, short y, struct LOC_historycommand *LINK)
    {
    	log_htrec *ht, *ht0;
    	double v1, v2, value, alpha, time;
    	log_hnrec *hn, *besthn;
    	short yy, besty;
    
    	time = (double)(x - histleft) / histdivision * histgattr[histsecdiv - 1].UU.r + histgattr[histfirsttime - 1].UU.r;
    	ht = gg.htbase;
    	ht0 = NULL;
    	while (ht != NULL && ht->time < time)
    	{
    		ht0 = ht;
    		ht = ht->next;
    	}
    
    	if (ht == NULL || ht0 == NULL)
    	{
    		return NULL;
    	}
    	else
    	{
    		alpha = (time - ht0->time) / (ht->time - ht0->time);
    		hn = gg.hnbase;
    		besty = 9999;
    		while (hn != NULL)
    		{
    			v1 = na_srtor(ht0->val[hn->num - 1]);
    			v2 = na_srtor(ht->val[hn->num - 1]);
    			value = v1 + (v2 - v1) * alpha;
    			historyvaluey(hn, value, &v1, &yy);
    			if (abs(yy - y) < besty)
    			{
    				besty = abs(yy - y);
    				besthn = hn;
    			}
    			hn = hn->next;
    		}
    
    		if (besty < tolerance)
    			return besthn;
    		else
    			return NULL;
    	}
    }
    
    #undef tolerance
    
    static void refrtrigger(struct LOC_historycommand *LINK)
    {
    	if (gg.histactive == LINK->oldtrigger || LINK->whichmenu != 0)
    		return;
    	remcursor();
    	clipoff();
    	if (gg.histactive)
    		m_color((long)gg.color.selword);
    	else
    		m_color((long)gg.color.menuword);
    	drawstr2((int)triggerpos, LINK->vmenu1, "Trigger");
    	LINK->oldtrigger = gg.histactive;
    }
    
    static void refrreset(struct LOC_historycommand *LINK)
    {
    	if (gg.resetflag == LINK->oldreset || LINK->whichmenu != 0)
    		return;
    	remcursor();
    	clipoff();
    	if (gg.resetflag)
    		m_color((long)gg.color.selword);
    	else
    		m_color((long)gg.color.menuword);
    	drawstr2((int)resetpos, LINK->vmenu1, "Reset");
    	LINK->oldreset = gg.resetflag;
    }
    
    static void refronoff(struct LOC_historycommand *LINK)
    {
    	if (gg.pwrflag == LINK->oldonoff || LINK->whichmenu != 0)
    		return;
    	remcursor();
    	clipoff();
    	if (gg.pwrflag)
    	{
    		m_color((long)gg.color.selword);
    		drawstr2((int)onoffpos, LINK->vmenu1, "ON ");
    	}
    	else
    	{
    		m_color((long)gg.color.menuword);
    		drawstr2((int)onoffpos, LINK->vmenu1, "OFF");
    	}
    	LINK->oldonoff = gg.pwrflag;
    }
    
    static void refrgridmode(struct LOC_historycommand *LINK)
    {
    	if (histgridmode != LINK->oldgridmode && LINK->whichmenu == 0)
    	{
    		remcursor();
    		clipoff();
    		m_color((long)gg.color.selword);
    		switch (histgridmode)
    		{
    
    			case 0:
    				drawstr2((int)gridpos, LINK->vmenu1, "Delta:   ");
    				break;
    
    			case 1:
    				drawstr2((int)gridpos, LINK->vmenu1, "Absolute:");
    				break;
    
    			case 2:
    				drawstr2((int)gridpos, LINK->vmenu1, "Value:   ");
    				break;
    
    			case 3:
    				drawstr2((int)gridpos, LINK->vmenu1, "Slope:   ");
    				break;
    		}
    		LINK->oldgridmode = histgridmode;
    	}
    
    	if (histgridwhich == LINK->oldgridwhich)
    		return;
    	remcursor();
    	clipoff();
    	switch (histgridwhich)
    	{
    
    		case 0:
    			m_color((long)gg.color.selword);
    			drawstr2((int)gridwpos, LINK->vmenu1, "Time  ");
    			break;
    
    		case 1:
    			m_color((long)gg.color.selword);
    			drawstr2((int)gridwpos, LINK->vmenu1, "Freq  ");
    			break;
    
    		case 2:
    			m_color((long)gg.color.menuword);
    			drawstr2((int)gridwpos, LINK->vmenu1, "Signal");
    			break;
    	}
    	LINK->oldgridwhich = histgridwhich;
    }
    
    static void refrfast(struct LOC_historycommand *LINK)
    {
    	int fast;
    
    	fast = (gg.fastspeed == gg.fastmax);
    	if (fast == LINK->oldfast || LINK->whichmenu != 0)
    		return;
    	remcursor();
    	clipoff();
    	if (fast)
    		m_color((long)gg.color.selword);
    	else
    		m_color((long)gg.color.menuword);
    	drawstr2((int)fastpos, LINK->vmenu1, "Fast");
    	LINK->oldfast = fast;
    }
    
    static void drawsigname(log_hnrec *hn, short opt, struct LOC_historycommand *LINK)
    {
    	remcursor();
    	clipoff();
    	if (opt == 3)
    		m_colormode((long)m_xor);
    	else
    		m_colormode((long)m_normal);
    
    	if (opt == 2)
    		m_color((long)gg.color.backgr);
    	else if (hn == histgridhn && opt != 1)
    		m_color((long)gg.color.selword);
    	else
    		m_color((long)gg.color.signal);
    
    	drawstr2(0, hn->y - 4, gg.signaltab[hn->sig - 1].name);
    	m_colormode((long)m_normal);
    }
    
    /* Local variables for drawhistory: */
    struct LOC_drawhistory {
    	struct LOC_historycommand *LINK;
    	short x, y, oldx;
    	log_htrec *ht;
    	short *ar;
    } ;
    
    static void drawtrace(log_hnrec *hn, short i, struct LOC_drawhistory *LINK)
    {
    	historypointy(hn, LINK->ht, &LINK->y);
    	if ((unsigned long)gg.acty > 15)
    	{
    		LINK->ar[i - 1] = log_maxshint;
    		return;
    	}
    	m_color(gg.acty);
    	if (LINK->ar[i - 1] != log_maxshint)
    	{
    		m_move((long)LINK->oldx, (long)LINK->ar[i - 1]);
    		m_draw((long)LINK->x, (long)LINK->y);
    	}
    	LINK->ar[i - 1] = LINK->y;
    }
    
    static void drawhistory(struct LOC_historycommand *LINK)
    {
    	struct LOC_drawhistory V;
    	short i, gridi;
    	log_hnrec *hn;
    	log_htrec *ht1;
    	short FORLIM;
    
    	V.LINK = LINK;
    	hn = gg.hnbase;
    	while (hn != NULL)
    	{
    		if (histgridhn != hn)
    			drawsigname(hn, 0, LINK);
    		hn = hn->next;
    	}
    	
    	if (histgridhn != NULL)
    		drawsigname(histgridhn, 0, LINK);
    	
    	if (gg.htbase == NULL)
    		return;
    	
    	V.ar = (short *)Malloc(hncount * 2);
    	FORLIM = hncount;
    	for (i = 0; i < FORLIM; i++)
    		V.ar[i] = log_maxshint;
    
    	m_clip((long)histleft, 0L, (long)across, (long)histdown);
    	V.ht = gg.htbase;
    	ht1 = gg.htbase;
    	
    	while (ht1 != NULL && ht1->time < histgattr[histfirsttime - 1].UU.r)
    	{
    		V.ht = ht1;
    		ht1 = ht1->next;
    	}
    	
    	do
    	{
    		historypointx(V.ht, &V.x);
    		hn = gg.hnbase;
    		i = 0;
    		while (hn != NULL)
    		{
    			i++;
    			if (histgridhn != hn)
    				drawtrace(hn, i, &V);
    			else
    				gridi = i;
    			hn = hn->next;
    		}
    		if (histgridhn != NULL)
    			drawtrace(histgridhn, gridi, &V);
    		V.oldx = V.x;
    		V.ht = V.ht->next;
    	} while (V.ht != NULL && V.x <= across);
    	m_noclip();
    	Free(V.ar);
    }
    
    static void setgridwhich(log_hnrec *hn, struct historycommand *LINK)
    {
    	if (histgridhn != NULL)
    		drawsigname(histgridhn, 1, LINK);
    	histgridhn = hn;
    	if (hn != NULL)
    		histgridwhich = 2;
    	else if (histgridwhich == 2)
    		histgridwhich = 0;
    	if (histgridhn != NULL)
    		drawsigname(histgridhn, 0, LINK);
    }
    
    static void nextgridwhich(struct LOC_historycommand *LINK)
    {
    	log_hnrec *nexthn;
    
    	nexthn = histgridhn;
    	if (nexthn != NULL)
    		drawsigname(nexthn, 1, LINK);
    	switch (histgridwhich)
    	{
    
    		case 0:
    			histgridwhich = 1;
    			break;
    
    		case 1:
    			nexthn = gg.hnbase;
    			if (nexthn != NULL)
    				histgridwhich = 2;
    			else
    				histgridwhich = 0;
    			break;
    
    		case 2:
    			nexthn = nexthn->next;
    			if (nexthn == NULL)
    				histgridwhich = 0;
    			break;
    	}
    	histgridhn = nexthn;
    	if (histgridhn != NULL)
    		drawsigname(histgridhn, 0, LINK);
    }
    
    static void nextgridmode(struct LOC_historycommand *LINK)
    {
    	if (histgridmode == 0)
    		histgridmode = 3;
    	else
    		histgridmode--;
    }
    
    static void confighistmode(struct LOC_historycommand *LINK)
    {
    	int flag;
    	log_hnrec *hn;
    	void (*TEMP) ();
    	void (*TEMP5) ();
    	void (*TEMP6) ();
    
    	flag = histgattr[histalignsigs - 1].UU.b;
    	TEMP = haproc1;
    	TEMP5 = haproc2;
    	TEMP6 = haproc3;
    	editattrs(histgattr, histnumattrs, histkattr, histlbl, "Scope", TEMP, TEMP5,
    			TEMP6, &LINK->stamp);
    	if (flag)
    		return;
    	hn = gg.hnbase;
    	while (hn != NULL)
    	{
    		alignsigname(&hn->y);
    		hn = hn->next;
    	}
    }
    
    static void passetc(struct LOC_historycommand *LINK)
    {
    	m_noclip();
    	refrtrigger(LINK);
    	refrreset(LINK);
    	refronoff(LINK);
    	refrfast(LINK);
    	pass();
    	pen();
    }
    
    static void fastmode(struct LOC_historycommand *LINK)
    {
    	long t0;
    
    	t0 = timers_sysclock();
    	do {
    		gg.fastspeed = gg.fastmax;
    		passetc(LINK);
    	} while (gg.t.near_ && timers_sysclock() <= t0 + 50);
    	gg.fastspeed = gg.fastmax;
    }
    
    static void dumpcmd(struct LOC_historycommand *LINK)
    {
    	char fn[256];
    	log_htrec *ht;
    	log_hnrec *hn;
    	short i;
    	long j;
    	char STR2[256], STR3[256];
    	short FORLIM;
    
    	if (gg.htbase == NULL)
    		return;
    
    	m_color((long)gg.color.selword);
    	drawstr2((int)dumppos, LINK->vmenu1, "Dump");
    	beginbottom();
    	m_alpha_on();
    	printf("Dump file name");
    	
    	if (*dumpfname != '\0')
    		printf(" [%s]", dumpfname);
    	printf(": ");
    	readlnpass(fn, 0);
    	endbottom();
    	beginbottom();
    	m_alpha_on();
    	
    	if (*fn != '\0')
    		setdumpname(fn);
    	else
    		printf("Dump file is %s\n", dumpfname);
    	
    	if (*dumpfname != '\0') {
    		TRY(try23);
    
    		/* Procedure to write the scope data to the dump file.
    
    		   GG.HNBASE points to a linked list of History Names.  HN is a temp. variable.
    		   HNCOUNT is a count of the number of things in this list.
    		   The name of a trace is given by:  gg.signaltab^[hn^.sig].name^
    
    		   GG.HTBASE points to a list of History Timesteps.  HT is a temp. variable.
    		   For each entry, the time is stored in:  ht^.time
    		   and the value of the I'th history trace is:  na_srtor(ht^.val[i])
    		   */
    		dumpmessage("");
    		sprintf(STR2, "%s (", dumpfname);
    		dumpmessage(STR2);   /*file name in header*/
    		dumpmessage("(DATA:");
    		dumpmessage("(TITLE: TIME )");
    		dumpmessage("(POINTS:");
    		ht = gg.htbase;
    		
    		/* list of time values */
    		while (ht != NULL)
    		{
    			sprintf(STR2, "%g", ht->time);
    			dumpmessage(STR2);
    			ht = ht->next;
    		}
    		dumpmessage("))");
    		hn = gg.hnbase;
    		FORLIM = hncount;
    
    		/* for each trace... */
    		for (i = 0; i < FORLIM; i++)
    		{
    			dumpmessage("(DATA:");   /*write its name*/
    			sprintf(STR3, "(TITLE: \\\\%s\\)", gg.signaltab[hn->sig - 1].name);
    			dumpmessage(STR3);
    			dumpmessage("(POINTS:");
    			ht = gg.htbase;
    			
    			/* and list of values */
    			while (ht != NULL)
    			{
    				sprintf(STR3, "%g", na_srtor(ht->val[i]));
    				dumpmessage(STR3);
    				ht = ht->next;
    			}
    			dumpmessage("))");
    			hn = hn->next;
    		}
    		dumpmessage(")");
    		/* End of Dump routine.*/
    
    		closedump();
    		RECOVER(try23);
    		if (P_escapecode == -20)
    			_Escape(P_escapecode);
    		i = P_ioresult;
    		j = P_escapecode;
    		beginerror();
    		if (Debugging || debugprint)
    			printf("%ld/%d/%ld   ", j, i, EXCP_LINE);
    		printf("Unable to write dump file \"%s\"\n", dumpfname);
    		enderror();
    		ENDTRY(try23);
    	}
    	endbottom();
    	LINK->rflag = true;
    }
    
    static void refraxis(long pos, char *name, char *expr, int flag, struct LOC_historycommand *LINK)
    {
    	if (flag)
    		m_color((long)gg.color.selword);
    	else
    		m_color((long)gg.color.menuword);
    
    	drawstr2((int)pos, LINK->vmenu1, name);
    	uerase((int)pos, LINK->vmenu2 - 2, (int)(pos + axiswidth - 3),
    			LINK->vmenu2 + 12);
    	m_clip(pos, LINK->vmenu2 - 2L, pos + axiswidth - 3, LINK->vmenu2 + 12L);
    	m_color((long)gg.color.menuword);
    	drawstr2((int)pos, LINK->vmenu2, expr);
    	m_noclip();
    }
    
    static void refraxes(struct LOC_historycommand *LINK)
    {
    	refraxis(xaxispos, "X-axis", LINK->xexpr, LINK->xactive, LINK);
    	refraxis(yaxispos, "Y-axis", LINK->yexpr, LINK->yactive, LINK);
    }
    
    static void setaxis(char *expr, struct LOC_historycommand *LINK)
    {
    	if (LINK->xactive)
    	{
    		LINK->xactive = false;
    		strcpy(LINK->xexpr, expr);
    		if (*LINK->yexpr == '\0')
    			LINK->yactive = true;
    		refraxes(LINK);
    		return;
    	}
    	
    	if (!LINK->yactive)
    		return;
    	
    	LINK->yactive = false;
    	strcpy(LINK->yexpr, expr);
    	if (*LINK->xexpr == '\0')
    		LINK->xactive = true;
    	refraxes(LINK);
    }
    
    static void getexpr(struct LOC_historycommand *LINK)
    {
    	char expr[256];
    
    	if (!(LINK->xactive || LINK->yactive))
    		return;
    	beginbottom();
    	m_alpha_on();
    	printf("Expression to plot: ");
    	readlnpass(expr, 0);
    	endbottom();
    	strcompress(expr, " ", true);
    	if (*expr != '\0')
    		setaxis(expr, LINK);
    }
    
    static void plotcmd(struct LOC_hostorycommand *LINK)
    {
    	char STR1[256];
    
    	if (*LINK->xexpr == '\0' || *LINK->yexpr == '\0')
    		return;
    	sprintf(STR1, "PLOT SCOPE %s %s", LINK->xexpr, LINK->yexpr);
    	assertfunc(STR1);
    	dofunction();
    	clearfunc();
    	LINK->rflag = true;
    }
    
    static void measurecmd(struct LOC_historycommand *LINK)
    {
    	char STR1[81];
    
    	do
    	{
    		while ((gg.t.x < histleft || gg.t.y > histdown) && gg.t.depressed)
    			pen();
    		LINK->gridx2 = gg.t.x;
    		LINK->gridy2 = gg.t.y;
    		m_colormode((long)m_xor);
    		m_color((long)gg.color.scroll);
    		*LINK->gridstr = '\0';
    		if (histgridwhich == 2)
    		{
    			gg.actx = histgridhn->sig;
    			gg.actgattr = histgridhn->attr;
    		}
    		*gg.actstr = '\0';
    		gg.acty = histgridmode;
    		switch (histgridwhich * 100 + histgridmode)
    		{
    
    			case 0:
    				m_drawline((long)LINK->gridx1, 0L, (long)LINK->gridx1, (long)histdown);
    				m_drawline((long)LINK->gridx2, 0L, (long)LINK->gridx2, (long)histdown);
    				gg.actval = (double)abs(LINK->gridx2 - LINK->gridx1) / histdivision;
    				realunit(LINK->gridstr, gg.actval * histgattr[histsecdiv - 1].UU.r, 4, "s", true);
    				break;
    
    			case 1:
    			case 101:
    			case 2:
    			case 102:
    				m_drawline((long)LINK->gridx2, 0L, (long)LINK->gridx2, (long)histdown);
    				gg.actval = (double)(LINK->gridx2 - histleft) / histdivision;
    				realunit(LINK->gridstr, gg.actval * histgattr[histsecdiv - 1].UU.r +
    						histgattr[histfirsttime - 1].UU.r, 4, "s", true);
    				break;
    
    			case 3:
    			case 103:
    				m_drawline((long)LINK->gridx1, (long)LINK->gridy1, (long)LINK->gridx2,
    						(long)LINK->gridy2);
    				break;
    
    			case 100:
    				m_drawline((long)LINK->gridx1, 0L, (long)LINK->gridx1, (long)histdown);
    				m_drawline((long)LINK->gridx2, 0L, (long)LINK->gridx2, (long)histdown);
    				gg.actval = (double)abs(LINK->gridx2 - LINK->gridx1) / histdivision;
    				if (gg.actval != 0)
    					realunit(LINK->gridstr,
    							1 / (gg.actval * histgattr[histsecdiv - 1].UU.r), 4, "Hz", true);
    				break;
    
    			case 200:
    				m_drawline((long)histleft, (long)LINK->gridy1, (long)across, (long)LINK->gridy1);
    				m_drawline((long)histleft, (long)LINK->gridy2, (long)across, (long)LINK->gridy2);
    				gg.actval2 = (double)LINK->gridy1 / histdivision;
    				gg.actval3 = (double)LINK->gridy2 / histdivision;
    				gg.actval = fabs(gg.actval3 - gg.actval2);
    				calltoolnode(gg.signaltab[gg.actx - 1].np, act_histstr);
    
    				if (*gg.actstr == '\0')
    					realunit(LINK->gridstr, gg.actval, 4, "", true);
    				else
    					strcpy(LINK->gridstr, gg.actstr);
    				break;
    
    			case 201:
    				m_drawline((long)histleft, (long)LINK->gridy2, (long)across, (long)LINK->gridy2);
    				gg.actval = (double)(histgridhn->y - LINK->gridy2) / histdivision;
    				calltoolnode(gg.signaltab[gg.actx - 1].np, act_histstr);
    
    				if (*gg.actstr == '\0')
    					realunit(LINK->gridstr, gg.actval, 4, "", true);
    				else
    					strcpy(LINK->gridstr, gg.actstr);
    				break;
    
    			case 202:
    				LINK->gridtime =
    					(double)(LINK->gridx2 - histleft) / histdivision *
    					histgattr[histsecdiv - 1].UU.r + histgattr[histfirsttime - 1].UU.r;
    				LINK->gridval2 = valueattime(histgridhn, LINK->gridtime, LINK);
    				historyvaluey(histgridhn, LINK->gridval2, &LINK->gridval, &LINK->valuey);
    				m_drawline((long)LINK->gridx2, 0L, (long)LINK->gridx2, (long)histdown);
    				m_drawline((long)histleft, (long)LINK->valuey, (long)across, (long)LINK->valuey);
    				gg.actval = LINK->gridval;
    				gg.actval2 = LINK->gridval2;
    				gg.actval3 = LINK->gridtime;
    				*gg.actstr = '\0';
    				gg.acty = histgridmode;
    				gg.actx = histgridhn->sig;
    				gg.actgattr = histgridhn->attr;
    				calltoolnode(gg.signaltab[gg.actx - 1].np, act_histstr);
    
    				if (*gg.actstr == '\0')
    					strcpy(gg.actstr, realunit(STR1, gg.actval, 4, "", true));
    				sprintf(LINK->gridstr, "%s  ->  %s", realunit(STR1, LINK->gridtime, 4, "s", true), gg.actstr);
    				break;
    
    			case 203:
    				m_drawline((long)LINK->gridx1, (long)LINK->gridy1, (long)LINK->gridx2, (long)LINK->gridy2);
    				if (LINK->gridx1 != LINK->gridx2)
    				{
    					gg.actval2 = (LINK->gridx2 - LINK->gridx1) * histgattr[histsecdiv - 1].UU.r;
    					gg.actval = (LINK->gridy1 - LINK->gridy2) / gg.actval2;
    					gg.actval2 /= histdivision;
    					gg.actval3 = (double)LINK->gridy1 / histdivision;
    					calltoolnode(gg.signaltab[gg.actx - 1].np, act_histstr);
    
    					if (*gg.actstr == '\0')
    						realunit(LINK->gridstr, gg.actval, 4, "", true);
    					else
    						strcpy(LINK->gridstr, gg.actstr);
    					strcat(LINK->gridstr, "/s");
    				}
    				break;
    		}
    
    		m_color((long)gg.color.selword);
    		m_colormode((long)m_normal);
    		clipoff();
    		drawstr2((int)gridpos, LINK->vmenu2, LINK->gridstr);
    
    		do
    		{
    			passetc(LINK);
    		} while (!gg.t.moving);
    
    		m_colormode((long)m_xor);
    		m_color((long)gg.color.selword);
    		clipoff();
    		drawstr2((int)gridpos, LINK->vmenu2, LINK->gridstr);
    		m_color((long)gg.color.scroll);
    
    		switch (histgridwhich * 100 + histgridmode)
    		{
    
    			case 0:
    			case 100:
    				m_drawline((long)LINK->gridx1, 0L, (long)LINK->gridx1, (long)histdown);
    				m_drawline((long)LINK->gridx2, 0L, (long)LINK->gridx2, (long)histdown);
    				break;
    
    			case 1:
    			case 101:
    			case 2:
    			case 102:
    				m_drawline((long)LINK->gridx2, 0L, (long)LINK->gridx2, (long)histdown);
    				break;
    
    			case 3:
    			case 103:
    			case 203:
    				m_drawline((long)LINK->gridx1, (long)LINK->gridy1, (long)LINK->gridx2,
    						(long)LINK->gridy2);
    				break;
    
    			case 200:
    				m_drawline((long)histleft, (long)LINK->gridy1, (long)across,
    						(long)LINK->gridy1);
    				m_drawline((long)histleft, (long)LINK->gridy2, (long)across,
    						(long)LINK->gridy2);
    				break;
    
    			case 201:
    				m_drawline((long)histleft, (long)LINK->gridy2, (long)across,
    						(long)LINK->gridy2);
    				break;
    
    			case 202:
    				m_drawline((long)LINK->gridx2, 0L, (long)LINK->gridx2, (long)histdown);
    				m_drawline((long)histleft, (long)LINK->valuey, (long)across,
    						(long)LINK->valuey);
    				break;
    		}
    		m_colormode((long)m_normal);
    	} while (gg.t.depressed);
    }
    
    
    static void historycommand()
    {
    	struct LOC_historycommand V;
    	short y, i;
    	long t;
    	log_hnrec *hn, *hn0, *hn1, *hn2, *hn1a, *hn2a, *movinghn;
    	uchar ch;
    	char name[256];
    	log_tool *tool;
    	int flag, rmflag, keyflag, savecaps;
    	short scrollpos, scrollmin;
    	double newhistfirsttime;
    	int gridflag;
    	void (*TEMP) ();
    	void (*TEMP5) ();
    	void (*TEMP6) ();
    	char STR2[256];
    	char STR3[256];
    	char TEMP7;
    
    	savecaps = nk_setcapslock(signalcaps);
    	remcursor();
    	clipoff();
    	V.vmenu1 = histdown + 5;
    	V.vmenu2 = V.vmenu1 + 11;
    	gridflag = false;
    	*V.xexpr = '\0';
    	*V.yexpr = '\0';
    	V.xactive = false;
    	V.yactive = true;
    	V.whichmenu = 0;
    	V.rflag = true;
    	rmflag = true;
    	hn = gg.hnbase;
    	while (hn != NULL)
    	{
    		if (hn->y > histdown)
    			hn->y = histaddsignalpos();
    		hn = hn->next;
    	}
    	do
    	{
    		if (V.rflag)
    		{
    			clearscreen();
    			movinghn = NULL;
    			pass();
    			gg.showpage = log_page_history;
    			rmflag = true;
    		}
    		
    		if (rmflag)
    		{
    			uerase(0, histdown + 1, across, down);
    			m_color((long)gg.color.menuword);
    			drawstr2(quit1pos, V.vmenu1, "QUIT");
    			drawstr2(quit2pos, V.vmenu1, "QUIT");
    			switch (V.whichmenu)
    			{
    
    				case 0:
    					drawstr2((int)configpos, V.vmenu1, "Configure");
    					V.oldfast = (gg.fastspeed != gg.fastmax);
    					refrfast(&V);
    					m_color((long)gg.color.menuword);
    					drawstr2((int)dumppos, V.vmenu1, "Dump");
    					drawstr2((int)otherpos, V.vmenu1, "PLOT");
    					V.oldtrigger = !gg.histactive;
    					refrtrigger(&V);
    					V.oldreset = !gg.resetflag;
    					refrreset(&V);
    					V.oldonoff = !gg.pwrflag;
    					refronoff(&V);
    					V.oldgridmode = histgridmode - 1;
    					V.oldgridwhich = histgridwhich - 1;
    					refrgridmode(&V);
    					break;
    
    				case 1:
    					drawstr2((int)exprpos, V.vmenu1, "Expression");
    					drawstr2((int)timepos, V.vmenu1, "Time");
    					drawstr2((int)plotpos, V.vmenu1, "Plot");
    					drawstr2((int)otherpos, V.vmenu1, "SCOPE");
    					refraxes(&V);
    					break;
    			}
    		}
    		if (V.rflag)
    		{
    			drawhistdivisions(histleft, across);
    			drawhistory(&V);
    		}
    		
    		V.rflag = false;
    		rmflag = false;
    		refrgridmode(&V);
    		ch = '\0';
    		do
    		{
    			if (histgattr[histsweeptype - 1].UU.nv == histsweep_contin && gg.histactive)
    			{
    				passetc(&V);
    				flag = (gg.time < histgattr[histfirsttime - 1].UU.r + histdivsacross * histgattr[histsecdiv - 1].UU.r);
    				if (!flag && histonscreen) {
    					histgattr[histfirsttime - 1].UU.r = gg.time - histdivsacross * histgattr[histsecdiv - 1].UU.r * 0.1;
    					ch = ' ';
    				}
    				histonscreen = flag;
    			} else {
    				passetc(&V);
    				histonscreen = false;
    			}
    			if (pollkbd2())
    				ch = inkey2();
    		} while (!(gg.t.dn || ch != '\0'));
    
    		if (gg.t.dn)
    		{
    			remcursor();
    			clipoff();
    			V.gridx1 = gg.t.x;
    			V.gridy1 = gg.t.y;
    			if (gg.t.y > histdown)
    			{
    				if (gg.t.x < configpos - 3)
    					ch = '\003';
    				else if (gg.t.x >= quit2pos - 3)
    					ch = '\003';
    				else if (gg.t.x >= otherpos - 3) {
    					V.whichmenu = (V.whichmenu + 1) & (nummenus - 1);
    					rmflag = true;
    				}
    				else
    				{
    					switch (V.whichmenu)
    					{
    
    						case 0:
    							if (gg.t.x < triggerpos - 3)
    							{
    								confighistmode(&V);
    								V.rflag = true;
    							}
    							else if (gg.t.x < resetpos - 3)
    							{
    								if (gg.histactive)
    								{
    									gg.histactive = false;
    								}
    								else
    								{
    									gg.histactive = true;
    									histreset = true;
    								}
    							}
    							else if (gg.t.x < onoffpos - 3)
    							{
    								gg.resetflag = true;
    							}
    							else if (gg.t.x < gridpos - 3)
    							{
    								gg.pwrflag = !gg.pwrflag;
    							}
    							else if (gg.t.x < gridwpos - 3)
    							{
    								nextgridmode(&V);
    							}
    							else if (gg.t.x < fastpos - 3)
    							{
    								nextgridwhich(&V);
    							}
    							else if (gg.t.x < dumppos - 3)
    							{
    								fastmode(&V);
    							}
    							else if (gg.t.x < nextpos - 3)
    							{
    								dumpcmd(&V);
    							}
    							break;
    
    						case 1:
    							if (gg.t.x < yaxispos - 3)
    							{
    								V.xactive = !V.xactive;
    								V.yactive = false;
    								refraxes(&V);
    							}
    							else if (gg.t.x < exprpos - 3)
    							{
    								V.xactive = false;
    								V.yactive = !V.yactive;
    								refraxes(&V);
    							}
    							else if (gg.t.x < timepos - 3)
    							{
    								getexpr(&V);
    							}
    							else if (gg.t.x < plotpos - 3)
    							{
    								setaxis("Time", &V);
    							}
    							else if (gg.t.x < next2pos - 3)
    							{
    								plotcmd(&V);
    							}
    							break;
    					}
    				}
    			}
    			else if (gg.t.x < histleft - 3)
    			{
    				hn = gg.hnbase;
    				hn0 = NULL;
    				hn1 = NULL;
    				hn2 = NULL;
    				hn1a = NULL;
    				hn2a = NULL;
    				while (hn != NULL)
    				{
    					if (hn->y > gg.t.y - histvscale && hn->y < gg.t.y + histvscale)
    					{
    						if (histgridhn == hn)
    						{
    							hn2 = hn;
    							hn2a = hn0;
    						}
    						else
    						{
    							hn1 = hn;
    							hn1a = hn0;
    						}
    					}
    					hn0 = hn;
    					hn = hn->next;
    				}
    
    				if (hn2 != NULL)
    				{
    					hn = hn2;
    					hn0 = hn2a;
    				}
    				else
    				{
    					hn = hn1;
    					hn0 = hn1a;
    				}
    				
    				if (hn != NULL)
    				{
    					switch (V.whichmenu)
    					{
    
    						case 0:
    							if (justtap())
    							{
    								gg.actnode = gg.signaltab[hn->sig - 1].np;
    								gg.acty = hn->sig;
    								gg.acttool = gg.actnode->simtype;
    								TEMP = hnproc1;
    								TEMP5 = hnproc2;
    								TEMP6 = hnproc3;
    								editattrs(hn->attr, gg.acttool->hnumattrs, gg.acttool->hattr,
    										gg.acttool->hlbl, gg.signaltab[hn->sig - 1].name,
    										TEMP, TEMP5, TEMP6, &V.stamp);
    								V.rflag = true;
    							}
    							else
    							{
    								movinghn = hn;
    								drawsigname(hn, 2, &V);
    								do
    								{
    									hn->y = gg.t.y;
    									flag = (gg.t.y > 0 && gg.t.y < histdown + 3);
    									alignsigname(&hn->y);
    									if (gg.t.y >= histdown)
    										gg.t.y = histdown;
    									if (flag)
    										drawsigname(hn, 3, &V);
    									do
    									{
    										passetc(&V);
    									} while (gg.t.depressed && gg.t.y == gg.t0.y);
    									if (flag)
    										drawsigname(hn, 3, &V);
    								} while (gg.t.depressed);
    
    								if (!flag)
    								{
    									if (gg.traceflag)
    										fprintf(tracefile, "Delete trace %ld\n", (long)hn);
    									if (hn == histgridhn) {
    										histgridwhich = 0;
    										histgridhn = NULL;
    									}
    									tool = gg.signaltab[hn->sig - 1].np->simtype;
    									disposeattrs(&hn->attr, tool->hnumattrs, tool->hattr);
    									if (hn0 == NULL)
    										gg.hnbase = hn->next;
    									else
    										hn0->next = hn->next;
    									Free(hn);
    									reshuffle();
    								}
    								V.rflag = true;
    							}
    							break;
    
    						case 1:
    							setaxis(gg.signaltab[hn->sig - 1].name, &V);
    							break;
    					}
    				}
    			}
    			else
    			{
    				switch (V.whichmenu)
    				{
    
    					case 0:
    						if (justtap())
    						{
    							hn = findtrace(V.gridx1, V.gridy1, &V);
    							if (hn != NULL)
    								setgridwhich(hn, &V);
    						}
    						else
    						{
    							measurecmd(&V);
    						}
    						break;
    
    					case 1:
    						hn = findtrace((int)gg.t.x, (int)gg.t.y, &V);
    						if (hn != NULL)
    							setaxis(gg.signaltab[hn->sig - 1].name, &V);
    						break;
    				}
    			}
    		} else if (ch == 251 || ch == 250 || ch == ' ')
    		{
    			V.rflag = true;
    		}
    		else if (ch == '<')
    		{
    			do
    			{
    				histgattr[histsecdiv - 1].UU.r *= 2;
    				t = timers_sysclock() + knobwait;
    				do
    				{
    				} while (!(timers_sysclock() > t || pollkbd2()));
    				
    				if (testkey2() == '<')
    					ch = inkey2();
    				else
    					V.rflag = true;
    			} while (!V.rflag);
    		}
    		else if (ch == '>')
    		{
    			do
    			{
    				histgattr[histsecdiv - 1].UU.r /= 2;
    				t = timers_sysclock() + knobwait;
    				do
    				{
    				} while (!(timers_sysclock() > t || pollkbd2()));
    				if (testkey2() == '>')
    					ch = inkey2();
    				else
    					V.rflag = true;
    			} while (!V.rflag);
    		}
    		else if (ch < 32 && ((1L << ch) & 0x10000100L) != 0)
    		{
    			scrollpos = 0;
    			gg.actval = -histgattr[histfirsttime - 1].UU.r / histgattr[histsecdiv - 1].UU.r;
    
    			if (gg.actval < -histdivsacross)
    				scrollmin = -across * 2;
    			else
    				scrollmin = (long)floor(gg.actval * histdivision + 0.5);
    
    			do
    			{
    				if (ch == '\b')
    					scrollpos -= hscrollspd * 5;
    				if (ch == '\034')
    					scrollpos += hscrollspd * 5;
    				if (scrollpos < scrollmin)
    					scrollpos = scrollmin;
    				m_colormode((long)m_xor);
    				m_color((long)gg.color.scroll);
    				if (scrollpos > 0)
    					m_drawline(scrollpos + histleft - 1L, 0L, scrollpos + histleft - 1L, (long)histdown);
    				m_drawline(scrollpos + across + 1L, 0L, scrollpos + across + 1L, (long)histdown);
    				m_colormode((long)m_normal);
    				t = timers_sysclock() + knobwait;
    				do
    				{
    				} while (!(timers_sysclock() > t || pollkbd2()));
    				TEMP7 = testkey2();
    
    				if ((uchar)TEMP7 < 32 && ((1L << TEMP7) & 0x10000100L) != 0)
    					ch = inkey2();
    				else
    					ch = ' ';
    
    				m_colormode((long)m_xor);
    				m_color((long)gg.color.scroll);
    				if (scrollpos > 0)
    					m_drawline(scrollpos + histleft - 1L, 0L, scrollpos + histleft - 1L, (long)histdown);
    				m_drawline(scrollpos + across + 1L, 0L, scrollpos + across + 1L, (long)histdown);
    				m_colormode((long)m_normal);
    			} while (ch < 32 && ((1L << ch) & 0x10000100L) != 0 && abs(scrollpos) <= across - histleft - 10);
    
    			if (scrollpos == scrollmin)
    				newhistfirsttime = 0.0;
    			else
    				newhistfirsttime = histgattr[histfirsttime - 1].UU.r +
    					(double)scrollpos / histdivision * histgattr[histsecdiv - 1].UU.r;
    
    			if (histgattr[histfirsttime - 1].UU.r != newhistfirsttime)
    			{
    				histgattr[histfirsttime - 1].UU.r = newhistfirsttime;
    				histgattr[histfirsttime - 1].changed = true;
    				V.rflag = true;
    			}
    			histonscreen = false;
    		}
    		else if (ch == '!')
    		{
    			doshellescape("");
    			V.rflag = true;
    		}
    		else if (ch > ' ')
    		{
    			switch (V.whichmenu)
    			{
    
    				case 0:
    					y = histaddsignalpos();
    					*name = '\0';
    					keyflag = true;
    					do
    					{
    						strcat(name, "_");
    						remcursor();
    						clipoff();
    						m_colormode((long)m_xor);
    						m_color((long)gg.color.signal);
    						drawstr2(0, y - 4, name);
    						m_colormode((long)m_normal);
    						while (!gg.t.dn && !keyflag)
    						{
    							passetc(&V);
    							if (pollkbd2())
    							{
    								ch = inkey2();
    								keyflag = true;
    							}
    						}
    						m_colormode((long)m_xor);
    						m_color((long)gg.color.signal);
    						clipoff();
    						drawstr2(0, y - 4, name);
    						m_colormode((long)m_normal);
    						name[strlen(name) - 1] = '\0';
    						if (keyflag)
    						{
    							keyflag = false;
    							if (ch > ' ' || (ch == ' ' && *name != '\0'))
    								sprintf(name + strlen(name), "%c", ch);
    							if (ch == '\007' && *name != '\0')
    								name[strlen(name) - 1] = '\0';
    						}
    					} while (!((ch < 32 && ((1L << ch) & 0x2008) != 0) || gg.t.dn));
    					sprintf(STR2, "%c", ch);
    					
    					if (!strcmp(STR2, EXEC))
    						*name = '\0';
    					else
    						strcpy(name, strrtrim(strcpy(STR3, name)));
    					
    					remcursor();
    					clipoff();
    					i = getsignal(0, name);
    					if (i != 0)
    					{
    						histaddsignal(&hn, i, y);
    						V.rflag = true;
    					}
    					break;
    
    				case 1:
    					if (V.xactive || V.yactive)
    					{
    						ungetkey2(realkey);
    						getexpr(&V);
    					}
    					break;
    			}
    		}
    	} while (strcmp((sprintf(STR2, "%c", ch), STR2), EXEC));
    	signalcaps = nk_setcapslock(savecaps);
    }
    
    #undef quit1pos
    #undef configpos
    #undef triggerpos
    #undef resetpos
    #undef onoffpos
    #undef gridpos
    #undef gridwpos
    #undef fastpos
    #undef dumppos
    #undef nextpos
    #undef quit2pos
    #undef otherpos
    #undef axiswidth
    #undef xaxispos
    #undef yaxispos
    #undef exprpos
    #undef timepos
    #undef plotpos
    #undef next2pos
    #undef nummenus
    
    
    /* Local variables for savepage: */
    struct LOC_savepage {
    	log_hwrec *firsthwire;
    	log_vwrec *firstvwire;
    	log_nrec *firstnode;
    	short numhw, maxunat;
    } ;
    
    static short countnode(log_nrec *n, struct LOC_savepage *LINK)
    {
    	short i;
    	log_nrec *n1;
    
    	i = 1;
    	n1 = LINK->firstnode;
    	while (n1 != n && n1 != NULL)
    	{
    		i++;
    		n1 = (log_nrec *)n1->temp;
    	}
    	return i;
    }
    
    static short counthw(log_hwrec *hw, struct LOC_savepage *LINK)
    {
    	short i;
    	log_hwrec *hw1;
    
    	i = 1;
    	hw1 = LINK->firsthwire;
    	while (hw1 != hw && hw1 != NULL)
    	{
    		i++;
    		hw1 = (log_hwrec *)hw1->temp;
    	}
    	if (hw1 == NULL)
    		printf("\007Unable to find hwire %ld\n", (long)hw);
    	return i;
    }
    
    static short countvw(log_vwrec *vw, struct LOC_savepage *LINK)
    {
    	short i;
    	log_vwrec *vw1;
    
    	i = 1;
    	vw1 = LINK->firstvwire;
    	while (vw1 != vw && vw1 != NULL)
    	{
    		i++;
    		vw1 = (log_vwrec *)vw1->temp;
    	}
    
    	if (vw1 == NULL)
    		printf("\007Unable to find vwire %ld\n", (long)vw);
    	return (i + LINK->numhw);
    }
    
    static int eqattr(log_kattrrec *ka, log_gattrrec *ga, struct LOC_savepage *LINK)
    {
    	int Result;
    
    	switch (ka->dtype)
    	{
    
    		case 'R':
    		case 'U':
    		case 'F':
    			Result = (ga->blnk == ka->blnk && ga->UU.r == ka->UU.U82.r);
    			break;
    
    		case 'I':
    		case 'H':
    			Result = (ga->blnk == ka->blnk && ga->UU.U73.i1 == ka->UU.U73.i1);
    			break;
    
    		case 'C':
    			Result = (strcmp(ga->UU.c, ka->UU.c) == 0);
    			break;
    
    		case 'A':
    			Result = (strcmp(ga->UU.sp, ka->UU.sp) == 0);
    			break;
    
    		case 'B':
    			Result = (ga->blnk == ka->blnk && ga->UU.b == ka->UU.b);
    			break;
    
    		case 'V':
    			Result = (ga->UU.nv == ka->UU.U86.dv);
    			break;
    	}
    	return Result;
    }
    
    static na_strlist_t *attrname(short i, na_strlist_t *lbl, struct LOC_savepage *LINK)
    {
    	na_strlist_t *l1;
    
    	l1 = lbl;
    	while (l1 != NULL && l1->kind != '\001')
    		l1 = l1->next;
    
    	if (l1 == NULL)
    		return l1;
    	l1 = (na_strlist_t *)l1->value;
    
    	while (l1 != NULL && (long)l1->value != i)
    		l1 = l1->next;
    
    	return l1;
    }
    
    static short countattrs(log_gattrrec *gattr, short numattrs, log_kattrrec *kattr, na_strlist_t *lbl, struct LOC_savepage *LINK)
    {
    	short i, j;
    
    	j = 0;
    	for (i = 1; i <= numattrs; i++)
    	{
    		if (!eqattr(&kattr[i - 1], &gattr[i - 1], LINK) &&
    				attrname(i, lbl, LINK) == NULL)
    			j = i;
    	}
    	LINK->maxunat = j;
    	for (i = j; i < numattrs; i++)
    	{
    		if (!eqattr(&kattr[i], &gattr[i], LINK))
    			j++;
    	}
    	return j;
    }
    
    static void writeattrs(FILE **f, log_gattrrec *gattr, short numattrs, log_kattrrec *kattr, na_strlist_t *lbl, struct LOC_savepage *LINK)
    {
    	short num, i;   /*reads maxunat from last call to countattrs*/
    	na_strlist_t *l1;
    	char STR2[81];
    
    	num = countattrs(gattr, numattrs, kattr, lbl, LINK);
    	for (i = 1; i <= numattrs; i++)
    	{
    		if (i <= LINK->maxunat || !eqattr(&kattr[i - 1], &gattr[i - 1], LINK))
    		{
    			l1 = attrname(i, lbl, LINK);
    			if (l1 != NULL)
    			{
    				fprintf(*f, "[%s] ", l1->s);
    			}
    			if (gattr[i - 1].blnk)
    			{
    				fprintf(*f, "X\n");
    			}
    			else
    			{
    				putc(kattr[i - 1].dtype, *f);
    				switch (kattr[i - 1].dtype)
    				{
    
    					case 'R':
    					case 'U':
    					case 'F':
    						fprintf(*f, "%s\n", realstr(STR2, gattr[i - 1].UU.r, kattr[i - 1].prec));
    						break;
    
    					case 'I':
    					case 'H':
    						fprintf(*f, "%ld\n", gattr[i - 1].UU.U73.i1);
    						break;
    
    					case 'C':
    						fprintf(*f, "%s\n", gattr[i - 1].UU.c);
    						break;
    
    					case 'A':
    						fprintf(*f, "%s\n", gattr[i - 1].UU.sp);
    						break;
    
    					case 'B':
    						fprintf(*f, "%d\n", gattr[i - 1].UU.b);
    						break;
    
    					case 'V':
    						fprintf(*f, "%d\n", gattr[i - 1].UU.nv);
    						break;
    				}
    			}
    		}
    	}
    }
    
    
    static void savepage(short pgnum, char *filename_)
    {
    	struct LOC_savepage V;
    	char filename[256];
    	FILE *f;
    	log_grec *g;
    	log_srec *s, *firstsolder;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_lrec *l, *firstlabel;
    	log_brec *b, *firstbox;
    	log_krec *k;
    	log_hnrec *hn;
    	char buf[256];
    	log_nrec *n1, *lastnode;
    	short i, j, count, numvw, numnodes;
    	char STR1[9];
    	char STR2[256];
    	short FORLIM;
    
    	strcpy(filename, filename_);
    	f = NULL;
    	newci_fixfname(filename, "lgf", "");
    	if (*filename != '\0' && pageempty(pgnum) && access(filename, F_OK) == 0)
    	{
    		sprintf(STR2, "File %s not overwritten with empty page!", filename);
    		message(STR2);
    		*filename = '\0';
    	}
    
    	if (*filename != '\0')
    	{
    		TRY(try24);
    		strcpy(buf, filename);
    		newci_forcefname(buf, "lfo", "");
    		fp_change(filename, buf);
    		RECOVER(try24);
    		if (P_escapecode == -20)
    			_Escape(P_escapecode);
    		ENDTRY(try24);
    		if (f != NULL)
    			f = freopen(filename, "w", f);
    		else
    			f = fopen(filename, "w");
    		if (f == NULL)
    			_EscIO(FileNotFound);
    		fprintf(f, "-5\n");
    		/* if vlsi then
    		   writeln(f, 'f v')
    		   else */
    		fprintf(f, "f s\n");
    		n1 = gg.nbase;
    		while (n1 != NULL)
    		{
    			n1->flag = false;
    			n1 = n1->next;
    		}
    		
    		hw = gg.hwbase[pgnum - 1];
    		while (hw != NULL)
    		{
    			hw->node->flag = true;
    			hw = hw->next;
    		}
    		
    		vw = gg.vwbase[pgnum - 1];
    		while (vw != NULL)
    		{
    			vw->node->flag = true;
    			vw = vw->next;
    		}
    		
    		g = gg.gbase[pgnum - 1];
    		while (g != NULL)
    		{
    			FORLIM = g->kind->numpins;
    			for (i = 0; i < FORLIM; i++)
    				g->pin[i]->flag = true;
    			g = g->next;
    		}
    		
    		numnodes = 0;
    		V.firstnode = NULL;
    		lastnode = NULL;
    		n1 = gg.nbase;
    		while (n1 != NULL)
    		{
    			if (n1->flag)
    			{
    				numnodes++;
    				/* n1^.temp.p := firstnode;
    firstnode := n1; */
    				if (lastnode != NULL)
    					lastnode->temp = (void *)n1;
    				else
    					V.firstnode = n1;
    				n1->temp = NULL;
    				lastnode = n1;
    			}
    			n1 = n1->next;
    		}
    		fprintf(f, "n %d\n", numnodes);
    		n1 = V.firstnode;
    		while (n1 != NULL)
    		{
    			fprintf(f, "%d ", n1->simtype->simtype);
    			fprintf(f, "%d\n", countattrs(n1->attr, n1->simtype->nnumattrs, n1->simtype->nattr,
    						n1->simtype->nlbl, &V));
    			writeattrs(&f, n1->attr, n1->simtype->nnumattrs, n1->simtype->nattr, n1->simtype->nlbl, &V);
    			gg.actfile = &f;
    			gg.actflag = false;
    			calltoolnode(n1, act_writenode);
    			putc('\n', f);
    			n1 = (log_nrec *)n1->temp;
    		}
    
    		/* ensure that each signal has a named gate on this page. */
    		FORLIM = gg.lastsignal;
    		for (i = 0; i < FORLIM; i++)
    			gg.signaltab[i].f = false;
    
    		g = gg.gbase[pgnum - 1];
    		while (g != NULL)
    		{
    			if (g->sig > 0 && g->sig <= gg.lastsignal && gg.signaltab[g->sig -1].np != NULL &&
    					gg.signaltab[g->sig -1].np->flag)
    				gg.signaltab[g->sig -1].f = true;
    			g = g->next;
    		}
    
    		count = 0;
    		for (i = 0; i < FORLIM; i++)
    		{
    			if (gg.signaltab[i].f)
    				count++;
    		}
    
    		fprintf(f, "s %d\n", count);
    		for (i = 0; i < FORLIM; i++)
    		{
    			if (gg.signaltab[i].f)
    				fprintf(f, "%d %s\n",
    						countnode(gg.signaltab[i].np, &V), gg.signaltab[i].name);
    		}
    		V.numhw = 0;
    		hw = gg.hwbase[pgnum - 1];
    		V.firsthwire = NULL;
    		while (hw != NULL)
    		{
    			V.numhw++;
    			hw->temp = (void *)V.firsthwire;
    			V.firsthwire = hw;
    			hw = hw->next;
    		}
    		numvw = 0;
    		vw = gg.vwbase[pgnum - 1];
    		V.firstvwire = NULL;
    		while (vw != NULL)
    		{
    			numvw++;
    			vw->temp = (void *)V.firstvwire;
    			V.firstvwire = vw;
    			vw = vw->next;
    		}
    		fprintf(f, "w %d\n", V.numhw + numvw);
    		hw = V.firsthwire;
    		while (hw != NULL)
    		{
    			fprintf(f, "%d %d %d %d %d %s\n",
    					hw->x1, hw->y, hw->x2, hw->y, countnode(hw->node, &V),
    					colorname(STR1, hw->wcolr));
    			hw = (log_hwrec *)hw->temp;
    		}
    		vw = V.firstvwire;
    		while (vw != NULL)
    		{
    			fprintf(f, "%d %d %d %d %d %s\n",
    					vw->x, vw->y1, vw->x, vw->y2, countnode(vw->node, &V),
    					colorname(STR1, vw->wcolr));
    			vw = (log_vwrec *)vw->temp;
    		}
    		count = 0;
    		s = gg.sbase[pgnum - 1];
    		firstsolder = NULL;
    		while (s != NULL)
    		{
    			count++;
    			s->temp = (void *)firstsolder;
    			firstsolder = s;
    			s = s->next;
    		}
    		fprintf(f, "p %d\n", count);
    		s = firstsolder;
    		while (s != NULL)
    		{
    			fprintf(f, "%d %d", s->x, s->y);
    			if (s->hwire != NULL)
    				fprintf(f, " %d", counthw(s->hwire, &V));
    			if (s->hwire2 != NULL)
    				fprintf(f, " %d", counthw(s->hwire2, &V));
    			if (s->vwire != NULL)
    				fprintf(f, " %d", countvw(s->vwire, &V));
    			if (s->vwire2 != NULL)
    				fprintf(f, " %d", countvw(s->vwire2, &V));
    			putc('\n', f);
    			s = (log_srec *)s->temp;
    		}
    		count = 0;
    		l = gg.lbase[pgnum - 1];
    		firstlabel = NULL;
    		while (l != NULL)
    		{
    			count++;
    			l->temp = (void *)firstlabel;
    			firstlabel = l;
    			l = l->next;
    		}
    		fprintf(f, "l %d\n", count);
    		l = firstlabel;
    		while (l != NULL)
    		{
    			fprintf(f, "%d %d %ld %s\n",
    					l->x, l->y, m_strwidth(logfont_lfont, l->name) / log_scale0,
    					l->name);
    			l = (log_lrec *)l->temp;
    		}
    		count = 0;
    		b = gg.bbase[pgnum - 1];
    		firstbox = NULL;
    		while (b != NULL)
    		{
    			count++;
    			b->temp = (void *)firstbox;
    			firstbox = b;
    			b = b->next;
    		}
    		fprintf(f, "b %d\n", count);
    		b = firstbox;
    		while (b != NULL)
    		{
    			fprintf(f, "%d %d %d %d\n", b->x1, b->y1, b->x2, b->y2);
    			b = (log_brec *)b->temp;
    		}
    		count = 0;
    		g = gg.gbase[pgnum - 1];
    		while (g != NULL)
    		{
    			count++;
    			g = g->next;
    		}
    		fprintf(f, "g %d\n", count);
    		g = gg.gbase[pgnum - 1];
    		while (g != NULL)
    		{
    			k = g->kind;
    			fprintf(f, "%s\n", k->name);
    			i = 0;
    			if (g->sig != 0)
    			{
    				FORLIM = g->sig;
    				for (j = 0; j < FORLIM; j++)
    				{
    					if (gg.signaltab[j].f)
    						i++;
    				}
    			}
    			fprintf(f, "%d %d %d ", g->x, g->y, g->rot);
    			fprintf(f, "%d %ld %d ", g->gc, (long)g->vars, i);
    			fprintf(f, "%d\n", countattrs(g->attr, k->numattrs, k->attr, k->lbl, &V));
    			FORLIM = k->numpins;
    			for (i = 1; i <= FORLIM; i++)
    			{
    				if (i != 1)
    					putc(' ', f);
    				fprintf(f, "%d", countnode(g->pin[i - 1], &V));
    			}
    			putc('\n', f);
    			writeattrs(&f, g->attr, k->numattrs, k->attr, k->lbl, &V);
    			gg.actfile = &f;
    			gg.actflag = false;
    			calltoolgate(g, act_writegate);
    			putc('\n', f);
    			g = g->next;
    		}
    		fprintf(f, "h %d\n", hncount);
    		hn = gg.hnbase;
    		while (hn != NULL)
    		{
    			n1 = gg.signaltab[hn->sig - 1].np;
    			fprintf(f, "%d ", hn->y);
    			fprintf(f, "%d", countattrs(hn->attr, n1->simtype->hnumattrs, n1->simtype->hattr, n1->simtype->hlbl, &V));
    			fprintf(f, " %s\n", gg.signaltab[hn->sig - 1].name);
    			writeattrs(&f, hn->attr, n1->simtype->hnumattrs, n1->simtype->hattr, n1->simtype->hlbl, &V);
    			hn = hn->next;
    		}
    		fprintf(f, ".\n");
    		if (f != NULL)
    			fclose(f);
    		f = NULL;
    		gg.pagechanged[pgnum - 1] = false;
    		if (curfilename[pgnum - 1] == NULL)
    			curfilename[pgnum - 1] = (char *)Malloc(256);
    		strcpy(curfilename[pgnum - 1], filename);
    	}
    	if (f != NULL)
    		fclose(f);
    }
    
    
    static void emergencysave(short pgnum)
    {
    	char filename[256];
    
    	TRY(try25);
    	printf("File name");
    	if (curfilename[pgnum - 1] != NULL)
    		printf("(was %s)", curfilename[pgnum - 1]);
    	printf(": ");
    	gets(filename);
    	if (*filename != '\0')
    		savepage(pgnum, filename);
    	RECOVER(try25);
    	if (P_escapecode == -20)
    		_Escape(P_escapecode);
    	printf("Saving page %d failed.\n", pgnum);
    	ENDTRY(try25);
    }
    
    
    void safesavepage(short pgnum, char *fn)
    {
    	long i, j;
    
    	if (*fn == '\0')
    		return;
    	beginbottom();
    	TRY(try26);
    	printf("Saving file %s\n", fn);
    	m_alpha_on();
    	savepage(pgnum, fn);
    	endbottom();
    	RECOVER(try26);
    	i = P_escapecode;
    	j = P_ioresult;
    	endbottom();
    	beginerror();
    	if (Debugging || debugprint || gg.traceflag)
    		printf("%ld/%ld/%ld   ", i, j, EXCP_LINE);
    	printf("Unable to save file %s\n", fn);
    	char *fn;
    	enderror();
    	ENDTRY(try26);
    }
    
    
    static void savecommand()
    {
    	short pgnum;
    	char filename[256];
    	short FORLIM;
    	char STR1[256];
    	char STR2[256];
    
    	garbagecoll();
    	if (*gg.funcarg == '\0')
    	{
    		FORLIM = gg.numpages;
    		for (pgnum = 1; pgnum <= FORLIM; pgnum++)
    		{
    			if (!pagechanged(pgnum))
    			{
    				sprintf(STR2, "No changes to page %d", pgnum);
    				message(STR2);
    			}
    			else if (curfilename[pgnum - 1] == NULL)
    			{
    				sprintf(STR2, "Page %d: no file name!", pgnum);
    				message(STR2);
    			}
    			else
    			{
    				sprintf(STR1, "Saving page %d", pgnum);
    				message(STR1);
    				safesavepage(pgnum, curfilename[pgnum - 1]);
    			}
    		}
    	}
    	else if (!strcmp(gg.funcarg, "*"))
    	{
    		beginbottom();
    		printf("File name to save: ");
    		if (curfilename[gg.curpage - 1] != NULL)
    			strcpy(filename, curfilename[gg.curpage - 1]);
    		else
    			*filename = '\0';
    		readlnpass(filename, 3);
    		endbottom();
    		if (*filename != '\0')
    			safesavepage((int)gg.curpage, filename);
    	}
    	else
    	{
    		safesavepage((int)gg.curpage, gg.funcarg);
    	}
    	clearfunc();
    }
    
    
    static void namecommand()
    {
    	char filename[256];
    	char STR2[256], STR3[256];
    
    	if (*gg.funcarg == '\0') {
    		beginbottom();
    		printf("File name for page %ld", gg.curpage);
    		if (curfilename[gg.curpage - 1] != NULL)
    			printf(" [%s]", curfilename[gg.curpage - 1]);
    		printf(": ");
    		readlnpass(filename, 0);
    		endbottom();
    	} else if (!strcmp(gg.funcarg, "?"))
    		*filename = '\0';
    	else
    		strcpy(filename, gg.funcarg);
    	if (*filename != '\0') {
    		if (!strcmp(filename, "\"\"") || *strcpy(STR3, strltrim(filename)) == '\0')
    			Free(curfilename[gg.curpage - 1]);
    		else {
    			newci_fixfname(filename, "lgf", "");
    			if (curfilename[gg.curpage - 1] == NULL)
    				curfilename[gg.curpage - 1] = (char *)Malloc(256);
    			strcpy(curfilename[gg.curpage - 1], filename);
    		}
    	}
    	if (curfilename[gg.curpage - 1] == NULL) {
    		sprintf(STR2, "No file name for page %ld", gg.curpage);
    		message(STR2);
    	} else {
    		sprintf(STR2, "Current file name is %s", curfilename[gg.curpage - 1]);
    		message(STR2);
    	}
    	clearfunc();
    }
    
    
    static void loadlog30(FILE **f, short ver)
    {
    	short i, j, x, y, x1, y1, x2, y2;
    	char nam[81];
    	char ch;
    	log_lrec *l;
    	log_brec *b;
    	char *TEMP;
    
    	fscanf(*f, "%*[^\n]");   /*version number*/
    	getc(*f);
    	fscanf(*f, "%c%*[^\n]", &ch);
    	getc(*f);
    	if (ch == '\n')
    		ch = ' ';
    	switch (ch)
    	{
    
    		case 'V':
    		case 'v':
    			vlsi = true;
    			break;
    
    		case 'T':
    		case 't':
    			vlsi = false;
    			break;
    	}
    	fscanf(*f, "%*[^\n]");   /*numnodes, nullnode*/
    	getc(*f);
    	setvlsimode(vlsi);
    	j = gg.color.wire[0];
    	if (vlsi)
    	{
    		fscanf(*f, "%hd%hd%hd%hd%hd%*[^\n]", &x1, &x2, &y, &i, &j);
    		getc(*f);
    	}
    	else
    	{
    		fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x1, &x2, &y, &i);
    		getc(*f);
    	}
    	
    	while (x1 != -9999)
    	{
    		addhwire(x1, x2, y, log_wcol_normal);
    		if (vlsi)
    		{
    			fscanf(*f, "%hd%hd%hd%hd%hd%*[^\n]", &x1, &x2, &y, &i, &j);
    			getc(*f);
    		}
    		else
    		{
    			fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x1, &x2, &y, &i);
    			getc(*f);
    		}
    	}
    
    	if (vlsi)
    	{
    		fscanf(*f, "%hd%hd%hd%hd%hd%*[^\n]", &x, &y1, &y2, &i, &j);
    		getc(*f);
    	}
    	else
    	{
    		fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x, &y1, &y2, &i);
    		getc(*f);
    	}
    	
    	while (x != -9999)
    	{
    		addvwire(x, y1, y2, log_wcol_normal);
    		if (vlsi)
    		{
    			fscanf(*f, "%hd%hd%hd%hd%hd%*[^\n]", &x, &y1, &y2, &i, &j);
    			getc(*f);
    		}
    		else
    		{
    			fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x, &y1, &y2, &i);
    			getc(*f);
    		}
    	}
    	fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x, &y, &i, &j);
    	getc(*f);
    	while (x != -9999)
    	{
    		closerwire(x, y);
    		if (gg.nearhw != NULL && gg.nearvw != NULL)
    		{
    			if (trycombinenodes(&gg.nearvw->node, &gg.nearhw->node))
    			{
    				clipon();
    				addsolder(x, y, gg.nearhw, NULL, gg.nearvw, NULL);
    				clipoff();
    			}
    			else
    			{
    				frysolder(x, y);
    			}
    		}
    		fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x, &y, &i, &j);
    		getc(*f);
    	}
    
    	if (ver >= 3)
    	{
    		fscanf(*f, "%hd%hd%hd%c", &x, &y, &i, &ch);
    		if (ch == '\n')
    			ch = ' ';
    		fgets(nam, 81, *f);
    		TEMP = (char *)strchr(nam, '\n');
    		if (TEMP != NULL)
    			*TEMP = 0;
    	}
    	else
    	{
    		fscanf(*f, "%hd%hd%c", &x, &y, &ch);
    		if (ch == '\n')
    			ch = ' ';
    		fgets(nam, 81, *f);
    		TEMP = (char *)strchr(nam, '\n');
    		if (TEMP != NULL)
    			*TEMP = 0;
    	}
    	
    	while (x != -9999)
    	{
    		newlabel(&l);
    		l->x = x;
    		l->y = y;
    		strcpy(l->name, nam);
    		l->w = m_strwidth(logfont_lfont, l->name) / log_scale0;
    		if (ver >= 3)
    		{
    			fscanf(*f, "%hd%hd%hd%c", &x, &y, &i, &ch);
    			if (ch == '\n')
    				ch = ' ';
    			fgets(nam, 81, *f);
    			TEMP = (char *)strchr(nam, '\n');
    			if (TEMP != NULL)
    				*TEMP = 0;
    		}
    		else
    		{
    			fscanf(*f, "%hd%hd%c", &x, &y, &ch);
    			if (ch == '\n')
    				ch = ' ';
    			fgets(nam, 81, *f);
    			TEMP = (char *)strchr(nam, '\n');
    			if (TEMP != NULL)
    				*TEMP = 0;
    		}
    		if (ch != ':')
    			_Escape(0);
    	}
    	fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x, &y, &x1, &y1);
    	getc(*f);
    	while (x != -9999)
    	{
    		newbox(&b);
    		b->x1 = x;
    		b->y1 = y;
    		b->x2 = x1;
    		b->y2 = y1;
    		fscanf(*f, "%hd%hd%hd%hd%*[^\n]", &x, &y, &x1, &y1);
    		getc(*f);
    	}
    	fscanf(*f, "%hd%hd%hd%hd%hd%hd%hd%c", &i, &x, &y, &y1, &x1, &y2, &x2, &ch);
    	
    	if (ch == '\n')
    		ch = ' ';
    	
    	fgets(nam, 81, *f);
    	TEMP = (char *)strchr(nam, '\n');
    	if (TEMP != NULL)
    		*TEMP = 0;
    
    	while (i != -9999)
    	{
    		if ((unsigned)(i & 127) < 32 && ((1L << (i & 127)) & 0x1800) != 0)
    		{
    			if (i == 11)
    				j = readlibrary("TO");
    			else
    				j = readlibrary("FROM");
    			addgate1(x, y, j + i / 128 * 128);
    			gg.neargate->sig = getsignal(0, nam);
    		}
    		else
    		{
    			j = readlibrary(nam);
    			addgate1(x, y, j + i / 128 * 128);
    		}
    		
    		for (i = 1; i <= y2 + x2; i++)
    		{   /*ignore all pins, attributes!*/
    			fscanf(*f, "%*[^\n]");
    			getc(*f);
    		}
    		
    		fscanf(*f, "%hd%hd%hd%hd%hd%hd%hd%c", &i, &x, &y, &y1, &x1, &y2, &x2, &ch);
    		if (ch == '\n')
    			ch = ' ';
    		fgets(nam, 81, *f);
    		TEMP = (char *)strchr(nam, '\n');
    		if (TEMP != NULL)
    			*TEMP = 0;
    	}
    	chpage((int)gg.curpage);
    }
    
    
    static void readattrs(FILE **f, log_gattrrec **gattr, short numattrs, log_kattrrec *kattr, na_strelist_t *lbl, short count)
    {
    	short j, jj;
    	char ch;
    	char buf[256];
    	na_strlist_t *l1, *names;
    
    	l1 = lbl;
    	while (l1 != NULL && l1->kind != '\001')
    		l1 = l1->next;
    
    	if (l1 != NULL)
    		names = (na_strlist_t *)l1->value;
    	else
    		names = NULL;
    
    	for (j = 1; j <= count; j++)
    	{
    		ch = getc(*f);
    		if (ch == '\n')
    			ch = ' ';
    
    		if (ch == '[')
    		{
    			*buf = '\0';
    			ch = getc(*f);
    
    			if (ch == '\n')
    				ch = ' ';
    
    			while (ch != ']' && !P_eoln(*f))
    			{
    				sprintf(buf + strlen(buf), "%c", ch);
    				ch = getc(*f);
    				if (ch == '\n')
    					ch = ' ';
    			}
    
    			jj = -1;
    			if (!P_eoln(*f))
    			{
    				l1 = names;
    				while (l1 != NULL && strcmp(buf, l1->s))
    					l1 = l1->next;
    
    				if (l1 != NULL)
    					jj = (long)l1->value;
    
    				do
    				{
    					ch = getc(*f);
    					if (ch == '\n')
    						ch = ' ';
    				} while (ch == ' ');
    			}
    		}
    		else
    		{
    			jj = j;
    		}
    
    		if (jj >= 1 && jj <= numattrs)
    		{
    			ch = toupper(ch);
    			if (ch == 'X')
    			{
    				(*gattr)[jj - 1].blnk = true;
    				switch (kattr[jj - 1].dtype)
    				{
    
    					case 'C':
    						*(*gattr)[jj - 1].UU.c = '\0';
    						break;
    
    					case 'A':
    						strchange(&(*gattr)[jj - 1].UU.sp, "");
    						break;
    				}
    			}
    			else
    			{
    				(*gattr)[jj - 1].blnk = false;
    				switch (kattr[jj - 1].dtype)
    				{
    
    					case 'R':
    					case 'U':
    					case 'F':
    						if (ch == 'F' || ch == 'U' || ch == 'R')
    							fscanf(*f, "%lg", &(*gattr)[jj - 1].UU.r);
    						break;
    
    					case 'I':
    					case 'H':
    						if (ch == 'H' || ch == 'I')
    							fscanf(*f, "%ld", &(*gattr)[jj - 1].UU.U73.i1);
    						break;
    
    					case 'C':
    						if (ch == 'A' || ch == 'C')
    						{
    							*buf = '\0';
    							fscanf(*f, "%[^\n]", buf);
    							if (strlen(buf) <= kattr[jj - 1].prec)
    								strcpy((*gattr)[jj - 1].UU.c, buf);
    						}
    						break;
    
    					case 'A':
    						if (ch == 'A' || ch == 'C')
    						{
    							*buf = '\0';
    							fscanf(*f, "%[^\n]", buf);
    							strchange(&(*gattr)[jj - 1].UU.sp, buf);
    						}
    						break;
    
    					case 'B':
    						if (ch == 'B')
    						{
    							ch = getc(*f);
    							if (ch == '\n')
    								ch = ' ';
    							(*gattr)[jj - 1].UU.b = (ch == 't' || ch == 'T' || ch == '1');
    						}
    						break;
    
    					case 'V':
    						if (ch == 'V')
    						{
    							fscanf(*f, "%hd", &(*gattr)[jj - 1].UU.nv);
    							if ((*gattr)[jj - 1].UU.nv >= kattr[jj - 1].UU.U86.nv)
    								(*gattr)[jj - 1].UU.nv = 0;
    						}
    						break;
    				}
    			}
    		}
    		fscanf(*f, "%*[^\n]");
    		getc(*f);
    	}
    }
    
    
    #define rtn             "LOADPAGE"
    
    
    typedef log_nrec *nodearray[log_million];
    
    typedef struct wirerec {
    	int horiz;
    	union {
    		log_hwrec *hw;
    		log_vwrec *vw;
    	} UU;
    } wirerec;
    
    typedef wirerec wirearray[log_million];
    typedef long intarray[log_million];
    
    
    /* Local variables for loadpage: */
    struct LOC_loadpage {
    	char *reason;
    	FILE *f;
    	long *ip;
    	short numnodes;
    	log_nrec **np;
    } ;
    
    static void loadfail(char *msg, struct LOC_loadpage *LINK)
    {
    	if (LINK->f)
    		fclose(LINK->f);
    	if (LINK->ip)
    		Free(LINK->ip);
    	if (msg == NULL)
    		_Escape(0);
    	strcpy(LINK->reason, msg);
    	_Escape(1);
    }
    
    static log_nrec *countnode_(short i, struct LOAC_loadpage *LINK)
    	short i;
    	struct LOC_loadpage *LINK;
    {
    	char STR2[256];
    
    	if (i >= 1 && i <= LINK->numnodes)
    		return (refnode(LINK->np[i - 1]));
    	sprintf(STR2, "Bad node number: %d", i);
    	loadfail(STR2, LINK);
    
    	return NULL; /* should never happen */
    }
    
    
    /* Local variables for initialize: */
    struct LOC_initialize {
    	short j;
    	na_strlist_t *loadgates, *logmenu;
    	char cmdbuf[81];
    	cnfrec *cnflast;
    } ;
    
    
    static int tryfindfile(char *name, char *path, struct LOC_initialize *LINK)
    {
    	int Result;
    	char fname[256];
    	FILE *f;
    	char *ep;
    
    	f = NULL;
    	Result = false;
    	if (*name != '\0' && (*path == '\0' || (name[0] != '*' && name[0] != '/' && name[0] != '%' && name[0] != '~')))
    	{
    		TRY(try31);
    		if (name[0] == '~')
    		{
    			ep = tilde_expand(name);
    			strncpy(fname, ep, 256);
    			Free(ep);
    		}
    		else
    			sprintf(fname, "%s%s", path, name);
    
    		if (f != NULL)
    			f = freopen(fname, "r", f);
    		else
    			f = fopen(fname, "r");
    
    		if (f == NULL)
    		{
    			P_escapecode = -10;
    			P_ioresult = FileNotFound;
    			goto _Ltry31;
    		}
    		strcpy(name, fname);
    		Result = true;
    		RECOVER2(try31,_Ltry31);
    		if (P_escapecode == -20)
    			_Escape(P_escapecode);
    		ENDTRY(try31);
    	}
    	if (f != NULL)
    		fclose(f);
    	return Result;
    }
    
    static int locatefile(char *name, struct LOC_initialize *LINK)
    {
    	char path[256];
    
    	sprintf(path, "%s/", GetChipmunkPath("LOGLIB", LOGLIB));
    	return (tryfindfile(name, "", LINK) ||
    			tryfindfile(name, gg.homedirname, LINK) ||
    			tryfindfile(name, path, LINK));
    }
    
    
    static void loadpage(char *filename_, char *reason_)
    {
    	struct LOC_loadpage V;
    	char filename[256];
    	log_nrec *n, *n1;
    	log_grec *g, *g1;
    	log_srec *s;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_lrec *l;
    	log_brec *b;
    	log_hnrec *hn;
    	short i, j, k, x, y, x1, y1, x2, y2, numwires, count, ver;
    	long ii;
    	cnrec *cnbase;
    	char tempname[256];
    	char labelname[log_lablen + 1];
    	char ch, ch1, ch2;
    	wirerec *wp;
    	char STR2[20];
    	char STR3[18];
    	short FORLIM;
    	char *TEMP;
    
    	strcpy(filename, filename_);
    	V.reason = reason_;
    	V.f = NULL;
    	V.ip = NULL;
    	*V.reason = '\0';
    	if (*filename != '\0')
    	{
    		newci_fixfname(filename, "lgf", "");
    #ifdef LOAD_SEARCH
    		locatefile(filename, NULL);
    #endif
    		if (V.f != NULL)
    			V.f = freopen(filename, "r", V.f);
    		else
    			V.f = fopen(filename, "r");
    		if (V.f == NULL)
    			_EscIO(FileNotFound);
    		fscanf(V.f, "%hd", &ver);
    		ver = -ver;
    		gg.actx = gg.curpage;
    		calltools(act_clear);
    		hw = gg.hwbase[gg.curpage - 1];
    		while (hw != NULL)
    		{
    			gg.hwbase[gg.curpage - 1] = hw->next;
    			stamp(&hw->node->simtype->netstamp);
    			Free(hw);
    			hw = gg.hwbase[gg.curpage - 1];
    		}
    		
    		vw = gg.vwbase[gg.curpage - 1];
    		while (vw != NULL)
    		{
    			gg.vwbase[gg.curpage - 1] = vw->next;
    			stamp(&vw->node->simtype->netstamp);
    			Free(vw);
    			vw = gg.vwbase[gg.curpage - 1];
    		}
    		
    		s = gg.sbase[gg.curpage - 1];
    		while (s != NULL)
    		{
    			gg.sbase[gg.curpage - 1] = s->next;
    			Free(s);
    			s = gg.sbase[gg.curpage - 1];
    		}
    		
    		g = gg.gbase[gg.curpage - 1];
    		while (g != NULL)
    		{
    			gg.gbase[gg.curpage - 1] = g->next;
    			stamp(&g->kind->simtype->netstamp);
    			disposegate(&g);
    			g = gg.gbase[gg.curpage - 1];
    		}
    		
    		l = gg.lbase[gg.curpage - 1];
    		if (l != NULL)
    			stamp(&gg.labelstamp);
    		
    		while (l != NULL)
    		{
    			gg.lbase[gg.curpage - 1] = l->next;
    			Free(l);
    			l = gg.lbase[gg.curpage - 1];
    		}
    		
    		b = gg.bbase[gg.curpage - 1];
    		if (b != NULL)
    			stamp(&gg.boxstamp);
    		
    		while (b != NULL)
    		{
    			gg.bbase[gg.curpage - 1] = b->next;
    			Free(b);
    			b = gg.bbase[gg.curpage - 1];
    		}
    		
    		garbagecoll();
    		stamp(&gg.loadstamp);
    		stamp(&gg.pagestamp[gg.curpage - 1]);
    		if (ver < 5)
    		{
    			loadlog30(&V.f, ver);
    		}
    		else
    		{
    			cnbase = NULL;
    			fscanf(V.f, "%*[^\n]");
    			getc(V.f);
    			fscanf(V.f, "%c%c%c%*[^\n]", &ch, &ch1, &ch2);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (ch1 == '\n')
    				ch1 = ' ';
    			if (ch2 == '\n')
    				ch2 = ' ';
    			if (tolower(ch) != 'f' || ch1 != ' ')
    				loadfail("Bad format line", &V);
    
    			if (tolower(ch2) != 's')
    			{
    				sprintf(STR2, "Bad format name: %c", ch2);
    				loadfail(STR2, &V);
    			}
    			vlsi = false;
    			setvlsimode(vlsi);
    			fscanf(V.f, "%c%hd%*[^\n]", &ch, &V.numnodes);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (tolower(ch) != 'n')
    				loadfail("No node-count line", &V);
    			V.np = (log_nrec **)Malloc(V.numnodes * sizeof(log_nrec *));
    			n = gg.nbase;
    			while (n != NULL && n->next != NULL)
    				n = n->next;
    			FORLIM = V.numnodes;
    			for (i = 0; i < FORLIM; i++)
    			{
    				fscanf(V.f, "%hd%hd%*[^\n]", &j, &x1);
    				getc(V.f);
    				n1 = n;
    				newnode(&n, j);
    				gg.nbase = n->next;
    				if (n1 == NULL)
    					gg.nbase = n;
    				else
    					n1->next = n;
    				n->next = NULL;
    				readattrs(&V.f, &n->attr, n->simtype->nnumattrs, n->simtype->nattr, n->simtype->nlbl, x1);
    				V.np[i] = n;
    				gg.actfile = &V.f;
    				calltoolnode(n, act_readnode);
    				stamp(&n->simtype->netstamp);
    				while (!P_eoln(V.f) && !P_eof(V.f))
    				{
    					fscanf(V.f, "%*[^\n]");
    					getc(V.f);
    				}
    				if (P_eof(V.f))
    					loadfail("End-of-file while reading nodes", &V);
    				fscanf(V.f, "%*[^\n]");
    				getc(V.f);
    			}
    			fscanf(V.f, "%c%hd%*[^\n]", &ch, &count);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (tolower(ch) != 's')
    				loadfail("No signal-count line", &V);
    			V.ip = (long *) Malloc(count * sizeof(long));
    			for (i = 0; i < count; i++)
    			{
    				fscanf(V.f, "%hd%c", &j, &ch);
    				if (ch == '\n')
    					ch = ' ';
    				fgets(tempname, 256, V.f);
    				TEMP = (char *)strchr(tempname, '\n');
    				if (TEMP != NULL)
    					*TEMP = 0;
    				n = V.np[j - 1];
    				x = getsignal(0, tempname);
    				if (x == 0)
    					loadfail(NULL, &V);
    				V.ip[i] = x;
    				queuecombine(&cnbase, &V.np[j - 1], &gg.signaltab[x - 1].np);
    			}
    			fscanf(V.f, "%c%hd%*[^\n]", &ch, &count);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (tolower(ch) != 'w')
    				loadfail("No wire-count line", &V);
    			numwires = count;
    			wp = (wirerec *)Malloc(numwires * sizeof(wirerec));
    			for (i = 0; i < numwires; i++)
    			{
    				fscanf(V.f, "%hd%hd%hd%hd%hd%c%c%*[^\n]", &x1, &y1, &x2, &y2, &j, &ch,
    						&ch1);
    				getc(V.f);
    				if (ch == '\n')
    					ch = ' ';
    				if (ch1 == '\n')
    					ch1 = ' ';
    				switch (ch1)
    				{
    
    					case 'U':
    						x = log_wcol_normal;
    						break;
    
    					case 'G':
    						x = log_wcol_green;
    						break;
    
    					case 'R':
    						x = log_wcol_red;
    						break;
    
    					case 'B':
    						x = log_wcol_blue;
    						break;
    
    					case 'Y':
    						x = log_wcol_yellow;
    						break;
    
    					default:
    						sprintf(STR3, "Bad color name: %c", ch1);
    						loadfail(STR3, &V);
    						break;
    				}
    				
    				n = countnode_(j, &V);
    				if (y1 == y2)
    				{
    					newhw(&hw);
    					hw->x1 = x1;
    					hw->x2 = x2;
    					hw->y = y1;
    					hw->node = n;
    					hw->wcolr = x;
    					wp[i].horiz = true;
    					wp[i].UU.hw = hw;
    				}
    				else if (x1 == x2)
    				{
    					newvw(&vw);
    					vw->x = x1;
    					vw->y1 = y1;
    					vw->y2 = y2;
    					vw->node = n;
    					vw->wcolr = x;
    					wp[i].horiz = false;
    					wp[i].UU.vw = vw;
    				}
    				else
    				{
    					loadfail("Wire is not horizontal or vertical", &V);
    				}
    			}
    			fscanf(V.f, "%c%hd%*[^\n]", &ch, &count);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    
    			if (tolower(ch) != 'p')
    				loadfail("No solder-count line", &V);
    
    			for (i = 1; i <= count; i++)
    			{
    				fscanf(V.f, "%hd%hd", &x, &y);
    				newsolder(&s);
    				s->x = x;
    				s->y = y;
    				while (!P_eoln(V.f))
    				{
    					fscanf(V.f, "%hd", &j);
    					if (wp[j - 1].horiz) {
    						if (s->hwire == NULL)
    							s->hwire = wp[j - 1].UU.hw;
    						else
    							s->hwire2 = wp[j - 1].UU.hw;
    					}
    					else
    					{
    						if (s->vwire == NULL)
    							s->vwire = wp[j - 1].UU.vw;
    						else
    							s->vwire2 = wp[j - 1].UU.vw;
    					}
    				}
    				fscanf(V.f, "%*[^\n]");
    				getc(V.f);
    			}
    			fscanf(V.f, "%c%hd%*[^\n]", &ch, &count);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (tolower(ch) != 'l')
    				loadfail("No label-count line", &V);
    			if (count > 0)
    				stamp(&gg.labelstamp);
    
    			for (i = 1; i <= count; i++)
    			{
    				fscanf(V.f, "%hd%hd%hd%c", &x, &y, &j, &ch);
    				if (ch == '\n')
    					ch = ' ';
    				fgets(labelname, log_lablen + 1, V.f);
    				TEMP = (char *)strchr(labelname, '\n');
    				if (TEMP != NULL)
    					*TEMP = 0;
    				if (ch != ' ')
    					loadfail("Bad label name", &V);
    				newlabel(&l);
    				l->x = x;
    				l->y = y;
    				strcpy(l->name, labelname);
    				l->w = m_strwidth(logfont_lfont, l->name) / log_scale0;
    			}
    			fscanf(V.f, "%c%hd%*[^\n]", &ch, &count);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (tolower(ch) != 'b')
    				loadfail("No box-count line", &V);
    			if (count > 0)
    				stamp(&gg.boxstamp);
    
    			for (i = 1; i <= count; i++)
    			{
    				fscanf(V.f, "%hd%hd%hd%hd%*[^\n]", &x1, &y1, &x2, &y2);
    				getc(V.f);
    				newbox(&b);
    				b->x1 = x1;
    				b->y1 = y1;
    				b->x2 = x2;
    				b->y2 = y2;
    			}
    
    			fscanf(V.f, "%c%hd%*[^\n]", &ch, &count);
    			getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (tolower(ch) != 'g')
    				loadfail("No gate-count line", &V);
    			g = NULL;
    			for (i = 1; i <= count; i++)
    			{
    				fgets(tempname, 256, V.f);
    				TEMP = (char *)strchr(tempname, '\n');
    				if (TEMP != NULL)
    					*TEMP = 0;
    				j = readlibrary(tempname);
    				if (j != 0)
    				{
    					fscanf(V.f, "%hd%hd%hd%hd%ld%hd%hd%*[^\n]", &x, &y, &x1, &y1, &ii,
    							&x2, &y2);
    					getc(V.f);
    					g1 = g;
    					newgate(&g, j + x1 * log_kindoffset);
    					if (g1 == NULL)
    						gg.gbase[gg.curpage - 1] = g;
    					else
    						g1->next = g;
    					g->next = NULL;
    					g->rot = x1;
    					g->x = x;
    					g->y = y;
    					g->gc = y1;
    					g->vars = (na_long)ii;
    					if (x2 == 0)
    						g->sig = 0;
    					else
    						g->sig = V.ip[x2 - 1];
    					stamp(&g->kind->simtype->netstamp);
    					j = 1;
    					while (j <= g->kind->numpins && !P_eoln(V.f))
    					{
    						fscanf(V.f, "%hd", &k);
    						g->pin[j - 1] = countnode_(k, &V);
    						j++;
    					}
    					while (j <= g->kind->numpins)
    					{
    						newnode(&g->pin[j - 1], g->kind->pin[j - 1].s);
    						j++;
    					}
    					fscanf(V.f, "%*[^\n]");
    					getc(V.f);
    					readattrs(&V.f, &g->attr, g->kind->numattrs, g->kind->attr, g->kind->lbl, y2);
    					initpinpos(g);
    					gg.actflag = true;
    					calltoolgate(g, act_connectgate);
    					if (!gg.actflag)
    						report(11, rtn);
    					gg.actfile = &V.f;
    					gg.actflag = true;
    					calltoolgate(g, act_readgate);
    				}
    				while (!P_eoln(V.f) && !P_eof(V.f))
    				{
    					fscanf(V.f, "%*[^\n]");
    					getc(V.f);
    				}
    				if (P_eof(V.f))
    					loadfail("End-of-file while reading gates", &V);
    				fscanf(V.f, "%*[^\n]");
    				getc(V.f);
    			}
    			if (!checkcombine(&cnbase))
    				loadfail("Simtype collision on signal names", &V);
    			ch = getc(V.f);
    			if (ch == '\n')
    				ch = ' ';
    			if (tolower(ch) == 'h')
    			{
    				fscanf(V.f, "%hd%*[^\n]", &count);
    				getc(V.f);
    				histdelsignals();
    				for (i = 1; i <= count; i++)
    				{
    					fscanf(V.f, "%hd%hd%c", &y, &x1, &ch);
    					if (ch == '\n')
    						ch = ' ';
    					fgets(tempname, 256, V.f);
    					TEMP = (char *)strchr(tempname, '\n');
    					if (TEMP != NULL)
    						*TEMP = 0;
    					x = getsignal(0, tempname);
    					if (x == 0)
    						loadfail(NULL, &V);
    					n = gg.signaltab[x - 1].np;
    					histaddsignal(&hn, x, y);
    					readattrs(&V.f, &hn->attr, n->simtype->hnumattrs, n->simtype->hattr,
    							n->simtype->hlbl, x1);
    				}
    				ch = getc(V.f);
    				if (ch == '\n')
    					ch = ' ';
    			}
    			if (tolower(ch) != '.')
    				loadfail("No end line in file", &V);
    		}
    		if (V.f != NULL)
    			fclose(V.f);
    		V.f = NULL;
    		if (V.ip != NULL)
    			Free(V.ip);
    		chpage((int)gg.curpage);
    		gg.pagechanged[gg.curpage - 1] = false;
    		if (curfilename[gg.curpage - 1] == NULL)
    			curfilename[gg.curpage - 1] = (char *)Malloc(256);
    		strcpy(curfilename[gg.curpage - 1], filename);
    	}
    }
    
    #undef rtn
    
    
    #define catsize         21
    #define maxdirmax       45
    #define maxdircol       8
    
    
    typedef misc_catentry catarray[catsize];
    typedef char dirarray[maxdirmax + 1][fidleng + 1];
    
    
    /*=================  LOADCOMMAND  ================*/
    /*=                                              =*/
    /*=  Load circuit page from disk.  Previous      =*/
    /*=     contents of current page are lost.       =*/
    /*=                                              =*/
    /*================================================*/
    
    static void loadcommand()
    {
    	short i, j, x, y, x1, y1, dirmax, dircol;
    	char filename[256];
    	char ch;
    	char name[fidleng + 1];
    	misc_catentry *cat;
    	char (*dirs[maxdircol + 1])[fidleng + 1];
    	char STR3[256];
    
    	dircol = P_imin2((txacross - 14L) / 15, (long)maxdircol);
    	dirmax = -1;
    	cat = NULL;
    	for (i = 0; i <= dircol; i++)
    		dirs[i] = NULL;
    	if (!strcmp(gg.funcarg, "*"))
    	{
    		beginbottom();
    		printf("Name of file to load: ");
    		readlnpass(filename, 0);
    		endbottom();
    	}
    	else if (*gg.funcarg == '\0')
    	{
    		clearshowalpha();
    		if (cat != NULL)
    			Free(cat);
    		nk_gotoxy(5, txdown - 1);
    		printf("Press ENTER alone to abort command.\n");
    		nk_gotoxy(2, txdown - 2);
    		printf("Name of file to load: ");
    		*filename = '\0';
    		ch = '\015';
    		do
    		{
    			do
    			{
    				x = (gg.t.ax - 2) / 15;
    				y = gg.t.ay - 2;
    				/*  x := (gg.t.x-22) div 90;
    y := (gg.t.y-46) div 15;
    if gg.t.x < 22 then x := 0;
    if gg.t.y < 46 then y := 0; */
    				if (x < 0 || (unsigned)y > dirmax || x > dircol || dirs[x] == NULL || *dirs[x][y] == '\0')
    				{
    					x = -1;
    				}
    				else
    				{
    					nk_gotoxy(x * 15 + 2, y + 2);
    					printf("%c%s%c", chrinverse, dirs[x][y], chrplain);
    				}
    
    				if (gg.t.near_ && gg.t.inalpha)
    					nk_gotoxy(gg.t.ax, gg.t.ay);
    				else
    					nk_gotoxy((int)(strlen(filename) + 24), txdown - 2);
    				
    				nc_cursor_on();
    				do
    				{
    					pass();
    					pen();
    					x1 = (gg.t.ax - 2) / 15;
    					y1 = gg.t.ay - 2;
    					/* x1 := (gg.t.x-22) div 90;
    y1 := (gg.t.y-46) div 15;
    if gg.t.x < 22 then x1 := 0;
    if gg.t.y < 46 then y1 := 0; */
    					if (y1 < 0 || x1 < 0 || y1 > dirmax || x1 > dircol || dirs[x1] == NULL || *dirs[x1][y1] == '\0')
    						x1 = -1;
    				} while (!(pollkbd2() || gg.t.dn || x != x1 || y != y1) && gg.t.near_);
    				nc_cursor_off();
    				remcursor();
    				if (x != -1)
    				{
    					nk_gotoxy(x * 15 + 2, y + 2);
    					fputs(dirs[x][y], stdout);
    				}
    			} while (!(pollkbd2() || gg.t.dn));
    
    			if (gg.t.dn && x != -1)
    			{
    				strcpy(filename, dirs[x][y]);
    				nk_gotoxy(24, txdown - 2);
    				printf("%s\t", filename);
    			}
    
    			if (gg.t.dn)
    				ch = '\015';
    			else
    				ch = inkey2();
    
    			if (ch == '\007' && *filename != '\0')
    			{
    				nk_gotoxy((int)(strlen(filename) + 23), txdown - 2);
    				putchar(' ');
    				filename[strlen(filename) - 1] = '\0';
    			}
    			else if (ch >= ' ' && ch <= '~' && strlen(filename) < 255)
    			{
    				nk_gotoxy((int)(strlen(filename) + 24), txdown - 2);
    				putchar(ch);
    				strcat(filename, " ");
    				filename[strlen(filename) - 1] = ch;
    			}
    		} while ((uchar)ch >= 32 || ((1L << ch) & 0x2008) == 0);
    
    		for (i = 0; i <= dircol; i++)
    		{
    			if (dirs[i] != NULL)
    				Free(dirs[i]);
    		}
    		
    		sprintf(STR3, "%c", ch);
    		if (!strcmp(STR3, EXEC))
    			*filename = '\0';
    		clearalpha();
    		
    		if (m_autoraise)
    		{
    		}
    		else
    		{
    			m_graphics_on();
    		}
    	}
    	else
    	{
    		strcpy(filename, gg.funcarg);
    	}
    
    	if (*filename != '\0')
    	{
    		beginbottom();
    		TRY(try27);
    		printf("Loading file %s\n", filename);
    		m_alpha_on();
    		loadpage(filename, name);
    		endbottom();
    		RECOVER(try27);
    		i = P_escapecode;
    		j = P_ioresult;
    		endbottom();
    		beginerror();
    		if (Debugging || debugprint || gg.traceflag)
    			printf("%d/%d/%ld  ", i, j, EXCP_LINE);
    		if (i == -10 && (unsigned)j < 32 && ((1L << j) & 0x600) != 0)
    			printf("Can't find file \"%s\"\n", filename);
    		else if (i == -20)
    			printf("STOP key pressed while loading file.\n");
    		else if (i > 0)
    			printf("Format error in file \"%s\" (%s)\n", filename, name);
    		else
    			printf("Unable to load file \"%s\"\n", filename);
    		enderror();
    		ENDTRY(try27);
    	}
    	clearfunc();
    	refrscreen();
    }
    
    #undef catsize
    #undef maxdirmax
    #undef maxdircol
    
    
    typedef long intarray_[log_million];
    
    
    /* Local variables for readlgf: */
    struct LOC_readlgf {
    	char *reason;
    	FILE **f;
    	long *ip;
    } ;
    
    static void loadfail_(char *msg, struct LOC_readlgf *LINK)
    {
    	if (*LINK->f)
    		fclose(*LINK->f);
    	if (LINK->ip)
    		Free(LINK->ip);
    	if (msg == NULL)
    		_Escape(0);
    	strcpy(LINK->reason, msg);
    	_Escape(1);
    }
    
    
    static void readlgf(FILE **f, char *reason_)
    {
    	struct LOC_readlgf V;
    	char buf[256];
    	char ch;
    	long i, j, k, m, n, ii;
    	short x1, y1, x2, y2;
    	log_grec *g;
    	log_hnrec *hn;
    	log_nrec *n1;
    	char *TEMP;
    	char STR2[38];
    
    	V.reason = reason_;
    	V.f = f;
    	V.ip = NULL;
    	fgets(buf, 256, *V.f);
    	TEMP = (char *)strchr(buf, '\n');
    	if (TEMP != NULL)
    		*TEMP = 0;
    	if (strcmp(buf, "f s"))
    		loadfail_("Not an LGF file", &V);
    	do
    	{
    		while (P_eoln(*V.f) && !P_eof(*V.f))
    		{
    			fscanf(*V.f, "%*[^\n]");
    			getc(*V.f);
    		}
    		do
    		{
    			if (P_eof(*V.f))
    				ch = '.';
    			else {
    				ch = getc(*V.f);
    				if (ch == '\n')
    					ch = ' ';
    			}
    		} while (ch == ' ');
    
    		switch (tolower(ch))
    		{
    
    			case '#':   /*comment*/
    				fscanf(*V.f, "%*[^\n]");
    				getc(*V.f);
    				break;
    
    			case 'n':   /*nodes*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				for (j = 1; j <= i; j++) {
    					fscanf(*V.f, "%ld%ld%*[^\n]", &m, &n);
    					getc(*V.f);   /*simtype, num attrs*/
    					for (m = 1; m <= n; m++)
    					{   /*skip attributes*/
    						fscanf(*V.f, "%*[^\n]");
    						getc(*V.f);
    					}
    					while (!P_eoln(*V.f) && !P_eof(*V.f))
    					{   /*skip simtype info*/
    						fscanf(*V.f, "%*[^\n]");
    						getc(*V.f);
    					}
    				}
    				break;
    
    			case 's':   /*signal names*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				V.ip = (long *)Malloc(i * sizeof(long) );
    				for (j = 0; j < i; j++)
    				{
    					fscanf(*V.f, "%ld%c", &n, &ch);
    					if (ch == '\n')
    						ch = ' ';
    					fgets(buf, 256, *V.f);
    					TEMP = (char *)strchr(buf, '\n');
    					if (TEMP != NULL)
    						*TEMP = 0;
    					V.ip[j] = getsignal(0, buf);
    					if (V.ip[j] == 0)
    						loadfail_(NULL, &V);
    				}
    				break;
    
    			case 'w':   /*wires*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				for (j = 1; j <= i; j++)
    				{
    					fscanf(*V.f, "%hd%hd%hd%hd%*[^\n]", &x1, &y1, &x2, &y2);
    					getc(*V.f);   /*skip node & color info*/
    					if (x1 != x2)
    						addhwire2(x1, x2, y1);
    					else if (y1 != y2)
    						addvwire2(x1, y1, y2);
    				}
    				break;
    
    			case 'p':   /*solder*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				for (j = 1; j <= i; j++)
    				{
    					fscanf(*V.f, "%hd%hd%*[^\n]", &x1, &y1);
    					getc(*V.f);   /*skip over wire numbers*/
    					solderat(x1, y1);
    				}
    				break;
    
    			case 'l':   /*labels*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				for (j = 1; j <= i; j++)
    				{
    					fscanf(*V.f, "%hd%hd%ld%c", &x1, &y1, &k, &ch);
    					if (ch == '\n')
    						ch = ' ';
    					fgets(buf, 256, *V.f);
    					TEMP = (char *) strchr(buf, '\n');
    					if (TEMP != NULL)
    						*TEMP = 0;
    					if (ch != ' ')
    						loadfail_("Bad label name", &V);
    					addlabelat(x1, y1, buf);
    				}
    				break;
    
    			case 'b':   /*boxes*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				for (j = 1; j <= i; j++)
    				{
    					fscanf(*V.f, "%hd%hd%hd%hd%*[^\n]", &x1, &y1, &x2, &y2);
    					getc(*V.f);
    					addboxat(x1, y1, x2, y2);
    				}
    				break;
    
    			case 'g':   /*gates*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				for (j = 1; j <= i; j++)
    				{
    					fgets(buf, 256, *V.f);
    					TEMP = (char *)strchr(buf, '\n');
    					if (TEMP != NULL)
    						*TEMP = 0;
    					k = readlibrary(buf);
    					if (k != 0) {
    						fscanf(*V.f, "%hd%hd%hd%hd%ld%ld%ld%*[^\n]", &x1, &y1, &x2, &y2, &ii, &m, &n);
    						getc(*V.f);
    						addgate1(x1, y1, (int)(k + x2 * log_kindoffset));
    						if (gg.neargate != NULL)
    						{
    							g = gg.neargate;
    							g->gc = y2;
    							g->vars = (na_long)ii;
    							if (m != 0)
    								settofrom(&g, gg.signaltab[ V.ip[m - 1] - 1].name);
    							fscanf(*V.f, "%*[^\n]");   /*ignore pins*/
    							getc(*V.f);
    							readattrs(V.f, &g->attr, g->kind->numattrs, g->kind->attr,
    									g->kind->lbl, (int)n);
    							gg.actfile = V.f;
    							gg.actflag = false;
    							calltoolgate(g, act_readgate);
    						}
    					}
    					while (!P_eoln(*V.f) && !P_eof(*V.f))
    					{
    						fscanf(*V.f, "%*[^\n]");
    						getc(*V.f);
    					}
    					
    					if (P_eof(*V.f))
    						loadfail_("End-of-file while reading gates", &V);
    					fscanf(*V.f, "%*[^\n]");
    					getc(*V.f);
    				}
    				break;
    
    			case 'h':   /*history names*/
    				fscanf(*V.f, "%ld%*[^\n]", &i);
    				getc(*V.f);
    				histdelsignals();
    				for (j = 1; j <= i; j++)
    				{
    					fscanf(*V.f, "%hd%hd%c", &y1, &x1, &ch);
    					if (ch == '\n')
    						ch = ' ';
    					fgets(buf, 256, *V.f);
    					TEMP = (char *)strchr(buf, '\n');
    					if (TEMP != NULL)
    						*TEMP = 0;
    					x2 = getsignal(0, buf);
    					if (x2 == 0)
    						loadfail_(NULL, &V);
    					n1 = gg.signaltab[x2 - 1].np;
    					histaddsignal(&hn, x2, y1);
    					readattrs(V.f, &hn->attr, n1->simtype->hnumattrs, n1->simtype->hattr, n1->simtype->hlbl, x1);
    				}
    				break;
    
    			case '.':
    				/* blank case */
    				break;
    
    			default:
    				sprintf(STR2, "Don't understand header character: %c", ch);
    				loadfail_(STR2, &V);
    				break;
    		}
    	} while (ch != '.');
    	if (V.ip != NULL)
    		Free(V.ip);
    }
    
    
    /* Local variables for readpage: */
    struct LOC_readpage {
    	char *reason;
    } ;
    
    static void loadfail__(char *msg, struct LOC_radpage *LINK)
    {
    	strcpy(LINK->reason, msg);
    	_Escape(1);
    }
    
    
    static void readpage(char *filename_, char *reason_)
    {
    	struct LOC_readpage V;
    	char filename[256];
    	FILE *f;
    	char buf[256];
    	char *TEMP;
    
    	strcpy(filename, filename_);
    	V.reason = reason_;
    	f = NULL;
    	*V.reason = '\0';
    	newci_fixfname(filename, "lgf", "");
    	if (f != NULL)
    		f = freopen(filename, "r", f);
    	else
    		f = fopen(filename, "r");
    	if (f == NULL)
    		_EscIO(FileNotFound);
    	fgets(buf, 256, f);
    	TEMP = (char *)strchr(buf, '\n');
    	if (TEMP != NULL)
    		*TEMP = 0;
    	if (!strcmp(buf, "-5"))
    		readlgf(&f, V.reason);
    	else if (*buf == '-')
    		loadfail__("Unable to read old-format files", &V);
    	else
    		loadfail__("Not an LGF file", &V);
    	if (f != NULL)
    		fclose(f);
    	f = NULL;
    	chpage((int)gg.curpage);
    	gg.pagechanged[gg.curpage - 1] = false;
    	if (curfilename[gg.curpage - 1] == NULL)
    		curfilename[gg.curpage - 1] = (char *)Malloc(256);
    	strcpy(curfilename[gg.curpage - 1], filename);
    	if (f != NULL)
    		fclose(f);
    }
    
    
    static void readcommand()
    {
    	char filename[256], reason[256];
    	long i, j;
    
    	if (*gg.funcarg == '\0' || !strcmp(gg.funcarg, "*"))
    	{
    		beginbottom();
    		printf("Name of file to read: ");
    		readlnpass(filename, 0);
    		endbottom();
    	}
    	else
    	{
    		strcpy(filename, gg.funcarg);
    	}
    
    	if (*filename != '\0')
    	{
    		beginbottom();
    		printf("Reading file %s\n", filename);
    		deleverything();
    		garbagecoll();
    		TRY(try28);
    		m_alpha_on();
    		readpage(filename, reason);
    		endbottom();
    		RECOVER(try28);
    		i = P_escapecode;
    		j = P_ioresult;
    		endbottom();
    		beginerror();
    		if (Debugging || debugprint || gg.traceflag)
    			printf("%ld/%ld/%ld  ", i, j, EXCP_LINE);
    
    		if (i == -10 && (unsigned long)j < 32 && ((1L << j) & 0x600) != 0)
    			printf("Can't find file \"%s\"\n", filename);
    		else if (i == -20)
    			printf("STOP key pressed while reading file.\n");
    		else if (i > 0)
    			printf("Format error in file \"%s\" (%s)\n", filename, reason);
    		else
    			printf("Unable to read file \"%s\"\n", filename);
    		enderror();
    		ENDTRY(try28);
    	}
    	clearfunc();
    }
    
    
    static void singlestep()
    {
    	gg.singlestepcount = getint(gg.funcarg, 1L);
    	steppingoff = gg.pwrflag;
    	gg.pwrflag = true;
    	gg.refrflag = true;
    }
    
    
    static void getgatecmd()
    {
    	short i;
    	char name[9];
    
    	do
    	{
    		getword(gg.funcarg, name);
    		if (*name != '\0')
    			i = readlibrary(name);
    	} while (*name != '\0');
    	clearfunc();
    }
    
    
    static void makegatecmd()
    {
    	short i;
    	char name[9];
    
    	do
    	{
    		getword(gg.funcarg, name);
    		if (*name != '\0') {
    			i = readlibrary(name);
    			if (i != 0)
    				uaddgate(0, 0, i);
    		}
    	} while (*name != '\0');
    	clearfunc();
    }
    
    
    #define maxtools        23
    
    
    /* Local variables for toolcommand: */
    struct LOC_toolcommand {
    	log_tool *ta[maxtools + 1];
    	int refrflag, wasselected;
    } ;
    
    static void describe(long i, LOC_toolcommand *LINK)
    {
    	if (LINK->ta[i] == NULL)
    		return;
    	remcursor();
    	nk_gotoxy(4, (int)i);
    	if (LINK->ta[i]->ready)
    		putchar(chryellow);
    	printf("%16s   ", LINK->ta[i]->name);
    	fputs(LINK->ta[i]->comment, stdout);
    	printf("%c\n", chrgreen);
    }
    
    static long which(struct LOC_toolcommand *LINK)
    {
    	if (gg.t.near_ && gg.t.ay >= 1 && gg.t.ay <= maxtools)
    		return (gg.t.ay);
    	else
    		return -1;
    }
    
    static void selecttool(char *name, struct LOC_toolcommand *LINK)
    {
    	log_tool *tp;
    
    	tp = findtool(name);
    	if (!tp->ready)
    	{
    		warning();
    		return;
    	}
    	
    	calltool(tp, act_select);
    	if (!tp->keep)
    		closetool(tp);
    	LINK->refrflag = true;
    	LINK->wasselected = true;
    }
    
    static void toolcommand()
    {
    	struct LOC_toolcommand V;
    	log_tool *tp;
    	long i, j, numtools;
    	int exitflag;
    	char ch;
    
    	V.wasselected = false;
    	if (*gg.funcarg != '\0')
    	{
    		selecttool(gg.funcarg, &V);
    	}
    	else
    	{
    		do
    		{
    			for (i = 0; i <= maxtools; i++)
    				V.ta[i] = NULL;
    			numtools = 0;
    			tp = gg.toolbase;
    			while (tp != NULL)
    			{
    				if (*tp->comment != '\0' && numtools < maxtools)
    				{
    					numtools++;
    					V.ta[numtools + 1] = tp;
    				}
    				tp = tp->next;
    			}
    			clearshowalpha();
    			printf("LOG tools available:\n");
    			for (i = 0; i <= maxtools; i++)
    				describe(i, &V);
    			exitflag = false;
    			V.refrflag = false;
    			do
    			{
    				do
    				{
    					j = which(&V);
    					if (j >= 0)
    					{
    						putchar(chrinverse);
    						describe(j, &V);
    						putchar(chrplain);
    					}
    					
    					if (gg.t.near_ && gg.t.inalpha)
    						nk_gotoxy(gg.t.ax, gg.t.ay);
    					else
    						noblink();
    					
    					do
    					{
    						pass();
    						pen();
    					} while (!(which(&V) != j || gg.t.dn || pollkbd2()));
    					
    					if (j >= 0)
    						describe(j, &V);
    				}
    				while (!(gg.t.dn || pollkbd2()));
    				nk_gotoxy(0, txdown);
    				
    				if (pollkbd2())
    					ch = toupper(inkey2());
    				else
    					ch = '\0';
    				
    				if (gg.t.dn)
    				{
    					switch (j)
    					{
    
    						case -1:
    							ch = '\003';
    							break;
    
    						default:
    							ch = (char)(j + 64);
    							if (V.ta[ch - 64] == NULL)
    								ch = '\003';
    							break;
    					}
    				}
    
    				if (ch >= 'A' && ch <= 'X')
    				{
    					tp = V.ta[ch - 64];
    					if (tp != NULL)
    					{
    						selecttool(tp->name, &V);
    						exitflag = true;
    					}
    				}
    				else if (ch == '\003' || ch == '\015' || ch == ' ')
    				{
    					exitflag = true;
    				}
    			} while (!(V.refrflag || exitflag));
    		} while (!exitflag);
    	}
    	clearalpha();
    	if (V.wasselected)
    	{
    		m_graphics_on();
    		refresh();
    	}
    	m_graphics_on();
    }
    
    #undef maxtools
    
    
    #define whichmin        (-2)
    
    
    static log_tool *counttool(long i)
    {
    	log_tool *tp;
    
    	tp = gg.toolbase;
    	while (tp->nostatus)
    		tp = tp->next;
    	while (i > 1)
    	{
    		tp = tp->next;
    		if (!tp->nostatus)
    			i--;
    	}
    	return tp;
    }
    
    static char *onoff(Result, b)
    	char *Result;
    	int b;
    {
    	if (b)
    		return strcpy(Result, "ON ");
    	else
    		return strcpy(Result, "OFF");
    }
    
    static void status_log()
    {
    	timerec time;
    	daterec date;
    	char STR2[9];
    	char STR3[81];
    	char * months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
    		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    
    	if (gg.actflag)
    	{
    		sysdate(&date);
    		printf("   Date %2d-%s-%02d   Time\n",
    				date.day, months[date.month - 1], date.year);
    		printf("   Available memory:   \n\n");
    		printf("   Simulation time:    \n");
    		printf("   Simulation timestep:\n");
    		printf("   Simulation status:  \n\n\n");
    		printf("   Invisible mode %s", onoff(STR2, gg.invisible));
    		printf("     Invisible labels %s", onoff(STR2, gg.textinvisible));
    		printf("   Glow mode %s\n", onoff(STR2, gg.glowmode));
    		printf("   Simulation %s", onoff(STR2, gg.pwrflag));
    		printf("         Snap-to-grid %s", onoff(STR2, snapflag));
    		printf("       Markers %s\n", onoff(STR2, gg.markers));
    		printf("   Quiet mode %s", onoff(STR2, gg.quiet));
    		printf("         Verbose mode %s", onoff(STR2, gg.verbose));
    		printf("       Trace mode %s\n", onoff(STR2, gg.traceflag));
    		nk_gotoxy(0, txdown - 3);
    		printf("Use the arrow keys to view status pages.  Press the space bar to quit.\n");
    		status_oldtime = -1.0;
    		status_oldtstep = -1.0;
    		status_oldmem = -1;
    	}
    
    	if (labs(timers_sysclock() - gg.actx) > 50)
    	{
    		nk_gotoxy(25, 4);
    		systime(&time);
    		printf("%2d:%02d:%02ld", time.hour, time.minute, time.centisecond / 100L);
    		gg.actx = timers_sysclock();
    	}
    
    	if (memavail() != status_oldmem)
    	{
    		nk_gotoxy(23, 5);
    		printf("%ld", memavail());
    		status_oldmem = memavail();
    	}
    
    	if (gg.time != status_oldtime)
    	{
    		nk_gotoxy(23, 7);
    		printf("%s\t", realunit(STR3, gg.time, 4, "sec", false));
    		status_oldtime = gg.time;
    	}
    
    	if (gg.prevtimestep != status_oldtstep)
    	{
    		nk_gotoxy(23, 8);
    		printf("%s\t", realunit(STR3, gg.prevtimestep, 4, "sec", false));
    		status_oldtstep = gg.prevtimestep;
    	}
    
    	if (gg.simstate == gg.oldsimstate && gg.simstatetool == gg.oldsimstatetool)
    		return;
    	nk_gotoxy(23, 9);
    
    	switch (gg.simstate)
    	{
    
    		case simst_off:
    			printf("Off\t");
    			break;
    
    		case simst_notactive:
    			printf("Not active\t");
    			break;
    
    		case simst_notready:
    			printf("Halted (%s)\t", gg.simstatetool->shortname);
    			break;
    
    		case simst_running:
    			if (gg.simstatetool == NULL)
    				printf("Running (scope-mode interpolation)\t");
    			else
    				printf("Running (%s)\t", gg.simstatetool->shortname);
    			break;
    
    		default:
    			break;
    	}
    }
    
    
    static void status_mem()
    {
    	long i, j;
    	log_grec *g;
    	log_hwrec *hw;
    	log_vwrec *vw;
    	log_lrec *l;
    	log_brec *b;
    	log_nrec *n;
    	long FORLIM;
    
    	if (!gg.actflag)
    		return;
    
    	printf("          gates  wires labels  boxes  changed  filename\n");
    	for (i = 0; i <= 8; i++)
    	{
    		if (i + 1 == gg.curpage)
    			putchar(chryellow);
    		printf("Page %ld -- ", i + 1);
    		if (i + 1 <= gg.numpages)
    		{
    			g = gg.gbase[i];
    			j = 0;
    			while (g != NULL)
    			{
    				j++;
    				g = g->next;
    			}
    			printf("%4ld", j);
    			hw = gg.hwbase[i];
    			j = 0;
    			while (hw != NULL)
    			{
    				j++;
    				hw = hw->next;
    			}
    			vw = gg.vwbase[i];
    			while (vw != NULL)
    			{
    				j++;
    				vw = vw->next;
    			}
    			printf("%7ld", j);
    			l = gg.lbase[i];
    			j = 0;
    			while (l != NULL)
    			{
    				j++;
    				l = l->next;
    			}
    			printf("%7ld", j);
    			b = gg.bbase[i];
    			j = 0;
    			while (b != NULL)
    			{
    				j++;
    				b = b->next;
    			}
    			printf("%7ld     ", j);
    			
    			if (pagechanged((int)(i + 1)))
    				printf("Yes    ");
    			else
    				printf("No     ");
    			
    			if (curfilename[i] != NULL)
    				fputs(curfilename[i], stdout);
    		}
    		else
    		{
    			printf("Empty.");
    		}
    		printf("%c\n", chrgreen);
    	}
    	printf("\nPaste  -- ");
    	if (copybuf.valid)
    	{
    		g = copybuf.gcopy;
    		j = 0;
    		while (g != NULL)
    		{
    			j++;
    			g = g->next;
    		}
    		printf("%4ld", j);
    		hw = copybuf.hwcopy;
    		j = 0;
    		while (hw != NULL)
    		{
    			j++;
    			hw = hw->next;
    		}
    		vw = copybuf.vwcopy;
    		while (vw != NULL)
    		{
    			j++;
    			vw = vw->next;
    		}
    		printf("%7ld", j);
    		l = copybuf.lcopy;
    		j = 0;
    		while (l != NULL)
    		{
    			j++;
    			l = l->next;
    		}
    		printf("%7ld", j);
    		b = copybuf.bcopy;
    		j = 0;
    		while (b != NULL)
    		{
    			j++;
    			b = b->next;
    		}
    		printf("%7ld\n", j);
    	}
    	else
    	{
    		printf("Empty.\n");
    	}
    	putchar('\n');
    	n = gg.nbase;
    	j = 0;
    	while (n != NULL)
    	{
    		j++;
    		n = n->next;
    	}
    	printf("Total nodes:         %12ld\n", j);
    	j = 0;
    	FORLIM = gg.lastsignal;
    	for (i = 0; i < FORLIM; i++)
    	{
    		if (gg.signaltab[i].np != NULL)
    			j++;
    	}
    	printf("Total signal names:  %12ld\n", j);
    }
    
    static void status_macro(int v)
    {
    	macrorec *mp;
    	char ch;
    	long i, j;
    	int half;
    	int k;
    	static int n;
    	int n_displayed;
    	int n_macros;
    	int n_to_print;
    
    	if (!gg.actflag)
    		return;
    	for (k=0,mp = macrobase; mp != NULL; mp = mp->next, k++)
    		;
    	n_macros = k;
    	n_displayed = ((txacross / 40)+1) * (txdown -4);
    
    	half = k / 2;
    	if (k & 1)
    		half++;
    	if (v > 0)
    		n += (txdown -4);
    	else if (v < 0)
    		n -= (txdown -4);
    	if (n > half)
    		n -= (txdown -4);
    	if (n < 0)
    		n = 0;
    	mp = macrobase;
    	i = 2;
    	n_to_print = P_min(half-n,txdown-4);
    	do
    	{
    		j = 4;
    		for (k=0; k < n && mp != NULL; k++)
    			mp = mp->next;
    		do
    		{
    			if (mp != NULL)
    			{
    				nk_gotoxy((int)i, (int)j);
    				ch = mp->key;
    				if (ch == '\007')
    					printf("bs ");
    				else if (ch == '\t')
    					printf("tab");
    				else if (ch == '\015')
    					printf("cr ");
    				else if (ch == ' ')
    					printf("sp ");
    				else if ((ch & 255) >= 168 && (ch & 255) <= 193)
    					printf("^%c ", (char)((uchar)ch - 'g'));
    				else if (ch <= '\037' || (ch & (~127)) != 0)
    					printf("%3d", ch);
    				else
    					printf("%c  ", ch);
    				printf("  %s", mp->name);
    				mp = mp->next;
    			}
    			j++;
    		} while (j < txdown && j < n_to_print+4 && mp != NULL);
    
    		if (i < 40)
    		{
    			for (k = 0, mp = macrobase; mp != NULL && k < half ; k++)
    				mp = mp->next;
    		}
    		i += 40;
    	} while (i <= txacross && mp != NULL);
    
    	for (k=0; mp != NULL; k++, mp = mp->next)
    		;
    	nk_gotoxy((int)2, (int)txdown);
    	printf("[%d of %d]",((n+1)/(n_displayed/2))+1,(n_macros/n_displayed)+1);
    
    }
    
    static void statusdisplay(char *name_)
    {
    	char name[256];
    	char ch;
    	short which, whichmax;
    	long savex, savey;
    	int refrflag, exitflag;
    	log_tool *tp;
    	char STR2[256], STR3[256];
    	int n = 0;
    
    	strcpy(name, name_);
    	clearshowalpha();
    	whichmax = 0;
    	tp = gg.toolbase;
    	while (tp != NULL)
    	{
    		if (!tp->nostatus)
    			whichmax++;
    		tp = tp->next;
    	}
    	strupper(name, strcpy(STR2, strltrim(strrtrim(strcpy(STR3, name)))));
    	
    	if (!strcmp(name, "LOG"))
    		which = -2;
    	else if (!strcmp(name, "MEMORY"))
    		which = -1;
    	else if (!strcmp(name, "MACRO") || !strcmp(name, "KEYBOARD"))
    		which = 0;
    	else
    	{
    		tp = gg.toolbase;
    		which = 1;
    		while (tp != NULL && strcmp(tp->name, name))
    		{
    			if (!tp->nostatus)
    				which++;
    			tp = tp->next;
    		}
    		if (tp == NULL)
    			which = whichmin;
    	}
    
    	exitflag = false;
    	do
    	{
    		clearshowalpha();
    		printf("                           LOG V%s    Status Display\n\n",
    				log_version);
    		printf("Status:  ");
    		switch (which)
    		{
    
    			case -2:
    				printf("LOG");
    				break;
    
    			case -1:
    				printf("Memory");
    				break;
    
    			case 0:
    				printf("Keyboard assignments");
    				break;
    
    			default:
    				tp = counttool((long)which);
    				fputs(tp->name, stdout);
    				if (*tp->comment != '\0')
    					printf(" (%s)", tp->comment);
    				break;
    		}
    		savex = 0;
    		savey = 0;
    		refrflag = false;
    		gg.actflag = true;
    		nk_gotoxy(0, 4);
    		do
    		{
    			gg.actx = savex;
    			gg.acty = savey;
    			switch (which)
    			{
    
    				case -2:
    					status_log();
    					break;
    
    				case -1:
    					status_mem();
    					break;
    
    				case 0:
    					status_macro(n);
    					n = 0;
    					break;
    
    				default:
    					if (tp->ready)
    						calltool(tp, act_status);
    					if (gg.actflag) {
    						if (tp->ready)
    							printf("   (No status for this tool)\n");
    						else
    							printf("   (Not yet activated)\n");
    					}
    					break;
    			}
    			savex = gg.actx;
    			savey = gg.acty;
    			pen();
    			pass();
    			ch = '\0';
    			if (gg.t.dn)
    				ch = '\003';
    			if (pollkbd2())
    				ch = inkey2();
    			switch (ch)
    			{
    				case 31:
    					n = -1;
    					refrflag = true;
    					break;
    
    				case 10:
    					n = 1;
    					refrflag = true;
    					break;
    
    				case '+':
    				case '\034':
    					if (which < whichmax)
    					{
    						which++;
    						refrflag = true;
    					}
    					break;
    
    				case '-':
    				case '\b':
    					if (which > whichmin)
    					{
    						which--;
    						refrflag = true;
    					}
    					break;
    
    				case ' ':
    				case '\003':
    				case '\015':
    					exitflag = true;
    					break;
    			}
    			gg.actflag = false;
    			nk_gotoxy(9, 2);
    		} while (!(refrflag || exitflag));
    	} while (!exitflag);
    	if (m_autoraise)
    	{
    		m_graphics_on();  /* fix from WES */
    	}
    	clearalpha();
    }
    
    #undef whichmin
    
    
    #define cols            4
    
    
    /*==================  POPUPMENU  =================*/
    /*=                                              =*/
    /*=  Process a pop-up menu selection.  Menu      =*/
    /*=     items are named in MENU.  Use result to  =*/
    /*=     look up in table S to find a char.       =*/
    /*=                                              =*/
    /*================================================*/
    
    static void popupmenu(short num)
    {
    	short i, j, x, y, xx, x0, y0, x1, y1, x00, y00;
    	logmenurec *menu;
    	char STR1[256];
    
    	menu = popupmenus[num - 1];
    	popup_grid = (cursortype == grid);
    	remcursor();
    	clipoff();
    	/*  if menupicture <> nil then
    		m_disposepicture(menupicture);
    		m_getcpicture(kindgroupleft+1, baseline, kindgroupright-1, down, menupicture);  */
    	m_color((long)gg.color.backgr);
    	m_fillrect(kindgroupleft + 1L, (long)baseline, kindgroupright - 1L,
    			(long)down);
    	m_color((long)gg.color.popupbox);
    	m_drawrect(kindgroupleft + 3L, (long)baseline, kindgroupright - 3L,
    			down - 2L);
    	m_drawrect(kindgroupleft + 5L, baseline + 2L, kindgroupright - 5L,
    			down - 4L);
    	xx = (kindgroupsize * kindgroupspacing - 10) / (cols + 1);
    	x = across / 2 - xx * (cols - 1) / 2;
    	x0 = x;
    	for (i = 1; i <= 4; i++)
    	{
    		y = line1 + 2;
    		for (j = i * 2 - 2; j < i * 2; j++)
    		{
    			if (*menu[j].name != '\0') {
    				if (menu[j].bool_ != NULL && *menu[j].bool_)
    					m_color((long)gg.color.selword);
    				else if (menu[j].name[0] == '*')
    					m_color((long)gg.color.redword);
    				else if (menu[j].name[0] == '#')
    					m_color((long)gg.color.blueword);
    				else
    					m_color((long)gg.color.popupword);
    
    				if (menu[j].name[0] == '#' || menu[j].name[0] == '*')
    				{
    					sprintf(STR1, "%.*s",
    							(int)(strlen(menu[j].name) - 1L), menu[j].name + 1);
    					m_centerstr((long)x0, (long)y, logfont_lfont, STR1);
    				}
    				else
    				{
    					m_centerstr((long)x0, (long)y, logfont_lfont, menu[j].name);
    				}
    			}
    			y += line2 - line1 - 4;
    		}
    		x0 += xx;
    	}
    	do
    	{
    		x0 = (gg.t.x - x + xx / 2) / xx;
    		y0 = (gg.t.y - baseline) / 26;
    		if (gg.t.x + xx / 2 < x || gg.incircuit || x0 > 3 || y0 > 1)
    		{
    			x0 = -1;
    			y0 = 0;
    		}
    		else
    		{
    			x00 = x + x0 * xx - xx / 2;
    			y00 = line1 + y0 * (line2 - line1 - 4) - 1;
    			m_color((long)gg.color.popupsel);
    			m_drawrect((long)x00, (long)y00, x00 + xx - 1L, y00 + 15L);
    		}
    		do
    		{
    			pass();
    			pollkbd2();
    			pen();
    			x1 = (gg.t.x - x + xx / 2) / xx;
    			y1 = (gg.t.y - baseline) / 26;
    			if (gg.t.x + xx / 2 < x || gg.incircuit || x1 > 3 || y1 > 1)
    			{
    				x1 = -1;
    				y1 = 0;
    			}
    		} while (gg.t.depressed && x0 == x1 && y0 == y1);
    		remcursor();
    		clipoff();
    		if (x0 != -1) {
    			m_color((long)gg.color.backgr);
    			m_drawrect((long)x00, (long)y00, x00 + xx - 1L, y00 + 15L);
    		}
    	} while (gg.t.depressed);
    	/*  m_putcpicture(kindgroupleft+1, baseline, menupicture);  */
    	refrmenu();
    	if (x0 == -1)
    		return;
    	i = x0 * 2 + 1;
    	if (y0 != 0)
    		i++;
    	if (*menu[i - 1].name == '\0')
    		return;
    	immedscroll = true;
    	assertfunc(menu[i - 1].cmd);
    	immedscroll = false;
    	scroll();
    }
    
    #undef cols
    
    
    static short reducecolor8(short c)
    {
    	short Result;
    
    	if (!eightcolors)
    		return c;
    
    	switch (c)
    	{
    
    		case log_mred:
    			Result = log_red;
    			break;
    
    		case log_orange:
    			Result = log_red;
    			break;
    
    		case log_black:
    			Result = log_black8;
    			break;
    
    		case log_pink:
    			Result = log_red;
    			break;
    
    		case log_dyellow:
    			Result = log_yellow;
    			break;
    
    		case log_xgreen:
    			Result = log_green;
    			break;
    
    		case log_dcyan:
    			Result = log_black8;
    			break;
    
    		case log_dred:
    			Result = log_black8;
    			break;
    
    		case log_lgray:
    			Result = log_white;
    			break;
    
    		case log_cred:
    			Result = log_cred8;
    			break;
    
    		default:
    			Result = c;
    			break;
    	}
    	return Result;
    }
    
    
    
    static void setcmap(short n, short r, short g, short b)
    {
    	n = reducecolor8(n);
    	rcolormap[n] = r;
    	gcolormap[n] = g;
    	bcolormap[n] = b;
    	m_vsetcolors((long)n, 1L, &rcolormap[n], &gcolormap[n], &bcolormap[n]);
    }
    
    
    static void getcolor(char *name_, short *val, short def)
    {
    	char name[256];
    	na_strlist_t *cp;
    	char STR2[256];
    	char STR3[256];
    
    	strcpy(name, name_);
    	strupper(name, strcpy(STR2, strltrim(strrtrim(strcpy(STR3, name)))));
    	cp = strlist_find(colorbase, name);
    	if (cp != NULL)
    		*val = (long)cp->value;
    	else
    		*val = reducecolor8(def);
    }
    
    static void initcolors()
    {
    	getcolor("BACKGR", &gg.color.backgr, log_gray);   /* Color of background */
    	getcolor("CURSOR", &gg.color.cursor, log_white);   /* Color of cursors */
    	recolor_log_cursors(gg.color.cursor, false);
    	getcolor("GATE", &gg.color.gate, log_cyan);   /* Color of gate in circuit */
    	getcolor("DIMGATE", &gg.color.dimgate, log_dcyan);
    	/* Color of dimmed gate */
    	getcolor("KINDGATE", &gg.color.kindgate, log_green);
    	/* Color of gate in menu area */
    	getcolor("CATGATE", &gg.color.catgate, log_cyan);
    	/* Color of gate in catalog */
    	getcolor("GATEPIN", &gg.color.gatepin, log_red);
    	/* Color of pins on gates */
    	getcolor("PINNUM", &gg.color.pinnum, log_yellow);
    	/* Color of pin numbers on gates */
    	getcolor("WIRE", gg.color.wire, log_green);
    	getcolor("VLSIGREEN", &gg.color.wire[log_wcol_green - log_wcol_normal],
    			log_green);
    	getcolor("VLSIYELLOW", &gg.color.wire[log_wcol_yellow - log_wcol_normal],
    			log_yellow);
    	getcolor("VLSIRED", &gg.color.wire[log_wcol_red - log_wcol_normal], log_red);
    	getcolor("VLSIBLUE", &gg.color.wire[log_wcol_blue - log_wcol_normal],
    			log_cyan);
    	getcolor("XWIRE", &gg.color.xwire, log_xgreen);
    	/* Color of wires while moving */
    	getcolor("SOLDER", &gg.color.solder, log_green);
    	/* Color of solder point in circuit */
    	getcolor("CONFLICT", &gg.color.conflict, log_cred);
    	/* Color of wire during node conflict */
    	getcolor("MENUWORD", &gg.color.menuword, log_green);
    	/* Color of words in menu area */
    	getcolor("SELWORD", &gg.color.selword, log_yellow);
    	/* Color of highlighted words */
    	getcolor("MESSAGE", &gg.color.message, log_yellow);
    	/* Color of messages */
    	getcolor("BASELINE", &gg.color.baseline, log_cyan);
    	/* Color of baseline (default) */
    	getcolor("PAGE1", &gg.color.page1, log_green);   /* Color of word "PAGE" */
    	getcolor("PAGE2", &gg.color.page2, log_yellow);   /* Color of page number */
    	getcolor("PAGE3", &gg.color.page3, log_green);   /* Color of word "OF" */
    	getcolor("PAGE4", &gg.color.page4, log_yellow);
    	/* Color of number of pages */
    	getcolor("SELECT", &gg.color.select, log_white);
    	/* Color of selected areas */
    	getcolor("SCROLL", &gg.color.scroll, log_white);
    	/* Color of scroll feedback */
    	getcolor("SIGNAL", &gg.color.signal, log_pink);
    	/* Color of TO/FROM node name */
    	getcolor("LABELTEXT", &gg.color.labeltext, log_dyellow);
    	/* Color of text labels */
    	getcolor("DASHBOX", &gg.color.dashbox, log_dyellow);
    	/* Color of dashed boxes */
    	getcolor("MARKER", &gg.color.marker, log_pink);
    	/* Color of printing markers */
    	getcolor("CHART", &gg.color.chart, log_yellow);
    	/* Color of node history trace */
    	getcolor("DIVISION", &gg.color.division, log_white);
    	/* Color of scope divisions */
    	getcolor("POPUPBOX", &gg.color.popupbox, log_white);
    	/* Color of pop-up menu outline */
    	getcolor("POPUPWORD", &gg.color.popupword, log_green);
    	/* Color of text in pop-up menus */
    	getcolor("POPUPSEL", &gg.color.popupsel, log_pink);
    	/* Color of selection in pop-up menus */
    	getcolor("REDWORD", &gg.color.redword, log_pink);
    	/* Color of special menu items */
    	getcolor("BLUEWORD", &gg.color.blueword, log_cyan);
    	/* Color of experimental menu items */
    	getcolor("VLSICUT", &gg.color.vlsicut, log_white);
    	/* Color of VLSI contact cuts */
    	getcolor("GATEGREEN", &gategreen, log_green);
    	getcolor("GATEYELLOW", &gateyellow, log_yellow);
    	getcolor("GATERED", &gatered, log_red);
    	getcolor("GATEWHITE", &gatewhite, log_white);
    	getcolor("GATEBLACK", &gateblack, log_black);
    	getcolor("GATEORANGE", &gateorange, log_orange);
    	getcolor("DEFINEBOX", &defineboxcolor, log_cyan);
    	/* Color of DEFINE command's box */
    	getcolor("DEFINEBACK", &definebackcolor, log_black);
    	/* Color of background of DEFINE box */
    	getcolor("DEFINETEXT", &definetextcolor, log_green);
    	/* Color of text in DEFINE box */
    	getcolor("CATALOGBOX", &catboxcolor, log_dyellow);
    	/* Color of Catalog grouping box */
    	calltools(act_color);
    	stamp(&gg.colorstamp);
    }
    
    
    static void echomacro(char key)
    {
    	macrorec *mp;
    	char name[256];
    	char STR1[256];
    
    	if (isupper(key))
    		sprintf(name, "Shift-%c key", key);
    	else if (key > ' ' && (key & (~127)) == 0)
    		sprintf(name, "%c key", key);
    	else if (key == ' ')
    		strcpy(name, "Space bar");
    	else if (key == '\007')
    		strcpy(name, "Backspace key");
    	else if (key == '\t')
    		strcpy(name, "Tab key");
    	else if (key == '\015')
    		strcpy(name, "Enter key");
    	else
    		sprintf(name, "Key #%d", key);
    	mp = macrobase;
    	while (mp != NULL && mp->key != key)
    		mp = mp->next;
    
    	if (mp == NULL)
    	{
    		sprintf(STR1, "%s is not defined.", name);
    		message(STR1);
    	} else
    	{
    		sprintf(STR1, "%s is defined as \"%s\"", name, mp->name);
    		message(STR1);
    	}
    }
    
    
    static void definemacro(char key, char *name)
    {
    	macrorec *mp, *mp2, *mp3;
    
    	mp2 = NULL;
    	mp = macrobase;
    	while (mp != NULL && mp->key < key)
    	{
    		mp2 = mp;
    		mp = mp->next;
    	}
    	mp3 = (macrorec *)Malloc(strlen(name) + 9L);
    	if (mp != NULL && mp->key == key)
    	{
    		mp3->next = mp->next;
    		Free(mp);
    	} else
    	{
    		mp3->next = mp;
    	}
    
    	if (mp2 == NULL)
    		macrobase = mp3;
    	else
    		mp2->next = mp3;
    	mp3->key = key;
    	strcpy(mp3->name, name);
    }
    
    
    static void definemenu(short num, short part, char *name, char *cmd, short bool_)
    {
    	logmenurec *menu;
    
    	menu = popupmenus[num - 1];
    	strcpy(menu[part - 1].name, name);
    	strcpy(menu[part - 1].cmd, cmd);
    	switch (bool_)
    	{
    
    		case 1:
    			menu[part - 1].bool_ = &gg.invisible;
    			break;
    
    		case 2:
    			menu[part - 1].bool_ = &gg.textinvisible;
    			break;
    
    		case 3:
    			menu[part - 1].bool_ = &gg.markers;
    			break;
    
    		case 4:
    			menu[part - 1].bool_ = &vlsi;
    			break;
    
    		case 5:
    			menu[part - 1].bool_ = &popup_grid;
    			break;
    
    		case 6:
    			menu[part - 1].bool_ = &gg.probemode;
    			break;
    
    		case 7:
    			menu[part - 1].bool_ = &gg.glowmode;
    			break;
    
    		case 8:
    			menu[part - 1].bool_ = &snapflag;
    			break;
    
    		case 9:
    			menu[part - 1].bool_ = &gg.pwrflag;
    			break;
    
    		default:
    			menu[part - 1].bool_ = NULL;
    			break;
    	}
    }
    
    
    typedef char cnamearray[16][8];
    
    
    const cnamearray cnames =
    {
    	"GRAY", "RED", "GREEN", "YELLOW", "MRED", "ORANGE", "CYAN", "WHITE",
    	"BLACK", "PINK", "DYELLOW", "XGREEN", "DCYAN", "DRED", "LGRAY", "CRED"
    };
    
    
    static long getcolorname(char *w_)
    {
    	long Result;
    	char w[256];
    	short i;
    	char STR1[256];
    	char STR2[256];
    
    	strcpy(w, w_);
    	strcpy(STR1, strltrim(strrtrim(strupper(STR2, w))));
    	strcpy(w, STR1);
    	i = 15;
    	while (i >= 0 && strcmp(cnames[i], w))
    		i--;
    	if (i >= 0)
    		return i;
    	TRY(try29);
    	i = getint(w, -1L);
    	if ((unsigned)i > 15)
    		Result = -1;
    	else
    		Result = i;
    	RECOVER(try29);
    	if (P_escapecode == -20)
    		_Escape(P_escapecode);
    	else
    		return -1;
    	ENDTRY(try29);
    	return Result;
    }
    
    static void docnffunction()
    {
    	char arg[256];
    	long i, j, k;
    	char ch;
    	na_strlist_t *cp;
    	long clrarr[3];
    	int flag;
    	librstrrec *lsp, **lspp;
    	char STR2[256];
    
    	if (*gg.func == '\0')
    		return;
    	if (!strcmp(gg.func, "COLOR"))
    	{
    		getword(gg.funcarg, arg);
    		k = getcolorname(arg);
    		if (k >= 0)
    		{
    			flag = true;
    			for (i = 1; i <= 3; i++)
    			{
    				j = getint(gg.funcarg, -1L);
    				if ((unsigned long)j > 255)
    					flag = false;
    				else
    					clrarr[i - 1] = j;
    			}
    			if (flag)
    			{
    				k = reducecolor8((int)k);
    				rcolormap[k] = clrarr[0];
    				gcolormap[k] = clrarr[1];
    				bcolormap[k] = clrarr[2];
    				m_vsetcolors(k, 1L, &rcolormap[k], &gcolormap[k], &bcolormap[k]);
    			}
    			clearfunc();
    			return;
    		}
    		k = getcolorname(gg.funcarg);
    		strlist_remove(&colorbase, arg);
    		if (k >= 0)
    		{
    			cp = strlist_add(&colorbase, arg);
    			cp->value = (na_long)k;
    		}
    		else if (gg.initdone)
    		{
    			beginerror();
    			printf("No such color as \"%s\"\n", gg.funcarg);
    			enderror();
    		}
    		if (gg.initdone)
    		{
    			initcolors();
    			if (gg.showpage > 0)
    				refrscreen();
    		}
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "MACRO"))
    	{
    		strwordx(gg.funcarg, arg);
    		if (*arg != '\0')
    		{
    			if (strlen(arg) > 1)
    			{
    				if (strcicmp(arg, "sp") == 0)
    					ch = ' ';
    				else if (strcicmp(arg, "bs") == 0)
    					ch = '\007';
    				else if (strcicmp(arg, "tab") == 0)
    					ch = '\t';
    				else if (strcicmp(arg, "cr") == 0)
    					ch = '\015';
    				else if (strlen(arg) == 2 && arg[0] == '^')
    					ch = (arg[1] & 31) + 167;
    				else
    					ch = (char)getint(arg, 32L);
    			}
    			else
    			{
    				ch = arg[0];
    			}
    
    			if (*gg.funcarg == '\0')
    				echomacro(ch);
    			else
    				definemacro(ch, gg.funcarg);
    		}
    		else if (gg.initdone)
    		{
    			statusdisplay("MACRO");
    		}
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "POPUP")) {
    		i = getint(gg.funcarg, 0L);
    		j = getint(gg.funcarg, 0L);
    		if (i >= 1 && i <= 4 && j >= 1 && j <= 8) {
    			k = getint(gg.funcarg, 0L);
    			getword(gg.funcarg, arg);
    			if (*arg != '\0')
    				definemenu((int)i, (int)j, gg.funcarg, arg, (int)k);
    			else
    				definemenu((int)i, (int)j, "", "", 0);
    		}
    		clearfunc();
    		return;
    	}
    	if (!strcmp(gg.func, "GROUP")) {
    		i = getint(gg.funcarg, 0L);
    		if ((unsigned long)i <= 8) {
    			if (*gg.funcarg == '\0')
    				curlistgroup = i;
    			else {
    				getword(gg.funcarg, arg);
    				strchange(&librgroupnames[i], arg);
    			}
    		}
    		clearfunc();
    		return;
    	}
    	if (strcmp(gg.func, "LIBRSTR"))
    		return;
    	/*   else if gg.func = 'VLSI' then
    		 begin
    		 getbool(gg.funcarg^, vlsi);
    		 clearfunc;
    		 end;  */
    	getword(gg.funcarg, arg);
    	if (*arg != '\0' && *gg.funcarg != '\0') {
    		strcpy(arg, strreverse(STR2, arg));
    		lspp = &librstrs;
    		while (*lspp != NULL && strcmp((*lspp)->name, arg)) {
    			if (strcmp(arg, (*lspp)->name) < 0)
    				lspp = &(*lspp)->left;
    			else
    				lspp = &(*lspp)->right;
    		}
    		if (*lspp == NULL) {
    			lsp = (librstrrec *)Malloc(sizeof(librstrrec));
    			*lspp = lsp;
    			lsp->left = NULL;
    			lsp->right = NULL;
    			strcpy(lsp->name, arg);
    			lsp->str = NULL;
    		} else
    			lsp = *lspp;
    		strchange(&lsp->str, gg.funcarg);
    	}
    	clearfunc();
    }
    
    
    
    static void dofunction()
    {
    	log_tool *tp;
    	char cmd[17];
    	short i;
    	int oflag;
    	char STR2[256];
    	short FORLIM;
    	unsigned char TEMP;
    
    	TRY(try30);
    	remcursor();
    	doimmedfunction();
    	if (*gg.func != '\0')
    	{
    		strcpy(cmd, gg.func);
    		tp = gg.toolbase;
    		while (tp != NULL && !strcmp(gg.func, cmd))
    		{
    			if (tp->ready)
    				calltool(tp, act_func);
    			tp = tp->next;
    		}
    	}
    	docnffunction();
    	if (*gg.func != '\0')
    	{
    		if (!strcmp(gg.func, "DEL"))
    		{
    			delcommand();
    		}
    		else if (!strcmp(gg.func, "COPY"))
    		{
    			copycommand();
    		}
    		else if (!strcmp(gg.func, "CLEAR"))
    		{
    			clearfunc();
    			deleverything();
    			histdelsignals();
    		}
    		else if (!strcmp(gg.func, "PASTE"))
    		{
    			pastecommand(0L);
    		}
    		else if (!strcmp(gg.func, "EXTRACT"))
    		{
    			extract();
    		}
    		else if (!strcmp(gg.func, "MOVE"))
    		{
    			movecommand(strcmp(gg.funcarg, "*") != 0);
    		}
    		else if (!strcmp(gg.func, "OPENH"))
    		{
    			openhoriz();
    		}
    		else if (!strcmp(gg.func, "OPENV"))
    		{
    			openvert();
    		}
    		else if (!strcmp(gg.func, "CLOSEH"))
    		{
    			closehoriz();
    		}
    		else if (!strcmp(gg.func, "CLOSEV"))
    		{
    			closevert();
    		}
    		else if (!strcmp(gg.func, "CENTER"))
    		{
    			centercommand();
    		}
    		else if (!strcmp(gg.func, "YARDSTICK"))
    		{
    			yardstickcommand();
    		}
    		else if (!strcmp(gg.func, "DEFINE"))
    		{
    			gatedefinitioncommand();
    		}
    		else if (!strcmp(gg.func, "TOOL"))
    		{
    			toolcommand();
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "LABEL"))
    		{
    			clearfunc();
    			if (!gg.textinvisible)
    			{
    				if (*gg.funcarg == '\0')
    					editlabel(NULL);
    				else
    					addlabel(&gg.nearlabel, gg.funcarg);
    			}
    		}
    		else if (!strcmp(gg.func, "BOX"))
    		{
    			if (!gg.textinvisible)
    				addbox();
    			else
    				clearfunc();
    		}
    		else if (!strcmp(gg.func, "VLSI"))
    		{
    			clearfunc();
    			if (gg.gbase[gg.curpage - 1] != NULL ||
    					gg.hwbase[gg.curpage - 1] != NULL ||
    					gg.vwbase[gg.curpage - 1] != NULL)
    				warning();
    			else
    				setvlsimode(!vlsi);
    		}
    		else if (!strcmp(gg.func, "FAST"))
    		{
    			clearfunc();
    			message("FAST mode enabled.");
    			gg.fastspeed = gg.fastmax;
    		}
    		else if (!strcmp(gg.func, "SCOPE"))
    		{
    			clearfunc();
    			historycommand();
    		}
    		else if (!strcmp(gg.func, "DUMPSCOPE"))
    		{
    			clearfunc();
    			dumphistory();
    		}
    		else if (!strcmp(gg.func, "STEP"))
    		{
    			singlestep();
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "TAPMODE"))
    		{
    			clearfunc();
    			if (cureditmode == maxeditmodes)
    				cureditmode = 1;
    			else
    				cureditmode++;
    			refreditmode();
    		}
    		else if (!strcmp(gg.func, "ROT"))
    		{
    			clearfunc();
    			cureditmode = 1;
    			refreditmode();
    		}
    		else if (!strcmp(gg.func, "MIRX"))
    		{
    			clearfunc();
    			cureditmode = 2;
    			refreditmode();
    		}
    		else if (!strcmp(gg.func, "MIRY"))
    		{
    			clearfunc();
    			cureditmode = 3;
    			refreditmode();
    		} else if (!strcmp(gg.func, "CNFG"))
    		{
    			clearfunc();
    			cureditmode = 4;
    			refreditmode();
    		}
    		else if (!strcmp(gg.func, "CAT"))
    		{
    			gatecatalog(false);
    		}
    		else if (!strcmp(gg.func, "LIBRARY"))
    		{
    			gatecatalog(true);
    		}
    		else if (!strcmp(gg.func, "MAKE"))
    		{
    			makegatecmd();
    		}
    		else if (!strcmp(gg.func, "GET"))
    		{
    			getgatecmd();
    		}
    		else if (!strcmp(gg.func, "NAME"))
    		{
    			namecommand();
    		}
    		else if (!strcmp(gg.func, "SAVE"))
    		{
    			savecommand();
    		}
    		else if (!strcmp(gg.func, "LOAD"))
    		{
    			loadcommand();
    		}
    		else if (!strcmp(gg.func, "READ"))
    		{
    			readcommand();
    		}
    		else if (!strcmp(gg.func, "MESSAGE"))
    		{
    			message(gg.funcarg);
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "VMESSAGE"))
    		{
    			vmessage(gg.funcarg);
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "DUMPCONFLICTS"))
    		{
    			dumpconflicts();
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "TRAIN"))
    		{
    			/*  training := not training;
    				if training and firsttraining then
    				begin
    				gethelp('[Tutorial]');
    firsttraining := false;
    end;
    if not training then
    m_graphics_on;
    clearalpha;  */
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "STATUS"))
    		{
    			statusdisplay(gg.funcarg);
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "MARKER"))
    		{
    			oflag = gg.markers;
    			getbool(gg.funcarg, &gg.markers);
    			if (gg.markers != oflag)
    			{
    				if (gg.markers)
    				{
    					gg.markerx1 = (gg.xoff + 30) / gg.scale;
    					gg.markery1 = (gg.yoff + 30) / gg.scale;
    					gg.markerx2 = (gg.xoff + across - 30) / gg.scale;
    					gg.markery2 = (gg.yoff + baseline - 30) / gg.scale;
    					drawmarkersc(gg.color.marker);
    				} else
    				{
    					drawmarkersc(gg.color.backgr);
    				}
    				stamp(&gg.markerstamp);
    			}
    			vmessageflag("Markers are ", gg.markers);
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "TRAIN+"))
    		{
    			if (training)
    			{
    				help_show(helpptr, "+Q");
    			}
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "TRAIN-"))
    		{
    			if (training)
    			{
    				help_show(helpptr, "-Q");
    			}
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "REFRESH"))
    		{
    			clearfunc();
    			refrscreen();
    		}
    		else if (!strcmp(gg.func, "RESIZE"))
    		{
    			clearfunc();
    			resize_screen();
    		}
    		else if (!strcmp(gg.func, "REFR"))
    			scroll();
    		else if (!strcmp(gg.func, "SHELL"))
    		{
    			doshellescape(gg.funcarg);
    			clearfunc();
    		}
    		else if (*gg.func == '!')
    		{
    			sprintf(STR2, "%s %s", gg.func, gg.funcarg);
    			doshellescape(STR2);
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "EXIT"))
    		{
    			if (strcmp(gg.funcarg, "*") && !anychanged())
    			{
    				P_escapecode = 20;
    				goto _Ltry30;
    			}
    			clearshowalpha();
    			putchar('\n');
    			if (anychanged())
    			{
    				printf("The following page(s) have not been saved: ");
    				FORLIM = gg.numpages;
    				for (i = 1; i <= FORLIM; i++)
    				{
    					if (pagechanged(i))
    						printf("%d ", i);
    				}
    				putchar('\n');
    			}
    			m_alpha_on();
    			m_graphics_off();
    			nk_gotoxy(31, 10);
    			printf("%c%cExit from program? %c", chryellow, chrplain, chrgreen);
    			do
    				TEMP = nk_getkey();
    			while ((TEMP == 250)||(TEMP == 251));
    			if (TEMP == 'y' || TEMP == 'Y')
    			{
    				P_escapecode = 20;
    				goto _Ltry30;
    			}
    			m_graphics_on();
    			clearalpha();
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "ABORT"))
    		{
    			remcursor();
    			if (cursortype == grid)
    				cursortype = normal;
    			gg.probemode = false;
    			clearfunc();
    		}
    		else if (!strcmp(gg.func, "X"))
    		{
    			clearfunc();
    		}
    	}
    	RECOVER2(try30,_Ltry30);
    	if (excpline == -1)
    		excpline = EXCP_LINE;
    	if (P_escapecode != 5)
    		_Escape(P_escapecode);
    	remcursor();
    	gg.startpoint = false;
    	log_setmode("");
    	/* refreshsoon; */
    	if (gg.t.dn && !gg.incircuit)
    	{
    		gg.t.dn = false;
    		gg.t.depressed = false;
    	}
    	cursortype = normal;
    	ENDTRY(try30);
    
    	/*debugging*/
    }
    
    
    
    static void initmacros()
    {
    	definemacro(171, "EXIT *");   /*control-D*/
    	definemacro(':', "DO");
    	definemacro(' ', "REFRESH");
    	definemacro('!', "SHELL");
    	definemacro('1', "PAGE 1");
    	definemacro('2', "PAGE 2");
    	definemacro('3', "PAGE 3");
    	definemacro('4', "PAGE 4");
    	definemacro('5', "PAGE 5");
    	definemacro('6', "PAGE 6");
    	definemacro('7', "PAGE 7");
    	definemacro('8', "PAGE 8");
    	definemacro('9', "PAGE 9");
    	definemacro('*', "PASTE");
    	definemacro(',', "ALTPOSN");
    	definemacro('.', "PROBE");
    	definemacro('/', "COPY");
    	definemacro('0', "RESET");
    	definemacro('<', "ZOOMDN");
    	definemacro('>', "ZOOMUP");
    	definemacro('?', "HELP");
    	definemacro('+', "PAGE +");
    	definemacro('-', "PAGE -");
    	definemacro('A', "AUTOWINDOW");
    	definemacro('b', "BOX");
    	definemacro('c', "CNFG");
    	definemacro('C', "CAT");
    	definemacro('d', "DEL");
    	definemacro('D', "DEFINE");
    	definemacro('e', "EXAMINE");
    	definemacro('E', "EXAMINE");
    	definemacro('f', "FAST");
    	definemacro('g', "GLOW");
    	definemacro('G', "GRID");
    	definemacro('h', "HOME");
    	definemacro('i', "INVISIBLE");
    	definemacro('I', "INVLABEL");
    	definemacro('k', "SHOWCONFLICTS");
    	definemacro('l', "LABEL");
    	definemacro('L', "LOAD");
    	definemacro('m', "MOVE");
    	definemacro('M', "TAPMODE");
    	definemacro('n', "INVPINNUM");
    	definemacro('o', "ONOFF");
    	definemacro('p', "PLOT");
    	definemacro('r', "ROT");
    	definemacro('R', "RESET");
    	definemacro('q', "QUIET");
    	definemacro('Q', "EXIT *");
    	definemacro('s', "SCOPE");
    	definemacro('S', "SAVE *");
    	definemacro('t', "STEP");
    	definemacro('T', "TOOL");
    	definemacro('v', "VERBOSE");
    	definemacro('x', "EXAMINE");
    	definemacro('y', "YARDSTICK");
    	definemacro('Z', "EXIT *");
    	definemacro(250, "REFRESH");
    	definemacro(251, "RESIZE");
    }
    
    
    static void newmenu(logmenurec **menu)
    {
    	short i;
    
    	*menu = (logmenurec *)Malloc(sizeof(logmenutype));
    	for (i = 0; i <= 7; i++)
    		*(*menu)[i].name = '\0';
    }
    
    
    
    static void initmenus()
    {
    	short i;
    
    	for (i = 0; i <= 3; i++)
    		newmenu(&popupmenus[i]);
    	definemenu(1, 1, "Box", "BOX", 0);
    	definemenu(1, 2, "Label", "LABEL", 0);
    	definemenu(1, 3, "Invisible", "INVISIBLE", 1);
    	definemenu(1, 4, "Inv lbls", "INVLABEL", 2);
    	definemenu(1, 5, "Zoom up", "ZOOMUP", 0);
    	definemenu(1, 6, "Zoom dn", "ZOOMDN", 0);
    	definemenu(1, 7, "Markers", "MARKER", 3);
    	definemenu(1, 8, "Yardstick", "YARDSTICK", 0);
    	definemenu(2, 1, "Delete", "DEL", 0);
    	definemenu(2, 2, "Copy", "COPY", 0);
    	definemenu(2, 3, "Move", "MOVE", 0);
    	definemenu(2, 4, "Paste", "PASTE", 0);
    	definemenu(2, 5, "#Open H", "OPENH", 0);
    	definemenu(2, 6, "#Open V", "OPENV", 0);
    	definemenu(2, 7, "#Close H", "CLOSEH", 0);
    	definemenu(2, 8, "#Close V", "CLOSEV", 0);
    	definemenu(3, 1, "Grid", "GRID", 5);
    	definemenu(3, 2, "Probe", "PROBE", 6);
    	definemenu(3, 3, "Glow", "GLOW", 7);
    	definemenu(3, 5, "Alt posn", "ALTPOSN", 0);
    	definemenu(3, 6, "Home", "HOME", 0);
    	definemenu(3, 8, "Refresh", "REFRESH", 0);
    	definemenu(4, 1, "Load page", "LOAD", 0);
    	definemenu(4, 2, "Save page", "SAVE *", 0);
    	definemenu(4, 3, "Plotting", "PLOT", 0);
    	definemenu(4, 4, "Status", "STATUS", 0);
    	definemenu(4, 5, "Scope", "SCOPE", 0);
    	definemenu(4, 6, "Reset", "RESET", 0);
    	definemenu(4, 7, "Simulation", "ONOFF", 9);
    	definemenu(4, 8, "*Exit", "EXIT", 0);
    }
    
    
    
    static void inithooks()
    {
    	gg.hook.hidecursor = hidecursor_hook;
    	gg.hook.unhidecursor = unhidecursor_hook;
    	gg.hook.hidecursorrect = hidecursorrect_hook;
    	gg.hook.nodeconflict = reportnodeconflict;
    	gg.hook.gateconflict = reportgateconflict;
    	gg.hook.clearconflicts = clearconflicts;
    	gg.hook.setdimgate = setdimgate;
    	gg.hook.xform = xformcoords;
    	gg.hook.getsig = getsigname;
    	gg.hook.report = report;
    	gg.hook.alert = alert;
    	gg.hook.warning = warning;
    	gg.hook.working = working;
    	gg.hook.message = message;
    	gg.hook.vmessage = vmessage;
    	gg.hook.vmessageflag = vmessageflag;
    	gg.hook.trace = tracemessage;
    	gg.hook.dump = dumpmessage;
    	gg.hook.setdump = setdumpname;
    	gg.hook.closefiles = closedumpfiles;
    	gg.hook.clearalpha = clearalpha;
    	gg.hook.drawstr = drawstr2;
    	gg.hook.rightstr = rightstr2;
    	gg.hook.centerstr = centerstr2;
    	gg.hook.clip = clipon;
    	gg.hook.remcursor = remcursor;
    	gg.hook.clearscreen = clearscreen;
    	gg.hook.setmode = log_setmode;
    	gg.hook.getword = getword;
    	gg.hook.getint = pgetint;
    	gg.hook.getreal = pgetreal;
    	gg.hook.getbool = getbool;
    	gg.hook.pen = pen;
    	gg.hook.pass = pass;
    	gg.hook.trykbd = trykbd;
    	gg.hook.scroll = scroll;
    	gg.hook.trykbdscroll = trykbdscroll;
    	gg.hook.inkey = inkey3;
    	gg.hook.udrawgate = udrawgatec;
    	gg.hook.gdrawgate = drawgatec;
    	gg.hook.drawgate = drawgatex;
    	gg.hook.erasegate = eragate;
    	gg.hook.drawnode = drawnodec;
    	gg.hook.refresh = refresh;
    	gg.hook.refreshsoon = refreshsoon;
    	gg.hook.beginbottom = beginbottom;
    	gg.hook.endbottom = endbottom;
    	gg.hook.beginerror = beginerror;
    	gg.hook.enderror = enderror;
    	gg.hook.redraw = refrscreen1;
    	gg.hook.redrawscreen = refrscreen;
    	gg.hook.change = chpage;
    	gg.hook.newgate = newgate;
    	gg.hook.copygate = copygate;
    	gg.hook.disposegate = disposegate;
    	gg.hook.newnode = newnode;
    	gg.hook.copynode = copynode;
    	gg.hook.disposenode = disposenode;
    	gg.hook.switchnode = switchnode;
    	gg.hook.dumpnodes = dumpnodes;
    	gg.hook.readlnpass = readlnpass;
    	gg.hook.clearfunc = clearfunc;
    	gg.hook.refrfunc = refrfunc;
    	gg.hook.assertfunc = assertfunc;
    	gg.hook.findobject = closergate;
    	gg.hook.findwire = closerwire;
    	gg.hook.deletehw = delhwire;
    	gg.hook.deletevw = delvwire;
    	gg.hook.disconnectgate = disconnectgate;
    	gg.hook.deletegate = delgate;
    	gg.hook.addhw = addhwire2;
    	gg.hook.addvw = addvwire2;
    	gg.hook.connectgate = pconnectgate;
    	gg.hook.waitnear = waitnear;
    	gg.hook.addgate = addgate1;
    	gg.hook.uaddgate = uaddgate;
    	gg.hook.getgate = getgate;
    	gg.hook.realunit = prealunit;
    	gg.hook.realunit2 = prealunit2;
    	gg.hook.addlabel = addlabel;
    	gg.hook.getcolor = getcolor;
    	gg.hook.setcmap = setcmap;
    	gg.hook.parselabel = parselabel;
    	gg.hook.editattrs = editattrsx;
    	gg.hook.newattrs = newattrs;
    	gg.hook.disposeattrs = disposeattrs;
    	gg.hook.copyattrs = copyattrs;
    	gg.hook.initscreen = initscreen;
    	gg.hook.clearshowalpha = clearshowalpha;
    	gg.hook.setupregion = setupregion;
    	gg.hook.stamp = stamp;
    	gg.hook.noclip = clipoff;
    	gg.hook2 = (log_hook2_t *)Malloc(sizeof(log_hook2_t));
    	gg.hook2->getnodeval = getnodeval;
    	gg.hook2->solderat = solderat;
    	gg.hook2->unsolderwires = unsolderwires;
    	gg.hook2->settofrom = settofrom;
    	gg.hook2->findattrnum = findattrnum;
    	gg.hook2->findattrname = findattrname;
    	gg.hook2->findpinnum = findpinnum;
    	gg.hook2->findpinname = findpinname;
    	gg.hook2->setgattr = setgattr;
    	gg.hook2->setnattr = setnattr;
    	gg.hook2->findpointmarker = findpointmarker;
    	gg.hook2->findboxmarker = findboxmarker;
    	gg.hook2->send_general = send_general;
    	gg.hook2->send_gennode = send_gennode;
    	gg.hook2->send_genkind = send_genkind;
    	gg.hook2->send_gengate = send_gengate;
    	gg.hook2->send_all = send_all;
    	gg.hook2->send_allnodes = send_allnodes;
    	gg.hook2->send_allkinds = send_allkinds;
    	gg.hook2->send_allgates = send_allgates;
    	gg.hook2->addlabelat = addlabelat;
    	gg.hook2->addboxat = addboxat;
    	gg.hook2->plainxform = plainxformcoords;
    	gg.hook2->findattrnum2 = findattrnum2;
    	gg.hook2->findattrname2 = findattrname2;
    	gg.hook2->showpinname = showpinname;
    }
    
    
    #define rtn             "INITIALIZE"
    
    #if 0
    /* Local variables for initialize: */
    struct LOC_initialize {
    	short j;
    	na_strlist_t *loadgates, *logmenu;
    	char cmdbuf[81];
    	cnfrec *cnflast;
    } ;
    #endif
    
    static void beginfatal(struct LOC_initialize *LINK)
    {
    	if (P_escapecode == -20)
    		_Escape(P_escapecode);
    	clearshowalpha();
    	warning();
    	printf("\n\n%c", chryellow);
    }
    
    static void endfatal(struct LOC_initialize *LINK)
    {
    	printf("%c  Program aborted.\n", chrgreen);
    	_Escape(0);
    }
    
    static void addgatesfile(char *fn_, struct LOC_initialize *LINK)
    {
    	char fn[256];
    	na_strlist_t *l1;
    
    	strcpy(fn, fn_);
    	newci_fixfname(fn, "gate", "");
    	if (!locatefile(fn, LINK))
    		*fn = '\0';
    	if (*fn != '\0' && strlist_find(gatefilenames, fn) == NULL)
    		l1 = strlist_append(&gatefilenames, fn);
    }
    
    static void sethomedirname(char *dir_, struct LOC_initialize *LINK)
    {
    	char dir[256], buf[256];
    	char *ep;
    
    	if (dir_[0] == '~')
    	{
    		ep = tilde_expand(dir_);
    		strncpy(dir, ep, 256);
    		Free(ep);
    	}
    	else
    	{
    		strncpy(dir, dir_, 256);
    	}
    	strcpy(gg.homedirname, dir);
    	if (buf[strlen(buf) - 1] != ':' && buf[strlen(buf) - 1] != '/')
    		strcat(gg.homedirname, "/");
    }
    
    static void removepath(char *name)
    {
    	char *cp = (char *)strrchr(name, '/');
    	if (cp)
    		strcpy_overlap(name, cp + 1);
    }
    
    static void readcnf(char *fn_, struct LOC_initialize *LINK)
    {
    	char fn[256];
    	int flag;
    	long cnflin;
    	FILE *tx;
    	char txbuf[256], txarg[256], txarg2[256];
    	int erasegates, eraseload, erasemenu;
    	na_strlist_t *l1, *l2;
    	log_tool *tp;
    	cnfrec *cnfp;
    	char *TEMP;
    
    	strcpy(fn, fn_);
    	tx = NULL;
    	erasegates = true;
    	eraseload = true;
    	erasemenu = true;
    	flag = false;
    	if (!strcmp(fn, "*"))
    	{
    		strcpy(fn, P_argv[0]);
    		removepath(fn);
    		strcat(fn, ".cnf");
    		if (!locatefile(fn, LINK))
    		{
    			strcpy(fn, "log.cnf");
    			if (!locatefile(fn, LINK))
    				*fn = '\0';
    
    		}
    	}
    	else
    	{
    		newci_fixfname(fn, "cnf", "");
    		if (!locatefile(fn, LINK))
    			*fn = '\0';
    	}
    	if (*fn != '\0')
    	{
    		TRY(try32);
    		if (tx != NULL)
    			tx = freopen(fn, "r", tx);
    		else
    			tx = fopen(fn, "r");
    
    		if (tx == NULL) {
    			P_escapecode = -10;
    			P_ioresult = FileNotFound;
    			goto _Ltry32;
    		}
    		flag = true;
    		RECOVER2(try32,_Ltry32);
    		if (P_escapecode == -20)
    			_Escape(P_escapecode);
    
    		ENDTRY(try32);
    	}
    	cnflin = 0;
    	if (flag)
    	{
    		TRY(try33);
    		while (!P_eof(tx))
    		{
    			cnflin++;
    			fgets(txbuf, 256, tx);
    			TEMP = (char *)strchr(txbuf, '\n');
    			if (TEMP != NULL)
    				*TEMP = 0;
    
    			strcomment(txbuf, "{}");
    			getword(txbuf, LINK->cmdbuf);
    			if (!strcmp(LINK->cmdbuf, "BOBCAT"))
    			{
    				if (nc_gType() != nc_g300)
    					*txbuf = '\0';
    
    				getword(txbuf, LINK->cmdbuf);
    			}
    			else if (!strcmp(LINK->cmdbuf, "CHIPMUNK"))
    			{
    				if (nc_gType() == nc_g300)
    					*txbuf = '\0';
    
    				getword(txbuf, LINK->cmdbuf);
    			}
    			if (!strcmp(LINK->cmdbuf, "LOG:"))
    				getword(txbuf, LINK->cmdbuf);
    
    			strcpy(gg.func, LINK->cmdbuf);
    			strcpy(gg.funcarg, txbuf);
    			if (*LINK->cmdbuf != '\0')
    			{
    				doimmedcnffunction();
    				docnffunction();
    			}
    			if (*LINK->cmdbuf == '\0' || strcmp(gg.func, LINK->cmdbuf))
    				continue;
    			if (strends(LINK->cmdbuf, ":") && strlen(LINK->cmdbuf) > 1)
    			{
    				if (*txbuf == '\0')
    					continue;
    
    				LINK->cmdbuf[strlen(LINK->cmdbuf) - 1] = '\0';
    				cnfp = (cnfrec *)Malloc(sizeof(cnfrec));
    				cnfp->next = NULL;
    				if (LINK->cnflast == NULL)
    					cnfbase = cnfp;
    				else
    					LINK->cnflast->next = cnfp;
    
    				cnfp->next = NULL;
    				strcpy(cnfp->tool, LINK->cmdbuf);
    				strcpy(cnfp->s, txbuf);
    				LINK->cnflast = cnfp;
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "INCLUDE"))
    			{
    				do
    				{
    					strwordx(txbuf, txarg);
    					if (*txarg != '\0')
    						readcnf(txarg, LINK);
    				}
    				while (*txarg != '\0');
    
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "HOME"))
    			{
    				sethomedirname(txbuf, LINK);
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "GATES"))
    			{
    				strwordx(txbuf, txarg);
    				if (!strcmp(txarg, "+"))
    					strwordx(txbuf, txarg);
    				else
    				{
    					if (erasegates)
    						strlist_empty(&gatefilenames);
    				}
    				erasegates = false;
    				while (*txarg != '\0')
    				{
    					addgatesfile(txarg, LINK);
    					strwordx(txbuf, txarg);
    				}
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "HELP"))
    			{
    				if (locatefile(txbuf, LINK))
    					strcpy(loghelpname, txbuf);
    
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "NEWS"))
    			{
    				if (locatefile(txbuf, LINK))
    					strcpy(lognewsname, txbuf);
    
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "TABLET"))
    			{
    				tabletaddr = getint(txbuf, tabletaddr);
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "MENU"))
    			{
    				getword(txbuf, txarg);
    				if (!strcmp(txarg, "+"))
    					getword(txbuf, txarg);
    				else
    				{
    					if (erasemenu)
    						strlist_empty(&LINK->logmenu);
    				}
    				erasemenu = false;
    				while (*txarg != '\0')
    				{
    					l1 = strlist_append(&LINK->logmenu, txarg);
    					getword(txbuf, txarg);
    				}
    
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "GET") || !strcmp(LINK->cmdbuf, "LOAD"))
    			{
    				getword(txbuf, txarg);
    				if (!strcmp(txarg, "+"))
    					getword(txbuf, txarg);
    				else
    				{
    					if (eraseload)
    						strlist_empty(&LINK->loadgates);
    				}
    				eraseload = false;
    				while (*txarg != '\0')
    				{
    					l1 = strlist_append(&LINK->loadgates, txarg);
    					getword(txbuf, txarg);
    				}
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "GETGROUP"))
    			{
    				getword(txbuf, txarg);
    				if (!strcmp(txarg, "+"))
    					getword(txbuf, txarg);
    				else
    				{
    					if (eraseload)
    						strlist_empty(&LINK->loadgates);
    				}
    				eraseload = false;
    				l1 = strlist_append(&LINK->loadgates, "");
    				l1->value = (na_long)NULL;
    				while (*txarg != '\0')
    				{
    					l2 = strlist_append((na_strlist_t **)(&l1->value), txarg);
    					getword(txbuf, txarg);
    				}
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "TOOL"))
    			{
    				getword(txbuf, txarg);
    				if (*txarg == '\0')
    					continue;
    
    				tp = gg.toolbase;
    				while (tp != NULL && strcmp(tp->name, txarg))
    					tp = tp->next;
    
    				if (tp != NULL)
    					continue;
    
    				newtool(&tp, txarg);
    				strwordx(txbuf, txarg);
    				if (*txarg != '\0')
    					strcpy(tp->comment, txarg);
    
    				getword(txbuf, txarg);
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "COMMAND"))
    			{
    				getword(txbuf, txarg2);
    				if (*txarg2 == '\0')
    					continue;
    
    				do
    				{
    					getword(txbuf, txarg);
    					if (*txarg != '\0')
    					{
    						l1 = strlist_add(&commandlist, txarg);
    						*(char **)((char **)(&l1->value)) = strdup(txarg2);
    					}
    				}
    				while (*txarg != '\0');
    
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "SIGNALS") || !strcmp(LINK->cmdbuf, "NODES"))
    			{
    				LINK->j = getint(txbuf, 0L);
    				if (LINK->j < 1)
    				{
    					P_escapecode = -1;
    					goto _Ltry33;
    				}
    				gg.maxsignal = LINK->j;
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "DO"))
    			{
    				l2 = strlist_append(&thingstodo, gg.funcarg);
    				continue;
    			}
    			if (!strcmp(LINK->cmdbuf, "UNDO"))
    				strlist_empty(&thingstodo);
    			else if (strcmp(LINK->cmdbuf, "CTOLERANCE") &&
    					strcmp(LINK->cmdbuf, "CLOCK") &&
    					strcmp(LINK->cmdbuf, "SCOPE") &&
    					strcmp(LINK->cmdbuf, "AUTO") &&
    					strcmp(LINK->cmdbuf, "POST") &&
    					strcmp(LINK->cmdbuf, "PRINTER") &&
    					strcmp(LINK->cmdbuf, "HELPIX") &&
    					strcmp(LINK->cmdbuf, "GATESIX") &&
    					strcmp(LINK->cmdbuf, "PLOTTER") &&
    					strcmp(LINK->cmdbuf, "SIMMODE"))
    			{
    				P_escapecode = -1;
    				goto _Ltry33;
    			}
    		}
    		RECOVER2(try33,_Ltry33);
    		if (P_escapecode == -20)
    			_Escape(P_escapecode);
    
    		if (P_escapecode != 0)
    		{
    			beginfatal(LINK);
    			printf("Error in line %ld of configuration file \"%s\"\n", cnflin, fn);
    			endfatal(LINK);
    		}
    		ENDTRY(try33);
    	}
    	if (tx != NULL)
    		fclose(tx);
    
    	/*obsolete*/
    }
    
    /*==================  INITIALIZE  ================*/
    /*=                                              =*/
    /*=  Initialize all variables.  Read basic gates =*/
    /*=     from library.  Clear Catalog screen.     =*/
    /*=     Initialize data structures.              =*/
    /*=                                              =*/
    /*================================================*/
    
    static void initialize()
    {
    	struct LOC_initialize V;
    	newci_parserec swtab[10];
    	short i, k, curgate;
    	short gptr[maxgatesfiles], ggroup[maxgatesfiles], gsize[maxgatesfiles];
    	char gname[maxgatesfiles][9];
    	na_strlist_t *l1, *l2;
    	char s[256];
    	int flag;
    	char cnfname[256];
    	nk_keytransinfo *keytrans;
    	char STR2[256], STR3[256];
    	short FORLIM;
    	nk_keytransinfo *WITH;
    	log_sigrec *WITH1;
    
    	strcpy(swtab[0].switch_, "cC");   /* CNF file name */
    	swtab[0].kind = 'M';
    	strcpy(swtab[1].switch_, "vV");   /* Vanilla LOG (no CNF) */
    	swtab[1].kind = 'B';
    	strcpy(swtab[2].switch_, "zZ");   /* Trace mode initially on */
    	swtab[2].kind = 'S';
    	strcpy(swtab[3].switch_, "dD");   /* Dump file name */
    	swtab[3].kind = 'S';
    	strcpy(swtab[4].switch_, "tT");   /* Trace file name */
    	swtab[4].kind = 'S';
    	strcpy(swtab[5].switch_, "hH");   /* Home directory name */
    	swtab[5].kind = 'S';
    	strcpy(swtab[6].switch_, "rR");   /* Tool to run */
    	swtab[6].kind = 'M';
    
    	/* Added X display support.  stafford 7/17/91 */
    
    	strcpy(swtab[7].switch_, "xX");   /* XDisplay name */
    	swtab[7].kind = 'M';
    
    	newci_parseswitch(swtab, 8L, V.cmdbuf);
    
    
    	if (*V.cmdbuf != '\0')
    	{
    		if (*V.cmdbuf != '\0')
    			printf("Unrecognized option:  -%s\n", V.cmdbuf);
    		printf(
    				"\nUsage:  LOG [ -v ] [ -c cnffile ] [ -x X_display_name ] [ file ]\n");
    		_Escape(0);
    	}
    
    	/* Added X display support.  stafford 7/17/91 */
    	/* grab the display name off the parsed switches */
    
    	if (swtab[7].used > 0)
    	{
    		m_set_display_name(swtab[7].UU.s);
    	}
    
    	tabletaddr = 0;
    	gg.curstamp = 0;
    	initscreen2();
    	initcolormap();
    	libptr = 0;
    	helpptr = 0;
    	cursortype = normal;
    	oldcursortype = normal;
    	cursorflag = false;
    	setscale(0);
    	/*  menupicture := nil;
    		{  errorpicture := nil;  */
    	curlistgroup = 0;
    	messagepos = topmessagepos;
    	resetmessages();
    	gg.verbose = true;
    	tempverbose = false;
    	gg.glowmode = false;
    	gg.probemode = false;
    	gg.textinvisible = false;
    	gg.pnuminvisible = true;
    	gg.invisible = false;
    	gg.pwrflag = true;
    	gg.busyflag = true;
    	snapflag = false;
    	glowsolder = true;
    	gg.quiet = false;
    	gg.dotsvisible = true;
    	gg.showconflicts = false;
    	avoidrabbits = true;
    	pushedbackkey = '\0';
    	conflictenbl = true;
    	conflictstop = false;
    	conflictdelay = 1;
    	anyconflicts = false;
    	gg.actstr = (char *)Malloc(256);
    	*gg.actstr = '\0';
    	gg.maxsignal = defmaxsignal;
    	freenode = NULL;
    	freegate = NULL;
    	strlist_init(&histlbl);
    	l2 = strlist_append(&histlbl, "Scope mode");
    	l2 = strlist_append(&histlbl, "");
    	l2 = strlist_append(&histlbl,
    			"VContinuous,On Reset,Triggered,Manual:Type of trigger:");
    	l2 = strlist_append(&histlbl, "Triggered;C(none):Trigger signal:");
    	l2 = strlist_append(&histlbl, "On Reset;OUs:Time to start trigger:");
    	l2 = strlist_append(&histlbl, "On Reset;OUs:Time to stop trigger:");
    	l2 = strlist_append(&histlbl,
    			"VTrigger off,Simulation off:Action when memory full:");
    	l2 = strlist_append(&histlbl, "");
    	l2 = strlist_append(&histlbl, "Us:Minimum timestep:");
    	l2 = strlist_append(&histlbl, "Us:Maximum timestep:");
    	l2 = strlist_append(&histlbl, "I100000:Timestep memory limit:");
    	l2 = strlist_append(&histlbl, "I:Timestep memory size:");
    	l2 = strlist_append(&histlbl, "");
    	l2 = strlist_append(&histlbl, "BY:Align signal names?");
    	l2 = strlist_append(&histlbl, "");
    	l2 = strlist_append(&histlbl, "Us,0:Time at left edge:");
    	l2 = strlist_append(&histlbl, "Us:Current time:");
    	l2 = strlist_append(&histlbl, "");
    	l2 = strlist_append(&histlbl, "Us,100us:Seconds per division:");
    	l2 = strlist_append(&histlbl, "Us:Current timestep:");
    	parselabel(&histlbl, &histnumattrs, &histkattr);
    	newattrs(&histgattr, histnumattrs, histkattr);
    	gg.singlestepcount = 0;
    	steppingoff = false;
    	vlsi = false;
    	gg.dumpopen = false;
    	gg.dumpfile = &dumpfile;
    	dumpfname = (char *)Malloc(256);
    	*dumpfname = '\0';
    	gg.traceopen = false;
    	gg.tracefile = &tracefile;
    	tracefname = (char *)Malloc(256);
    	*tracefname = '\0';
    
    	if (swtab[3].used > 0)
    		strcpy(dumpfname, swtab[3].UU.s);
    	if (swtab[4].used > 0)
    		strcpy(tracefname, swtab[4].UU.s);
    	else if (swtab[2].used > 0)
    		strcpy(tracefname, swtab[2].UU.s);
    	if (*tracefname != '\0')
    		newci_fixfname(tracefname, "text", "");
    	gg.traceflag = (swtab[2].used > 0);
    	if (gg.traceflag)
    		tracemessage("Trace mode ON");
    	gg.homedirname = (char *)Malloc(256);
    
    	if (swtab[5].used > 0)
    	{
    		if (*swtab[5].UU.s == '\0')
    			sethomedirname("", &V);
    		else
    			sethomedirname(swtab[5].UU.s, &V);
    	}
    	else
    	{
    		sethomedirname("~/log", &V);
    	}
    	cursorhide = false;
    	initmenus();
    	gg.funcarg = (char *)Malloc(256);
    	*gg.funcarg = '\0';
    	gg.host = log_host_log;
    	gg.toolbase = NULL;
    	inithooks();
    	gg.rndseed = timers_sysclock();
    	gg.simstate = simst_null;
    	gg.simstatetool = NULL;
    	for (i = 0; i < maxgatesfiles; i++)
    		gatesname[i] = NULL;
    	for (i = 0; i <= 8; i++)
    		librgroupnames[i] = NULL;
    	loghelpname = (char *)Malloc(256);
    	strcpy(loghelpname, "loghelp");
    	lognewsname = (char *)Malloc(256);
    	strcpy(lognewsname, "lognews");
    	gg.fastmin = deffastmin;
    	gg.fastmax = deffastmax;
    	gg.fastrate = deffastrate;
    	gg.fastspeed = gg.fastmin;
    	stamp(&gg.labelstamp);
    	stamp(&gg.boxstamp);
    	stamp(&gg.msgstamp);
    	stamp(&gg.refrstamp);
    	stamp(&gg.nattrstamp);
    	stamp(&gg.gattrstamp);
    	stamp(&gg.sigstamp);
    	stamp(&gg.loadstamp);
    	stamp(&gg.colorstamp);
    	stamp(&gg.resetstamp);
    	stamp(&gg.markerstamp);
    	strlist_init(&V.loadgates);
    	strlist_init(&V.logmenu);
    	strlist_init(&gatefilenames);
    	cnfbase = NULL;
    	V.cnflast = NULL;
    	colorbase = NULL;
    	macrobase = NULL;
    	initmacros();
    	librstrs = NULL;
    	commandlist = NULL;
    	thingstodo = NULL;
    	nexttodo = NULL;
    	messages = NULL;
    	*cnfname = '\0';
    	flag = false;
    	if (swtab[0].used > 0)
    		strcpy(cnfname, swtab[0].UU.s);
    	if (*cnfname == '\0' && swtab[1].used == 0)
    		strcpy(cnfname, "*");
    	if (*cnfname != '\0')
    		readcnf(cnfname, &V);
    	initcolors();
    	gg.color.curbaseline = gg.color.baseline;
    	gg.baselinecolor = gg.color.baseline;
    	newci_fixfname(loghelpname, "help", "");
    	newci_fixfname(lognewsname, "text", "");
    	displaynews = (*lognewsname != '\0');
    	if (P_argc > 1)
    	{
    		sprintf(STR2, "LOAD %s", P_argv[1]);
    		l2 = strlist_append(&thingstodo, STR2);
    		FORLIM = P_argc;
    		for (i = 2; i < FORLIM; i++)
    		{
    			sprintf(STR3, "PAGE %d", i);
    			l2 = strlist_append(&thingstodo, STR3);
    			sprintf(STR3, "LOAD %s", P_argv[i]);
    			l2 = strlist_append(&thingstodo, STR3);
    		}
    		displaynews = false;
    	}
    	if (swtab[6].used > 0 && *swtab[6].UU.s != '\0')
    	{
    		sprintf(STR3, "TOOL %s", swtab[6].UU.s);
    		l2 = strlist_append(&thingstodo, STR3);
    		displaynews = false;
    		justonecommand = true;
    	}
    	else
    	{
    		justonecommand = false;
    	}
    	TRY(try34);
    	m_init_pen(tabletaddr);
    	RECOVER(try34);
    	if (P_escapecode == -20)
    		_Escape(P_escapecode);
    	beginfatal(&V);
    	printf("Can't find graphics tablet!\n");
    	endfatal(&V);
    	ENDTRY(try34);
    	if (gatefilenames == NULL)
    		addgatesfile("log", &V);
    	idxsize = 0;
    	for (k = 0; k < maxgatesfiles; k++)
    	{
    		*gname[k] = '\0';
    		if (gatefilenames != NULL) {
    			TRY(try35);
    			gatesname[k] = (char *)Malloc(256);
    			strcpy(gatesname[k], gatefilenames->s);
    			gatefilenames = gatefilenames->next;
    			libf1[k] = (filerecfilerec *)Malloc(sizeof(filerecfilerec));
    			libf1[k]->f = NULL;
    			newci_fixfname(gatesname[k], "gate", "");
    			flag = false;
    			TRY(try36);
    			if (libf1[k]->f != NULL)
    				libf1[k]->f = freopen(gatesname[k], "r", libf1[k]->f);
    			else
    				libf1[k]->f = fopen(gatesname[k], "r");
    
    			if (libf1[k]->f == NULL)
    			{
    				P_escapecode = -10;
    				P_ioresult = FileNotFound;
    				goto _Ltry36;
    			}
    			RESETBUF(libf1[k]->f, filerec);
    			flag = true;
    			RECOVER2(try36,_Ltry36);
    			if (P_escapecode == -20)
    				goto _Ltry35;
    			TRY(try37);
    			if (libf1[k]->f != NULL)
    			{
    				sprintf(STR2, "%s/%s", GetChipmunkPath("LOGLIB", LOGLIB),
    						gatesname[k]);
    				libf1[k]->f = freopen(STR2, "r", libf1[k]->f);
    			} else
    			{
    				sprintf(STR2, "%s/%s", GetChipmunkPath("LOGLIB", LOGLIB),
    						gatesname[k]);
    				libf1[k]->f = fopen(STR2, "r");
    			}
    			if (libf1[k]->f == NULL)
    			{
    				P_escapecode = -10;
    				P_ioresult = FileNotFound;
    				goto _Ltry37;
    			}
    			RESETBUF(libf1[k]->f, filerec);
    			sprintf(STR2, "%s/%s", GetChipmunkPath("LOGLIB", LOGLIB),
    					gatesname[k]);
    			strcpy(gatesname[k], STR2);
    			flag = true;
    			RECOVER2(try37,_Ltry37);
    			if (P_escapecode == -20)
    				goto _Ltry35;
    			ENDTRY(try37);
    			ENDTRY(try36);
    			if (flag)
    			{
    				if (libf1[k]->f != NULL)
    					rewind(libf1[k]->f);
    				else
    					libf1[k]->f = tmpfile();
    				if (libf1[k]->f == NULL)
    				{
    					P_escapecode = -10;
    					P_ioresult = FileNotFound;
    					goto _Ltry35;
    				}
    				SETUPBUF(libf1[k]->f, filerec);
    				fseek(libf1[k]->f, 0L, 0);
    				SETUPBUF(libf1[k]->f, filerec);
    				GET(libf1[k]->f, filerec);
    				gsize[k] = getshortsw((char *)(&GETFBUF(libf1[k]->f, filerec).b[4]));
    				idxsize += gsize[k];
    				libfstart[k] = GETFBUF(libf1[k]->f, filerec).b[6] + 1;
    				gptr[k] = 0;
    			}
    			else
    			{
    				Free(libf1[k]);
    				gatesname[k] = NULL;
    			}
    			RECOVER2(try35,_Ltry35);
    			if (P_escapecode == -20)
    				_Escape(P_escapecode);
    			beginfatal(&V);
    			printf("Can't open gates file \"%s\"\n", gatesname[k]);
    			endfatal(&V);
    			ENDTRY(try35);
    		}
    	}
    	if (idxsize == 0)
    	{
    		beginfatal(&V);
    		printf("No gates files!\n");
    		endfatal(&V);
    	}
    	index_ = (char(*)[9])Malloc(idxsize * 10L);
    	indexfile = (uchar *)Malloc(idxsize);
    	indexoffset = (short *)Malloc(idxsize * sizeof(short));
    	indexgroup = (uchar *)Malloc(idxsize);
    	loadedgates = (uchar *)Malloc((idxsize + 9L) / 8);
    	FORLIM = idxsize;
    	for (i = 0; i < FORLIM; i++)
    		P_clrbits_B(loadedgates, i, 0, 3);
    	curgate = 1;
    	do
    	{
    		k = 0;
    		strcpy(s, "\177");
    		for (i = 0; i < maxgatesfiles; i++)
    		{
    			if (gatesname[i] != NULL && *gname[i] == '\0' && gptr[i] < gsize[i])
    			{
    				TRY(try38);
    				gptr[i]++;
    				if ((gptr[i] & 31) == 0)
    					GET(libf1[i]->f, filerec);
    				strcpy(gname[i], "        ");
    				strmove(8, GETFBUF(libf1[i]->f, filerec).ix[gptr[i] & 31], 1,
    						gname[i], 1);
    				ggroup[i] = 0;
    				for (V.j = 1; V.j <= 8; V.j++)
    				{
    					if ((gname[i][V.j - 1] & (~127)) != 0)
    					{
    						ggroup[i] = V.j;
    						gname[i][V.j - 1] = (char)((uchar)gname[i][V.j - 1] - 128);
    					}
    				}
    				RECOVER(try38);
    				if (P_escapecode == -20)
    					_Escape(P_escapecode);
    				beginfatal(&V);
    				printf("Can't read gates file \"%s\"\n", gatesname[i]);
    				endfatal(&V);
    				ENDTRY(try38);
    			}
    			if (strcmp(gname[i], s) < 0 && *gname[i] != '\0')
    			{
    				strcpy(s, gname[i]);
    				k = i + 1;
    			}
    		}
    		indexfile[curgate - 1] = k;
    		indexoffset[curgate - 1] = gptr[k - 1];
    		indexgroup[curgate - 1] = ggroup[k - 1];
    		strcpy(index_[curgate - 1], strrtrim(strcpy(STR3, s)));
    		for (i = 1; i <= maxgatesfiles; i++)
    		{
    			if (!strcmp(gname[i - 1], s))
    			{
    				*gname[i - 1] = '\0';
    				if (i != k)
    					idxsize--;
    			}
    		}
    		curgate++;
    	} while (curgate <= idxsize);
    	if (m_across >= 1023)
    	{
    		maxkinds = P_imin2(280L, (long)maxmaxkinds);
    		catwidth = 20;
    	}
    	else
    	{
    		maxkinds = P_imin2(70L, (long)maxmaxkinds);
    		catwidth = 10;
    	}
    	catboxes = NULL;
    	FORLIM = maxkinds;
    	for (i = 0; i < FORLIM; i++)
    		kind[i] = NULL;
    	m_graphics_on();
    	clearalpha();
    	gg.curpage = 1;
    	gg.showpage = 1;
    	realcurpage = 1;
    	setvlsimode(vlsi);
    	labelcaps = true;
    	signalcaps = true;
    	nk_settransarray(nk_ktstandard, &keytrans);
    	curkeytrans = (nk_keytransinfo *)Malloc(sizeof(nk_keytransinfo));
    	*curkeytrans = *keytrans;
    	nk_settransarray(nk_ktsupplied, &curkeytrans);
    	WITH = curkeytrans;
    	for (i = 25; i <= 125; i++)
    	{
    		if (WITH->matrix[i - nk_keylow][-nk_keymodlow].c == 154)   /*del chr*/
    			WITH->matrix[i - nk_keylow][-nk_keymodlow].c = 24;
    		else if (islower(WITH->matrix[i - nk_keylow][-nk_keymodlow].c))
    		{
    			WITH->matrix[i - nk_keylow][2 - nk_keymodlow].c =
    				WITH->matrix[i - nk_keylow][-nk_keymodlow].c + 71;
    			WITH->matrix[i - nk_keylow][3 - nk_keymodlow].c =
    				WITH->matrix[i - nk_keylow][-nk_keymodlow].c + 117;
    			WITH->matrix[i - nk_keylow][2 - nk_keymodlow].k = nk_kknormal;
    			WITH->matrix[i - nk_keylow][3 - nk_keymodlow].k = nk_kknormal;
    		} else if (isdigit(WITH->matrix[i - nk_keylow][-nk_keymodlow].c))
    		{
    			WITH->matrix[i - nk_keylow][2 - nk_keymodlow].c =
    				WITH->matrix[i - nk_keylow][-nk_keymodlow].c + 192;
    			WITH->matrix[i - nk_keylow][3 - nk_keymodlow].c =
    				WITH->matrix[i - nk_keylow][-nk_keymodlow].c + 192;
    			WITH->matrix[i - nk_keylow][2 - nk_keymodlow].k = nk_kknormal;
    			WITH->matrix[i - nk_keylow][3 - nk_keymodlow].k = nk_kknormal;
    		}
    		if (WITH->matrix[i - nk_keylow][1 - nk_keymodlow].c == 157)
    			/*shift-left*/
    			WITH->matrix[i - nk_keylow][1 - nk_keymodlow].c = 25;
    		else if (WITH->matrix[i - nk_keylow][1 - nk_keymodlow].c == 158)
    			WITH->matrix[i - nk_keylow][1 - nk_keymodlow].c = 26;
    	}
    	for (i = 60; i <= 79; i++)
    	{
    		WITH->matrix[i - nk_keylow][1 - nk_keymodlow].c = i + 134;
    		WITH->matrix[i - nk_keylow][2 - nk_keymodlow].c = i + 68;
    		WITH->matrix[i - nk_keylow][3 - nk_keymodlow].c = i + 88;
    		WITH->matrix[i - nk_keylow][1 - nk_keymodlow].k = nk_kknormal;
    		WITH->matrix[i - nk_keylow][2 - nk_keymodlow].k = nk_kknormal;
    		WITH->matrix[i - nk_keylow][3 - nk_keymodlow].k = nk_kknormal;
    	}
    	WITH->matrix[46 - nk_keylow][-nk_keymodlow].c = 7;
    	WITH->matrix[46 - nk_keylow][-nk_keymodlow].k = nk_kknormal;
    	XRebindKeysym(m_display, XStringToKeysym("BackSpace"), NULL, 0, (unsigned char * )"\007", 1);
    	gg.refrflag = true;
    	gg.markers = false;
    	gg.numpages = 1;
    	*gg.func = '\0';
    	*gg.genfunc = '\0';
    	gg.xoff = origin;
    	gg.yoff = origin;
    	xoffp[0] = origin;
    	yoffp[0] = origin;
    	xoff0 = 0;
    	yoff0 = 0;
    	gatecount[0] = 0;
    	gg.gbase[0] = NULL;
    	gg.sbase[0] = NULL;
    	gg.hwbase[0] = NULL;
    	gg.vwbase[0] = NULL;
    	gg.lbase[0] = NULL;
    	gg.bbase[0] = NULL;
    	gg.nbase = NULL;
    	gg.pagechanged[0] = false;
    	stamp(gg.pagestamp);
    	gg.pageregions[0] = NULL;
    	curfilename[0] = NULL;
    	initbuf(&copybuf);
    	nodeconflictbase = NULL;
    	gateconflictbase = NULL;
    	gg.movinghw = NULL;
    	gg.movingvw = NULL;
    	gg.signaltab = (log_sigrec *)Malloc(gg.maxsignal * sizeof(log_sigrec));
    	FORLIM = gg.maxsignal;
    	for (i = 0; i < FORLIM; i++)
    	{
    		WITH1 = &gg.signaltab[i];
    		WITH1->name = NULL;
    		WITH1->np = NULL;
    	}
    	gg.lastsignal = 0;
    	gg.hnbase = NULL;
    	hncount = 0;
    	hnocount = 0;
    	gg.htbase = NULL;
    	gg.htlast = NULL;
    	htcount = 0;
    	histtrig = 0;
    	gg.histactive = false;
    	histonscreen = false;
    	histgridmode = 2;
    	histgridwhich = 0;
    	histgridhn = NULL;
    	gg.probenode = NULL;
    	gg.probegate = NULL;
    	gg.probepin = 0;
    	gg.probesimtype = NULL;
    	gg.probekind = NULL;
    	probeflag = false;
    	briefprobe = false;
    	rabstate = 0;
    	rabbits = false;
    	rabflag = false;
    	firsttraining = true;
    	training = false;
    	cureditmode = 1;
    	*modename = '\0';
    	modeflag = false;
    	modetime = 0;
    	modeprobekind = NULL;
    	gg.time = 0.0;
    	gg.prevtimestep = 0.0;
    	reportnowait = false;
    	gg.startpoint = false;
    	simtype_ignore = findtool("0");
    	if (!simtype_ignore->ready)
    		report(10, rtn);
    	simtype_common = findtool("1");
    	if (!simtype_common->ready)
    		report(11, rtn);
    	i = 1;
    	l1 = V.loadgates;
    	while (l1 != NULL && i != 0)
    	{
    		if (*l1->s == '\0')
    			getgategroup((na_strlist_t *)l1->value);
    		else
    			i = readlibrary(l1->s);
    		l1 = l1->next;
    	}
    	strlist_empty(&V.loadgates);
    	l1 = V.logmenu;
    	FORLIM = kindgroupsize;
    	for (i = 0; i < FORLIM; i++)
    	{
    		kindgroup[i] = 0;
    		kindsig[i] = 0;
    		kindattr[i] = NULL;
    		if (l1 != NULL)
    		{
    			kindgroup[i] = readlibrary(l1->s);
    			l1 = l1->next;
    		}
    	}
    	strlist_empty(&V.logmenu);
    	refrscreen();
    	clearalpha();
    
    	/*shift-right*/
    }
    
    #undef rtn
    
    
    
    static void shownews()
    {
    	FILE *f;
    	char s[256];
    	char *TEMP;
    
    	f = NULL;
    	TRY(try39);
    	if (f != NULL)
    		f = freopen(lognewsname, "r", f);
    	else
    		f = fopen(lognewsname, "r");
    
    	if (f == NULL)
    	{
    		P_escapecode = -10;
    		P_ioresult = FileNotFound;
    		goto _Ltry39;
    	}
    	clearalpha();
    	while (fgets(s, 256, f) != NULL)
    	{
    		TEMP = (char *)strchr(s, '\n');
    		if (TEMP != NULL)
    			*TEMP = '\0';
    		puts(s);
    	}
    	m_alpha_on();
    	noblink();
    	RECOVER2(try39,_Ltry39);
    	if (P_escapecode == -20)
    		_Escape(P_escapecode);
    	ENDTRY(try39);
    	if (f != NULL)
    		fclose(f);
    }
    
    
    /*================  MAIN PROGRAM  ================*/
    /*=                                              =*/
    /*=  Initialize.                                 =*/
    /*=  Process pen:                                =*/
    /*=     Add gates.  Add wires.  Solder wires.    =*/
    /*=  Refresh screen when necessary.              =*/
    /*=  Process keyboard/menu areas.                =*/
    /*=                                              =*/
    /*================================================*/
    
    int main(int argc, char * argv[])
    {
    	long FORLIM;
    	char STR1[81];
    
    	nc_text_in_window = 1;
    	PASCAL_MAIN(argc, argv);
    	tracefile = NULL;
    	dumpfile = NULL;
    	newci_markprogram(&programmark);   /*NEWCI*/
    	gg.initdone = false;
    	entrycapslock = nk_capslock;
    	nk_settransarray(nk_ktcurrent, &curkeytrans);
    	gg.traceopen = false;
    	gg.dumpopen = false;
    	gg.runstamp = timers_sysclock();
    	excpline = -1;
    	for (temp1 = 1; temp1 <= maxgatesfiles; temp1++)
    		libf1[temp1 - 1] = NULL;
    	TRY(try40);
    	initialize();
    	printf("\210\f Starting\201\210 LOG\f\200");
    	do
    	{
    		gg.initdone = true;
    		gg.fastspeed = gg.fastmin;
    		TRY(try41);
    		do
    		{
    			excpline = -1;
    			tempverbose = false;
    			suppressdots = false;
    			if (justonecommand && thingstodo == NULL)
    			{
    				P_escapecode = 20;
    				goto _Ltry41;
    			}
    			if (gg.showpage <= 0)
    				refrscreen();
    			m_graphics_on();
    			nc_cursor_off();
    			while (messages != NULL)
    			{
    				switch ((long)messages->value)
    				{
    
    					case 0:
    						message(messages->s);
    						break;
    
    					case 1:
    						vmessage(messages->s);
    						break;
    				}
    				strlist_delete(&messages, &messages);
    			}
    			if (gg.startpoint)
    				crosshair(gg.posx, gg.posy);
    			else
    				nocrosshair();
    			gg.stillnear = true;
    			rabtime = timers_sysclock();
    			if (displaynews)
    				shownews();
    			if (*gg.func == '\0')
    			{
    				do
    				{
    					if (refrtimer == 0 && !gg.startpoint)
    					{
    						refresh();
    						gg.refrflag = true;
    					}
    					if (refrtimer > 0)
    					{
    						if (gg.t.moving)
    							refrtimer = refrtimer0;
    						else
    							refrtimer--;
    					}
    					pass();
    					trykbdscroll();
    					pen();
    					if (!gg.stillnear)
    					{
    						gg.startpoint = false;
    						gg.stillnear = true;
    						nocrosshair();
    					}
    
    					if (gg.t.near_)
    					{
    						if (rabflag)
    							norabbits();
    						rabtime = timers_sysclock();
    					}
    
    					if (timers_sysclock() - rabtime > rabdelay && !avoidrabbits)
    						addrabbit();
    				} while (!(gg.t.dn || *gg.func != '\0'));
    			}
    			if (displaynews)
    			{
    				clearalpha();
    				displaynews = false;
    			}
    			if (rabflag)
    				norabbits();
    			nocrosshair();
    			clipoff();
    			if (*gg.func != '\0')
    			{
    				commandfound = false;
    				dofunction();
    				if (!commandfound)
    				{
    					beginerror();
    					printf("Can't understand function %s\n", gg.func);
    					enderror();
    					clearfunc();
    				}
    			}
    			else if (gg.incircuit)
    			{
    				pass();
    				clipoff();
    				gg.oldx = gg.posx;
    				gg.oldy = gg.posy;
    				ospointflag = gg.startpoint;
    				gg.posx = gg.gridx;
    				gg.posy = gg.gridy;
    				gg.startpoint = true;
    				if (!ospointflag && !justtap() && !gg.invisible && !gg.showconflicts)
    				{
    					if (gg.probemode)
    					{
    						yardstick();
    					}
    					else
    					{
    						moveobject();
    						gg.movinghw = NULL;
    						gg.movingvw = NULL;
    					}
    				}
    				else
    				{
    					closergate(gg.posx, gg.posy);
    					if (gg.nearlabel != NULL && !gg.invisible && !gg.textinvisible)
    					{
    						editlabel(gg.nearlabel);
    						gg.startpoint = false;
    					}
    					else if (!ospointflag && gg.neargate != NULL)
    					{
    						if (gg.probemode)
    						{
    							configgate(gg.neargate);
    							gg.startpoint = false;
    						}
    						else
    						{
    							touchgate(gg.neargate);
    							gg.startpoint = false;
    						}
    					}
    					else if (!ospointflag)
    					{
    						closerwire(gg.posx, gg.posy);
    						if (gg.probemode)
    						{
    							if (gg.nearhw != NULL)
    								confignode(gg.nearhw->node, "(Node)");
    							else if (gg.nearvw != NULL)
    								confignode(gg.nearvw->node, "(Node)");
    							gg.startpoint = false;
    						}
    						else if (gg.nearhw != NULL && gg.nearvw != NULL &&
    								gg.nearhw->x1 != gg.posx &&
    								gg.nearhw->x2 != gg.posx &&
    								gg.nearvw->y1 != gg.posy &&
    								gg.nearvw->y2 != gg.posy)
    						{
    							if (findsolder(gg.posx, gg.posy) != NULL)
    							{
    								unsoldernear();
    								pen();   /* Restore cursor */
    								gg.startpoint = false;
    							}
    							else if (!vlsi || gg.nearhw->wcolr == log_wcol_blue ||
    									gg.nearvw->wcolr == log_wcol_blue)
    							{
    								soldernear();
    								gg.startpoint = false;
    							}
    						}
    					}
    					else
    					{
    						if (hvline(gg.oldx, gg.oldy, &gg.posx, &gg.posy))
    						{
    							if (gg.posx != gg.oldx)
    								addhwire(gg.posx, gg.oldx, gg.posy, curwcolor);
    							if (gg.posy != gg.oldy)
    								addvwire(gg.posx, gg.oldy, gg.posy, curwcolor);
    						}
    					}
    					if (gg.invisible || gg.probemode || gg.showconflicts)
    						gg.startpoint = false;
    				}
    			}
    			else if (inbox((int)(menux1 - 4), line1 - 5, 34, 20))
    				popupmenu(1);
    			else if (inbox((int)(menux1 - 4), line2 - 5, 34, 20))
    				assertfunc("HELP");
    			else if (inbox((int)(menux2 - 4), line1 - 5, 34, 20))
    				popupmenu(2);
    			else if (inbox((int)(menux2 - 4), line2 - 5, 34, 20))
    				assertfunc("CAT");
    			else if (inbox((int)(across + menux3 - 4), line1 - 5, 34, 20))
    				popupmenu(3);
    			else if (inbox((int)(across + menux4 - 4), line1 - 5, 34, 20))
    				popupmenu(4);
    			else if (inbox((int)(across + menux4 - 4), line2 - 5, 34, 20))
    				assertfunc("TAPMODE");
    			else
    			{
    				if (kindgroupleft <= gg.t.x && gg.t.x < kindgroupright &&
    						gg.t.y < down) {
    					temp1 = (gg.t.x - kindgroupleft) / kindgroupspacing + 1;
    					if (gg.probemode)
    						configkind((int)temp1);
    					else if (justtap())
    						flipkind();
    					else if (!gg.invisible && !gg.probemode && !gg.showconflicts)
    					{
    						if (addgate(kindgroup[temp1 - 1], kindsig[temp1 - 1],
    									kindattr[temp1 - 1]))
    							nextkindsig((int)temp1);
    					}
    				}
    				gg.startpoint = false;
    			}
    			/*        sleep(2);zfprintf(stdout, "z"); fflush(stdout);  **MDG** test */
    		} while (!pigsfly);
    		RECOVER2(try41,_Ltry41);
    		gg.curpage = realcurpage;
    		*gg.func = '\0';
    		if (excpline == -1)
    			excpline = EXCP_LINE;
    		if (P_escapecode == 20)
    		{
    			working();
    			P_escapecode = -20;
    			goto _Ltry40;
    		}
    
    		if (P_escapecode != -20)
    			goto _Ltry40;
    		clearshowalpha();
    		printf( "\n\n%c%cPress CLR I/O again to exit, any other key to continue.%c\n\n",
    				chryellow, chrplain, chrgreen);
    		nk_keybufclear();
    		waitforkey();
    		m_graphics_on();
    		clearalpha();
    		ENDTRY(try41);
    		refrscreen();
    	} while (!pigsfly);
    	RECOVER2(try40,_Ltry40);
    	TRY(try42);
    	temp1 = P_ioresult;
    	temp2 = P_escapecode;
    	if (excpline == -1)
    		excpline = EXCP_LINE;
    	for (temp4 = 1; temp4 <= maxgatesfiles; temp4++)
    	{
    		if (libf1[temp4 - 1] != NULL)
    		{
    			if (libf1[temp4 - 1]->f != NULL)
    				fclose(libf1[temp4 - 1]->f);
    			libf1[temp4 - 1]->f = NULL;
    		}
    	}
    	nk_setcapslock(entrycapslock);
    	if (temp2 == 0)
    	{
    		showalpha();
    	}
    	else if (temp2 == -20 && timers_sysclock() < watchdog + watchdogtime)
    	{
    		clearshowalpha();
    		printf("%c%c\n\n", chrgreen, chrplain);
    	}
    	else
    	{
    		clearshowalpha();
    		printf("\n\n%c%cUnexpected runtime error%c%c\n\n",
    				chryellow, chrunderl, chrplain, chrgreen);
    		printf("    Escapecode =  %ld\n", temp2);
    		if (temp2 == -10)
    			printf("    Ioresult   =  %ld = %s\n",
    					temp1, ioresult_message(STR1, temp1));
    		if (excpline != -1)
    			printf("    Line num   =  %ld\n", excpline);
    		printf("\n Probable cause:  ");
    		switch (-temp2)
    		{
    
    			case 2:
    				printf("Not enough memory\n");
    				break;
    
    			case 4:
    			case 5:
    			case 6:
    			case 7:
    			case 15:
    			case 16:
    			case 17:
    			case 18:
    			case 19:
    				printf("Arithmetic overflow\n");
    				break;
    
    			case 20:
    				printf("Unexpected user termination\n");
    				break;
    
    			case 10:
    				printf("I/O problem\n");
    				break;
    
    			case 26:
    				printf("Low-level I/O\n");
    				break;
    
    			default:
    				putchar('\n');
    				break;
    		}
    		putchar('\n');
    		warning();
    		nk_keybufclear();
    		if (gg.initdone)
    		{
    			printf("Want debugging printout? ");
    			do
    			{
    				tempch = nk_getkey();
    			} while (tempch != 'n' && tempch != 'N' && tempch != 'y' &&
    					tempch != 'Y');
    			printf("%c\n", tempch);
    			if (tempch == 'y' || tempch == 'Y')
    			{
    				TRY(try43);
    				gg.traceflag = true;
    				tracemessage("");
    				fprintf(tracefile, "ESCAPECODE %ld\n", temp2);
    				fprintf(tracefile, "IORESULT   %ld\n", temp1);
    				fprintf(tracefile, "LINE       %ld\n\n", excpline);
    				fprintf(tracefile, "Current page: %ld\n", gg.curpage);
    				dumpnodes();
    				RECOVER(try43);
    				printf("Debugging printout failed.\n");
    				ENDTRY(try43);
    			}
    			putchar('\n');
    		}
    		FORLIM = gg.numpages;
    		for (temp1 = 1; temp1 <= FORLIM; temp1++)
    		{
    			printf("Try to save page %ld? ", temp1);
    			do
    			{
    				tempch = nk_getkey();
    			} while (tempch != 'n' && tempch != 'N' && tempch != 'y' &&
    					tempch != 'Y');
    			printf("%c\n", tempch);
    			if (tempch == 'y' || tempch == 'Y')
    				emergencysave((int)temp1);
    		}
    	}
    	RECOVER(try42);
    	printf("Error %d in outer TRY-RECOVER\n", P_escapecode);
    	ENDTRY(try42);
    	ENDTRY(try40);
    	TRY(try44);
    	closetools();
    	RECOVER(try44);
    	;
    	ENDTRY(try44);
    	closedumpfiles();
    	newci_releaseprogram(&programmark);   /*NEWCI*/
    	nk_setcapslock(entrycapslock);
    	nk_settransarray(nk_ktstandard, &curkeytrans);
    	showalpha();
    	if (dumpfile != NULL)
    		fclose(dumpfile);
    	if (tracefile != NULL)
    		fclose(tracefile);
    	exit(0);
    }
    
    
    /* End. */