1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usr.c
6  * User interface tool: main module
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "egraphics.h"
34 #include "edialogs.h"
35 #include "tech.h"
36 #include "usr.h"
37 #include "usrtrack.h"
38 #include "usrdiacom.h"
39 #include "sim.h"
40 #include "tecart.h"
41 #include "tecgen.h"
42 #include "tecschem.h"
43 #include <setjmp.h>		/* for nonlocal goto's */
44 
45 TOOL        *us_tool;					/* the USER tool object */
46 INTBIG       us_longcount;				/* number of long commands */
47 void       (*us_displayroutine)(POLYGON*, WINDOWPART*); /* routine for graphics display */
48 INTBIG       us_currenteditor;			/* the current editor (index to "us_editortable") */
49 INTBIG       us_cursorstate;			/* current cursor being displayed */
50 INTBIG       us_normalcursor;			/* default cursor to use */
51 BOOLEAN      us_optionschanged;			/* true if options changed */
52 INTBIG       us_layer_letters_key;		/* variable key for "USER_layer_letters" */
53 INTBIG       us_highlightedkey;			/* variable key for "USER_highlighted" */
54 INTBIG       us_highlightstackkey;		/* variable key for "USER_highlightstack" */
55 INTBIG       us_binding_keys_key;		/* variable key for "USER_binding_keys" */
56 INTBIG       us_binding_buttons_key;	/* variable key for "USER_binding_buttons" */
57 INTBIG       us_binding_menu_key;		/* variable key for "USER_binding_menu" */
58 INTBIG       us_current_node_key;		/* variable key for "USER_current_node" */
59 INTBIG       us_current_arc_key;		/* variable key for "USER_current_arc" */
60 INTBIG       us_placement_angle_key;	/* variable key for "USER_placement_angle" */
61 INTBIG       us_alignment_ratio_key;	/* variable key for "USER_alignment_ratio" */
62 INTBIG       us_alignment_edge_ratio_key;/* variable key for "USER_alignment_edge_ratio" */
63 INTBIG       us_arcstylekey;			/* variable key for "USER_arc_style" */
64 INTBIG       us_current_technology_key;	/* variable key for "USER_current_technology" */
65 INTBIG       us_current_window_key;		/* variable key for "USER_current_window" */
66 INTBIG       us_current_constraint_key;	/* variable key for "USER_current_constraint" */
67 INTBIG       us_colormap_red_key;		/* variable key for "USER_colormap_red" */
68 INTBIG       us_colormap_green_key;		/* variable key for "USER_colormap_green" */
69 INTBIG       us_colormap_blue_key;		/* variable key for "USER_colormap_blue" */
70 INTBIG       us_copyright_file_key;		/* variable key for "USER_copyright_file" */
71 INTBIG       us_menu_position_key;		/* variable key for "USER_menu_position" */
72 INTBIG       us_menu_x_key;				/* variable key for "USER_menu_x" */
73 INTBIG       us_menu_y_key;				/* variable key for "USER_menu_y" */
74 INTBIG       us_macrorunningkey;		/* variable key for "USER_macrorunning" */
75 INTBIG       us_macrobuildingkey;		/* variable key for "USER_macrobuilding" */
76 INTBIG       us_text_editorkey;			/* variable key for "USER_text_editor" */
77 INTBIG       us_optionflagskey;			/* variable key for "USER_optionflags" */
78 INTBIG       us_gridfloatskey;			/* variable key for "USER_grid_floats" */
79 INTBIG       us_gridboldspacingkey;		/* variable key for "USER_grid_bold_spacing" */
80 INTBIG       us_quickkeyskey;			/* variable key for "USER_quick_keys" */
81 INTBIG       us_interactiveanglekey;	/* variable key for "USER_interactive_angle" */
82 INTBIG       us_tinylambdaperpixelkey;	/* variable key for "USER_tiny_lambda_per_pixel" */
83 INTBIG       us_ignoreoptionchangeskey;	/* variable key for "USER_ignore_option_changes" */
84 INTBIG       us_displayunitskey;		/* variable key for "USER_display_units" */
85 INTBIG       us_electricalunitskey;		/* variable key for "USER_electrical_units" */
86 INTBIG       us_motiondelaykey;			/* variable key for "USER_motion_delay" */
87 INTBIG       us_java_flags_key;			/* variable key for "JAVA_flags" */
88 INTBIG       us_edtec_option_key;		/* variable key for "EDTEC_option" */
89 INTBIG       us_electricalunits;		/* mirror for "USER_electrical_units" */
90 INTBIG       us_javaflags;				/* mirror for "JAVA_flags" */
91 INTBIG       us_useroptions;			/* mirror for "USER_optionflags" */
92 INTBIG       us_tinyratio;				/* mirror for "USER_tiny_lambda_per_pixel" */
93 INTBIG       us_separatechar;			/* separating character in port names */
94 INTBIG       us_filetypecolormap;		/* Color map file descriptor */
95 INTBIG       us_filetypehelp;			/* Help file descriptor */
96 INTBIG       us_filetypelog;			/* Log file descriptor */
97 INTBIG       us_filetypemacro;			/* Macro file descriptor */
98 INTBIG       us_filetypenews;			/* News file descriptor */
99 
100 /* local state */
101 static BOOLEAN    us_ignore_cadrc;		/* set when user wants to ignore the cadrc file */
102 static CHAR      *us_firstlibrary;		/* library to read upon startup */
103 static CHAR      *us_firstmacrofile;	/* macro file to read upon startup */
104 static INTBIG     us_techlaststatekey;	/* variable key for "TECH_last_state" */
105 static INTBIG     us_filetypecadrc;		/* Startup file descriptor*/
106 static CHAR       us_desiredlibrary[300];	/* library to be read at startup */
107 static BOOLEAN    us_logging = TRUE;	/* nonzero to start session logging */
108 
109 /* for tracking broadcast changes */
110 static TOOL      *us_batchsource;
111 static WINDOWPART us_oldwindow, *us_firstnewwindow, *us_secondnewwindow, *us_killedwindow;
112 static INTBIG     us_maplow, us_maphigh, us_newwindowcount;
113 static BOOLEAN    us_menuchanged, us_gridfactorschanged, us_cellstructurechanged;
114 static INTBIG     us_oldstate, us_oldoptions;
115 static NODEPROTO *us_firstchangedcell, *us_secondchangedcell;
116 static NODEPROTO *us_cellwithkilledname;				/* cell whose name was just killed */
117 static CHAR      *us_killednameoncell;					/* name that was removed from cell */
118 
119 static VARMIRROR us_variablemirror[] =
120 {
121 	{&us_optionflagskey,        &us_useroptions},
122 	{&us_tinylambdaperpixelkey, &us_tinyratio},
123 	{&us_menu_x_key,            &us_menux},
124 	{&us_menu_y_key,            &us_menuy},
125 	{&us_menu_position_key,     &us_menupos},
126 	{&us_java_flags_key,        &us_javaflags},
127 	{&us_electricalunitskey,    &us_electricalunits},
128 	{0, 0}
129 };
130 
131 /* internal state */
132 INTBIG       us_state;					/* miscellaneous state of user interface */
133 
134 /* when modifying this list of status fields, update "usrcomwz.c:us_statusfields[]" */
135 STATUSFIELD *us_statusalign = 0;		/* current node alignment */
136 STATUSFIELD *us_statusangle = 0;		/* current placement angle */
137 STATUSFIELD *us_statusarc = 0;			/* current arc prototype */
138 STATUSFIELD *us_statuscell = 0;			/* current cell */
139 STATUSFIELD *us_statuscellsize = 0;		/* current cell size */
140 STATUSFIELD *us_statusselectcount = 0;	/* current selection count */
141 STATUSFIELD *us_statusgridsize = 0;		/* current grid size */
142 STATUSFIELD *us_statuslambda = 0;		/* current lambda */
143 STATUSFIELD *us_statusnode = 0;			/* current node prototype */
144 STATUSFIELD *us_statustechnology = 0;	/* current technology */
145 STATUSFIELD *us_statusxpos = 0;			/* current x position */
146 STATUSFIELD *us_statusypos = 0;			/* current y position */
147 STATUSFIELD *us_statusproject = 0;		/* current project */
148 STATUSFIELD *us_statusroot = 0;			/* current root */
149 STATUSFIELD *us_statuspart = 0;			/* current part */
150 STATUSFIELD *us_statuspackage = 0;		/* current package */
151 STATUSFIELD *us_statusselection = 0;	/* current selection */
152 
153 /* user interface state */
154 NODEPROTO   *us_curnodeproto;			/* current nodeproto */
155 ARCPROTO    *us_curarcproto;			/* current arcproto */
156 INTBIG       us_alignment_ratio;		/* current alignment in fractional units */
157 INTBIG       us_edgealignment_ratio;	/* current edge alignment in fractional units */
158 BOOLEAN      us_dupdistset;				/* true if duplication distance is valid */
159 NODEINST    *us_dupnode;				/* a node that was duplicated */
160 LIBRARY     *us_clipboardlib;			/* library with cut/copy/paste cell */
161 NODEPROTO   *us_clipboardcell;			/* cell with cut/copy/paste objects */
162 INTBIG       us_dupx, us_dupy;			/* amount to move duplicated objects */
163 WINDOWFRAME *us_menuframe;				/* window frame on which menu resides */
164 #ifndef USEQT
165 INTSML       us_erasech, us_killch;		/* the erase and kill characters */
166 #endif
167 INTBIG       us_menux, us_menuy;		/* number of menu elements on the screen */
168 INTBIG       us_menupos;				/* position: 0:top 1:bottom 2:left 3:right */
169 INTBIG       us_menuxsz,us_menuysz;		/* size of menu elements */
170 INTBIG       us_menuhnx,us_menuhny;		/* highlighted nodeinst menu entry */
171 INTBIG       us_menuhax,us_menuhay;		/* highlighted arcinst menu entry */
172 INTBIG       us_menulx,us_menuhx;		/* X: low and high of menu area */
173 INTBIG       us_menuly,us_menuhy;		/* Y: low and high of menu area */
174 INTBIG       us_lastmeasurex, us_lastmeasurey;	/* last measured distance */
175 BOOLEAN      us_validmesaure;			/* true if a measure was done */
176 INTBIG       us_explorerratio = 25;		/* percentage of window used by cell explorer */
177 FILE        *us_logrecord;				/* logging record file */
178 FILE        *us_logplay;				/* logging playback file */
179 FILE        *us_termaudit;				/* messages window auditing file */
180 FILE        *us_tracefile = NULL;
181 INTBIG       us_logflushfreq;			/* session logging flush frequency */
182 INTBIG       us_quickkeyfactcount = 0;	/* number of quick keys in "factory" setup */
183 CHAR       **us_quickkeyfactlist;		/* quick keys in "factory" setup */
184 
185 INTBIG       us_lastcommandcount;		/* the keyword count for the last command set by the "remember" command */
186 INTBIG       us_lastcommandtotal = 0;	/* size of keyword array for the last command set by the "remember" command */
187 CHAR       **us_lastcommandpar;			/* the keywords for the last command set by the "remember" command */
188 
189 MACROPACK   *us_macropacktop;			/* top of list of defined macro packages */
190 MACROPACK   *us_curmacropack;			/* current macro package */
191 
192 USERCOM     *us_usercomfree;			/* list of free user commands */
193 USERCOM     *us_lastcom;				/* last command and arguments */
194 
195 POPUPMENU   *us_firstpopupmenu;			/* list of existing pop-up menus */
196 INTBIG       us_pulldownmenucount;		/* number of pulldown menus */
197 INTBIG      *us_pulldownmenupos;		/* position of pulldown menus */
198 POPUPMENU   **us_pulldowns;				/* the current pulldown menus */
199 
200 /* prototypes for local routines */
201 static BOOLEAN us_do2init(INTBIG*, CHAR1*[]);
202 static BOOLEAN us_do3init(void);
203 static void us_causeofslice(USERCOM*);
204 static void us_setcommand(CHAR*, USERCOM*, INTBIG, NODEPROTO*, ARCPROTO*, CHAR*, POPUPMENU*, BOOLEAN);
205 static BOOLEAN us_options(INTBIG*, CHAR1*[]);
206 static BOOLEAN us_docadrc(CHAR*);
207 static void us_findcadrc(void);
208 static void us_checkfontassociations(LIBRARY *lib);
209 static void us_setfontassociationdescript(UINTBIG *descript, INTBIG *fontmatch);
210 static void us_setfontassociationvar(INTSML numvar, VARIABLE *firstvar, INTBIG *fontmatch);
211 static void us_checkinplaceedits(NODEPROTO *cell);
212 
213 /******************** CONTROL ********************/
214 
215 /* initialize the user interface tool */
us_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)216 void us_init(INTBIG *argc, CHAR1 *argv[], TOOL *thistool)
217 {
218 	if (thistool == 0)
219 	{
220 		/* pass 3 */
221 		if (us_do3init())
222 			error(_("No memory to run the user interface"));
223 	} else if (thistool == NOTOOL)
224 	{
225 		/* pass 2 */
226 		if (us_do2init(argc, argv))
227 			error(_("No memory to run the user interface"));
228 	} else
229 	{
230 		/* pass 1 */
231 		us_tool = thistool;
232 		el_topwindowpart = NOWINDOWPART;	/* no windows defined */
233 	}
234 }
235 
236 /* pass 2 of initialization */
us_do2init(INTBIG * argc,CHAR1 * argv[])237 BOOLEAN us_do2init(INTBIG *argc, CHAR1 *argv[])
238 {
239 	CHAR *newpar[3], msg[150];
240 	REGISTER INTBIG i;
241 	INTBIG swid, shei, twid, thei;
242 	INTBIG keys[2];
243 	UINTBIG descript[TEXTDESCRIPTSIZE];
244 	REGISTER TECHNOLOGY *tech;
245 	extern GRAPHICS us_gbox, us_box;
246 	REGISTER WINDOWFRAME *wf;
247 	REGISTER VARIABLE *varred, *vargreen, *varblue;
248 
249 	/* initialize lists */
250 	us_usercomfree = NOUSERCOM;		/* no free command modules */
251 
252 	/* define the default macro called "macro" */
253 	newpar[0] = newpar[1] = newpar[2] = x_("");
254 	nextchangequiet();
255 	(void)setvalkey((INTBIG)us_tool, VTOOL, makekey(x_("USER_macro_macro")),
256 		(INTBIG)newpar, VSTRING|VISARRAY|(3<<VLENGTHSH)|VDONTSAVE);
257 
258 	/* basic initialization */
259 	us_logplay = NULL;					/* no session playback */
260 	us_logrecord = NULL;				/* no session recording */
261 	us_termaudit = NULL;				/* no terminal auditing */
262 	us_logflushfreq = 10;				/* flush session recording every 10 */
263 	us_lastcom = NOUSERCOM;				/* no last command issued */
264 	us_macropacktop = NOMACROPACK;		/* no defined macro packages */
265 	us_curmacropack = NOMACROPACK;		/* no current macro package */
266 	us_menuhnx = us_menuhax = -1;		/* no menu highlighting */
267 	us_menupos = 0;						/* menus on the top */
268 	us_firstpopupmenu = NOPOPUPMENU;	/* no popup menus yet */
269 	us_pulldownmenucount = 0;			/* no pulldown menus in menubar */
270 	us_state = 0;						/* all is well */
271 	us_dupdistset = FALSE;				/* duplication distance not set */
272 	us_dupnode = NONODEINST;			/* duplication node not set */
273 	us_currenteditor = 0;				/* use the first editor */
274 	us_tool->toolstate |= INTERACTIVE;	/* use interactive cursor commands */
275 	us_validmesaure = FALSE;			/* nothing measured */
276 	us_tinyratio = K4;					/* default ratio for hashing tiny cells */
277 	us_javaflags = 0;					/* default Java flags */
278 	us_separatechar = '_';				/* default separating character */
279 	us_curarcproto = NOARCPROTO;
280 	us_curnodeproto = NONODEPROTO;
281 	us_layer_letters_key = makekey(x_("USER_layer_letters"));
282 	us_highlightedkey = makekey(x_("USER_highlighted"));
283 	us_highlightstackkey = makekey(x_("USER_highlightstack"));
284 	us_binding_keys_key = makekey(x_("USER_binding_keys"));
285 	us_binding_buttons_key = makekey(x_("USER_binding_buttons"));
286 	us_binding_menu_key = makekey(x_("USER_binding_menu"));
287 	us_current_node_key = makekey(x_("USER_current_node"));
288 	us_current_arc_key = makekey(x_("USER_current_arc"));
289 	us_placement_angle_key = makekey(x_("USER_placement_angle"));
290 	us_alignment_ratio_key = makekey(x_("USER_alignment_ratio"));
291 	us_alignment_edge_ratio_key = makekey(x_("USER_alignment_edge_ratio"));
292 	us_arcstylekey = makekey(x_("USER_arc_style"));
293 	us_current_technology_key = makekey(x_("USER_current_technology"));
294 	us_current_window_key = makekey(x_("USER_current_window"));
295 	us_current_constraint_key = makekey(x_("USER_current_constraint"));
296 	us_colormap_red_key = makekey(x_("USER_colormap_red"));
297 	us_colormap_green_key = makekey(x_("USER_colormap_green"));
298 	us_colormap_blue_key = makekey(x_("USER_colormap_blue"));
299 	us_copyright_file_key = makekey(x_("USER_copyright_file"));
300 	us_menu_position_key = makekey(x_("USER_menu_position"));
301 	us_menu_x_key = makekey(x_("USER_menu_x"));
302 	us_menu_y_key = makekey(x_("USER_menu_y"));
303 	us_macrorunningkey = makekey(x_("USER_macrorunning"));
304 	us_macrobuildingkey = makekey(x_("USER_macrobuilding"));
305 	us_text_editorkey = makekey(x_("USER_text_editor"));
306 	us_gridfloatskey = makekey(x_("USER_grid_floats"));
307 	us_gridboldspacingkey = makekey(x_("USER_grid_bold_spacing"));
308 	us_quickkeyskey = makekey(x_("USER_quick_keys"));
309 	us_interactiveanglekey = makekey(x_("USER_interactive_angle"));
310 	us_tinylambdaperpixelkey = makekey(x_("USER_tiny_lambda_per_pixel"));
311 	us_techlaststatekey = makekey(x_("TECH_last_state"));
312 	us_optionflagskey = makekey(x_("USER_optionflags"));
313 	us_ignoreoptionchangeskey = makekey(x_("USER_ignore_option_changes"));
314 	us_displayunitskey = makekey(x_("USER_display_units"));
315 	us_electricalunitskey = makekey(x_("USER_electrical_units"));
316 	us_motiondelaykey = makekey(x_("USER_motion_delay"));
317 	us_java_flags_key = makekey(x_("JAVA_flags"));
318 	us_edtec_option_key = makekey(x_("EDTEC_option"));
319 
320 	/* setup disk file descriptors */
321 	us_filetypecadrc    = setupfiletype(x_(""),     x_("*.*"),    MACFSTAG('TEXT'), FALSE, x_("cadrc"), _("Startup"));
322 	us_filetypecolormap = setupfiletype(x_("map"),  x_("*.map"),  MACFSTAG('TEXT'), FALSE, x_("color"), _("Color map"));
323 	us_filetypehelp     = setupfiletype(x_("help"), x_("*.help"), MACFSTAG('TEXT'), FALSE, x_("help"), _("Help"));
324 	us_filetypelog      = setupfiletype(x_("log"),  x_("*.log"),  MACFSTAG('LOG '), FALSE,  x_("log"), _("Log"));
325 	us_filetypemacro    = setupfiletype(x_("mac"),  x_("*.mac"),  MACFSTAG('TEXT'), FALSE, x_("macro"), _("Macro package"));
326 	us_filetypenews     = setupfiletype(x_("news"), x_("*.news"), MACFSTAG('TEXT'), FALSE, x_("news"), _("News"));
327 
328 	/* initially ignore all graphics */
329 	us_displayroutine = us_nulldisplayroutine;
330 
331 	/* set opaque graphics data */
332 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
333 		us_figuretechopaque(tech);
334 
335 	/* set selectability/invisibility on primitives */
336 	us_figuretechselectability();
337 
338 	/* register technology-caching routines */
339 	keys[0] = us_layer_letters_key;
340 	registertechnologycache(us_initlayerletters, 1, keys);
341 
342 	/* count the number of commands */
343 	us_longcount = 0;
344 	for(i=0; us_lcommand[i].name != 0; i++) us_longcount++;
345 
346 	/* get switches to the program */
347 	us_firstlibrary = 0;
348 	us_desiredlibrary[0] = 0;
349 	us_firstmacrofile = 0;
350 	graphicsoptions(x_("display"), argc, argv);
351 	if (us_options(argc, argv)) return(TRUE);
352 
353 	/* establish the library location */
354 	setupenvironment();
355 
356 	/* initialize status output and graphics */
357 	if (initgraphics(TRUE)) exit(1);
358 	us_getcolormap(el_curtech, COLORSDEFAULT, FALSE);
359 	varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
360 	vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
361 	varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
362 	colormapload((INTBIG *)varred->addr, (INTBIG *)vargreen->addr,
363 		(INTBIG *)varblue->addr, 0, 255);
364 
365 	/* establish the colors to use for peripheral graphics */
366 	if (el_maplength == 2)
367 	{
368 		el_colcelltxt = 0;
369 		el_colcell = 0;
370 		el_colwinbor = 0;
371 		el_colhwinbor = 1;
372 		el_colmenbor = 0;
373 		el_colhmenbor = 1;
374 		el_colmentxt = 0;
375 		el_colmengly = 0;
376 		el_colcursor = 0;
377 	} else
378 	{
379 		if (el_maplength < 256)
380 		{
381 			us_gbox.bits = LAYERA;
382 			us_gbox.col = BLACK;
383 		} else
384 		{
385 			us_gbox.bits = LAYERG;
386 			us_gbox.col = GRID;
387 		}
388 		el_colcelltxt = CELLTXT;
389 		el_colcell = CELLOUT;
390 		el_colwinbor = WINBOR;
391 		el_colhwinbor = HWINBOR;
392 		el_colmenbor = MENBOR;
393 		el_colhmenbor = HMENBOR;
394 		el_colmentxt = MENTXT;
395 		el_colmengly = MENGLY;
396 	}
397 
398 	us_initstatus();
399 
400 	/* initialize state */
401 	nextchangequiet();
402 	(void)setval((INTBIG)us_tool, VTOOL, x_("USER_icon_style"),
403 		ICONSTYLEDEFAULT, VINTEGER|VDONTSAVE);
404 
405 	/* create the window frame that has the palette */
406 	us_menuframe = newwindowframe(TRUE, 0);
407 
408 	/* create the initial window structure */
409 	wf = newwindowframe(FALSE, 0);
410 	if (wf == NOWINDOWFRAME) wf = getwindowframe(FALSE);
411 	el_curwindowpart = newwindowpart(x_("entire"), NOWINDOWPART);
412 	if (el_curwindowpart == NOWINDOWPART) return(TRUE);
413 	el_curwindowpart->frame = wf;
414 	nextchangequiet();
415 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key,
416 		(INTBIG)el_curwindowpart, VWINDOWPART|VDONTSAVE);
417 	el_curwindowpart->buttonhandler = DEFAULTBUTTONHANDLER;
418 	el_curwindowpart->charhandler = DEFAULTCHARHANDLER;
419 	el_curwindowpart->changehandler = DEFAULTCHANGEHANDLER;
420 	el_curwindowpart->termhandler = DEFAULTTERMHANDLER;
421 	el_curwindowpart->redisphandler = DEFAULTREDISPHANDLER;
422 
423 	/* set shadows */
424 	changesquiet(TRUE);
425 	us_useroptions = PORTSFULL|CENTEREDPRIMITIVES|AUTOSWITCHTECHNOLOGY|CELLCENTERALWAYS;
426 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
427 		(INTBIG)us_useroptions, VINTEGER|VDONTSAVE);
428 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_constraint_key,
429 		(INTBIG)el_curconstraint, VCONSTRAINT|VDONTSAVE);
430 	us_alignment_ratio = WHOLE;
431 	us_edgealignment_ratio = 0;
432 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_displayunitskey,
433 		el_units&DISPLAYUNITS, VINTEGER|VDONTSAVE);
434 	us_electricalunits = ELEUNITDEFAULT;
435 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_electricalunitskey,
436 		us_electricalunits, VINTEGER|VDONTSAVE);
437 	changesquiet(FALSE);
438 
439 	/* if the screen is seriously wide, put menus on the left */
440 	getwindowframesize(el_curwindowpart->frame, &swid, &shei);
441 	if (swid*2 > shei*3) us_menupos = 2;
442 
443 	/* display initial message */
444 	TDCLEAR(descript);
445 	TDSETSIZE(descript, TXTSETPOINTS(20));
446 	screensettextinfo(el_curwindowpart, NOTECHNOLOGY, descript);
447 	us_box.col = BLACK;
448 	esnprintf(msg, 150, _("Electric Version %s"), el_version);
449 	screengettextsize(el_curwindowpart, msg, &twid, &thei);
450 	screendrawtext(el_curwindowpart, (swid-twid)/2, shei/2+thei, msg, &us_box);
451 	estrcpy(msg, _("Loading..."));
452 	screengettextsize(el_curwindowpart, msg, &twid, &thei);
453 	screendrawtext(el_curwindowpart, (swid-twid)/2, shei/2-thei, msg, &us_box);
454 	flushscreen();
455 	return(FALSE);
456 }
457 
458 /* pass 3 of initialization */
us_do3init(void)459 BOOLEAN us_do3init(void)
460 {
461 	REGISTER CHAR *libname, *libfile;
462 	REGISTER INTBIG oldverbose, len, lambda, haveoptionsfile, *msgloc, filestatus;
463 	REGISTER VARIABLE *var, *varred, *vargreen, *varblue;
464 	CHAR *newpar[3], clipboardname[20];
465 	REGISTER LIBRARY *lib;
466 
467 	/* default command binding */
468 	if (us_initialbinding()) return(TRUE);
469 
470 	/* initial display in status area */
471 	us_redostatus(NOWINDOWFRAME);
472 
473 	/* set application environment */
474 #if LANGLISP
475 	nextchangequiet();
476 	(void)setvalkey((INTBIG)us_tool, VTOOL, makekey(x_("USER_have_lisp")), 1,
477 		VINTEGER|VDONTSAVE);
478 #endif
479 #if LANGTCL
480 	nextchangequiet();
481 	(void)setvalkey((INTBIG)us_tool, VTOOL, makekey(x_("USER_have_tcl")), 1,
482 		VINTEGER|VDONTSAVE);
483 #endif
484 #if LANGJAVA
485 	nextchangequiet();
486 	(void)setvalkey((INTBIG)us_tool, VTOOL, makekey(x_("USER_have_java")), 1,
487 		VINTEGER|VDONTSAVE);
488 #endif
489 
490 #ifdef FORCECADENCE
491 	nextchangequiet();
492 	(void)setvalkey((INTBIG)us_tool, VTOOL, makekey(x_("USER_have_cadence")), 1,
493 		VINTEGER|VDONTSAVE);
494 #endif
495 
496 #ifdef FORCESUNTOOLS
497 	nextchangequiet();
498 	(void)setvalkey((INTBIG)us_tool, VTOOL, makekey(x_("USER_have_suntools")), 1,
499 		VINTEGER|VDONTSAVE);
500 #endif
501 
502 	/* set variable to tell whether there needs to be a quit command */
503 	if (!graphicshas(CANHAVEQUITCOMMAND))
504 	{
505 		nextchangequiet();
506 		(void)setvalkey((INTBIG)us_tool, VTOOL, makekey(x_("USER_no_quit_command")), 1,
507 			VINTEGER|VDONTSAVE);
508 	}
509 
510 	/* read "cadrc" files */
511 	if (!us_ignore_cadrc) us_findcadrc();
512 	if (us_firstmacrofile != 0)
513 	{
514 		if (us_docadrc(us_firstmacrofile))
515 			ttyputerr(_("Cannot find startup file '%s'"), us_firstmacrofile);
516 		efree((CHAR *)us_firstmacrofile);
517 		us_firstmacrofile = 0;
518 	}
519 
520 	/* gather initial quick keys and remember them as "factory settings" */
521 	us_buildquickkeylist();
522 	us_getquickkeylist(&us_quickkeyfactcount, &us_quickkeyfactlist);
523 	if (us_quickkeyfactcount > 0)
524 	{
525 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_quickkeyskey, (INTBIG)us_quickkeyfactlist,
526 			VSTRING|VISARRAY|(us_quickkeyfactcount<<VLENGTHSH)|VDONTSAVE);
527 	}
528 
529 	/* initial setup of the color map */
530 	us_getcolormap(el_curtech, COLORSDEFAULT, FALSE);
531 
532 	/* mark the current state of the color map as "unchanged" */
533 	varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
534 	vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
535 	varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
536 	if (varred != NOVARIABLE) varred->type |= VDONTSAVE;
537 	if (vargreen != NOVARIABLE) vargreen->type |= VDONTSAVE;
538 	if (varblue != NOVARIABLE) varblue->type |= VDONTSAVE;
539 
540 	/* read the options library */
541 	libname = us_tempoptionslibraryname();
542 	libfile = optionsfilepath();
543 	haveoptionsfile = 0;
544 	filestatus = fileexistence(truepath(libfile));
545 	if (filestatus == 1 || filestatus == 3)
546 	{
547 		haveoptionsfile = 1;
548 		lib = newlibrary(libname, libfile);
549 		if (lib == NOLIBRARY) ttyputerr(_("Cannot create options library %s"), libfile); else
550 		{
551 			lib->userbits |= HIDDENLIBRARY;
552 			oldverbose = asktool(io_tool, x_("verbose"), 0);
553 			(void)asktool(io_tool, x_("read"), (INTBIG)lib, (INTBIG)x_("binary"));
554 			(void)asktool(io_tool, x_("verbose"), oldverbose);
555 			killlibrary(lib);
556 
557 			/* adjust messages window position if information is there */
558 			var = getval((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, x_("USER_messages_position"));
559 			if (var != NOVARIABLE)
560 			{
561 				msgloc = (INTBIG *)var->addr;
562 				setmessagesframeinfo(msgloc[0], msgloc[1], msgloc[2], msgloc[3]);
563 			}
564 		}
565 	}
566 	cacheoptionbitvalues();
567 
568 	/* read an initial library if it was specified in program parameters */
569 	if (us_firstlibrary != 0)
570 	{
571 		if (reallocstring(&el_curlib->libfile, us_firstlibrary, el_curlib->cluster) != 0)
572 			return(TRUE);
573 		libname = skippath(us_firstlibrary);
574 		if (reallocstring(&el_curlib->libname, libname, el_curlib->cluster) != 0)
575 			return(TRUE);
576 		len = estrlen(el_curlib->libname);
577 		if (namesame(&el_curlib->libname[len-5], x_(".elib")) == 0)
578 			el_curlib->libname[len-5] = 0;
579 		if (asktool(io_tool, x_("read"), (INTBIG)el_curlib, (INTBIG)x_("binary")) != 0)
580 		{
581 			ttyputerr(_("Could not read %s"), el_curlib->libfile);
582 			el_curlib->curnodeproto = NONODEPROTO;
583 		} else
584 		{
585 			if (el_curlib->curnodeproto != NONODEPROTO)
586 			{
587 				if (el_curlib->curnodeproto->tech != gen_tech)
588 					el_curtech = el_curlib->curnodeproto->tech;
589 				if (el_curtech != sch_tech && el_curtech != art_tech && el_curtech != gen_tech)
590 					el_curlayouttech = el_curtech;
591 			}
592 		}
593 		efree((CHAR *)us_firstlibrary);
594 		us_firstlibrary = 0;
595 	} else el_curlib->curnodeproto = NONODEPROTO;
596 
597 	/* set the user's shadow of the current technology */
598 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_technology_key,
599 		(INTBIG)el_curtech, VTECHNOLOGY|VDONTSAVE);
600 
601 	/* setup menu properly */
602 	if (el_curtech != sch_tech)
603 	{
604 		newpar[0] = x_("size");
605 		newpar[1] = x_("auto");
606 		us_menu(2, newpar);
607 		us_setmenunodearcs();
608 	}
609 
610 	/* load the color map onto the display */
611 	varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
612 	vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
613 	varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
614 	colormapload((INTBIG *)varred->addr, (INTBIG *)vargreen->addr,
615 		(INTBIG *)varblue->addr, 0, 255);
616 
617 	/* setup current window */
618 	lambda = el_curlib->lambda[el_curtech->techindex];
619 	if (el_curwindowpart != NOWINDOWPART)
620 	{
621 		var = getval((INTBIG)us_tool, VTOOL, VFRACT|VISARRAY, x_("USER_default_grid"));
622 		if (var == NOVARIABLE)
623 		{
624 			el_curwindowpart->gridx = el_curwindowpart->gridy = WHOLE;
625 		} else
626 		{
627 			el_curwindowpart->gridx = ((INTBIG *)var->addr)[0];
628 			el_curwindowpart->gridy = ((INTBIG *)var->addr)[1];
629 		}
630 	}
631 	us_curarcproto = el_curtech->firstarcproto;
632 	us_curnodeproto = NONODEPROTO;
633 
634 	/* create the clipboard cell */
635 	estrcpy(clipboardname, x_("Clipboard!!"));
636 	us_clipboardlib = newlibrary(clipboardname, clipboardname);
637 	us_clipboardlib->userbits |= HIDDENLIBRARY;
638 	us_clipboardcell = newnodeproto(clipboardname, us_clipboardlib);
639 
640 	/* now allow graphics to reach the screen */
641 	us_displayroutine = us_showpoly;
642 
643 	/* now draw everything */
644 	us_drawmenu(1, NOWINDOWFRAME);	/* draw basic screen layout */
645 
646 #ifndef MACOS
647 	if (haveoptionsfile == 0)
648 	{
649 		if ((us_tool->toolstate&USEDIALOGS) != 0)
650 		{
651 			(void)us_aboutdlog();
652 		} else
653 			ttyputmsg(_("Electric, from Static Free Software"));
654 	}
655 #endif
656 
657 	/* if there is a current cell in the library, edit it */
658 	if (el_curlib->curnodeproto != NONODEPROTO)
659 	{
660 		newpar[0] = x_("editcell");
661 		newpar[1] = describenodeproto(el_curlib->curnodeproto);
662 		telltool(us_tool, 2, newpar);
663 
664 		/* must reset the library-changed bit now */
665 		el_curlib->curnodeproto->lib->userbits &= ~(LIBCHANGEDMAJOR | LIBCHANGEDMINOR);
666 	}
667 
668 	/* now end the batch to force these changes to be processed properly */
669 	us_endbatch();
670 	us_optionschanged = FALSE;				/* options are unchanged */
671 	return(FALSE);
672 }
673 
674 /* terminate the user interface tool */
us_done(void)675 void us_done(void)
676 {
677 	REGISTER WINDOWPART *w;
678 #ifdef DEBUGMEMORY
679 	REGISTER INTBIG i;
680 #endif
681 
682 	/* close messages audit window */
683 	if (us_termaudit != 0) xclose(us_termaudit);
684 
685 	/* delete all windows */
686 	if (us_menuframe != NOWINDOWFRAME)
687 		killwindowframe(us_menuframe);
688 	while (el_topwindowpart != NOWINDOWPART)
689 	{
690 		w = el_topwindowpart;
691 		el_topwindowpart = el_topwindowpart->nextwindowpart;
692 		killwindowpart(w);
693 	}
694 
695 	logfinishrecord();
696 	termgraphics();
697 
698 	/* close trace */
699 	if (us_tracefile != NULL)
700 	{
701 		xclose(us_tracefile);
702 		us_tracefile = NULL;
703 	}
704 
705 #ifdef DEBUGMEMORY
706 	/* free popups */
707 	while (us_firstpopupmenu != NOPOPUPMENU)
708 	{
709 		REGISTER POPUPMENU *pm;
710 		REGISTER POPUPMENUITEM *mi;
711 
712 		pm = us_firstpopupmenu;
713 		us_firstpopupmenu = us_firstpopupmenu->nextpopupmenu;
714 		efree((CHAR *)pm->name);
715 		efree((CHAR *)pm->header);
716 		efree((CHAR *)pm->list);
717 		for(i=0; i<pm->total; i++)
718 		{
719 			mi = &pm->list[i];
720 			efree((CHAR *)mi->attribute);
721 			if (mi->value != 0) efree((CHAR *)mi->value);
722 			us_freeusercom(mi->response);
723 		}
724 		efree((CHAR *)pm);
725 	}
726 	noundoallowed();
727 	us_freeparsememory();
728 	us_freehighmemory();
729 	us_freemiscmemory();
730 	us_freecomekmemory();
731 	us_freecomtvmemory();
732 	us_freediacommemory();
733 	us_freenetmemory();
734 	us_freeedtecpmemory();
735 	us_freeedpacmemory();
736 	us_freeedemacsmemory();
737 	us_freetranslatememory();
738 
739 	/* free user commands */
740 	while (us_usercomfree != NOUSERCOM)
741 	{
742 		REGISTER USERCOM *uc;
743 
744 		uc = us_usercomfree;
745 		us_usercomfree = us_usercomfree->nextcom;
746 		efree((CHAR *)uc);
747 	}
748 
749 	/* free remembered command */
750 	for(i=0; i<us_lastcommandtotal; i++)
751 	{
752 		if (us_lastcommandpar[i] != 0)
753 			efree((CHAR *)us_lastcommandpar[i]);
754 	}
755 	efree((CHAR *)us_lastcommandpar);
756 
757 	/* free miscellaneous memory */
758 	us_freestatusmemory();
759 	us_freewindowmemory();
760 
761 	/* free quick-key settings */
762 	{
763 		REGISTER INTBIG i;
764 
765 		for(i=0; i<us_quickkeyfactcount; i++)
766 			efree((CHAR *)us_quickkeyfactlist[i]);
767 	}
768 	if (us_quickkeyfactcount > 0) efree((CHAR *)us_quickkeyfactlist);
769 
770 	/* free pulldown bar */
771 	if (us_pulldownmenucount != 0)
772 	{
773 		efree((CHAR *)us_pulldowns);
774 		efree((CHAR *)us_pulldownmenupos);
775 	}
776 	us_pulldownmenucount = 0;
777 #endif
778 }
779 
780 /* set the nature of the user interface tool */
us_set(INTBIG count,CHAR * par[])781 void us_set(INTBIG count, CHAR *par[])
782 {
783 	REGISTER USERCOM *com;
784 	REGISTER INTBIG i;
785 	REGISTER void *infstr;
786 
787 	if (count == 0) return;
788 
789 	infstr = initinfstr();
790 	for(i=0; i<count; i++)
791 	{
792 		addstringtoinfstr(infstr, par[i]);
793 		addtoinfstr(infstr, ' ');
794 	}
795 	com = us_makecommand(returninfstr(infstr));
796 	us_execute(com, FALSE, TRUE, FALSE);
797 	us_freeusercom(com);
798 }
799 
800 /*
801  * make requests of the user interface tool:
802  *
803  ***************** CONTROL OF HIGHLIGHTING ****************
804  *  "show-object" TAKES: the GEOM module to highlight
805  *  "show-port" TAKES: the GEOM module and PORTPROTO to highlight
806  *  "show-area" TAKES: the lowx, highx, lowy, highy, cell of an area
807  *  "show-line" TAKES: the x1, y1, x2, y2, cell of a line
808  *  "show-multiple" TAKES: string of GEOM addresses separated by tabs
809  *  "clear" clears all highlighting
810  *  "down-stack" saves the currently highlighted objects on a stack
811  *  "up-stack" restores the stacked highlighted objects
812  *
813  ***************** INFORMATION ABOUT HIGHLIGHTED OBJECTS ****************
814  *  "get-node" RETURNS: the currently highlighted NODEINST
815  *  "get-port" RETURNS: the currently highlighted PORTPROTO
816  *  "get-arc" RETURNS: the currently highlighted ARCINST
817  *  "get-object" RETURNS: the currently highlighted GEOM
818  *  "get-all-nodes" RETURNS: a list of GEOMs
819  *  "get-all-arcs" RETURNS: a list of GEOMs
820  *  "get-all-objects" RETURNS: a list of GEOMs
821  *  "get-highlighted-area" TAKES: reference lx, hx, ly, hy bounds RETGURNS: cell
822  *
823  ***************** WINDOW CONTROL ****************
824  *  "window-new" RETURNS: newly created window
825  *  "window-horiz-new" RETURNS: newly created window (prefers horizontal split)
826  *  "window-vert-new" RETURNS: newly created window (prefers vertical split)
827  *  "display-to-routine" TAKES: routine to call with polygons
828  *  "display-highlighted-to-routine" TAKES: routine to call with polygons
829  *  "flush-changes" forces display changes to be visible
830  *
831  ***************** EDITOR CONTROL ****************
832  *  "edit-starteditor" TAKES: window, header, &chars, &lines RETURNS: zero: ok
833  *  "edit-totallines" TAKES: window RETURNS: number of lines of text
834  *  "edit-getline" TAKES: window and line index RETURNS: string
835  *  "edit-addline" TAKES: window and line index and string to insert
836  *  "edit-replaceline" TAKES: window and line index and new string
837  *  "edit-deleteline" TAKES: window and line index to delete
838  *  "edit-highlightline" TAKES: window and line index to highlight
839  *  "edit-suspendgraphics" TAKES: window in which to suspends display changes
840  *  "edit-resumegraphics" TAKES: window in which to resumes display of changes
841  *  "edit-describe" RETURNS: name of editor
842  *  "edit-readfile" TAKES: window and file name
843  *  "edit-writefile" TAKES: window and file name
844  *
845  ***************** MISCELLANEOUS ****************
846  *  "make-icon" TAKES: portlist, icon name, cell name, library RETURNS: cell
847  */
us_request(CHAR * command,va_list ap)848 INTBIG us_request(CHAR *command, va_list ap)
849 {
850 	HIGHLIGHT newhigh;
851 	REGISTER GEOM *from;
852 	REGISTER PORTPROTO *pp;
853 	REGISTER VARIABLE *var;
854 	REGISTER NODEPROTO *np;
855 	REGISTER void (*curdisplay)(POLYGON*, WINDOWPART*);
856 	REGISTER INTBIG len, i, arg1, arg2, arg3, arg4, arg5;
857 	REGISTER GEOM **list;
858 
859 	if (namesamen(command, x_("get-"), 4) == 0)
860 	{
861 		if (namesame(&command[4], x_("node")) == 0)
862 			return((INTBIG)us_getobject(VNODEINST, FALSE));
863 		if (namesame(&command[4], x_("arc")) == 0)
864 			return((INTBIG)us_getobject(VARCINST, FALSE));
865 		if (namesame(&command[4], x_("object")) == 0)
866 		{
867 			var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
868 			if (var == NOVARIABLE) return(-1);
869 			len = getlength(var);
870 			if (len > 1) return(-1);
871 			(void)us_makehighlight(((CHAR **)var->addr)[0], &newhigh);
872 			if ((newhigh.status&HIGHTYPE) != HIGHFROM) return(-1);
873 			return((INTBIG)newhigh.fromgeom);
874 		}
875 		if (namesame(&command[4], x_("port")) == 0)
876 		{
877 			var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
878 			if (var == NOVARIABLE) return(-1);
879 			len = getlength(var);
880 			if (len > 1) return(-1);
881 			(void)us_makehighlight(((CHAR **)var->addr)[0], &newhigh);
882 			if ((newhigh.status&HIGHTYPE) != HIGHFROM || !newhigh.fromgeom->entryisnode)
883 				return(-1);
884 			return((INTBIG)newhigh.fromport);
885 		}
886 		if (namesame(&command[4], x_("all-nodes")) == 0)
887 			return((INTBIG)us_gethighlighted(WANTNODEINST, 0, 0));
888 		if (namesame(&command[4], x_("all-arcs")) == 0)
889 			return((INTBIG)us_gethighlighted(WANTARCINST, 0, 0));
890 		if (namesame(&command[4], x_("all-objects")) == 0)
891 			return((INTBIG)us_gethighlighted(WANTNODEINST|WANTARCINST, 0, 0));
892 		if (namesame(&command[4], x_("highlighted-area")) == 0)
893 		{
894 			/* get the arguments */
895 			arg1 = va_arg(ap, INTBIG);
896 			arg2 = va_arg(ap, INTBIG);
897 			arg3 = va_arg(ap, INTBIG);
898 			arg4 = va_arg(ap, INTBIG);
899 			return((INTBIG)us_getareabounds((INTBIG *)arg1, (INTBIG *)arg2, (INTBIG *)arg3, (INTBIG *)arg4));
900 		}
901 	}
902 
903 	if (namesamen(command, x_("edit-"), 5) == 0)
904 	{
905 		if (namesame(&command[5], x_("getline")) == 0)
906 		{
907 			/* get the arguments */
908 			arg1 = va_arg(ap, INTBIG);
909 			arg2 = va_arg(ap, INTBIG);
910 			return((INTBIG)us_getline((WINDOWPART *)arg1, arg2));
911 		}
912 		if (namesame(&command[5], x_("totallines")) == 0)
913 		{
914 			/* get the arguments */
915 			arg1 = va_arg(ap, INTBIG);
916 			return(us_totallines((WINDOWPART *)arg1));
917 		}
918 		if (namesame(&command[5], x_("addline")) == 0)
919 		{
920 			/* get the arguments */
921 			arg1 = va_arg(ap, INTBIG);
922 			arg2 = va_arg(ap, INTBIG);
923 			arg3 = va_arg(ap, INTBIG);
924 			us_addline((WINDOWPART *)arg1, arg2, (CHAR *)arg3);
925 			return(0);
926 		}
927 		if (namesame(&command[5], x_("replaceline")) == 0)
928 		{
929 			/* get the arguments */
930 			arg1 = va_arg(ap, INTBIG);
931 			arg2 = va_arg(ap, INTBIG);
932 			arg3 = va_arg(ap, INTBIG);
933 			us_replaceline((WINDOWPART *)arg1, arg2, (CHAR *)arg3);
934 			return(0);
935 		}
936 		if (namesame(&command[5], x_("deleteline")) == 0)
937 		{
938 			/* get the arguments */
939 			arg1 = va_arg(ap, INTBIG);
940 			arg2 = va_arg(ap, INTBIG);
941 			us_deleteline((WINDOWPART *)arg1, arg2);
942 			return(0);
943 		}
944 		if (namesame(&command[5], x_("highlightline")) == 0)
945 		{
946 			/* get the arguments */
947 			arg1 = va_arg(ap, INTBIG);
948 			arg2 = va_arg(ap, INTBIG);
949 			us_highlightline((WINDOWPART *)arg1, arg2, arg2);
950 			return(0);
951 		}
952 		if (namesame(&command[5], x_("starteditor")) == 0)
953 		{
954 			/* get the arguments */
955 			arg1 = va_arg(ap, INTBIG);
956 			arg2 = va_arg(ap, INTBIG);
957 			arg3 = va_arg(ap, INTBIG);
958 			arg4 = va_arg(ap, INTBIG);
959 			if (us_makeeditor((WINDOWPART *)arg1, (CHAR *)arg2, (INTBIG *)arg3,
960 				(INTBIG *)arg4) == NOWINDOWPART) return(-1);
961 			return(0);
962 		}
963 		if (namesame(&command[5], x_("suspendgraphics")) == 0)
964 		{
965 			/* get the arguments */
966 			arg1 = va_arg(ap, INTBIG);
967 			us_suspendgraphics((WINDOWPART *)arg1);
968 			return(0);
969 		}
970 		if (namesame(&command[5], x_("resumegraphics")) == 0)
971 		{
972 			/* get the arguments */
973 			arg1 = va_arg(ap, INTBIG);
974 			us_resumegraphics((WINDOWPART *)arg1);
975 			return(0);
976 		}
977 		if (namesame(&command[5], x_("describe")) == 0)
978 		{
979 			/* get the arguments */
980 			arg1 = va_arg(ap, INTBIG);
981 			us_describeeditor((CHAR **)arg1);
982 			return(0);
983 		}
984 		if (namesame(&command[5], x_("readfile")) == 0)
985 		{
986 			/* get the arguments */
987 			arg1 = va_arg(ap, INTBIG);
988 			arg2 = va_arg(ap, INTBIG);
989 			us_readtextfile((WINDOWPART *)arg1, (CHAR *)arg2);
990 			return(0);
991 		}
992 		if (namesame(&command[5], x_("writefile")) == 0)
993 		{
994 			/* get the arguments */
995 			arg1 = va_arg(ap, INTBIG);
996 			arg2 = va_arg(ap, INTBIG);
997 			us_writetextfile((WINDOWPART *)arg1, (CHAR *)arg2);
998 			return(0);
999 		}
1000 	}
1001 
1002 	if (namesamen(command, x_("show-"), 5) == 0)
1003 	{
1004 		if (namesame(&command[5], x_("object")) == 0)
1005 		{
1006 			/* get the arguments */
1007 			arg1 = va_arg(ap, INTBIG);
1008 
1009 			/* fill in the highlight information */
1010 			from = (GEOM *)arg1;
1011 			us_ensurewindow(geomparent(from));
1012 			newhigh.status = HIGHFROM;
1013 			newhigh.cell = geomparent(from);
1014 			newhigh.fromgeom = from;
1015 			newhigh.fromport = NOPORTPROTO;
1016 			newhigh.frompoint = 0;
1017 			us_addhighlight(&newhigh);
1018 			us_showallhighlight();
1019 			return(0);
1020 		}
1021 		if (namesame(&command[5], x_("port")) == 0)
1022 		{
1023 			/* get the arguments */
1024 			arg1 = va_arg(ap, INTBIG);
1025 			arg2 = va_arg(ap, INTBIG);
1026 
1027 			/* fill in the highlight information */
1028 			from = (GEOM *)arg1;
1029 			pp = (PORTPROTO *)arg2;
1030 			us_ensurewindow(geomparent(from));
1031 			newhigh.status = HIGHFROM;
1032 			newhigh.cell = geomparent(from);
1033 			newhigh.fromgeom = from;
1034 			newhigh.fromport = pp;
1035 			newhigh.frompoint = 0;
1036 			us_addhighlight(&newhigh);
1037 			us_showallhighlight();
1038 			return(0);
1039 		}
1040 		if (namesame(&command[5], x_("line")) == 0)
1041 		{
1042 			/* get the arguments */
1043 			arg1 = va_arg(ap, INTBIG);
1044 			arg2 = va_arg(ap, INTBIG);
1045 			arg3 = va_arg(ap, INTBIG);
1046 			arg4 = va_arg(ap, INTBIG);
1047 			arg5 = va_arg(ap, INTBIG);
1048 
1049 			np = (NODEPROTO *)arg5;
1050 			if (np == NONODEPROTO) return(0);
1051 
1052 			/* fill in the highlight information */
1053 			us_ensurewindow(np);
1054 			newhigh.status = HIGHLINE;
1055 			newhigh.cell = np;
1056 			newhigh.stalx = arg1;
1057 			newhigh.staly = arg2;
1058 			newhigh.stahx = arg3;
1059 			newhigh.stahy = arg4;
1060 			us_addhighlight(&newhigh);
1061 			us_showallhighlight();
1062 			return(0);
1063 		}
1064 		if (namesame(&command[5], x_("area")) == 0)
1065 		{
1066 			/* get the arguments */
1067 			arg1 = va_arg(ap, INTBIG);
1068 			arg2 = va_arg(ap, INTBIG);
1069 			arg3 = va_arg(ap, INTBIG);
1070 			arg4 = va_arg(ap, INTBIG);
1071 			arg5 = va_arg(ap, INTBIG);
1072 
1073 			np = (NODEPROTO *)arg5;
1074 			if (np == NONODEPROTO) return(0);
1075 
1076 			/* fill in the highlight information */
1077 			us_ensurewindow(np);
1078 			newhigh.status = HIGHBBOX;
1079 			newhigh.cell = np;
1080 			newhigh.stalx = arg1;
1081 			newhigh.stahx = arg2;
1082 			newhigh.staly = arg3;
1083 			newhigh.stahy = arg4;
1084 			us_addhighlight(&newhigh);
1085 			us_showallhighlight();
1086 			return(0);
1087 		}
1088 		if (namesame(&command[5], x_("multiple")) == 0)
1089 		{
1090 			/* get the arguments */
1091 			arg1 = va_arg(ap, INTBIG);
1092 
1093 			/* fill in the highlight information */
1094 			us_setmultiplehighlight((CHAR *)arg1, FALSE);
1095 			us_showallhighlight();
1096 			return(0);
1097 		}
1098 	}
1099 
1100 	if (namesame(command, x_("flush-changes")) == 0)
1101 	{
1102 		us_endchanges(NOWINDOWPART);
1103 		us_showallhighlight();
1104 		us_beginchanges();
1105 		return(0);
1106 	}
1107 
1108 	if (namesame(command, x_("display-to-routine")) == 0)
1109 	{
1110 		if (el_curwindowpart == NOWINDOWPART) return(0);
1111 
1112 		/* get the arguments */
1113 		arg1 = va_arg(ap, INTBIG);
1114 
1115 		/* code cannot be called by multiple procesors: uses globals */
1116 		NOT_REENTRANT;
1117 
1118 		curdisplay = us_displayroutine;
1119 		us_displayroutine = (void (*)(POLYGON*, WINDOWPART*))arg1;
1120 		us_redisplaynow(el_curwindowpart, FALSE);
1121 		us_endchanges(el_curwindowpart);
1122 		us_displayroutine = curdisplay;
1123 		return(0);
1124 	}
1125 
1126 	if (namesame(command, x_("display-highlighted-to-routine")) == 0)
1127 	{
1128 		if (el_curwindowpart == NOWINDOWPART) return(0);
1129 
1130 		/* get the arguments */
1131 		arg1 = va_arg(ap, INTBIG);
1132 
1133 		/* code cannot be called by multiple procesors: uses globals */
1134 		NOT_REENTRANT;
1135 
1136 		curdisplay = us_displayroutine;
1137 		us_displayroutine = (void (*)(POLYGON*, WINDOWPART*))arg1;
1138 
1139 		/* get the objects to be displayed */
1140 		list = us_gethighlighted(WANTNODEINST | WANTARCINST, 0, 0);
1141 		begintraversehierarchy();
1142 		for(i=0; list[i] != NOGEOM; i++)
1143 		{
1144 			if (list[i]->entryisnode)
1145 			{
1146 				if (us_drawcell(list[i]->entryaddr.ni, LAYERA,
1147 					el_matid, 3, el_curwindowpart) < 0) break;
1148 			} else
1149 			{
1150 				if (us_drawarcinst(list[i]->entryaddr.ai, LAYERA,
1151 					el_matid, 3, el_curwindowpart) < 0) break;
1152 			}
1153 		}
1154 		us_displayroutine = curdisplay;
1155 		endtraversehierarchy();
1156 		return(0);
1157 	}
1158 
1159 	if (namesame(command, x_("make-icon")) == 0)
1160 	{
1161 		/* get the arguments */
1162 		arg1 = va_arg(ap, INTBIG);
1163 		arg2 = va_arg(ap, INTBIG);
1164 		arg3 = va_arg(ap, INTBIG);
1165 		arg4 = va_arg(ap, INTBIG);
1166 
1167 		return((INTBIG)us_makeiconcell((PORTPROTO *)arg1, (CHAR *)arg2,
1168 			(CHAR *)arg3, (LIBRARY *)arg4));
1169 	}
1170 
1171 	if (namesamen(command, x_("window-"), 7) == 0)
1172 	{
1173 		/* get a new window */
1174 		if (namesame(&command[7], x_("new")) == 0)
1175 		{
1176 			return((INTBIG)us_wantnewwindow(0));
1177 		}
1178 		if (namesame(&command[7], x_("horiz-new")) == 0)
1179 		{
1180 			if (us_needwindow()) return(0);
1181 			return((INTBIG)us_wantnewwindow(1));
1182 		}
1183 		if (namesame(&command[7], x_("vert-new")) == 0)
1184 		{
1185 			if (us_needwindow()) return(0);
1186 			return((INTBIG)us_wantnewwindow(2));
1187 		}
1188 		return(0);
1189 	}
1190 
1191 	if (namesame(command, x_("down-stack")) == 0)
1192 	{
1193 		us_pushhighlight();
1194 		return(0);
1195 	}
1196 
1197 	if (namesame(command, x_("up-stack")) == 0)
1198 	{
1199 		us_pophighlight(FALSE);
1200 		return(0);
1201 	}
1202 
1203 	if (namesame(command, x_("clear")) == 0)
1204 	{
1205 		us_clearhighlightcount();
1206 		return(0);
1207 	}
1208 	return(-1);
1209 }
1210 
1211 /* examine an entire cell */
us_examinenodeproto(NODEPROTO * np)1212 void us_examinenodeproto(NODEPROTO *np) { Q_UNUSED( np ); }
1213 
1214 /* one time slice for the user tool: process a command */
us_slice(void)1215 void us_slice(void)
1216 {
1217 #ifndef USEQT
1218 	INTBIG special, but, x, y;
1219 	INTSML cmd;
1220 #endif
1221 	CHAR *args[4];
1222 
1223 	if (us_desiredlibrary[0] != 0)
1224 	{
1225 		args[0] = x_("read");
1226 		args[1] = us_desiredlibrary;
1227 		args[2] = x_("make-current");
1228 		us_library(3, args);
1229 		us_desiredlibrary[0] = 0;
1230 	}
1231 
1232 	/* reset the cursor if it was waiting */
1233 	if (us_cursorstate == WAITCURSOR)
1234 		setdefaultcursortype(us_normalcursor);
1235 
1236 	/* switch to the right technology */
1237 	if ((us_state&CURCELLCHANGED) != 0)
1238 	{
1239 		us_state &= ~CURCELLCHANGED;
1240 		if (el_curwindowpart != NOWINDOWPART)
1241 		{
1242 			switch (el_curwindowpart->state&WINDOWTYPE)
1243 			{
1244 				case DISPWINDOW:
1245 				case DISP3DWINDOW:
1246 					us_ensurepropertechnology(el_curwindowpart->curnodeproto, 0, FALSE);
1247 					break;
1248 			}
1249 			us_setcellsize(el_curwindowpart);
1250 			return;
1251 		}
1252 	}
1253 
1254 	/* set all cell message changes detected during the last broadcast */
1255 	us_doubchanges();
1256 
1257 	/* handle language loops */
1258 	if ((us_state&LANGLOOP) != 0)
1259 	{
1260 		if (languageconverse(0))
1261 		{
1262 			us_state &= ~LANGLOOP;
1263 			ttyputmsg(_("Back to Electric"));
1264 		}
1265 
1266 		setactivity(_("Language Interpreter"));
1267 
1268 		/* set all cell message changes detected during the last broadcast */
1269 		us_doubchanges();
1270 		return;
1271 	}
1272 
1273 	/* start logging now if requested */
1274 	if (us_logging)
1275 	{
1276 		logstartrecord();
1277 		us_logging = FALSE;
1278 	}
1279 
1280 #ifndef USEQT
1281 	/* first see if there is any pending input */
1282 	el_pleasestop = 0;
1283 	if (ttydataready())
1284 	{
1285 		el_pleasestop = 0;
1286 		stoptablet();
1287 		cmd = ttygetchar(&special);
1288 		us_oncommand(cmd, special);
1289 		return;
1290 	}
1291 	if (el_pleasestop != 0) return;
1292 
1293 	/* get a button */
1294 	waitforbutton(&x, &y, &but);
1295 	if (el_pleasestop != 0) return;
1296 	if (but < 0) return;
1297 
1298 	/* execute the button */
1299 	us_ontablet(x, y, but);
1300 #endif
1301 }
1302 
1303 /*
1304  * handle button pushes
1305  */
us_ontablet(INTBIG x,INTBIG y,INTBIG but)1306 void us_ontablet(INTBIG x, INTBIG y, INTBIG but)
1307 {
1308 	REGISTER USERCOM *item;
1309 	REGISTER CHAR *str;
1310 	CHAR *par[2];
1311 	INTBIG lx, hx, ly, hy;
1312 	BOOLEAN verbose, drawexplorericon;
1313 	REGISTER VARIABLE *var;
1314 	REGISTER LIBRARY *lib;
1315 	REGISTER NODEPROTO *np;
1316 	REGISTER WINDOWPART *w;
1317 	REGISTER WINDOWFRAME *curframe, *wf;
1318 	COMMANDBINDING commandbinding;
1319 
1320 	/* reset single-key suspension flag */
1321 	if ((us_state&SKIPKEYS) != 0)
1322 	{
1323 		ttyputmsg(_("Single-key command suspension now lifted"));
1324 		us_state &= ~SKIPKEYS;
1325 	}
1326 
1327 	/* wheel rolls get handled immediately */
1328 	if (wheelbutton(but))
1329 	{
1330 		if (el_curwindowpart->buttonhandler != 0)
1331 		{
1332 			(*el_curwindowpart->buttonhandler)(el_curwindowpart, but, x, y);
1333 		}
1334 		return;
1335 	}
1336 
1337 	/* first see if this is a slide to a window partition divider */
1338 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1339 	{
1340 		/* see if the cursor is over a window partition separator */
1341 		us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
1342 		if (x >= lx-1 && x <= lx+1 && y > ly+1 && y < hy-1 &&
1343 			us_hasotherwindowpart(lx-10, y, w))
1344 		{
1345 			us_vpartdividerbegin(x, ly, hy, w->frame);
1346 			trackcursor(FALSE, us_nullup, us_nullvoid, us_vpartdividerdown, us_nullchar,
1347 				us_vpartdividerdone, TRACKNORMAL);
1348 			return;
1349 		} else if (x >= hx-1 && x <= hx+1 && y > ly+1 && y < hy-1 &&
1350 			us_hasotherwindowpart(hx+10, y, w))
1351 		{
1352 			us_vpartdividerbegin(x, ly, hy, w->frame);
1353 			trackcursor(FALSE, us_nullup, us_nullvoid, us_vpartdividerdown, us_nullchar,
1354 				us_vpartdividerdone, TRACKNORMAL);
1355 			return;
1356 		} else if (y >= ly-1 && y <= ly+1 && x > lx+1 && x < hx-1 &&
1357 			us_hasotherwindowpart(x, ly-10, w))
1358 		{
1359 			us_hpartdividerbegin(y, lx, hx, w->frame);
1360 			trackcursor(FALSE, us_nullup, us_nullvoid, us_hpartdividerdown, us_nullchar,
1361 				us_hpartdividerdone, TRACKNORMAL);
1362 			return;
1363 		} else if (y >= hy-1 && y <= hy+1 && x > lx+1 && x < hx-1 &&
1364 			us_hasotherwindowpart(x, hy+10, w))
1365 		{
1366 			us_hpartdividerbegin(y, lx, hx, w->frame);
1367 			trackcursor(FALSE, us_nullup, us_nullvoid, us_hpartdividerdown, us_nullchar,
1368 				us_hpartdividerdone, TRACKNORMAL);
1369 			return;
1370 		}
1371 	}
1372 
1373 	/* switch windows to the current frame */
1374 	curframe = getwindowframe(TRUE);
1375 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1376 	{
1377 		if (w->frame != curframe) continue;
1378 		if (x >= w->uselx && x <= w->usehx && y >= w->usely && y <= w->usehy)
1379 		{
1380 			/* make this window the current one */
1381 			if (w != el_curwindowpart)
1382 			{
1383 				(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
1384 					VWINDOWPART|VDONTSAVE);
1385 				if (w->curnodeproto == NONODEPROTO) lib = el_curlib; else
1386 					lib = w->curnodeproto->lib;
1387 				(void)setval((INTBIG)lib, VLIBRARY, x_("curnodeproto"),
1388 					(INTBIG)w->curnodeproto, VNODEPROTO);
1389 			}
1390 			break;
1391 		}
1392 	}
1393 
1394 	/* see if it is a fixed menu hit */
1395 	if ((us_tool->toolstate&MENUON) != 0 &&
1396 		(us_menuframe == NOWINDOWFRAME || curframe == us_menuframe) &&
1397 		y >= us_menuly && y <= us_menuhy && x >= us_menulx && x <= us_menuhx)
1398 	{
1399 		x = (x-us_menulx) / us_menuxsz;
1400 		y = (y-us_menuly) / us_menuysz;
1401 		if (x < 0 || y < 0 || x >= us_menux || y >= us_menuy) return;
1402 		var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
1403 		if (var == NOVARIABLE) return;
1404 		if (us_menupos <= 1) str = ((CHAR **)var->addr)[y * us_menux + x]; else
1405 			str = ((CHAR **)var->addr)[x * us_menuy + y];
1406 		us_parsebinding(str, &commandbinding);
1407 		item = us_makecommand(commandbinding.command);
1408 		us_freebindingparse(&commandbinding);
1409 		if (item == NOUSERCOM || item->active < 0)
1410 		{
1411 			ttyputerr(_("No command is attached to this menu entry"));
1412 			if (item != NOUSERCOM) us_freeusercom(item);
1413 			return;
1414 		}
1415 		if ((us_tool->toolstate&ONESHOTMENU) != 0)
1416 		{
1417 			us_menuhnx = x;   us_menuhny = y;
1418 			us_highlightmenu(x, y, el_colhmenbor);
1419 		}
1420 		us_state &= ~GOTXY;
1421 		us_forceeditchanges();
1422 		if ((us_tool->toolstate&ECHOBIND) != 0) verbose = TRUE; else
1423 			verbose = FALSE;
1424 		us_execute(item, verbose, TRUE, TRUE);
1425 		us_causeofslice(item);
1426 		if ((us_tool->toolstate&ONESHOTMENU) != 0)
1427 		{
1428 			us_highlightmenu(us_menuhnx, us_menuhny, el_colmenbor);
1429 			us_menuhnx = -1;
1430 		}
1431 		us_freeusercom(item);
1432 		flushscreen();
1433 	} else
1434 	{
1435 		/* get cursor position and check windows */
1436 		if (us_setxy(x, y))
1437 		{
1438 			/* see if it is a slider hit in a display window */
1439 			wf = getwindowframe(TRUE);
1440 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1441 			{
1442 				if (w->frame != wf) continue;
1443 				if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
1444 				{
1445 					if (x >= w->uselx-DISPLAYSLIDERSIZE && x < w->usehx &&
1446 						y >= w->usely-DISPLAYSLIDERSIZE && y < w->usehy)
1447 					{
1448 						if (w->buttonhandler != 0)
1449 							(*w->buttonhandler)(w, but, x, y);
1450 						return;
1451 					}
1452 				}
1453 				if ((w->state&WINDOWTYPE) == DISPWINDOW)
1454 				{
1455 					if (x > w->usehx && x <= w->usehx+DISPLAYSLIDERSIZE &&
1456 						y > w->usely && y < w->usehy)
1457 					{
1458 						/* check for vertical slider hit */
1459 						np = w->curnodeproto;
1460 						if (w != el_curwindowpart)
1461 						{
1462 							(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
1463 								VWINDOWPART|VDONTSAVE);
1464 							(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"),
1465 								(INTBIG)np, VNODEPROTO);
1466 						}
1467 						if (np == NONODEPROTO) return;
1468 						if (np->highy == np->lowy) return;
1469 						if (y <= w->usely+DISPLAYSLIDERSIZE)
1470 						{
1471 							/* small shift up (may repeat) */
1472 							us_arrowclickbegin(w, w->usehx, w->usehx+DISPLAYSLIDERSIZE,
1473 								w->usely, w->usely+DISPLAYSLIDERSIZE,
1474 								(w->screenhy - w->screenly) / DISPLAYSMALLSHIFT);
1475 							trackcursor(FALSE, us_nullup, us_nullvoid, us_varrowdown, us_nullchar,
1476 								us_nullvoid, TRACKNORMAL);
1477 							return;
1478 						}
1479 						if (y <= w->thumbly)
1480 						{
1481 							/* large shift up (may repeat) */
1482 							us_arrowclickbegin(w, w->usehx, w->usehx+DISPLAYSLIDERSIZE,
1483 								w->usely+DISPLAYSLIDERSIZE, w->thumbhy,
1484 								(w->screenhy - w->screenly) / DISPLAYLARGESHIFT);
1485 							trackcursor(FALSE, us_nullup, us_nullvoid, us_varrowdown, us_nullchar,
1486 								us_nullvoid, TRACKNORMAL);
1487 							return;
1488 						}
1489 						if (y <= w->thumbhy)
1490 						{
1491 							/* on thumb (track thumb motion) */
1492 							us_vthumbbegin(y, w, w->usehx, w->usely, w->usehy, FALSE,
1493 								us_vthumbtrackingcallback);
1494 							trackcursor(FALSE, us_nullup, us_nullvoid, us_vthumbdown, us_nullchar,
1495 								us_vthumbdone, TRACKNORMAL);
1496 							return;
1497 						}
1498 						if (y <= w->usehy-DISPLAYSLIDERSIZE)
1499 						{
1500 							/* large shift down (may repeat) */
1501 							us_arrowclickbegin(w, w->usehx, w->usehx+DISPLAYSLIDERSIZE,
1502 								w->thumbhy, w->usehy-DISPLAYSLIDERSIZE,
1503 								-(w->screenhy - w->screenly) / DISPLAYLARGESHIFT);
1504 							trackcursor(FALSE, us_nullup, us_nullvoid, us_varrowdown, us_nullchar,
1505 								us_nullvoid, TRACKNORMAL);
1506 							return;
1507 						}
1508 						if (y <= w->usehy)
1509 						{
1510 							/* small shift down (may repeat) */
1511 							us_arrowclickbegin(w, w->usehx, w->usehx+DISPLAYSLIDERSIZE,
1512 								w->usehy-DISPLAYSLIDERSIZE, w->usehy,
1513 								-(w->screenhy - w->screenly) / DISPLAYSMALLSHIFT);
1514 							trackcursor(FALSE, us_nullup, us_nullvoid, us_varrowdown, us_nullchar,
1515 								us_nullvoid, TRACKNORMAL);
1516 							return;
1517 						}
1518 					}
1519 					if (y < w->usely && y >= w->usely-DISPLAYSLIDERSIZE &&
1520 						x > w->uselx && x < w->usehx)
1521 					{
1522 						/* see if the explorer button was hit */
1523 						drawexplorericon = us_windowgetsexploericon(w);
1524 						lx = w->uselx;
1525 						if (drawexplorericon)
1526 						{
1527 							lx += DISPLAYSLIDERSIZE;
1528 							if (x <= lx)
1529 							{
1530 								par[0] = "explore";
1531 								us_window(1, par);
1532 								return;
1533 							}
1534 						}
1535 
1536 						/* check for horizontal slider hit */
1537 						np = w->curnodeproto;
1538 						if (w != el_curwindowpart)
1539 						{
1540 							(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
1541 								VWINDOWPART|VDONTSAVE);
1542 							(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"),
1543 								(INTBIG)np, VNODEPROTO);
1544 						}
1545 						if (np == NONODEPROTO) return;
1546 						if (np->highx == np->lowx) return;
1547 						if (x <= lx+DISPLAYSLIDERSIZE)
1548 						{
1549 							/* small shift left (may repeat) */
1550 							us_arrowclickbegin(w, lx, lx+DISPLAYSLIDERSIZE,
1551 								w->usely-DISPLAYSLIDERSIZE, w->usely,
1552 								-(w->screenhx - w->screenlx) / DISPLAYSMALLSHIFT);
1553 							trackcursor(FALSE, us_nullup, us_nullvoid, us_harrowdown, us_nullchar,
1554 								us_nullvoid, TRACKNORMAL);
1555 							return;
1556 						}
1557 						if (x <= w->thumblx)
1558 						{
1559 							/* large shift left (may repeat) */
1560 							us_arrowclickbegin(w, lx+DISPLAYSLIDERSIZE, w->thumblx,
1561 								w->usely-DISPLAYSLIDERSIZE, w->usely,
1562 								-(w->screenhx - w->screenlx) / DISPLAYLARGESHIFT);
1563 							trackcursor(FALSE, us_nullup, us_nullvoid, us_harrowdown, us_nullchar,
1564 								us_nullvoid, TRACKNORMAL);
1565 							return;
1566 						}
1567 						if (x <= w->thumbhx)
1568 						{
1569 							/* on thumb (track thumb motion) */
1570 							us_hthumbbegin(x, w, w->usely, lx, w->usehx, us_hthumbtrackingcallback);
1571 							trackcursor(FALSE, us_nullup, us_nullvoid, us_hthumbdown, us_nullchar,
1572 								us_hthumbdone, TRACKNORMAL);
1573 							return;
1574 						}
1575 						if (x <= w->usehx-DISPLAYSLIDERSIZE)
1576 						{
1577 							/* large shift right (may repeat) */
1578 							us_arrowclickbegin(w, w->thumbhx, w->usehx-DISPLAYSLIDERSIZE,
1579 								w->usely-DISPLAYSLIDERSIZE, w->usely,
1580 								(w->screenhx - w->screenlx) / DISPLAYLARGESHIFT);
1581 							trackcursor(FALSE, us_nullup, us_nullvoid, us_harrowdown, us_nullchar,
1582 								us_nullvoid, TRACKNORMAL);
1583 							return;
1584 						}
1585 						if (x <= w->usehx)
1586 						{
1587 							/* small shift right (may repeat) */
1588 							us_arrowclickbegin(w, w->usehx-DISPLAYSLIDERSIZE, w->usehx,
1589 								w->usely-DISPLAYSLIDERSIZE, w->usely,
1590 								(w->screenhx - w->screenlx) / DISPLAYSMALLSHIFT);
1591 							trackcursor(FALSE, us_nullup, us_nullvoid, us_harrowdown, us_nullchar,
1592 								us_nullvoid, TRACKNORMAL);
1593 							return;
1594 						}
1595 					}
1596 				}
1597 			}
1598 			ttyputerr(_("Cursor off the screen"));
1599 			return;
1600 		}
1601 		if (el_curwindowpart != NOWINDOWPART)
1602 		{
1603 			/* if in distance-measurement mode, track measurement */
1604 			if ((us_state&MEASURINGDISTANCE) != 0)
1605 			{
1606 				if ((el_curwindowpart->state&WINDOWTYPE) == DISPWINDOW &&
1607 					el_curwindowpart->curnodeproto != NONODEPROTO)
1608 				{
1609 					if ((us_state&MEASURINGDISTANCEINI) != 0)
1610 					{
1611 						us_state &= ~MEASURINGDISTANCEINI;
1612 						us_distanceinit();
1613 					}
1614 					trackcursor(FALSE, us_ignoreup, us_nullvoid, us_distancedown,
1615 						us_stoponchar, us_distanceup, TRACKDRAGGING);
1616 					return;
1617 				}
1618 			}
1619 
1620 			/* handle normal button click in this window */
1621 			if (el_curwindowpart->buttonhandler != 0)
1622 			{
1623 				(*el_curwindowpart->buttonhandler)(el_curwindowpart, but, x, y);
1624 			}
1625 		}
1626 	}
1627 }
1628 
1629 /*
1630  * Routine to return true if there is another window partion on the same frame as
1631  * "ow" that covers the coordinates (x,y).
1632  */
us_hasotherwindowpart(INTBIG x,INTBIG y,WINDOWPART * ow)1633 BOOLEAN us_hasotherwindowpart(INTBIG x, INTBIG y, WINDOWPART *ow)
1634 {
1635 	REGISTER WINDOWPART *w;
1636 	INTBIG lx, hx, ly, hy;
1637 
1638 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1639 	{
1640 		if (w == ow) continue;
1641 		if (w->frame != ow->frame) continue;
1642 		us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
1643 		if (x > lx && x < hx && y > ly && y < hy) return(TRUE);
1644 	}
1645 	return(FALSE);
1646 }
1647 
1648 /*
1649  * default button handler for buttons pushed in normal windows
1650  */
us_buttonhandler(WINDOWPART * w,INTBIG but,INTBIG x,INTBIG y)1651 void us_buttonhandler(WINDOWPART *w, INTBIG but, INTBIG x, INTBIG y)
1652 {
1653 	REGISTER USERCOM *item;
1654 	REGISTER VARIABLE *var;
1655 	BOOLEAN verbose;
1656 	COMMANDBINDING commandbinding;
1657 	INTBIG unimportant;
1658 	Q_UNUSED( w );
1659 	Q_UNUSED( x );
1660 	Q_UNUSED( y );
1661 
1662 	/* get the command attached to the button */
1663 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_buttons_key);
1664 	if (var == NOVARIABLE) return;
1665 	us_parsebinding(((CHAR **)var->addr)[but], &commandbinding);
1666 	item = us_makecommand(commandbinding.command);
1667 	us_freebindingparse(&commandbinding);
1668 	if (item == NOUSERCOM || item->active < 0)
1669 	{
1670 		ttyputerr(_("No command is attached to the %s button"),
1671 			buttonname(but, &unimportant));
1672 		if (item != NOUSERCOM) us_freeusercom(item);
1673 		return;
1674 	}
1675 	us_forceeditchanges();
1676 	if ((us_tool->toolstate&ECHOBIND) != 0) verbose = TRUE; else
1677 		verbose = FALSE;
1678 	us_execute(item, verbose, TRUE, TRUE);
1679 	us_causeofslice(item);
1680 	us_freeusercom(item);
1681 	flushscreen();
1682 }
1683 
1684 /* routine that is called when keyboard input is ready */
us_oncommand(INTSML cmd,INTBIG special)1685 void us_oncommand(INTSML cmd, INTBIG special)
1686 {
1687 	INTBIG x, y;
1688 
1689 	/* Read and execute the command */
1690 	us_state &= ~GOTXY;
1691 	(void)getxy(&x, &y);
1692 
1693 	if (el_curwindowpart != NOWINDOWPART && el_curwindowpart->charhandler != 0)
1694 	{
1695 		if ((*el_curwindowpart->charhandler)(el_curwindowpart, cmd, special))
1696 			us_killcurrentwindow(TRUE);
1697 	} else
1698 	{
1699 		(void)(*DEFAULTCHARHANDLER)(el_curwindowpart, cmd, special);
1700 	}
1701 }
1702 
1703 /* EMACS warning */
1704 static DIALOGITEM us_emawarndialogitems[] =
1705 {
1706  /*  1 */ {0, {160,116,184,196}, BUTTON, N_("OK")},
1707  /*  2 */ {0, {4,4,20,340}, MESSAGE, N_("You have just typed Control-X")},
1708  /*  3 */ {0, {24,4,40,340}, MESSAGE, N_("Followed quickly by another control character.")},
1709  /*  4 */ {0, {52,4,68,340}, MESSAGE, N_("Could it be that you think this is EMACS?")},
1710  /*  5 */ {0, {84,4,100,340}, MESSAGE, N_("The second control character has been ignored.")},
1711  /*  6 */ {0, {104,4,120,340}, MESSAGE, N_("If you wish to disable this check, click below.")},
1712  /*  7 */ {0, {128,32,144,284}, BUTTON, N_("Disable EMACS character check")}
1713 };
1714 static DIALOG us_emawarndialog = {{75,75,268,425}, N_("This is Not EMACS"), 0, 7, us_emawarndialogitems, 0, 0};
1715 
1716 /* special items for the "EMACS warning" dialog: */
1717 #define DEMW_DISABLECHECK     7		/* Disable EMACS check (button) */
1718 
1719 /*
1720  * default character handler for keys typed in normal windows
1721  */
us_charhandler(WINDOWPART * w,INTSML cmd,INTBIG special)1722 BOOLEAN us_charhandler(WINDOWPART *w, INTSML cmd, INTBIG special)
1723 {
1724 	REGISTER INTBIG i, longintro, bits, itemHit;
1725 	INTBIG count;
1726 	BOOLEAN verbose;
1727 	REGISTER void *dia;
1728 	static CHAR prompt[] = {x_("-")};
1729 	REGISTER USERCOM *uc;
1730 	CHAR *paramstart[MAXPARS], *pt;
1731 	static UINTBIG timeoflastctlx = 0;
1732 	static BOOLEAN doemacscheck = TRUE;
1733 	REGISTER UINTBIG thiseventtime;
1734 	extern COMCOMP us_userp;
1735 	COMMANDBINDING commandbinding;
1736 	Q_UNUSED( w );
1737 
1738 	/* special case: warn about EMACS-like commands */
1739 	thiseventtime = eventtime();
1740 	bits = getbuckybits();
1741 	if (thiseventtime - timeoflastctlx < 60)
1742 	{
1743 		/* another character typed less than a second after a ^X */
1744 		if ((bits&CONTROLDOWN) != 0)
1745 		{
1746 			/* a control character!  warn that this is not EMACS */
1747 			if (doemacscheck)
1748 			{
1749 				dia = DiaInitDialog(&us_emawarndialog);
1750 				if (dia == 0) return(FALSE);
1751 				for(;;)
1752 				{
1753 					itemHit = DiaNextHit(dia);
1754 					if (itemHit == OK) break;
1755 					if (itemHit == DEMW_DISABLECHECK) doemacscheck = FALSE;
1756 				}
1757 				DiaDoneDialog(dia);
1758 				return(FALSE);
1759 			}
1760 		}
1761 	}
1762 	if (cmd == 'x' && (bits&CONTROLDOWN) != 0)
1763 	{
1764 		timeoflastctlx = thiseventtime;
1765 	}
1766 
1767 	/* get the command attached to the key */
1768 	i = us_findboundkey(cmd, special, &pt);
1769 	if (i < 0) pt = x_("");
1770 	us_parsebinding(pt, &commandbinding);
1771 
1772 	/* see if the key introduces a long command */
1773 	longintro = 0;
1774 	if (namesame(commandbinding.command, x_("telltool user")) == 0) longintro = 1;
1775 
1776 	/* if single-key commands were suspended, wait for carriage-return */
1777 	if ((us_state&SKIPKEYS) != 0)
1778 	{
1779 		if ((cmd&127) == '\r' || (cmd&127) == '\n' || longintro != 0)
1780 		{
1781 			ttyputmsg(_("Single-key command suspension now lifted"));
1782 			us_state &= ~SKIPKEYS;
1783 		}
1784 		if (longintro == 0)
1785 		{
1786 			us_freebindingparse(&commandbinding);
1787 			return(FALSE);
1788 		}
1789 	}
1790 
1791 	/* if this is a "telltool user" character, fill out the command */
1792 	if (longintro != 0)
1793 	{
1794 		us_freebindingparse(&commandbinding);
1795 
1796 		/* get the full command */
1797 		prompt[0] = (CHAR)cmd;
1798 		count = ttygetfullparam(prompt, &us_userp, MAXPARS, paramstart);
1799 		if (count <= 0) return(FALSE);
1800 
1801 		/* parse into fields and execute */
1802 		uc = us_buildcommand(count, paramstart);
1803 		if (uc == NOUSERCOM)
1804 		{
1805 			/* this is very bad!  code should deal with it better!!! */
1806 			ttyputnomemory();
1807 			return(FALSE);
1808 		}
1809 		us_forceeditchanges();
1810 		us_execute(uc, FALSE, TRUE, TRUE);
1811 		us_causeofslice(uc);
1812 		us_freeusercom(uc);
1813 	} else
1814 	{
1815 		/* check for new windows and get set tablet position for command */
1816 		if (*commandbinding.command == 0)
1817 		{
1818 			us_abortcommand(_("The '%s' key has no meaning in this window"),
1819 				us_describeboundkey(cmd, special, 1));
1820 			us_freebindingparse(&commandbinding);
1821 			return(FALSE);
1822 		}
1823 		uc = us_makecommand(commandbinding.command);
1824 		us_freebindingparse(&commandbinding);
1825 		if (uc == NOUSERCOM) return(FALSE);
1826 		if (uc->active >= 0)
1827 		{
1828 			us_forceeditchanges();
1829 			if ((us_tool->toolstate&ECHOBIND) != 0) verbose = TRUE; else
1830 				verbose = FALSE;
1831 			us_execute(uc, verbose, TRUE, TRUE);
1832 			us_causeofslice(uc);
1833 		}
1834 		us_freeusercom(uc);
1835 	}
1836 	flushscreen();
1837 	return(FALSE);
1838 }
1839 
1840 /*
1841  * routine to save the command in "uc" as the one that produced this slice
1842  */
us_causeofslice(USERCOM * uc)1843 void us_causeofslice(USERCOM *uc)
1844 {
1845 	REGISTER void *infstr;
1846 
1847 	if (uc->active < 0) return;
1848 	infstr = initinfstr();
1849 	addstringtoinfstr(infstr, uc->comname);
1850 	us_appendargs(infstr, uc);
1851 	setactivity(returninfstr(infstr));
1852 }
1853 
us_forceeditchanges(void)1854 void us_forceeditchanges(void)
1855 {
1856 	REGISTER WINDOWPART *w;
1857 
1858 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1859 		if ((w->state&WINDOWTYPE) == TEXTWINDOW) us_shipchanges(w);
1860 }
1861 
1862 /******************** CHANGES TO THE DISPLAY ********************/
1863 
us_startbatch(TOOL * source,BOOLEAN undoredo)1864 void us_startbatch(TOOL *source, BOOLEAN undoredo)
1865 {
1866 	/* code cannot be called by multiple procesors: uses globals */
1867 	NOT_REENTRANT;
1868 	Q_UNUSED( undoredo );
1869 
1870 	us_batchsource = source;
1871 	us_firstchangedcell = us_secondchangedcell = NONODEPROTO;
1872 	us_state &= ~HIGHLIGHTSET;
1873 	us_beginchanges();
1874 	us_menuchanged = FALSE;
1875 	us_cellstructurechanged = FALSE;
1876 	us_cellwithkilledname = NONODEPROTO;
1877 }
1878 
us_endbatch(void)1879 void us_endbatch(void)
1880 {
1881 	REGISTER WINDOWPART *w;
1882 
1883 	/* redraw windows whose in-place context has changed */
1884 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
1885 	{
1886 		if ((w->state&INPLACEQUEUEREDRAW) == 0) continue;
1887 		w->state &= ~INPLACEQUEUEREDRAW;
1888 		if (w->redisphandler != 0) (*w->redisphandler)(w);
1889 	}
1890 	us_endchanges(NOWINDOWPART);
1891 	us_showallhighlight();
1892 	if (us_cellstructurechanged)
1893 		us_redoexplorerwindow();
1894 	if (us_batchsource == us_tool && us_firstchangedcell != NONODEPROTO &&
1895 		us_secondchangedcell != NONODEPROTO)
1896 	{
1897 		ttyputmsg(_("This change affected more than one cell"));
1898 	}
1899 }
1900 
1901 /*
1902  * routine to display any delayed highlighting
1903  */
us_showallhighlight(void)1904 void us_showallhighlight(void)
1905 {
1906 	REGISTER INTBIG i, len;
1907 	REGISTER VARIABLE *var;
1908 	HIGHLIGHT high;
1909 
1910 	/* stop now if highlighting has not been delayed */
1911 	if ((us_state&HIGHLIGHTSET) == 0) return;
1912 
1913 	/* show all highlighting */
1914 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1915 	if (var != NOVARIABLE)
1916 	{
1917 		len = getlength(var);
1918 		for(i=0; i<len; i++)
1919 		{
1920 			if (us_makehighlight(((CHAR **)var->addr)[i], &high)) continue;
1921 			us_sethighlight(&high, HIGHLIT);
1922 		}
1923 	}
1924 
1925 	/* mark that highlighting is not delayed */
1926 	us_state &= ~HIGHLIGHTSET;
1927 }
1928 
us_startobjectchange(INTBIG addr,INTBIG type)1929 void us_startobjectchange(INTBIG addr, INTBIG type)
1930 {
1931 	switch (type&VTYPE)
1932 	{
1933 		case VNODEINST:
1934 			us_undisplayobject(((NODEINST *)addr)->geom);   break;
1935 		case VARCINST:
1936 			us_undisplayobject(((ARCINST *)addr)->geom);    break;
1937 		case VWINDOWPART:
1938 			copywindowpart(&us_oldwindow, (WINDOWPART *)addr);  break;
1939 		case VTOOL:
1940 			if ((TOOL *)addr == us_tool) us_maplow = -1;
1941 			us_oldstate = us_tool->toolstate;
1942 			us_oldoptions = us_useroptions;
1943 			us_menuchanged = FALSE;
1944 			us_newwindowcount = 0;
1945 			us_firstnewwindow = us_secondnewwindow = NOWINDOWPART;
1946 			us_killedwindow = NOWINDOWPART;
1947 			us_gridfactorschanged = FALSE;
1948 			break;
1949 	}
1950 }
1951 
us_endobjectchange(INTBIG addr,INTBIG type)1952 void us_endobjectchange(INTBIG addr, INTBIG type)
1953 {
1954 	REGISTER WINDOWPART *w, *ow, *w1, *w2, *w3;
1955 	REGISTER INTBIG ulx, uhx, uly, uhy, bits, lambda;
1956 	static POLYGON *poly = NOPOLYGON;
1957 	REGISTER NODEPROTO *np;
1958 	REGISTER NODEINST *ni;
1959 	REGISTER ARCINST *ai;
1960 	REGISTER TECHNOLOGY *tech;
1961 	INTBIG dummy, cenx, ceny;
1962 	REGISTER INTBIG alignment;
1963 	extern GRAPHICS us_egbox, us_gbox;
1964 	REGISTER VARIABLE *varred, *vargreen, *varblue, *var;
1965 
1966 	switch (type&VTYPE)
1967 	{
1968 		case VNODEINST:
1969 			ni = (NODEINST *)addr;
1970 			us_queueredraw(ni->geom, FALSE);
1971 			us_geomhaschanged(ni->geom);
1972 			break;
1973 		case VARCINST:
1974 			ai = (ARCINST *)addr;
1975 			us_queueredraw(ai->geom, FALSE);
1976 			us_geomhaschanged(ai->geom);
1977 			break;
1978 		case VTOOL:
1979 			if ((TOOL *)addr != us_tool) break;
1980 
1981 			/* handle changes to the menu */
1982 			if ((us_oldstate&MENUON) != (us_tool->toolstate&MENUON) || us_menuchanged)
1983 			{
1984 				/* destroy or create the menu if requested */
1985 				us_menuchanged = FALSE;
1986 				if (us_menuframe != NOWINDOWFRAME && (us_tool->toolstate&MENUON) == 0)
1987 				{
1988 					killwindowframe(us_menuframe);
1989 					us_menuframe = NOWINDOWFRAME;
1990 					return;
1991 				}
1992 				if (us_menuframe == NOWINDOWFRAME && (us_tool->toolstate&MENUON) != 0)
1993 					us_menuframe = newwindowframe(TRUE, 0);
1994 				us_drawmenu(1, us_menuframe);
1995 				return;
1996 			}
1997 
1998 			/* handle changes to the color map */
1999 			if (us_maplow != -1)
2000 			{
2001 				varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
2002 				vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
2003 				varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
2004 				if (varred != NOVARIABLE && vargreen != NOVARIABLE && varblue != NOVARIABLE)
2005 					colormapload(&((INTBIG *)varred->addr)[us_maplow],
2006 						&((INTBIG *)vargreen->addr)[us_maplow], &((INTBIG *)varblue->addr)[us_maplow],
2007 							us_maplow, us_maphigh);
2008 			}
2009 
2010 			/* rewrite status information in header if configuration changed */
2011 			if (us_newwindowcount != 0 || us_killedwindow != NOWINDOWPART)
2012 			{
2013 				us_redostatus(NOWINDOWFRAME);
2014 			}
2015 
2016 			/* see if windows were created */
2017 			if (us_newwindowcount != 0)
2018 			{
2019 				/* special case for split edit windows */
2020 				if (us_killedwindow != NOWINDOWPART && us_newwindowcount == 2 &&
2021 					(us_firstnewwindow->state&WINDOWTYPE) == DISPWINDOW &&
2022 						(us_secondnewwindow->state&WINDOWTYPE) == DISPWINDOW &&
2023 							us_firstnewwindow->curnodeproto == us_secondnewwindow->curnodeproto &&
2024 								us_firstnewwindow->curnodeproto == us_killedwindow->curnodeproto)
2025 				{
2026 					/* use block transfer */
2027 					w1 = &us_oldwindow;
2028 					w2 = us_firstnewwindow;
2029 					w3 = us_secondnewwindow;
2030 
2031 					/* make sure the windows have the same scale */
2032 					if (us_windowcansplit(w1, w2, w3))
2033 					{
2034 						/* make sure that "w3" is the larger window */
2035 						if (w2->usehx - w2->uselx > w3->usehx - w3->uselx ||
2036 							w2->usehy - w2->usely > w3->usehy - w3->usely)
2037 						{
2038 							w = w2;   w2 = w3;   w3 = w;
2039 						}
2040 						screenmovebox(w2, (w1->usehx+w1->uselx - w3->usehx+w3->uselx) / 2,
2041 							(w1->usehy+w1->usely - w3->usehy+w3->usely) / 2,
2042 								w3->usehx-w3->uselx+1, w3->usehy-w3->usely+1,
2043 									w3->uselx, w3->usely);
2044 						if (w2->curnodeproto != NONODEPROTO && w2->curnodeproto == w3->curnodeproto)
2045 							screenmovebox(w2, w3->uselx, w3->usely, w2->usehx-w2->uselx+1,
2046 								w2->usehy-w2->usely+1, w2->uselx, w2->usely);
2047 						us_drawwindow(w2, el_colwinbor);
2048 						us_drawwindow(w3, el_colwinbor);
2049 						break;
2050 					}
2051 				}
2052 
2053 				/* simple window creation: draw and outline */
2054 				if (us_newwindowcount > 2)
2055 				{
2056 					/* many windows created: redraw all of them */
2057 					for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2058 					{
2059 						us_drawwindow(w, el_colwinbor);
2060 						if (w->redisphandler != 0) (*w->redisphandler)(w);
2061 					}
2062 				} else
2063 				{
2064 					/* one or two windows created: draw them */
2065 					us_drawwindow(us_firstnewwindow, el_colwinbor);
2066 					if (us_firstnewwindow->redisphandler != 0)
2067 						(*us_firstnewwindow->redisphandler)(us_firstnewwindow);
2068 					if (us_secondnewwindow != NOWINDOWPART)
2069 					{
2070 						us_drawwindow(us_secondnewwindow, el_colwinbor);
2071 						if (us_secondnewwindow->redisphandler != 0)
2072 							(*us_secondnewwindow->redisphandler)(us_secondnewwindow);
2073 					}
2074 				}
2075 				break;
2076 			}
2077 
2078 			/* redraw all windows if appropriate options changed */
2079 			bits = DRAWTINYCELLS|PORTLABELS|EXPORTLABELS|HIDETXTNODE|HIDETXTARC|
2080 				HIDETXTPORT|HIDETXTEXPORT|HIDETXTNONLAY|HIDETXTINSTNAME|HIDETXTCELL;
2081 			if ((us_oldoptions&bits) != (us_useroptions&bits))
2082 			{
2083 				for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2084 					if (w->redisphandler != 0) (*w->redisphandler)(w);
2085 			}
2086 			break;
2087 
2088 		case VWINDOWPART:
2089 			w = (WINDOWPART *)addr;
2090 			ow = &us_oldwindow;
2091 
2092 			/* adjust window if changing in or out of being a display window */
2093 			if ((w->state&WINDOWTYPE) == DISPWINDOW && (ow->state&WINDOWTYPE) != DISPWINDOW)
2094 			{
2095 				/* became a display window: shrink the bottom and right edge */
2096 				w->usehx -= DISPLAYSLIDERSIZE;
2097 				w->usely += DISPLAYSLIDERSIZE;
2098 				computewindowscale(w);
2099 			}
2100 			if ((w->state&WINDOWTYPE) != DISPWINDOW && (ow->state&WINDOWTYPE) == DISPWINDOW)
2101 			{
2102 				/* no longer a display window: shrink the bottom and right edge */
2103 				w->usehx += DISPLAYSLIDERSIZE;
2104 				w->usely -= DISPLAYSLIDERSIZE;
2105 				computewindowscale(w);
2106 			}
2107 
2108 			/* adjust window if changing in or out of being a waveform/tec edit/outline edit window */
2109 			if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW && (ow->state&WINDOWTYPE) != WAVEFORMWINDOW)
2110 			{
2111 				/* became a waveform window: shrink the left edge */
2112 				w->uselx += DISPLAYSLIDERSIZE;
2113 				w->usely += DISPLAYSLIDERSIZE;
2114 				computewindowscale(w);
2115 			}
2116 			if ((w->state&WINDOWTYPE) != WAVEFORMWINDOW && (ow->state&WINDOWTYPE) == WAVEFORMWINDOW)
2117 			{
2118 				/* no longer a waveform window: shrink the bottom and right edge */
2119 				w->uselx -= DISPLAYSLIDERSIZE;
2120 				w->usely -= DISPLAYSLIDERSIZE;
2121 				computewindowscale(w);
2122 			}
2123 
2124 			/* set the cursor according to the current window */
2125 			if (el_curwindowpart == NOWINDOWPART) setnormalcursor(NORMALCURSOR); else
2126 			{
2127 				if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
2128 				{
2129 					setnormalcursor(PENCURSOR);
2130 				} else
2131 				{
2132 					if ((el_curwindowpart->state&WINDOWTECEDMODE) != 0)
2133 					{
2134 						setnormalcursor(TECHCURSOR);
2135 					} else
2136 					{
2137 						setnormalcursor(NORMALCURSOR);
2138 					}
2139 				}
2140 			}
2141 
2142 			/* switch between 2-D and 3-D drawing */
2143 			if ((ow->state&WINDOWTYPE) == DISPWINDOW && (w->state&WINDOWTYPE) == DISP3DWINDOW)
2144 			{
2145 				if (w->redisphandler != 0) (*w->redisphandler)(w);
2146 				break;
2147 			}
2148 			if ((ow->state&WINDOWTYPE) == DISP3DWINDOW && (w->state&WINDOWTYPE) == DISPWINDOW)
2149 			{
2150 				if (w->redisphandler != 0) (*w->redisphandler)(w);
2151 				break;
2152 			}
2153 
2154 			/* adjust window if mode changed */
2155 			if ((w->state&WINDOWMODE) != (ow->state&WINDOWMODE))
2156 			{
2157 				us_setwindowmode(w, ow->state, w->state);
2158 				computewindowscale(w);
2159 				if (w->redisphandler != 0) (*w->redisphandler)(w);
2160 				break;
2161 			}
2162 
2163 			/* see if the cell changed */
2164 			if (w->curnodeproto != ow->curnodeproto || w->buttonhandler != ow->buttonhandler ||
2165 				w->charhandler != ow->charhandler || w->termhandler != ow->termhandler ||
2166 					w->redisphandler != ow->redisphandler || w->changehandler != ow->changehandler)
2167 			{
2168 				us_setcellname(w);
2169 				us_setcellsize(w);
2170 				us_setgridsize(w);
2171 				if (w->redisphandler != 0) (*w->redisphandler)(w);
2172 				break;
2173 			}
2174 
2175 			/* see if the window slid vertically */
2176 			if (w->screenlx == ow->screenlx && w->screenhx == ow->screenhx &&
2177 				w->screenly - ow->screenly == w->screenhy - ow->screenhy &&
2178 					w->screenly != ow->screenly)
2179 			{
2180 				/* window slid vertically */
2181 				ulx = w->uselx;       uhx = w->usehx;
2182 				uly = w->usely;       uhy = w->usehy;
2183 				ow->uselx = ulx;      ow->usehx = uhx;
2184 				ow->usely = uly;      ow->usehy = uhy;
2185 				computewindowscale(ow);
2186 
2187 				/* bit sliding didn't work, redisplay entire window */
2188 				if (w->redisphandler != 0) (*w->redisphandler)(w);
2189 				break;
2190 			}
2191 
2192 			/* see if the window slid horizontally */
2193 			if (w->screenly == ow->screenly && w->screenhy == ow->screenhy &&
2194 				w->screenlx - ow->screenlx == w->screenhx - ow->screenhx &&
2195 					w->screenlx != ow->screenlx)
2196 			{
2197 				/* window slid horizontally */
2198 				ulx = w->uselx;       uhx = w->usehx;
2199 				uly = w->usely;       uhy = w->usehy;
2200 				ow->uselx = ulx;      ow->usehx = uhx;
2201 				ow->usely = uly;      ow->usehy = uhy;
2202 				computewindowscale(ow);
2203 
2204 				/* bit sliding didn't work, redisplay entire window */
2205 				if (w->redisphandler != 0) (*w->redisphandler)(w);
2206 				break;
2207 			}
2208 
2209 			/* redraw waveform window */
2210 			if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
2211 			{
2212 				if (w->redisphandler != 0) (*w->redisphandler)(w);
2213 				break;
2214 			}
2215 
2216 			/* handle grid going off or changing size while on */
2217 			if (((ow->state&GRIDON) != 0 && (w->state&GRIDON) == 0) ||
2218 				((w->state&GRIDON) != 0 &&
2219 					(ow->gridx != w->gridx || ow->gridy != w->gridy || us_gridfactorschanged)))
2220 			{
2221 				/* must redraw everything on B&W displays or those with less than 8-bits */
2222 				us_setgridsize(w);
2223 				if (el_maplength < 256)
2224 				{
2225 					if (w->redisphandler != 0) (*w->redisphandler)(w);
2226 					break;
2227 				}
2228 
2229 				/* erase the grid layer */
2230 				screendrawbox(w, w->uselx, w->usehx, w->usely, w->usehy, &us_egbox);
2231 
2232 				/* if grid went off and nothing else changed, all is done */
2233 				if ((w->state&GRIDON) == 0 && w->screenlx == ow->screenlx &&
2234 					w->screenhx == ow->screenhx && w->screenly == ow->screenly &&
2235 						w->screenhy == ow->screenhy) break;
2236 			}
2237 
2238 			/* handle grid going on or staying on and changing size */
2239 			if (w->screenlx == ow->screenlx && w->screenhx == ow->screenhx &&
2240 				w->screenly == ow->screenly && w->screenhy == ow->screenhy)
2241 					if (((ow->state & (GRIDTOOSMALL|GRIDON)) != GRIDON &&
2242 						(w->state & (GRIDTOOSMALL|GRIDON)) == GRIDON) ||
2243 							((ow->state&GRIDON) != 0 && (w->state&GRIDON) != 0 &&
2244 								(ow->gridx != w->gridx || ow->gridy != w->gridy || us_gridfactorschanged)))
2245 			{
2246 				np = w->curnodeproto;
2247 				if (np == NONODEPROTO) break;
2248 
2249 				/* get polygon */
2250 				(void)needstaticpolygon(&poly, 6, us_tool->cluster);
2251 
2252 				/* grid spacing */
2253 				lambda = np->lib->lambda[np->tech->techindex];
2254 				poly->xv[0] = muldiv(w->gridx, lambda, WHOLE);
2255 				poly->yv[0] = muldiv(w->gridy, lambda, WHOLE);
2256 
2257 				/* initial grid location */
2258 				var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_gridfloatskey);
2259 				if (var == NOVARIABLE || var->addr == 0)
2260 				{
2261 					poly->xv[1] = w->screenlx / poly->xv[0] * poly->xv[0];
2262 					poly->yv[1] = w->screenly / poly->yv[0] * poly->yv[0];
2263 				} else
2264 				{
2265 					grabpoint(np, &cenx, &ceny);
2266 					tech = np->tech;
2267 					if (tech == NOTECHNOLOGY) tech = el_curtech;
2268 					alignment = muldiv(us_alignment_ratio, el_curlib->lambda[tech->techindex], WHOLE);
2269 					poly->xv[1] = us_alignvalue(cenx, alignment, &dummy);
2270 					poly->yv[1] = us_alignvalue(ceny, alignment, &dummy);
2271 					poly->xv[1] += (w->screenlx-poly->xv[1]) / poly->xv[0] * poly->xv[0];
2272 					poly->yv[1] += (w->screenly-poly->yv[1]) / poly->yv[0] * poly->yv[0];
2273 				}
2274 
2275 				/* display screen extent */
2276 				poly->xv[2] = w->uselx;     poly->yv[2] = w->usely;
2277 				poly->xv[3] = w->usehx;     poly->yv[3] = w->usehy;
2278 
2279 				/* object space extent */
2280 				poly->xv[4] = w->screenlx;  poly->yv[4] = w->screenly;
2281 				poly->xv[5] = w->screenhx;  poly->yv[5] = w->screenhy;
2282 
2283 				poly->count = 6;
2284 				poly->style = GRIDDOTS;
2285 				poly->desc = &us_gbox;
2286 				(*us_displayroutine)(poly, w);
2287 				flushscreen();
2288 				break;
2289 			}
2290 
2291 			/* no sliding or grid change: simply redisplay the window */
2292 			if (w->redisphandler != 0) (*w->redisphandler)(w);
2293 			break;
2294 	}
2295 }
2296 
us_modifynodeinst(NODEINST * ni,INTBIG oldlx,INTBIG oldly,INTBIG oldhx,INTBIG oldhy,INTBIG oldrot,INTBIG oldtran)2297 void us_modifynodeinst(NODEINST *ni, INTBIG oldlx, INTBIG oldly, INTBIG oldhx, INTBIG oldhy,
2298 	INTBIG oldrot, INTBIG oldtran)
2299 {
2300 	REGISTER INTBIG dlx, dhx, dly, dhy;
2301 	Q_UNUSED( oldrot );
2302 	Q_UNUSED( oldtran );
2303 
2304 	/* look for the special "cell-center" and "essential-bounds" nodes in the "generic" technology */
2305 	if (ni->proto == gen_cellcenterprim)
2306 		us_setnodeprotocenter(ni->lowx, ni->lowy, ni->parent); else
2307 			if (ni->proto == gen_essentialprim)
2308 				us_setessentialbounds(ni->parent);
2309 
2310 	/* track changes to node that was duplicated */
2311 	if (ni == us_dupnode)
2312 	{
2313 		us_dupx += (ni->lowx + ni->highx) / 2 - (oldlx + oldhx) / 2;
2314 		us_dupy += (ni->lowy + ni->highy) / 2 - (oldly + oldhy) / 2;
2315 	}
2316 
2317 	/* if node moved, remember the cell */
2318 	dlx = ni->lowx - oldlx;   dhx = ni->highx - oldhx;
2319 	dly = ni->lowy - oldly;   dhy = ni->highy - oldhy;
2320 	if ((dlx == dhx && dlx != 0) || (dly == dhy && dly != 0))
2321 	{
2322 		if (us_firstchangedcell == NONODEPROTO || us_firstchangedcell == ni->parent)
2323 		{
2324 			us_firstchangedcell = ni->parent;
2325 		} else if (us_secondchangedcell == NONODEPROTO || us_secondchangedcell != ni->parent)
2326 		{
2327 			us_secondchangedcell = ni->parent;
2328 		}
2329 	}
2330 
2331 	/* see if this affects in-place editing */
2332 	us_checkinplaceedits(ni->parent);
2333 }
2334 
us_modifynodeproto(NODEPROTO * np)2335 void us_modifynodeproto(NODEPROTO *np)
2336 {
2337 	REGISTER WINDOWPART *w;
2338 
2339 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2340 	{
2341 		if (np != w->curnodeproto) continue;
2342 		us_setcellsize(w);
2343 		us_drawdispwindowsliders(w);
2344 	}
2345 
2346 	/* see if this affects in-place editing */
2347 	us_checkinplaceedits(np);
2348 }
2349 
us_modifydescript(INTBIG addr,INTBIG type,INTBIG key,UINTBIG * old)2350 void us_modifydescript(INTBIG addr, INTBIG type, INTBIG key, UINTBIG *old)
2351 {
2352 	Q_UNUSED( key );
2353 	Q_UNUSED( old );
2354 
2355 	switch (type&VTYPE)
2356 	{
2357 		case VNODEINST:
2358 			us_computenodefartextbit((NODEINST *)addr);
2359 			break;
2360 		case VARCINST:
2361 			us_computearcfartextbit((ARCINST *)addr);
2362 			break;
2363 	}
2364 }
2365 
us_newobject(INTBIG addr,INTBIG type)2366 void us_newobject(INTBIG addr, INTBIG type)
2367 {
2368 	REGISTER NODEINST *ni;
2369 	REGISTER NODEPROTO *np;
2370 	REGISTER ARCINST *ai;
2371 	REGISTER PORTPROTO *pp;
2372 	REGISTER UINTBIG wiped;
2373 	REGISTER INTBIG i;
2374 	REGISTER WINDOWPART *w;
2375 	REGISTER NODEPROTO *onp;
2376 	REGISTER EDITOR *ed;
2377 
2378 	switch (type&VTYPE)
2379 	{
2380 		case VNODEINST:
2381 			ni = (NODEINST *)addr;
2382 
2383 			/* look for the "cell-center" or "essential-bounds" nodes in the "generic" technology */
2384 			if (ni->proto == gen_cellcenterprim) us_addcellcenter(ni); else
2385 				if (ni->proto == gen_essentialprim)
2386 					us_setessentialbounds(ni->parent);
2387 
2388 			/* if a new instance was created, then the cell structure has changed */
2389 			if (ni->proto->primindex == 0) us_cellstructurechanged = TRUE;
2390 
2391 			/* recompute the parent's technology */
2392 			ni->parent->tech = whattech(ni->parent);
2393 
2394 			/* see if this affects in-place editing */
2395 			us_checkinplaceedits(ni->parent);
2396 			break;
2397 
2398 		case VARCINST:
2399 			ai = (ARCINST *)addr;
2400 
2401 			/* see if this arcinst wipes out the visibility of some pins */
2402 			if ((ai->proto->userbits&CANWIPE) != 0) for(i=0; i<2; i++)
2403 			{
2404 				ni = ai->end[i].nodeinst;
2405 
2406 				wiped = us_computewipestate(ni);
2407 				if (wiped != (ni->userbits&WIPED))
2408 				{
2409 					/* if node was visible, erase it before setting WIPED bit */
2410 					if ((ni->userbits&WIPED) == 0) us_undisplayobject(ni->geom);
2411 					ni->userbits = (ni->userbits & ~WIPED) | wiped;
2412 				}
2413 			}
2414 
2415 			/* recompute the parent's technology */
2416 			ai->parent->tech = whattech(ai->parent);
2417 
2418 			/* see if this affects in-place editing */
2419 			us_checkinplaceedits(ai->parent);
2420 			break;
2421 
2422 		case VNODEPROTO:
2423 			np = (NODEPROTO *)addr;
2424 
2425 			/* update status display if this is new version of what's displayed */
2426 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2427 			{
2428 				if (w->curnodeproto == NONODEPROTO) continue;
2429 				if (w->curnodeproto != np) continue;
2430 				if ((w->state&WINDOWTYPE) == TEXTWINDOW)
2431 				{
2432 					ed = w->editor;
2433 					if (ed != NOEDITOR) (void)reallocstring(&ed->header,
2434 						describenodeproto(w->curnodeproto), us_tool->cluster);
2435 					w->redisphandler(w);
2436 				}
2437 				us_setcellname(w);
2438 			}
2439 
2440 			/* the cell structure has changed */
2441 			us_cellstructurechanged = TRUE;
2442 
2443 			onp = us_curnodeproto;
2444 			if (onp == NONODEPROTO) return;
2445 			if (onp->primindex != 0) return;
2446 			if (onp != np) return;
2447 			us_curnodeproto = NONODEPROTO;
2448 			us_shadownodeproto(NOWINDOWFRAME, onp);
2449 
2450 			/* recompute the technology */
2451 			np->tech = whattech(np);
2452 			break;
2453 
2454 		case VPORTPROTO:
2455 			pp = (PORTPROTO *)addr;
2456 
2457 			/* look at all instances of this nodeproto for use on display */
2458 			for(ni = pp->parent->firstinst; ni != NONODEINST; ni = ni->nextinst)
2459 				if ((ni->userbits & NEXPAND) == 0 || (pp->userbits&PORTDRAWN) != 0)
2460 					us_queueredraw(ni->geom, FALSE);
2461 
2462 			/* see if this affects in-place editing */
2463 			us_checkinplaceedits(pp->parent);
2464 			break;
2465 
2466 		case VLIBRARY:
2467 			/* the cell structure has changed */
2468 			us_cellstructurechanged = TRUE;
2469 			break;
2470 
2471 		case VWINDOWPART:
2472 			w = (WINDOWPART *)addr;
2473 			us_newwindowcount++;
2474 			if (us_firstnewwindow == NOWINDOWPART) us_firstnewwindow = w; else
2475 				us_secondnewwindow = w;
2476 			break;
2477 	}
2478 }
2479 
us_killobject(INTBIG addr,INTBIG type)2480 void us_killobject(INTBIG addr, INTBIG type)
2481 {
2482 	REGISTER INTBIG i;
2483 	REGISTER UINTBIG wiped;
2484 	REGISTER NODEINST *ni;
2485 	REGISTER NODEPROTO *np;
2486 	REGISTER PORTPROTO *pp;
2487 	REGISTER ARCINST *ai;
2488 	REGISTER WINDOWPART *w;
2489 
2490 	switch (type&VTYPE)
2491 	{
2492 		case VNODEINST:
2493 			ni = (NODEINST *)addr;
2494 			ni->userbits |= (RETDONN|REODONN);
2495 
2496 			/* stop tracking duplicated node if it is deleted */
2497 			if (ni == us_dupnode) us_dupnode = NONODEINST;
2498 
2499 			/* if an instance was deleted, then the cell structure has changed */
2500 			if (ni->proto->primindex == 0) us_cellstructurechanged = TRUE;
2501 
2502 			/* look for the "cell-center" node in the "generic" technology */
2503 			if (ni->proto == gen_cellcenterprim)
2504 				us_delnodeprotocenter(ni->parent); else
2505 					if (ni->proto == gen_essentialprim)
2506 						us_setessentialbounds(ni->parent);
2507 
2508 			/* recompute the parent's technology */
2509 			ni->parent->tech = whattech(ni->parent);
2510 
2511 			/* see if this affects in-place editing */
2512 			us_checkinplaceedits(ni->parent);
2513 			break;
2514 
2515 		case VARCINST:
2516 			ai = (ARCINST *)addr;
2517 
2518 			/* see if this arcinst wiped out the visibility of some pins */
2519 			if ((ai->proto->userbits&CANWIPE) != 0) for(i=0; i<2; i++)
2520 			{
2521 				ni = ai->end[i].nodeinst;
2522 
2523 				/* if nodeinst still live and has other arcs, leave it */
2524 				if ((ni->userbits&DEADN) != 0) continue;
2525 
2526 				wiped = us_computewipestate(ni);
2527 				if (wiped != (ni->userbits&WIPED))
2528 				{
2529 					/* if node was invisible, display before resetting WIPED bit */
2530 					if ((ni->userbits&WIPED) != 0) us_queueredraw(ni->geom, FALSE);
2531 					ni->userbits = (ni->userbits & ~WIPED) | wiped;
2532 				}
2533 			}
2534 
2535 			/* recompute the parent's technology */
2536 			ai->parent->tech = whattech(ai->parent);
2537 
2538 			/* see if this affects in-place editing */
2539 			us_checkinplaceedits(ai->parent);
2540 			break;
2541 
2542 		case VNODEPROTO:
2543 			np = (NODEPROTO *)addr;
2544 
2545 			/* if this may be a technology-edit cell, let it know */
2546 			if (namesamen(np->protoname, x_("layer-"), 6) == 0)
2547 				us_deltecedlayercell(np);
2548 			if (namesamen(np->protoname, x_("node-"), 5) == 0)
2549 				us_deltecednodecell(np);
2550 
2551 			us_removeubchange(np);
2552 
2553 			/* the cell structure has changed */
2554 			us_cellstructurechanged = TRUE;
2555 			break;
2556 
2557 		case VPORTPROTO:
2558 			pp = (PORTPROTO *)addr;
2559 
2560 			/* look at all instances of this nodeproto for use on display */
2561 			for(ni = pp->parent->firstinst; ni != NONODEINST; ni = ni->nextinst)
2562 				if ((ni->userbits & NEXPAND) == 0 || (pp->userbits&PORTDRAWN) != 0)
2563 			{
2564 				us_undisplayobject(ni->geom);
2565 				us_queueredraw(ni->geom, FALSE);
2566 			}
2567 
2568 			/* see if this affects in-place editing */
2569 			us_checkinplaceedits(pp->parent);
2570 			break;
2571 
2572 		case VLIBRARY:
2573 			/* the cell structure has changed */
2574 			us_cellstructurechanged = TRUE;
2575 			break;
2576 
2577 		case VWINDOWPART:
2578 			w = (WINDOWPART *)addr;
2579 			copywindowpart(&us_oldwindow, w);
2580 			us_killedwindow = w;
2581 			break;
2582 	}
2583 }
2584 
us_newvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG newtype)2585 void us_newvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG newtype)
2586 {
2587 	REGISTER INTBIG len, i, x, y;
2588 	REGISTER VARIABLE *var;
2589 	REGISTER WINDOWPART *w;
2590 	REGISTER POPUPMENU *pm;
2591 	REGISTER POPUPMENUITEM *mi;
2592 	REGISTER NODEPROTO *np;
2593 	REGISTER ARCPROTO *ap;
2594 	REGISTER LIBRARY *lib;
2595 	REGISTER TOOL *tool;
2596 	REGISTER TECHNOLOGY *tech;
2597 	REGISTER CHAR *name, *pt;
2598 	REGISTER USERCOM *rb;
2599 	COMMANDBINDING commandbinding;
2600 
2601 	if ((newtype&VCREF) != 0)
2602 	{
2603 		name = changedvariablename(type, key, newtype);
2604 
2605 		/* see if cell name changed */
2606 		if ((type&VTYPE) == VNODEPROTO && namesame(name, x_("protoname")) == 0)
2607 		{
2608 			np = (NODEPROTO *)addr;
2609 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2610 				if (w->curnodeproto != NONODEPROTO && w->curnodeproto == np)
2611 					us_setcellname(w);
2612 			us_cellstructurechanged = TRUE;
2613 			if (np == us_cellwithkilledname)
2614 			{
2615 				/* tell the technology editor that a cell name changed */
2616 				us_renametecedcell(us_cellwithkilledname, us_killednameoncell);
2617 			}
2618 			return;
2619 		}
2620 
2621 		/* see if screen extent changed */
2622 		if ((type&VTYPE) == VWINDOWPART && namesamen(name, x_("screen"), 6) == 0)
2623 		{
2624 			w = (WINDOWPART *)addr;
2625 			computewindowscale(w);
2626 			return;
2627 		}
2628 
2629 		/* see if technology name changed */
2630 		if ((type&VTYPE) == VTECHNOLOGY && namesame(name, x_("techname")) == 0)
2631 		{
2632 			tech = (TECHNOLOGY *)addr;
2633 			if (tech == el_curtech) us_settechname(NOWINDOWFRAME);
2634 			return;
2635 		}
2636 
2637 		/* see if layer visibility changed */
2638 		if ((type&VTYPE) == VGRAPHICS && namesame(name, x_("colstyle")) == 0)
2639 		{
2640 			us_figuretechselectability();
2641 			return;
2642 		}
2643 
2644 		/* see if current cell or library name changed */
2645 		if ((type&VTYPE) == VLIBRARY &&
2646 			(namesame(name, x_("curnodeproto")) == 0 || namesame(name, x_("libname")) == 0))
2647 		{
2648 			lib = (LIBRARY *)addr;
2649 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2650 			{
2651 				if (w->curnodeproto == NONODEPROTO) continue;
2652 				if (w->curnodeproto->lib == lib) us_setcellname(w);
2653 			}
2654 			if (namesame(name, x_("libname")) == 0) us_cellstructurechanged = TRUE;
2655 			if (namesame(name, x_("curnodeproto")) == 0) us_state |= CURCELLCHANGED;
2656 			return;
2657 		}
2658 
2659 		/* see if a tool was turned on */
2660 		if ((type&VTYPE) == VTOOL && namesame(name, x_("toolstate")) == 0)
2661 		{
2662 			tool = (TOOL *)addr;
2663 			if ((tool->toolstate & TOOLON) != 0 &&
2664 				(tool->toolstate & TOOLINCREMENTAL) != 0)
2665 					us_toolturnedon(tool);
2666 		}
2667 		return;
2668 	}
2669 
2670 	/* see if an option variable changed */
2671 	if ((newtype&VDONTSAVE) == 0)
2672 	{
2673 		if (isoptionvariable(addr, type, makename(key)))
2674 			us_optionschanged = TRUE;
2675 	}
2676 
2677 	/* handle changes to objects on the user interface */
2678 	if (addr == (INTBIG)us_tool)
2679 	{
2680 		/* pick up mirrors */
2681 		for(i=0; us_variablemirror[i].key != 0; i++)
2682 		{
2683 			if (key == *us_variablemirror[i].key)
2684 			{
2685 				var = getvalkey(addr, type, -1, key);
2686 				if (var != NOVARIABLE) *us_variablemirror[i].value = var->addr;
2687 				if (key == us_menu_x_key || key == us_menu_y_key || key == us_menu_position_key)
2688 					us_menuchanged = TRUE;
2689 				return;
2690 			}
2691 		}
2692 
2693 		if (key == us_alignment_ratio_key)
2694 		{
2695 			var = getvalkey(addr, type, VINTEGER, key);
2696 			if (var != NOVARIABLE) us_alignment_ratio = var->addr;
2697 			us_setalignment(NOWINDOWFRAME);
2698 			return;
2699 		}
2700 
2701 		if (key == us_alignment_edge_ratio_key)
2702 		{
2703 			var = getvalkey(addr, type, VINTEGER, key);
2704 			if (var != NOVARIABLE) us_edgealignment_ratio = var->addr;
2705 			us_setalignment(NOWINDOWFRAME);
2706 			return;
2707 		}
2708 
2709 		if (key == us_displayunitskey)
2710 		{
2711 			var = getvalkey(addr, type, VINTEGER, key);
2712 			if (var != NOVARIABLE)
2713 			{
2714 				/* code cannot be called by multiple procesors: uses globals */
2715 				NOT_REENTRANT;
2716 
2717 				el_units = (el_units & ~DISPLAYUNITS) | (var->addr & DISPLAYUNITS);
2718 			}
2719 			return;
2720 		}
2721 
2722 		/* see if default text editor changed */
2723 		if (key == us_text_editorkey)
2724 		{
2725 			var = getvalkey(addr, type, VSTRING, key);
2726 			if (var == NOVARIABLE) return;
2727 			for(i=0; us_editortable[i].editorname != 0; i++)
2728 				if (namesame((CHAR *)var->addr, us_editortable[i].editorname) == 0) break;
2729 			if (us_editortable[i].editorname == 0) return;
2730 
2731 			/* code cannot be called by multiple procesors: uses globals */
2732 			NOT_REENTRANT;
2733 
2734 			us_currenteditor = i;
2735 			return;
2736 		}
2737 
2738 		/* set current window if it changed */
2739 		if (key == us_current_window_key)
2740 		{
2741 			var = getvalkey(addr, type, VWINDOWPART, key);
2742 			if (var == NOVARIABLE) return;
2743 			w = (WINDOWPART *)var->addr;
2744 			us_highlightwindow(w, FALSE);
2745 			if (w != NOWINDOWPART) us_setcellsize(w);
2746 			return;
2747 		}
2748 
2749 		/* set colormap updating if it changed */
2750 		if (key == us_colormap_red_key || key == us_colormap_green_key ||
2751 			key == us_colormap_blue_key)
2752 		{
2753 			us_maplow = 0;
2754 			var = getvalkey(addr, type, VINTEGER|VISARRAY, key);
2755 			if (var == NOVARIABLE) return;
2756 			len = getlength(var);
2757 			if (us_maplow == -1) us_maphigh = len-1; else
2758 				if (len-1 > us_maphigh) us_maphigh = len-1;
2759 			return;
2760 		}
2761 
2762 		/* show highlight if it changed */
2763 		if (key == us_highlightedkey)
2764 		{
2765 			us_state |= HIGHLIGHTSET;
2766 			us_setselectioncount();
2767 			us_highlighthaschanged();
2768 			return;
2769 		}
2770 
2771 		/* shadow current nodeproto or arcproto if it changed */
2772 		if (key == us_current_node_key)
2773 		{
2774 			var = getvalkey(addr, type, VNODEPROTO, key);
2775 			if (var != NOVARIABLE) us_shadownodeproto(NOWINDOWFRAME, (NODEPROTO *)var->addr);
2776 			return;
2777 		}
2778 		if (key == us_current_arc_key)
2779 		{
2780 			var = getvalkey(addr, type, VARCPROTO, key);
2781 			if (var != NOVARIABLE) us_shadowarcproto(NOWINDOWFRAME, (ARCPROTO *)var->addr);
2782 			return;
2783 		}
2784 
2785 		/* shadow placement angle if it changed */
2786 		if (key == us_placement_angle_key)
2787 		{
2788 			us_setnodeangle(NOWINDOWFRAME);
2789 			return;
2790 		}
2791 
2792 		/* switch technology if it changed */
2793 		if (key == us_current_technology_key)
2794 		{
2795 			var = getvalkey(addr, type, VTECHNOLOGY, key);
2796 			if (var == NOVARIABLE) return;
2797 			el_curtech = (TECHNOLOGY *)var->addr;
2798 			if (el_curtech != sch_tech && el_curtech != art_tech && el_curtech != gen_tech)
2799 				el_curlayouttech = el_curtech;
2800 			us_settechname(NOWINDOWFRAME);
2801 			us_setlambda(NOWINDOWFRAME);
2802 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart) us_setcellsize(w);
2803 			return;
2804 		}
2805 
2806 		/* switch constraint solver if it changed */
2807 		if (key == us_current_constraint_key)
2808 		{
2809 			var = getvalkey(addr, type, VCONSTRAINT, key);
2810 			if (var == NOVARIABLE) return;
2811 			el_curconstraint = (CONSTRAINT *)var->addr;
2812 			return;
2813 		}
2814 
2815 		if (key == us_gridfloatskey || key == us_gridboldspacingkey)
2816 		{
2817 			us_gridfactorschanged = TRUE;
2818 			return;
2819 		}
2820 
2821 		if (key == us_quickkeyskey)
2822 		{
2823 			var = getvalkey(addr, type, VSTRING|VISARRAY, key);
2824 			if (var != NOVARIABLE) us_adjustquickkeys(var, FALSE);
2825 			return;
2826 		}
2827 
2828 		/* see if popup menu was created */
2829 		if (namesamen(makename(key), x_("USER_binding_popup_"), 19) == 0)
2830 		{
2831 			var = getvalkey(addr, type, VSTRING|VISARRAY, key);
2832 			if (var == NOVARIABLE) return;
2833 			len = getlength(var);
2834 
2835 			/* create the popup menu */
2836 			pm = (POPUPMENU *)emalloc(sizeof(POPUPMENU), us_tool->cluster);
2837 			if (pm == 0)
2838 			{
2839 				ttyputnomemory();
2840 				return;
2841 			}
2842 			mi = (POPUPMENUITEM *)emalloc((len-1) * sizeof(POPUPMENUITEM), us_tool->cluster);
2843 			if (mi == 0)
2844 			{
2845 				ttyputnomemory();
2846 				return;
2847 			}
2848 
2849 			/* code cannot be called by multiple procesors: uses globals */
2850 			NOT_REENTRANT;
2851 
2852 			pm->nextpopupmenu = us_firstpopupmenu;
2853 			us_firstpopupmenu = pm;
2854 			(void)allocstring(&pm->name, &makename(key)[19], us_tool->cluster);
2855 			(void)allocstring(&pm->header, ((CHAR **)var->addr)[0], us_tool->cluster);
2856 			pm->list = mi;
2857 			pm->total = len-1;
2858 
2859 			/* fill the menu */
2860 			for(i=1; i<len; i++)
2861 			{
2862 				mi[i-1].response = rb = us_allocusercom();
2863 				rb->active = -1;
2864 				(void)allocstring(&mi[i-1].attribute, x_(""), us_tool->cluster);
2865 				mi[i-1].value = 0;
2866 				us_parsebinding(((CHAR **)var->addr)[i], &commandbinding);
2867 				us_setcommand(commandbinding.command, rb, i-1, commandbinding.nodeglyph,
2868 					commandbinding.arcglyph, commandbinding.menumessage,
2869 						commandbinding.popup, commandbinding.inputpopup);
2870 				us_freebindingparse(&commandbinding);
2871 			}
2872 			return;
2873 		}
2874 		return;
2875 	}
2876 
2877 	/* detect change to SPICE primitive set */
2878 	if (type == VTOOL && key == sim_spice_partskey)
2879 	{
2880 		us_checkspiceparts();
2881 		return;
2882 	}
2883 
2884 	/* handle changes to objects on technologies */
2885 	if (type == VTECHNOLOGY)
2886 	{
2887 		/* changes to technology variables may invalidate caches */
2888 		changedtechnologyvariable(key);
2889 
2890 		/* if layer letters changed, recache the data */
2891 		if (key == us_layer_letters_key)
2892 		{
2893 			us_initlayerletters();
2894 			return;
2895 		}
2896 
2897 		if (key == el_techstate_key)
2898 		{
2899 			var = getvalkey(addr, VTECHNOLOGY, VINTEGER, el_techstate_key);
2900 			if (var != NOVARIABLE)
2901 				(void)asktech((TECHNOLOGY *)addr, x_("set-state"), var->addr);
2902 		}
2903 		return;
2904 	}
2905 
2906 	/* handle changes to objects on NODEPROTOs */
2907 	if (type == VNODEPROTO)
2908 	{
2909 		if (key == el_node_size_default_key)
2910 		{
2911 			/* remember the size of the wire-pin in Schematics */
2912 			np = (NODEPROTO *)addr;
2913 			if (np == sch_wirepinprim)
2914 			{
2915 				defaultnodesize(sch_wirepinprim, &sch_wirepinsizex, &sch_wirepinsizey);
2916 			}
2917 
2918 			/* redraw the node in the component menu */
2919 			if ((us_tool->toolstate&MENUON) == 0) return;
2920 			var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
2921 			if (var == NOVARIABLE) return;
2922 			len = getlength(var);
2923 			for(i=0; i<len; i++)
2924 			{
2925 				pt = ((CHAR **)var->addr)[i];
2926 				us_parsebinding(pt, &commandbinding);
2927 				if (commandbinding.nodeglyph != NONODEPROTO)
2928 				{
2929 					if (us_menupos <= 1)
2930 					{
2931 						y = i / us_menux;
2932 						x = i % us_menux;
2933 					} else
2934 					{
2935 						x = i / us_menuy;
2936 						y = i % us_menuy;
2937 					}
2938 					us_drawmenuentry(x, y, pt);
2939 				}
2940 				us_freebindingparse(&commandbinding);
2941 			}
2942 			return;
2943 		}
2944 		return;
2945 	}
2946 
2947 	/* update far text if displayable variable is added to NODEINST or ARCINST */
2948 	if ((newtype&VDISPLAY) != 0)
2949 	{
2950 		if (type == VNODEINST) us_computenodefartextbit((NODEINST *)addr); else
2951 			if (type == VARCINST) us_computearcfartextbit((ARCINST *)addr);
2952 	}
2953 
2954 	/* handle changes to objects on ARCPROTOs */
2955 	if (type == VARCPROTO)
2956 	{
2957 		if (key == el_arc_width_default_key)
2958 		{
2959 			/* redraw the arc in the component menu */
2960 			if ((us_tool->toolstate&MENUON) == 0) return;
2961 			var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
2962 			if (var == NOVARIABLE) return;
2963 			ap = (ARCPROTO *)addr;
2964 			len = getlength(var);
2965 			for(i=0; i<len; i++)
2966 			{
2967 				pt = ((CHAR **)var->addr)[i];
2968 				us_parsebinding(pt, &commandbinding);
2969 				if (commandbinding.arcglyph != NOARCPROTO)
2970 				{
2971 					if (us_menupos <= 1)
2972 					{
2973 						y = i / us_menux;
2974 						x = i % us_menux;
2975 					} else
2976 					{
2977 						x = i / us_menuy;
2978 						y = i % us_menuy;
2979 					}
2980 					us_drawmenuentry(x, y, pt);
2981 				}
2982 				us_freebindingparse(&commandbinding);
2983 			}
2984 			return;
2985 		}
2986 		return;
2987 	}
2988 }
2989 
us_killvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG oldaddr,INTBIG oldtype,UINTBIG * olddescript)2990 void us_killvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG oldaddr,
2991 	INTBIG oldtype, UINTBIG *olddescript)
2992 {
2993 	REGISTER INTBIG len, i;
2994 	REGISTER CHAR *name;
2995 	REGISTER POPUPMENU *pm, *lastpm;
2996 	HIGHLIGHT high;
2997 	REGISTER WINDOWPART *w;
2998 	REGISTER EDITOR *e;
2999 	Q_UNUSED( olddescript );
3000 
3001 	if ((oldtype&VCREF) != 0)
3002 	{
3003 		name = changedvariablename(type, key, oldtype);
3004 
3005 		/* see if cell name changed */
3006 		if ((type&VTYPE) == VNODEPROTO && namesame(name, x_("protoname")) == 0)
3007 		{
3008 			us_cellwithkilledname = (NODEPROTO *)addr;
3009 			us_killednameoncell = (CHAR *)oldaddr;
3010 			return;
3011 		}
3012 		return;
3013 	}
3014 
3015 	/* see if an option variable changed */
3016 	if (isoptionvariable(addr, type, makename(key)))
3017 		us_optionschanged = TRUE;
3018 
3019 	/* close any text editor windows that are examining the variable */
3020 	if ((oldtype&VTYPE) == VSTRING && (oldtype&VISARRAY) != 0)
3021 	{
3022 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
3023 			if ((w->state&WINDOWTYPE) == TEXTWINDOW)
3024 		{
3025 			e = w->editor;
3026 			if (e == NOEDITOR) continue;
3027 			if (e->editobjvar == NOVARIABLE) continue;
3028 			if (e->editobjvar->addr != oldaddr || e->editobjvar->type != (UINTBIG)oldtype) continue;
3029 			if ((INTBIG)e->editobjaddr != addr || e->editobjtype != type) continue;
3030 			us_delcellmessage(w->curnodeproto);
3031 		}
3032 	}
3033 
3034 	/* handle changes to objects on the user interface */
3035 	if (addr == (INTBIG)us_tool)
3036 	{
3037 		/* show highlight if it changed */
3038 		if (key == us_highlightedkey && (us_state&HIGHLIGHTSET) == 0)
3039 		{
3040 			len = (oldtype&VLENGTH) >> VLENGTHSH;
3041 			for(i=0; i<len; i++)
3042 			{
3043 				if (us_makehighlight(((CHAR **)oldaddr)[i], &high)) continue;
3044 				us_sethighlight(&high, ALLOFF);
3045 			}
3046 			us_setselectioncount();
3047 			us_highlighthaschanged();
3048 			return;
3049 		}
3050 
3051 		/* shadow placement angle if it changed */
3052 		if (key == us_placement_angle_key)
3053 		{
3054 			us_setnodeangle(NOWINDOWFRAME);
3055 			return;
3056 		}
3057 
3058 		/* see if popup menu was deleted */
3059 		if (namesamen(makename(key), x_("USER_binding_popup_"), 19) == 0)
3060 		{
3061 			/* code cannot be called by multiple procesors: uses globals */
3062 			NOT_REENTRANT;
3063 
3064 			name = &makename(key)[19];
3065 			lastpm = NOPOPUPMENU;
3066 			for(pm = us_firstpopupmenu; pm != NOPOPUPMENU; pm = pm->nextpopupmenu)
3067 			{
3068 				if (namesame(name, pm->name) == 0) break;
3069 				lastpm = pm;
3070 			}
3071 			if (pm == NOPOPUPMENU) return;
3072 			if (lastpm == NOPOPUPMENU) us_firstpopupmenu = pm->nextpopupmenu; else
3073 				lastpm->nextpopupmenu = pm->nextpopupmenu;
3074 			for(i=0; i<pm->total; i++)
3075 			{
3076 				efree(pm->list[i].attribute);
3077 				us_freeusercom(pm->list[i].response);
3078 			}
3079 			efree(pm->name);
3080 			efree(pm->header);
3081 			efree((CHAR *)pm->list);
3082 			efree((CHAR *)pm);
3083 			return;
3084 		}
3085 	}
3086 }
3087 
us_modifyvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG vartype,INTBIG aindex,INTBIG oldvalue)3088 void us_modifyvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG vartype,
3089 	INTBIG aindex, INTBIG oldvalue)
3090 {
3091 	REGISTER VARIABLE *var;
3092 	REGISTER INTBIG x, y;
3093 	REGISTER CHAR *str;
3094 	REGISTER USERCOM *rb;
3095 	POPUPMENU *pm;
3096 	COMMANDBINDING commandbinding;
3097 	Q_UNUSED( oldvalue );
3098 
3099 	if ((vartype&VCREF) != 0)
3100 	{
3101 		/* see if PORTPROTO's "textdescript[1]" field changed */
3102 		if ((type&VTYPE) == VPORTPROTO && aindex == 1)
3103 		{
3104 			str = changedvariablename(type, key, vartype);
3105 			if (namesame(str, x_("textdescript")) == 0)
3106 				us_computenodefartextbit(((PORTPROTO *)addr)->subnodeinst);
3107 		}
3108 		return;
3109 	}
3110 
3111 	/* see if an option variable changed */
3112 	if ((vartype&VDONTSAVE) == 0)
3113 	{
3114 		if (isoptionvariable(addr, type, makename(key)))
3115 			us_optionschanged = TRUE;
3116 	}
3117 
3118 	/* handle changes to objects on the user interface */
3119 	if (addr == (INTBIG)us_tool)
3120 	{
3121 		/* set colormap updating if it changed */
3122 		if (key == us_colormap_red_key || key == us_colormap_green_key || key == us_colormap_blue_key)
3123 		{
3124 			if (us_maplow == -1) us_maplow = us_maphigh = aindex; else
3125 			{
3126 				if (aindex < us_maplow) us_maplow = aindex;
3127 				if (aindex > us_maphigh) us_maphigh = aindex;
3128 			}
3129 		}
3130 
3131 		/* set menu binding if it changed */
3132 		if (key == us_binding_menu_key)
3133 		{
3134 			if (us_menuchanged) return;
3135 			if ((us_tool->toolstate&MENUON) == 0) return;
3136 			var = getvalkey(addr, type, VSTRING|VISARRAY, key);
3137 			if (var == NOVARIABLE) return;
3138 			us_parsebinding(((CHAR **)var->addr)[aindex], &commandbinding);
3139 			if (us_menupos <= 1)
3140 			{
3141 				y = aindex / us_menux;
3142 				x = aindex % us_menux;
3143 			} else
3144 			{
3145 				x = aindex / us_menuy;
3146 				y = aindex % us_menuy;
3147 			}
3148 			if (*commandbinding.command == 0) us_drawmenuentry(x, y, x_("")); else
3149 				us_drawmenuentry(x, y, ((CHAR **)var->addr)[aindex]);
3150 			us_freebindingparse(&commandbinding);
3151 			return;
3152 		}
3153 
3154 		/* set popup menu binding if it changed */
3155 		if (namesamen(makename(key), x_("USER_binding_popup_"), 19) == 0)
3156 		{
3157 			var = getvalkey(addr, type, VSTRING|VISARRAY, key);
3158 			if (var == NOVARIABLE) return;
3159 			if (aindex == 0)
3160 			{
3161 				/* special case: set menu header */
3162 				str = &makename(key)[19];
3163 				for(pm = us_firstpopupmenu; pm != NOPOPUPMENU; pm = pm->nextpopupmenu)
3164 					if (namesame(str, pm->name) == 0) break;
3165 				if (pm != NOPOPUPMENU)
3166 					(void)reallocstring(&pm->header, ((CHAR **)var->addr)[0], us_tool->cluster);
3167 				return;
3168 			}
3169 			us_parsebinding(((CHAR **)var->addr)[aindex], &commandbinding);
3170 			if (commandbinding.popup != NOPOPUPMENU)
3171 			{
3172 				rb = commandbinding.popup->list[aindex-1].response;
3173 				us_setcommand(commandbinding.command, rb, aindex-1, commandbinding.nodeglyph,
3174 					commandbinding.arcglyph, commandbinding.menumessage,
3175 						commandbinding.popup, commandbinding.inputpopup);
3176 				nativemenurename(commandbinding.popup, aindex-1);
3177 			}
3178 			us_freebindingparse(&commandbinding);
3179 			return;
3180 		}
3181 	}
3182 }
3183 
us_checkinplaceedits(NODEPROTO * cell)3184 void us_checkinplaceedits(NODEPROTO *cell)
3185 {
3186 	REGISTER WINDOWPART *w;
3187 	REGISTER INTBIG i;
3188 
3189 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
3190 	{
3191 		if ((w->state&INPLACEEDIT) == 0) continue;
3192 		for(i=0; i<w->inplacedepth; i++)
3193 			if (cell == w->inplacestack[i]->parent) break;
3194 		if (i < w->inplacedepth) continue;
3195 
3196 		/* must redraw window "w" */
3197 		w->state |= INPLACEQUEUEREDRAW;
3198 	}
3199 }
3200 
3201 /*
3202  * routine to place the command "str" in the command object "rb".  Also sets
3203  * the node glyph if "nodeglyph" is not NONODEPROTO, the arc glyph if
3204  * "arcglyph" is not NOARCPROTO and the menu message if "menumessage" is nonzero.
3205  * If "popup" is not NOPOPUPMENU, this is a popup (and is input-popup if
3206  * "inputpopup" is true).  For popup menus, "mindex" is the menu entry.
3207  */
us_setcommand(CHAR * str,USERCOM * rb,INTBIG mindex,NODEPROTO * nodeglyph,ARCPROTO * arcglyph,CHAR * menumessage,POPUPMENU * popup,BOOLEAN inputpopup)3208 void us_setcommand(CHAR *str, USERCOM *rb, INTBIG mindex,
3209 	NODEPROTO *nodeglyph, ARCPROTO *arcglyph, CHAR *menumessage,
3210 	POPUPMENU *popup, BOOLEAN inputpopup)
3211 {
3212 	CHAR *a[MAXPARS+1];
3213 	REGISTER INTBIG newcount, j, i;
3214 	COMCOMP *carray[MAXPARS];
3215 	extern COMCOMP us_userp;
3216 	REGISTER void *infstr;
3217 
3218 	/* handle un-binding */
3219 	if (*str == 0)
3220 	{
3221 		if (popup != NOPOPUPMENU)
3222 		{
3223 			if (rb->message != 0) efree(rb->message);
3224 			rb->message = 0;
3225 			if (menumessage != 0)
3226 			{
3227 				(void)allocstring(&rb->message, menumessage, us_tool->cluster);
3228 			}
3229 			if (rb->message == 0)
3230 				(void)reallocstring(&popup->list[mindex].attribute, x_(""), us_tool->cluster); else
3231 					(void)reallocstring(&popup->list[mindex].attribute, rb->message, us_tool->cluster);
3232 			popup->list[mindex].maxlen = -1;
3233 			/* should "popup->list[mindex].value" be freed here? !!! */
3234 		}
3235 		if (rb->active >= 0)
3236 		{
3237 			for(j=0; j<rb->count; j++) efree(rb->word[j]);
3238 			rb->count = 0;
3239 			if (rb->message != 0) efree(rb->message);
3240 			rb->message = 0;
3241 		}
3242 		rb->active = -1;
3243 		return;
3244 	}
3245 
3246 	/* parse this command */
3247 	newcount = us_parsecommand(str, a);
3248 	if (newcount <= 0) return;
3249 	i = parse(a[0], &us_userp, TRUE);
3250 	if (i < 0) return;
3251 
3252 	/* remove former command if it exists */
3253 	if (rb->active >= 0)
3254 	{
3255 		for(j=0; j<rb->count; j++) efree(rb->word[j]);
3256 		if (rb->message != 0) efree(rb->message);
3257 		rb->message = 0;
3258 	}
3259 
3260 	/* set the new command */
3261 	for(j=0; j<newcount-1; j++)
3262 	{
3263 		if (allocstring(&rb->word[j], a[j+1], us_tool->cluster))
3264 		{
3265 			ttyputnomemory();
3266 			rb->active = -1;
3267 			return;
3268 		}
3269 	}
3270 
3271 	/* set all other information */
3272 	if (menumessage == 0) rb->message = 0; else
3273 	{
3274 		if (rb->message != 0) efree(rb->message);
3275 		(void)allocstring(&rb->message, menumessage, us_tool->cluster);
3276 	}
3277 	rb->count = newcount-1;
3278 	rb->active = i;
3279 	rb->menu = us_getpopupmenu(a[0]);
3280 	if (rb->comname != 0) efree(rb->comname);
3281 	(void)allocstring(&rb->comname, a[0], us_tool->cluster);
3282 	rb->nodeglyph = nodeglyph;
3283 	rb->arcglyph = arcglyph;
3284 	if (popup != NOPOPUPMENU)
3285 	{
3286 		/* load popup menu with full command string */
3287 		if (rb->message != 0)
3288 			(void)reallocstring(&popup->list[mindex].attribute, rb->message, us_tool->cluster); else
3289 		{
3290 			infstr = initinfstr();
3291 			addstringtoinfstr(infstr, rb->comname);
3292 			us_appendargs(infstr, rb);
3293 			(void)reallocstring(&popup->list[mindex].attribute, returninfstr(infstr), us_tool->cluster);
3294 		}
3295 		popup->list[mindex].valueparse = NOCOMCOMP;
3296 		if (inputpopup)
3297 		{
3298 			/* determine command completion for input portion */
3299 			i = us_fillcomcomp(rb, carray);
3300 			if (i > rb->count && carray[rb->count] != NOCOMCOMP)
3301 				popup->list[mindex].valueparse = carray[rb->count];
3302 		}
3303 		if (popup->list[mindex].valueparse == NOCOMCOMP)
3304 			popup->list[mindex].maxlen = -1; else popup->list[mindex].maxlen = 20;
3305 	}
3306 }
3307 
3308 /* Technology: Different Options */
3309 static DIALOGITEM us_techdifoptdialogitems[] =
3310 {
3311  /*  1 */ {0, {140,264,164,440}, BUTTON, N_("Use Requested Options")},
3312  /*  2 */ {0, {140,32,164,208}, BUTTON, N_("Leave Current Options")},
3313  /*  3 */ {0, {8,8,24,344}, MESSAGE, N_("This library requests different options for technology:")},
3314  /*  4 */ {0, {8,348,24,472}, MESSAGE, x_("")},
3315  /*  5 */ {0, {32,8,48,132}, MESSAGE, N_("Current options:")},
3316  /*  6 */ {0, {32,136,80,472}, MESSAGE, x_("")},
3317  /*  7 */ {0, {84,8,100,132}, MESSAGE, N_("Requested options:")},
3318  /*  8 */ {0, {84,136,132,472}, MESSAGE, x_("")}
3319 };
3320 static DIALOG us_techdifoptdialog = {{75,75,248,556}, N_("Technology Options Conflict"), 0, 8, us_techdifoptdialogitems, 0, 0};
3321 
3322 /* special items for the "technology options" dialog: */
3323 #define DDFT_USEREQUESTED  1		/* Use requested options (button) */
3324 #define DDFT_LEAVECURRENT  2		/* Leave current options (button) */
3325 #define DDFT_TECHNAME      4		/* Technology name (stat text) */
3326 #define DDFT_CUROPTION     6		/* Current options (stat text) */
3327 #define DDFT_REQOPTION     8		/* Requested options (stat text) */
3328 
us_readlibrary(LIBRARY * lib)3329 void us_readlibrary(LIBRARY *lib)
3330 {
3331 	REGISTER VARIABLE *var;
3332 	REGISTER CHAR *pt, *name, *curstatename, *newstatename;
3333 	CHAR *par[MAXPARS];
3334 	REGISTER INTBIG majversion, minversion, found, i, j, nvers, len,
3335 		curstate, itemHit, col;
3336 	REGISTER BOOLEAN warnofchanges;
3337 	REGISTER TECHNOLOGY *mocmostech, *tech;
3338 	REGISTER POPUPMENU *pm;
3339 	REGISTER POPUPMENUITEM *mi;
3340 	REGISTER NODEPROTO *np;
3341 	REGISTER NODEINST *ni;
3342 	REGISTER ARCINST *ai;
3343 	REGISTER USERCOM *rb;
3344 	COMMANDBINDING commandbinding;
3345 	extern COMCOMP us_yesnop;
3346 	REGISTER void *infstr, *dia;
3347 
3348 	/* create any popup menus found in the library */
3349 	for(i=0; i<us_tool->numvar; i++)
3350 	{
3351 		/* only want permanent user-interface variables (ones just read in) */
3352 		var = &us_tool->firstvar[i];
3353 		if ((var->type&VDONTSAVE) != 0) continue;
3354 
3355 		/* handle popup menus */
3356 		if (namesamen(makename(var->key), x_("USER_binding_popup_"), 19) == 0)
3357 		{
3358 			name = &makename(var->key)[19];
3359 			if (us_getpopupmenu(name) != NOPOPUPMENU) continue;
3360 
3361 			/* create the popup menu */
3362 			len = getlength(var);
3363 			pm = (POPUPMENU *)emalloc(sizeof(POPUPMENU), us_tool->cluster);
3364 			if (pm == 0)
3365 			{
3366 				ttyputnomemory();
3367 				break;
3368 			}
3369 			mi = (POPUPMENUITEM *)emalloc((len-1) * sizeof(POPUPMENUITEM), us_tool->cluster);
3370 			if (mi == 0)
3371 			{
3372 				ttyputnomemory();
3373 				return;
3374 			}
3375 			pm->nextpopupmenu = us_firstpopupmenu;
3376 			us_firstpopupmenu = pm;
3377 			(void)allocstring(&pm->name, name, us_tool->cluster);
3378 			(void)allocstring(&pm->header, ((CHAR **)var->addr)[0], us_tool->cluster);
3379 			pm->list = mi;
3380 			pm->total = len-1;
3381 
3382 			/* initialize the menu */
3383 			for(j=1; j<len; j++)
3384 			{
3385 				mi[j-1].response = rb = us_allocusercom();
3386 				rb->active = -1;
3387 				(void)allocstring(&mi[j-1].attribute, x_(""), us_tool->cluster);
3388 				mi[j-1].value = 0;
3389 			}
3390 			us_scanforkeyequiv(pm);
3391 		}
3392 	}
3393 
3394 	/* fill any popup menus found in the library */
3395 	for(i=0; i<us_tool->numvar; i++)
3396 	{
3397 		/* only want permanent user-interface variables (ones just read in) */
3398 		var = &us_tool->firstvar[i];
3399 		if ((var->type&VDONTSAVE) != 0) continue;
3400 
3401 		/* handle popup menus */
3402 		if (namesamen(makename(var->key), x_("USER_binding_popup_"), 19) == 0)
3403 		{
3404 			var->type |= VDONTSAVE;
3405 			name = &makename(var->key)[19];
3406 			pm = us_getpopupmenu(name);
3407 			mi = pm->list;
3408 			len = getlength(var);
3409 
3410 			/* fill the menu */
3411 			for(j=1; j<len; j++)
3412 			{
3413 				rb = mi[j-1].response;
3414 				us_parsebinding(((CHAR **)var->addr)[j], &commandbinding);
3415 				us_setcommand(commandbinding.command, rb, j-1, commandbinding.nodeglyph,
3416 					commandbinding.arcglyph, commandbinding.menumessage,
3417 						pm, commandbinding.inputpopup);
3418 				us_freebindingparse(&commandbinding);
3419 			}
3420 		}
3421 	}
3422 
3423 	/* recache mirrored variables now that the library may have overridden them */
3424 	for(i=0; us_variablemirror[i].key != 0; i++)
3425 	{
3426 		var = getvalkey((INTBIG)us_tool, VTOOL, -1, *us_variablemirror[i].key);
3427 		if (var != NOVARIABLE)
3428 		{
3429 			*us_variablemirror[i].value = var->addr;
3430 		}
3431 	}
3432 
3433 	var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_alignment_ratio_key);
3434 	if (var != NOVARIABLE) us_alignment_ratio = var->addr;
3435 	var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_alignment_edge_ratio_key);
3436 	if (var != NOVARIABLE) us_edgealignment_ratio = var->addr;
3437 
3438 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_quickkeyskey);
3439 	if (var != NOVARIABLE)
3440 	{
3441 		if ((lib->userbits&HIDDENLIBRARY) == 0) warnofchanges = TRUE; else
3442 			warnofchanges = FALSE;
3443 		us_adjustquickkeys(var, warnofchanges);
3444 	}
3445 
3446 	var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_displayunitskey);
3447 	if (var != NOVARIABLE)
3448 		el_units = (el_units & ~DISPLAYUNITS) | (var->addr & DISPLAYUNITS);
3449 
3450 	/* make sure the electrical units are the same */
3451 	var = getvalkey((INTBIG)lib, VLIBRARY, VINTEGER, us_electricalunitskey);
3452 	if (var != NOVARIABLE && var->addr != us_electricalunits)
3453 	{
3454 		us_adjustelectricalunits(lib, var->addr);
3455 	}
3456 
3457 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_text_editorkey);
3458 	if (var != NOVARIABLE)
3459 	{
3460 		for(i=0; us_editortable[i].editorname != 0; i++)
3461 			if (namesame((CHAR *)var->addr, us_editortable[i].editorname) == 0) break;
3462 		if (us_editortable[i].editorname != 0)
3463 			us_currenteditor = i;
3464 	}
3465 	defaultnodesize(sch_wirepinprim, &sch_wirepinsizex, &sch_wirepinsizey);
3466 
3467 	/* grab new SPICE parts */
3468 	var = getvalkey((INTBIG)sim_tool, VTOOL, VSTRING, sim_spice_partskey);
3469 	if (var != NOVARIABLE) us_checkspiceparts();
3470 
3471 	/* recache technology variables */
3472 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3473 	{
3474 		/* reset technology state ("TECH_state") */
3475 		var = getvalkey((INTBIG)tech, VTECHNOLOGY, VINTEGER, el_techstate_key);
3476 		if (var != NOVARIABLE)
3477 			(void)asktech(tech, x_("set-state"), var->addr);
3478 
3479 		/* check out desired state ("TECH_last_state") */
3480 		var = getvalkey((INTBIG)tech, VTECHNOLOGY, VINTEGER, us_techlaststatekey);
3481 		if (var != NOVARIABLE)
3482 		{
3483 			curstate = asktech(tech, x_("get-state"));
3484 			if (curstate != var->addr)
3485 			{
3486 				/* see if there is anything from this technology in the library */
3487 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3488 				{
3489 					for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3490 					{
3491 						if (ni->proto->primindex == 0) continue;
3492 						if (ni->proto->tech == tech) break;
3493 					}
3494 					if (ni != NONODEINST) break;
3495 					for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3496 						if (ai->proto->tech == tech) break;
3497 					if (ai != NOARCINST) break;
3498 				}
3499 				if (np != NONODEPROTO)
3500 				{
3501 					curstatename = (CHAR *)asktech(tech, x_("describe-state"), curstate);
3502 					newstatename = (CHAR *)asktech(tech, x_("describe-state"), var->addr);
3503 					if (curstatename != 0 && newstatename != 0)
3504 					{
3505 						if ((lib->userbits&HIDDENLIBRARY) != 0) itemHit = DDFT_USEREQUESTED; else
3506 						{
3507 							/* display the technology option conflict dialog box */
3508 							dia = DiaInitDialog(&us_techdifoptdialog);
3509 							if (dia == 0) return;
3510 
3511 							/* load the message */
3512 							DiaSetText(dia, DDFT_TECHNAME, tech->techname);
3513 							DiaSetText(dia, DDFT_CUROPTION, curstatename);
3514 							DiaSetText(dia, DDFT_REQOPTION, newstatename);
3515 
3516 							/* loop until done */
3517 							for(;;)
3518 							{
3519 								itemHit = DiaNextHit(dia);
3520 								if (itemHit == DDFT_USEREQUESTED || itemHit == DDFT_LEAVECURRENT) break;
3521 							}
3522 							DiaDoneDialog(dia);
3523 						}
3524 
3525 						if (itemHit == DDFT_USEREQUESTED)
3526 						{
3527 							(void)asktech(tech, x_("set-state"), var->addr);
3528 							setvalkey((INTBIG)tech, VTECHNOLOGY, el_techstate_key, var->addr, VINTEGER);
3529 							if (el_curtech == tech)
3530 							{
3531 								par[0] = x_("size");
3532 								par[1] = x_("auto");
3533 								us_menu(2, par);
3534 								us_setmenunodearcs();
3535 							}
3536 						}
3537 					}
3538 				}
3539 			}
3540 		}
3541 
3542 		/* see if layer patterns changed */
3543 		for(i=0; i<tech->layercount; i++)
3544 		{
3545 			infstr = initinfstr();
3546 			addstringtoinfstr(infstr, x_("TECH_layer_pattern_"));
3547 			addstringtoinfstr(infstr, layername(tech, i));
3548 			pt = returninfstr(infstr);
3549 			var = getval((INTBIG)el_curtech, VTECHNOLOGY, VINTEGER|VISARRAY, pt);
3550 			if (var == NOVARIABLE) continue;
3551 
3552 			/* adjust for old patterns with smaller amounts of data */
3553 			len = getlength(var);
3554 			if (len < 16)
3555 			{
3556 				INTBIG newpattern[18];
3557 
3558 				for(j=0; j<8; j++)
3559 					newpattern[j] = newpattern[j+8] = ((INTBIG *)var->addr)[j];
3560 				for(j=8; j<len; j++)
3561 					newpattern[j+8] = ((INTBIG *)var->addr)[j];
3562 				nextchangequiet();
3563 				(void)setval((INTBIG)el_curtech, VTECHNOLOGY, pt,
3564 					(INTBIG)newpattern, VINTEGER|VISARRAY|(18<<VLENGTHSH));
3565 				var = getval((INTBIG)el_curtech, VTECHNOLOGY, VINTEGER|VISARRAY, pt);
3566 			}
3567 
3568 			(el_curtech->layers[i])->colstyle = (INTSML)(((INTBIG *)var->addr)[16]);
3569 			for(j=0; j<16; j++)
3570 				(el_curtech->layers[i])->raster[j] = (INTSML)(((INTBIG *)var->addr)[j]);
3571 			if (getlength(var) > 17)
3572 			{
3573 				col = ((INTBIG *)var->addr)[17];
3574 				(el_curtech->layers[i])->col = col;
3575 				if (col == COLORT1 || col == COLORT2 || col == COLORT3 ||
3576 					col == COLORT4 || col == COLORT5)
3577 						(el_curtech->layers[i])->bits = col; else
3578 							(el_curtech->layers[i])->bits = LAYERO;
3579 			}
3580 		}
3581 	}
3582 
3583 	/* redisplay the explorer window */
3584 	us_cellstructurechanged = TRUE;
3585 
3586 	/* set cell's technology and center attributes */
3587 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3588 	{
3589 		np->tech = whattech(np);
3590 		us_setessentialbounds(np);
3591 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3592 			if (ni->proto == gen_cellcenterprim)
3593 				us_setnodeprotocenter(ni->lowx, ni->lowy, np);
3594 	}
3595 
3596 	/* do font conversion if any is specified */
3597 	us_checkfontassociations(lib);
3598 
3599 	/*
3600 	 * see if the library is old enough to require MOCMOS conversion
3601 	 * or serpentine port conversion
3602 	 */
3603 	var = getval((INTBIG)lib, VLIBRARY, VSTRING, x_("LIB_former_version"));
3604 	if (var == NOVARIABLE) return;
3605 
3606 	/* parse the former Electric version number */
3607 	pt = (CHAR *)var->addr;
3608 	majversion = eatoi(pt);
3609 	while (*pt != 0 && *pt != '.') pt++;
3610 	if (*pt == 0) minversion = 0; else minversion = eatoi(pt+1);
3611 	nvers = majversion*100 + minversion;
3612 	if (nvers > 335) return;
3613 
3614 	/* versions 3.35 or earlier may require MOCMOS conversion */
3615 	mocmostech = gettechnology(x_("mocmos"));
3616 	if (mocmostech == NOTECHNOLOGY) return;
3617 
3618 	/* see if there is any MOCMOS data in the library */
3619 	found = 0;
3620 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3621 	{
3622 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3623 			if (ni->proto->primindex != 0 && ni->proto->tech == mocmostech)
3624 		{
3625 			found++;
3626 			break;
3627 		}
3628 		for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3629 			if (ai->proto->tech == mocmostech)
3630 		{
3631 			found++;
3632 			break;
3633 		}
3634 		if (found != 0) break;
3635 	}
3636 	if (found == 0) return;
3637 
3638 	/* there are MOCMOS elements in an old library: offer conversion */
3639 	ttyputmsg(_("This library contains old format MOSIS CMOS (mocmos) cells"));
3640 	i = ttygetparam(_("Would you like to convert them? [y] "), &us_yesnop, MAXPARS, par);
3641 	if (i > 0 && namesamen(par[0], x_("no"), estrlen(par[0])) == 0)
3642 	{
3643 		ttyputmsg(_("No conversion done.  To do this later, use:"));
3644 		ttyputmsg(x_("    -technology tell mocmos convert-old-format-library"));
3645 		return;
3646 	}
3647 
3648 	/* do the conversion */
3649 	tech_convertmocmoslib(lib);
3650 }
3651 
3652 /*
3653  * Routine to examine the font associations stored in the library and correct if
3654  * necessary.
3655  */
us_checkfontassociations(LIBRARY * lib)3656 void us_checkfontassociations(LIBRARY *lib)
3657 {
3658 	REGISTER NODEPROTO *np;
3659 	REGISTER NODEINST *ni;
3660 	REGISTER ARCINST *ai;
3661 	REGISTER PORTARCINST *pi;
3662 	REGISTER PORTEXPINST *pe;
3663 	REGISTER PORTPROTO *pp;
3664 	REGISTER INTBIG *fontmatch, i, len, index, j, maxindex;
3665 	CHAR *facename, *pt;
3666 	REGISTER VARIABLE *var;
3667 
3668 	var = getval((INTBIG)lib, VLIBRARY, VSTRING|VISARRAY, x_("LIB_font_associations"));
3669 	if (var == NOVARIABLE) return;
3670 	len = getlength(var);
3671 	maxindex = 0;
3672 	for(i=0; i<len; i++)
3673 	{
3674 		pt = ((CHAR **)var->addr)[i];
3675 		index = eatoi(pt);
3676 		if (index > maxindex) maxindex = index;
3677 	}
3678 	if (maxindex <= 0) return;
3679 	maxindex++;
3680 	fontmatch = (INTBIG *)emalloc(maxindex * SIZEOFINTBIG, us_tool->cluster);
3681 	if (fontmatch == 0) return;
3682 	for(i=0; i<maxindex; i++) fontmatch[i] = 0;
3683 	for(i=0; i<len; i++)
3684 	{
3685 		pt = ((CHAR **)var->addr)[i];
3686 		index = eatoi(pt);
3687 		while (*pt != 0 && *pt != '/') pt++;
3688 		if (*pt == 0) continue;
3689 		facename = &pt[1];
3690 
3691 		/* see if there is face "facename" and associate it with font "index" */
3692 		j = screenfindface(facename);
3693 		if (j >= 0) fontmatch[index] = j; else
3694 		{
3695 			ttyputerr(x_("Font %s not found, using default"), facename);
3696 		}
3697 	}
3698 
3699 	/* now apply the transformation to all face indices */
3700 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3701 	{
3702 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3703 		{
3704 			us_setfontassociationvar(ni->numvar, ni->firstvar, fontmatch);
3705 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
3706 				us_setfontassociationvar(pi->numvar, pi->firstvar, fontmatch);
3707 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
3708 				us_setfontassociationvar(pe->numvar, pe->firstvar, fontmatch);
3709 			if (ni->proto->primindex == 0)
3710 				us_setfontassociationdescript(ni->textdescript, fontmatch);
3711 		}
3712 		for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
3713 			us_setfontassociationvar(ai->numvar, ai->firstvar, fontmatch);
3714 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
3715 		{
3716 			us_setfontassociationvar(pp->numvar, pp->firstvar, fontmatch);
3717 			us_setfontassociationdescript(pp->textdescript, fontmatch);
3718 		}
3719 		us_setfontassociationvar(np->numvar, np->firstvar, fontmatch);
3720 	}
3721 	us_setfontassociationvar(lib->numvar, lib->firstvar, fontmatch);
3722 
3723 	(void)delval((INTBIG)lib, VLIBRARY, x_("LIB_font_associations"));
3724 	efree((CHAR *)fontmatch);
3725 }
3726 
3727 /*
3728  * Helper routine for "us_checkfontassociations".
3729  */
us_setfontassociationvar(INTSML numvar,VARIABLE * firstvar,INTBIG * fontmatch)3730 void us_setfontassociationvar(INTSML numvar, VARIABLE *firstvar, INTBIG *fontmatch)
3731 {
3732 	REGISTER INTBIG i;
3733 	REGISTER VARIABLE *var;
3734 
3735 	for(i=0; i<numvar; i++)
3736 	{
3737 		var = &firstvar[i];
3738 		us_setfontassociationdescript(var->textdescript, fontmatch);
3739 	}
3740 }
3741 
3742 /*
3743  * Helper routine for "us_checkfontassociations".
3744  */
us_setfontassociationdescript(UINTBIG * descript,INTBIG * fontmatch)3745 void us_setfontassociationdescript(UINTBIG *descript, INTBIG *fontmatch)
3746 {
3747 	REGISTER INTBIG face;
3748 
3749 	face = TDGETFACE(descript);
3750 	if (face != 0) TDSETFACE(descript, fontmatch[face]);
3751 }
3752 
us_eraselibrary(LIBRARY * lib)3753 void us_eraselibrary(LIBRARY *lib)
3754 {
3755 	REGISTER NODEPROTO *np;
3756 
3757 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3758 		us_removeubchange(np);
3759 	us_unqueueredraw(lib);
3760 }
3761 
us_writelibrary(LIBRARY * lib,BOOLEAN pass2)3762 void us_writelibrary(LIBRARY *lib, BOOLEAN pass2)
3763 {
3764 	REGISTER INTBIG state;
3765 	REGISTER TECHNOLOGY *tech;
3766 	Q_UNUSED( pass2 );
3767 
3768 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3769 	{
3770 		if (asktech(tech, x_("has-state")) == 0) continue;
3771 		state = asktech(tech, x_("get-state"));
3772 		nextchangequiet();
3773 		setvalkey((INTBIG)tech, VTECHNOLOGY, us_techlaststatekey, state, VINTEGER);
3774 	}
3775 
3776 	/* save electrical units on the library */
3777 	nextchangequiet();
3778 	setvalkey((INTBIG)lib, VLIBRARY, us_electricalunitskey, us_electricalunits, VINTEGER);
3779 }
3780 
3781 /*
3782  * handle options. Returns true upon error
3783  */
us_options(INTBIG * argc,CHAR1 * argv[])3784 BOOLEAN us_options(INTBIG *argc, CHAR1 *argv[])
3785 {
3786 	REGISTER CHAR *retur, *thisargv;
3787 
3788 	us_ignore_cadrc = FALSE;
3789 	us_logging = TRUE;
3790 
3791 	while (*argc > 1 && argv[1][0] == '-')
3792 	{
3793 		thisargv = string2byte(argv[1]);
3794 		switch (thisargv[1])
3795 		{
3796 			case '-':			/* long options */
3797 				if (estrcmp(&thisargv[2], x_("help")) == 0)
3798 				{
3799 					error(_("Usage: electric [-c] [-geom WxH+X+Y] [-i MACROFILE] [-m] [-n] [-t TECHNOLOGY] [LIBRARY]"));
3800 				}
3801 				if (estrcmp(&thisargv[2], x_("version")) == 0)
3802 				{
3803 					error(_("Electric version %s"), el_version);
3804 				}
3805 				break;
3806 
3807 			case 'c':			/* ignore cadrc file */
3808 				us_ignore_cadrc = TRUE;
3809 				break;
3810 
3811 			case 'g':			/* X11 Geometry spec SRP 2-19-91 */
3812 				(*argc)--; argv++;	/* bump past the geometry string */
3813 				break;
3814 
3815 			case 'i':			/* initial macro file to load after cadrc */
3816 				allocstring(&us_firstmacrofile, string2byte(argv[2]), us_tool->cluster);
3817 				(*argc)--;   argv++;
3818 				break;
3819 
3820 			case 'm':			/* search for multiple monitors, used in graphXXX.c */
3821 			case 'M':
3822 				break;
3823 
3824 			case 'n':			/* no session recording */
3825 				us_logging = FALSE;
3826 				break;
3827 
3828 			case 'q':			/* qt drawing, used in graphqt.cpp */
3829 				break;
3830 
3831 			case 't':
3832 				if (thisargv[2] != 0) retur = &thisargv[2]; else
3833 				{
3834 					retur = string2byte(argv[2]);
3835 					(*argc)--;   argv++;
3836 				}
3837 				el_curtech = gettechnology(retur);
3838 				if (el_curtech == NOTECHNOLOGY) error(_("Unknown technology: '%s'"), retur);
3839 				if (el_curtech != sch_tech && el_curtech != art_tech && el_curtech != gen_tech)
3840 					el_curlayouttech = el_curtech;
3841 				break;
3842 
3843 #ifdef	sun
3844 			case 'W':			/* SUN window switches must be ignored */
3845 				switch (thisargv[2])
3846 				{
3847 					case 'g':	/* default color */
3848 					case 'H':	/* help */
3849 					case 'i':	/* iconic */
3850 					case 'n':	/* no label */
3851 						break;
3852 					case 'I':	/* icon image */
3853 					case 'l':	/* label */
3854 					case 'L':	/* icon label */
3855 					case 't':	/* font */
3856 					case 'T':	/* icon font */
3857 					case 'w':	/* width */
3858 						(*argc)--;   argv++;   break;
3859 					case 'p':	/* position */
3860 					case 'P':	/* closed position */
3861 					case 's':	/* size */
3862 						(*argc) -= 2;   argv += 2;   break;
3863 					case 'b':	/* background color */
3864 					case 'f':	/* foreground color */
3865 						(*argc) -= 3;   argv += 3;   break;
3866 				}
3867 				break;
3868 #endif
3869 
3870 			default:
3871 				error(_("Unrecognized switch: %s"), thisargv);
3872 		}
3873 		(*argc)--;
3874 		argv++;
3875 	}
3876 
3877 	/* remember the initial library if specified */
3878 	if (*argc == 2)
3879 	{
3880 		(*argc)--;
3881 		allocstring(&us_firstlibrary, string2byte(argv[1]), us_tool->cluster);
3882 	}
3883 
3884 	/* check the arguments */
3885 	if (*argc > 1)
3886 		error(_("Usage: electric [-o] [-n] [-c] [-f] [-geom WxH+X+Y] [-t TECHNOLOGY] [LIBRARY]"));
3887 	return(FALSE);
3888 }
3889 
us_findcadrc(void)3890 void us_findcadrc(void)
3891 {
3892 	CHAR *suf, *hd;
3893 	REGISTER void *infstr;
3894 
3895 	/* try "cadrc" in current directory */
3896 	if (!us_docadrc(CADRCFILENAME)) return;
3897 
3898 	/* if there is a "home" directory, try it there */
3899 	hd = hashomedir();
3900 	if (hd != 0)
3901 	{
3902 		infstr = initinfstr();
3903 		addstringtoinfstr(infstr, hd);
3904 		addstringtoinfstr(infstr, CADRCFILENAME);
3905 		suf = returninfstr(infstr);
3906 		if (!us_docadrc(suf)) return;
3907 	}
3908 
3909 	/* not found there: try library directory */
3910 	infstr = initinfstr();
3911 	addstringtoinfstr(infstr, el_libdir);
3912 	addstringtoinfstr(infstr, CADRCFILENAME);
3913 	suf = returninfstr(infstr);
3914 	if (!us_docadrc(suf)) return;
3915 
3916 	ttyputerr(_("Cannot find '%s' startup file: installation may be incorrect"),
3917 		CADRCFILENAME);
3918 }
3919 
3920 /*
3921  * get the commands in the system's or user's "cadrc" file: "name".
3922  * Returns true if the file cannot be found.
3923  */
us_docadrc(CHAR * name)3924 BOOLEAN us_docadrc(CHAR *name)
3925 {
3926 	FILE *in;
3927 	CHAR *filename;
3928 
3929 	/* look for startup file */
3930 	in = xopen(name, us_filetypecadrc, x_(""), &filename);
3931 	if (in == NULL) return(TRUE);
3932 
3933 	/* create a new macro package */
3934 	us_curmacropack = us_newmacropack(x_("CADRC"));
3935 
3936 	/* execute commands beginning with "electric" in this file */
3937 	us_docommands(in, FALSE, x_("electric"));
3938 	xclose(in);
3939 
3940 	/* now there is no macro package */
3941 	us_curmacropack = NOMACROPACK;
3942 	return(FALSE);
3943 }
3944 
us_wanttoread(CHAR * name)3945 void us_wanttoread(CHAR *name)
3946 {
3947 	estrcpy(us_desiredlibrary, name);
3948 }
3949