1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrparse.c
6  * User interface tool: command parsing and execution
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 "usr.h"
34 #include "usrdiacom.h"
35 #include "edialogs.h"
36 
37 #define MAXLINE 400		/* maximum length of command file input lines */
38 
39 /* working memory for "us_parsecommand()" */
40 static CHAR *us_parseownbuild[MAXPARS];
41 static INTBIG us_parsemaxownbuild = -1;
42 
43 /* working memory for "us_evaluatevariable()" */
44 static INTBIG *us_evaluatevarlist;
45 static INTBIG  us_evaluatevarlimit = 0;
46 
47 static DIALOGHOOK *us_firstdialoghook = NODIALOGHOOK;
48 
49 /* global variables for parsing */
50        KEYWORD *us_pathiskey;				/* the current keyword list */
51 
52 /* local variables for parsing */
53 static INTBIG   us_pacurchar;				/* current character on current line */
54 static CHAR    *us_pattyline = 0;			/* current line image */
55 static CHAR    *us_paextra = 0;				/* extra chars that that can be appended as command completion */
56 static INTBIG   us_patruelength;			/* size of above two buffers */
57 static INTBIG   us_paparamcount;			/* number of parameters read in */
58 static INTBIG   us_paparamtotal;			/* total number of expected parameters with root parameter and null parameter */
59 static COMCOMP *us_paparamtype[MAXKEYWORD];		/* expected type of each parameter */
60 static CHAR    *us_paparamstart[MAXKEYWORD];		/* character position of each parameter */
61 static INTBIG   us_paparamadded[MAXKEYWORD];		/* number of parameters added here */
62 static BOOLEAN	us_painquote;				/* unclosed string at end of currnt line */
63 static COMCOMP  us_panullcomcomp = {NOKEYWORD, NOTOPLIST, NONEXTLIST, NOPARAMS,
64 				    0, x_(""), M_("too many parameters"), 0};
65 static INTBIG   us_pathisind;				/* pointer into the current keyword list */
66 static USERCOM *us_usercomstack = NOUSERCOM;    /* stack of temporary USERCOM's */
67 
68 /* prototypes for local routines */
69 static BOOLEAN  us_addusercom(USERCOM*, CHAR*);
70 static USERCOM *us_fleshcommand(USERCOM*);
71 static void     us_dopopupmenu(POPUPMENU*);
72 static void     us_domacro(CHAR*, INTBIG, CHAR*[]);
73 static BOOLEAN  us_expandvarlist(INTBIG **varlist, INTBIG *varlimit);
74 static BOOLEAN  us_pahandlechar(void*, INTBIG);
75 static void     us_pabackup(INTBIG to_curchar);
76 static void     us_expandttybuffers(INTBIG);
77 
78 /*
79  * Routine to free all memory associated with this module.
80  */
us_freeparsememory(void)81 void us_freeparsememory(void)
82 {
83 	REGISTER USERCOM *uc;
84 	REGISTER INTBIG i;
85 	REGISTER MACROPACK *p;
86 	REGISTER DIALOGHOOK *dh;
87 
88 	if (us_lastcom != NOUSERCOM) us_freeusercom(us_lastcom);
89 	us_lastcom = NOUSERCOM;
90 	while (us_usercomstack != NOUSERCOM)
91 	{
92 		uc = us_usercomstack;
93 		us_usercomstack = us_usercomstack->nextcom;
94 		us_freeusercom(uc);
95 	}
96 
97 	while (us_usercomfree != NOUSERCOM)
98 	{
99 		uc = us_usercomfree;
100 		us_usercomfree = us_usercomfree->nextcom;
101 		efree((CHAR *)uc);
102 	}
103 
104 	for(i=0; i<=us_parsemaxownbuild; i++)
105 		efree((CHAR *)us_parseownbuild[i]);
106 
107 	/* free macro packages */
108 	while (us_macropacktop != NOMACROPACK)
109 	{
110 		p = us_macropacktop;
111 		us_macropacktop = us_macropacktop->nextmacropack;
112 		efree((CHAR *)p->packname);
113 		efree((CHAR *)p);
114 	}
115 
116 	if (us_evaluatevarlimit > 0) efree((CHAR *)us_evaluatevarlist);
117 
118 	/* free hooks to dialogs in other tools */
119 	while (us_firstdialoghook != NODIALOGHOOK)
120 	{
121 		dh = us_firstdialoghook;
122 		us_firstdialoghook = dh->nextdialoghook;
123 		if (dh->terminputkeyword != 0) efree((CHAR *)dh->terminputkeyword);
124 		efree((CHAR *)dh);
125 	}
126 	if (us_paextra != 0) efree(us_paextra);
127 	if (us_pattyline != 0) efree(us_pattyline);
128 }
129 
130 /*
131  * routine to allocate a new user command from the pool (if any) or memory
132  */
us_allocusercom(void)133 USERCOM *us_allocusercom(void)
134 {
135 	REGISTER USERCOM *uc;
136 
137 	if (us_usercomfree == NOUSERCOM)
138 	{
139 		uc = (USERCOM *)emalloc((sizeof (USERCOM)), us_tool->cluster);
140 		if (uc == 0) return(NOUSERCOM);
141 	} else
142 	{
143 		/* take usercom from free list */
144 		uc = us_usercomfree;
145 		us_usercomfree = (USERCOM *)uc->nextcom;
146 	}
147 	uc->active = -1;
148 	uc->comname = 0;
149 	uc->menu = NOPOPUPMENU;
150 	uc->message = 0;
151 	uc->nodeglyph = NONODEPROTO;
152 	uc->arcglyph = NOARCPROTO;
153 	uc->count = 0;
154 	uc->nextcom = NOUSERCOM;
155 	return(uc);
156 }
157 
158 /*
159  * routine to return user command "uc" to the pool of free commands
160  */
us_freeusercom(USERCOM * uc)161 void us_freeusercom(USERCOM *uc)
162 {
163 	REGISTER INTBIG i;
164 
165 	uc->nextcom = us_usercomfree;
166 	for(i=0; i<uc->count; i++) efree(uc->word[i]);
167 	if (uc->comname != 0) efree(uc->comname);
168 	if (uc->message != 0) efree(uc->message);
169 	us_usercomfree = uc;
170 }
171 
172 /*
173  * routine to establish a new macro package with name "name"
174  */
us_newmacropack(CHAR * name)175 MACROPACK *us_newmacropack(CHAR *name)
176 {
177 	REGISTER MACROPACK *p;
178 
179 	p = (MACROPACK *)emalloc((sizeof (MACROPACK)), us_tool->cluster);
180 	if (p == 0) return(NOMACROPACK);
181 	if (allocstring(&p->packname, name, us_tool->cluster)) return(NOMACROPACK);
182 	p->nextmacropack = us_macropacktop;
183 	us_macropacktop = p;
184 	return(p);
185 }
186 
187 /*
188  * routine to add user command "uc" to macro "mac".  Returns true upon error
189  */
us_addusercom(USERCOM * uc,CHAR * mac)190 BOOLEAN us_addusercom(USERCOM *uc, CHAR *mac)
191 {
192 	REGISTER INTBIG i, parnumber, parsed, len, count, total, j, tot, hasspace;
193 	REGISTER CHAR *pt, **manystrings;
194 	COMCOMP *comarray[MAXPARS];
195 	CHAR *build[MAXPARS], line[30];
196 	REGISTER VARIABLE *var;
197 	extern COMCOMP us_macparamp;
198 	REGISTER void *infstr, *subinfstr;
199 
200 	var = us_getmacro(mac);
201 	if (var == NOVARIABLE) return(TRUE);
202 	len = getlength(var);
203 
204 	/* make room for one more command */
205 	manystrings = (CHAR **)emalloc(((len+1) * (sizeof (CHAR *))), el_tempcluster);
206 	if (manystrings == 0) return(TRUE);
207 
208 	/* load the existing commands */
209 	for(i=0; i<len; i++)
210 		(void)allocstring(&manystrings[i], ((CHAR **)var->addr)[i], el_tempcluster);
211 
212 	/* build the new command */
213 	parsed = 0;
214 	tot = 0;
215 	infstr = initinfstr();
216 	addstringtoinfstr(infstr, uc->comname);
217 	addtoinfstr(infstr, ' ');
218 	for(i=0; i<uc->count; i++)
219 	{
220 		/* look for parameter substitution */
221 		hasspace = 0;
222 		for(pt = uc->word[i]; *pt != 0; pt++)
223 		{
224 			if (*pt == ' ' || *pt == '\t') hasspace++;
225 			if (*pt != '%') continue;
226 			if (!isdigit(pt[1])) continue;
227 
228 			/* formal parameter found: determine command completion for it */
229 			parnumber = pt[1] - '0';
230 			if (parsed == 0)
231 			{
232 				tot = us_fillcomcomp(uc, comarray);
233 				parsed++;
234 			}
235 			count = us_parsecommand(manystrings[2], build);
236 			total = maxi(count, parnumber);
237 			subinfstr = initinfstr();
238 			for(j=0; j<total; j++)
239 			{
240 				if (j == parnumber-1 && tot > i && comarray[i] != NOCOMCOMP)
241 				{
242 					(void)esnprintf(line, 30, x_("0%lo"), (UINTBIG)comarray[i]);
243 					addstringtoinfstr(subinfstr, line);
244 				} else if (j < count) addstringtoinfstr(subinfstr, build[j]); else
245 				{
246 					(void)esnprintf(line, 30, x_("0%lo"), (UINTBIG)&us_macparamp);
247 					addstringtoinfstr(subinfstr, line);
248 				}
249 				addtoinfstr(subinfstr, ' ');
250 			}
251 			(void)reallocstring(&manystrings[2], returninfstr(subinfstr), el_tempcluster);
252 		}
253 
254 		if (hasspace == 0) addstringtoinfstr(infstr, uc->word[i]); else
255 		{
256 			/* must quote this parameter: it has spaces */
257 			addtoinfstr(infstr, '"');
258 			for(pt = uc->word[i]; *pt != 0; pt++)
259 			{
260 				if (*pt == '"') addtoinfstr(infstr, '"');
261 				addtoinfstr(infstr, *pt);
262 			}
263 			addtoinfstr(infstr, '"');
264 		}
265 		addtoinfstr(infstr, ' ');
266 	}
267 
268 	manystrings[len] = returninfstr(infstr);
269 	(void)setvalkey((INTBIG)us_tool, VTOOL, var->key, (INTBIG)manystrings,
270 		VSTRING|VISARRAY|((len+1)<<VLENGTHSH)|VDONTSAVE);
271 	for(i=0; i<len; i++) efree(manystrings[i]);
272 	efree((CHAR *)manystrings);
273 	return(FALSE);
274 }
275 
276 /*
277  * routine to examine the command in "uc" and fill the command completion array
278  * "comarray" with appropriate entries for parsing the string.  Returns the
279  * number of valid entries in the array.
280  */
us_fillcomcomp(USERCOM * uc,COMCOMP * comarray[])281 INTBIG us_fillcomcomp(USERCOM *uc, COMCOMP *comarray[])
282 {
283 	REGISTER INTBIG j, k, com, pos, curtotal, count;
284 	REGISTER CHAR *pt;
285 	CHAR *build[MAXPARS];
286 	COMCOMP *nextparams[MAXPARS+5];
287 	REGISTER VARIABLE *var;
288 
289 	comarray[0] = NOCOMCOMP;
290 	com = uc->active;
291 
292 	/* if the command is not valid, exit now */
293 	if (com < 0) return(0);
294 
295 	/* handle normal commands */
296 	if (com < us_longcount)
297 	{
298 		/* initialize the command completion array with the default parameters */
299 		for(curtotal=0; curtotal<us_lcommand[com].params; curtotal++)
300 			comarray[curtotal] = us_lcommand[com].par[curtotal];
301 	} else
302 	{
303 		/* ignore popup menus */
304 		if (uc->menu != NOPOPUPMENU) return(0);
305 
306 		/* handle macros */
307 		var = us_getmacro(uc->comname);
308 		if (var == NOVARIABLE) return(0);
309 		pt = ((CHAR **)var->addr)[2];
310 		count = us_parsecommand(pt, build);
311 		for(curtotal=0; curtotal<count; curtotal++)
312 			comarray[curtotal] = (COMCOMP *)myatoi(build[curtotal]);
313 	}
314 	comarray[curtotal] = NOCOMCOMP;
315 
316 	/* now run through the parameters, inserting whatever is appropriate */
317 	for(pos=0; comarray[pos] != NOCOMCOMP; pos++)
318 	{
319 		if (pos >= uc->count) break;
320 
321 		/* load the necessary global and get the next parameters */
322 		us_pathiskey = comarray[pos]->ifmatch;
323 		k = (*comarray[pos]->params)(uc->word[pos], nextparams, ' ');
324 
325 		/* clip to the number of allowable parameters */
326 		if (k+curtotal >= MAXPARS-1) k = MAXPARS-2-curtotal;
327 
328 		/* spread open the list */
329 		for(j = MAXPARS-k-1; j >= curtotal; j--) comarray[j+k] = comarray[j];
330 
331 		/* fill in the parameter types */
332 		for(j = 0; j < k; j++) comarray[curtotal+j] = nextparams[j];
333 		curtotal += k;
334 	}
335 	return(curtotal);
336 }
337 
338 /*
339  * routine to execute user command "item".  The command is echoed if "print"
340  * is true.  If "macro" is true, the command is saved in the
341  * macro.  If "fromuser" is true, the command was issued from the
342  * terminal and is saved in the 1-command stack "us_lastcom"
343  * "item" is saved in "us_usercomstack" and is properly deleted on shutdown.
344  */
us_executesafe(USERCOM * item,BOOLEAN print,BOOLEAN macro,BOOLEAN fromuser)345 void us_executesafe(USERCOM *item, BOOLEAN print, BOOLEAN macro, BOOLEAN fromuser)
346 {
347 	item->nextcom = us_usercomstack;
348 	us_usercomstack = item;
349 	us_execute(item, print, macro, fromuser);
350 	if (us_usercomstack == item)
351 		us_usercomstack = item->nextcom;
352 	else
353 		us_usercomstack = NOUSERCOM;
354 }
355 
356 /*
357  * routine to execute user command "item".  The command is echoed if "print"
358  * is true.  If "macro" is true, the command is saved in the
359  * macro.  If "fromuser" is true, the command was issued from the
360  * terminal and is saved in the 1-command stack "us_lastcom"
361  */
us_execute(USERCOM * item,BOOLEAN print,BOOLEAN macro,BOOLEAN fromuser)362 void us_execute(USERCOM *item, BOOLEAN print, BOOLEAN macro, BOOLEAN fromuser)
363 {
364 	REGISTER INTBIG i, j, runit, act, ismacend, count, wasmacro;
365 	REGISTER USERCOM *uc, *ucnew;
366 	CHAR *userpars[MAXPARS];
367 	REGISTER VARIABLE *var, *varmacro;
368 	REGISTER void *infstr;
369 
370 	/* for segmentation fault correction */
371 	us_state &= ~COMMANDFAILED;
372 
373 	/* stop if interrupted */
374 	if (stopping(STOPREASONEXECUTE)) return;
375 
376 	/* see if the status display should be cleared */
377 	if ((us_state&DIDINPUT) != 0)
378 	{
379 		ttynewcommand();
380 		us_state &= ~DIDINPUT;
381 	}
382 
383 	/* see if the command is valid */
384 	act = item->active;
385 	if (act < 0)
386 	{
387 		us_unknowncommand();
388 		return;
389 	}
390 
391 	/* copy the command */
392 	uc = us_allocusercom();
393 	if (uc != NOUSERCOM)
394 	{
395 		uc->active = act;
396 		(void)allocstring(&uc->comname, item->comname, us_tool->cluster);
397 		uc->menu = item->menu;
398 		uc->count = item->count;
399 		for(j=0; j<item->count; j++)
400 			if (allocstring(&uc->word[j], item->word[j], us_tool->cluster))
401 		{
402 			uc = NOUSERCOM;
403 			break;
404 		}
405 		if (uc != NOUSERCOM)
406 		{
407 			uc->nextcom = us_usercomstack;
408 			us_usercomstack = uc;
409 		}
410 	}
411 	if (uc == NOUSERCOM)
412 	{
413 		/*
414 		 * when there is no memory, things are basically wedged.  This
415 		 * little hack lets the command be executed but may cause all
416 		 * kinds of hell in other places.
417 		 */
418 		ttyputnomemory();
419 		us_usercomstack = NOUSERCOM;
420 		uc = item;
421 	}
422 
423 	/* if this is a macro definition, see if the command is to be executed */
424 	runit = 1;
425 	ismacend = 0;
426 	wasmacro = 0;
427 	if (macro)
428 	{
429 		var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrobuildingkey);
430 		if (var != NOVARIABLE)
431 		{
432 			/* see if macro was begun with the "no-execute" option */
433 			varmacro = us_getmacro((CHAR *)var->addr);
434 			if (varmacro != NOVARIABLE)
435 			{
436 				wasmacro++;
437 				count = us_parsecommand(((CHAR **)varmacro->addr)[0], userpars);
438 				for(i=0; i<count; i++)
439 					if (namesame(userpars[i], x_("noexecute")) == 0)
440 				{
441 					runit = 0;
442 					break;
443 				}
444 			}
445 
446 			/* see if a "macdone" was encountered */
447 			if ((us_state&MACROTERMINATED) != 0) runit = 0;
448 
449 			/* always execute the "macend" command */
450 			if (act < us_longcount &&
451 				estrcmp(us_lcommand[act].name, x_("macend")) == 0) ismacend = runit = 1;
452 		}
453 	}
454 
455 	ucnew = NOUSERCOM;
456 	if (runit)
457 	{
458 		/* expand "%" macros, "$" variables, and "^" quotes in command line */
459 		ucnew = us_fleshcommand(uc);
460 		if (ucnew != uc)
461 		{
462 			ucnew->nextcom = us_usercomstack;
463 			us_usercomstack = ucnew;
464 		}
465 
466 		/* print the command if requested */
467 		if (print)
468 		{
469 			infstr = initinfstr();
470 			addtoinfstr(infstr, '-');
471 			addstringtoinfstr(infstr, ucnew->comname);
472 			us_appendargs(infstr, ucnew);
473 			ttyputmsg(x_("%s"), returninfstr(infstr));
474 		}
475 
476 		/* handle normal commands */
477 		if (act < us_longcount)
478 		{
479 			/* make copy of parameter pointers in case user changes it */
480 			for(i=0; i<ucnew->count; i++) userpars[i] = ucnew->word[i];
481 
482 			/* execute the command */
483 			(*us_lcommand[act].routine)(ucnew->count, userpars);
484 		} else
485 		{
486 			/* if command is a popup menu, execute it differently */
487 			if (ucnew->menu != NOPOPUPMENU) us_dopopupmenu(ucnew->menu); else
488 			{
489 				/* presume macro */
490 				us_domacro(ucnew->comname, ucnew->count, ucnew->word);
491 			}
492 		}
493 	} else ttyputmsg(_("(command not executed)"));
494 	if (ucnew != uc && ucnew != NOUSERCOM)
495 	{
496 		if (us_usercomstack == ucnew)
497 			us_usercomstack = ucnew->nextcom;
498 		else
499 			us_usercomstack = NOUSERCOM;
500 		us_freeusercom(ucnew);
501 	}
502 
503 	/* save the command in a macro if requested */
504 	if (wasmacro != 0 && (us_state&COMMANDFAILED) == 0 && ismacend == 0)
505 	{
506 		var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrobuildingkey);
507 		if (var != NOVARIABLE)
508 			if (us_addusercom(uc, (CHAR *)var->addr))
509 				ttyputnomemory();
510 	}
511 
512 	/* if command had an error, set flag to not save it */
513 	if ((us_state&COMMANDFAILED) != 0) fromuser = FALSE;
514 
515 	/* if command was "iterate", don't save it in iteration stack */
516 	if (fromuser)
517 	{
518 		if (act < us_longcount && estrcmp(us_lcommand[act].name, x_("iterate")) == 0)
519 			fromuser = FALSE;
520 	}
521 
522 	/* if command is to be saved for iteration, do so */
523 	if (us_usercomstack == uc)
524 		us_usercomstack = uc->nextcom;
525 	else
526 		us_usercomstack = NOUSERCOM;
527 	if (fromuser)
528 	{
529 		if (us_lastcom != NOUSERCOM) us_freeusercom(us_lastcom);
530 		us_lastcom = uc;
531 	} else
532 	{
533 		us_freeusercom(uc);
534 	}
535 }
536 
537 /*
538  * routine to convert command "uc" into a fully fleshed-out command (with all
539  * "%" macros, "$" variables, and "^" quoted characters properly converted).
540  */
us_fleshcommand(USERCOM * uc)541 USERCOM *us_fleshcommand(USERCOM *uc)
542 {
543 	REGISTER USERCOM *ucnew;
544 	REGISTER BOOLEAN err;
545 	REGISTER INTBIG j, l, letter, aindex, indexsave, hasparams, count, chr;
546 	REGISTER VARIABLE *var, *varrunning, *varbuilding;
547 	VARIABLE localvar;
548 	REGISTER CHAR *pp, *closeparen, *pars;
549 	CHAR *qual, *tmpstring, *params[MAXPARS];
550 	INTBIG objaddr, objtype;
551 	REGISTER void *infstr;
552 
553 	/* look for macro/variable/quote expansion possibilities */
554 	hasparams = 0;
555 	for(j=0; j<uc->count; j++)
556 	{
557 		for(pp = uc->word[j]; *pp != 0; pp++)
558 			if (*pp == '%' || *pp == '$' || *pp == '^') hasparams++;
559 		if (hasparams != 0) break;
560 	}
561 	if (hasparams == 0) return(uc);
562 
563 	/* make a new user command */
564 	ucnew = us_allocusercom();
565 	if (ucnew == NOUSERCOM) return(uc);
566 	ucnew->active = uc->active;
567 	(void)allocstring(&ucnew->comname, uc->comname, us_tool->cluster);
568 	ucnew->menu = uc->menu;
569 	ucnew->count = uc->count;
570 
571 	/* run through each parameter */
572 	err = FALSE;
573 	for(j=0; j<ucnew->count; j++)
574 	{
575 		/* copy the original parameter */
576 		err |= allocstring(&tmpstring, uc->word[j], el_tempcluster);
577 
578 		/* expand macro if it has parameters */
579 		for(infstr = initinfstr(), pp = tmpstring; *pp != 0; pp++)
580 		{
581 			/* handle escape character */
582 			if (*pp == '^')
583 			{
584 				addtoinfstr(infstr, *pp++);
585 				if (*pp != 0) addtoinfstr(infstr, *pp);
586 				continue;
587 			}
588 
589 			/* if not a command interpreter macro character, just copy it */
590 			if (*pp != '%') { addtoinfstr(infstr, *pp);  continue; }
591 			pp++;
592 
593 			/* handle command interpreter variables */
594 			if (isalpha(*pp))
595 			{
596 				/* handle array indices */
597 				aindex = -1;
598 				indexsave = l = 0;
599 				if (pp[1] == '[') for(l=2; pp[l] != 0; l++) if (pp[l] == ']')
600 				{
601 					aindex = myatoi(&pp[2]);
602 					indexsave = pp[1];
603 					pp[1] = 0;
604 					break;
605 				}
606 
607 				var = getval((INTBIG)us_tool, VTOOL, -1, us_commandvarname(*pp));
608 				if (var != NOVARIABLE)
609 					addstringtoinfstr(infstr, describevariable(var, aindex, -1));
610 				if (aindex >= 0)
611 				{
612 					pp[1] = (CHAR)indexsave;
613 					pp += l;
614 				}
615 				continue;
616 			}
617 
618 			/* if "%" form is parameter substitution, do that */
619 			if (isdigit(*pp))
620 			{
621 				/* substitute macro parameter */
622 				varrunning = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrorunningkey);
623 				varbuilding = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrobuildingkey);
624 				if (varrunning != NOVARIABLE && (varbuilding == NOVARIABLE ||
625 					namesame((CHAR *)varrunning->addr, (CHAR *)varbuilding->addr) != 0))
626 				{
627 					/* find the number of parameters to this macro */
628 					var = us_getmacro((CHAR *)varrunning->addr);
629 					if (var == NOVARIABLE) count = 0; else
630 						count = us_parsecommand(((CHAR **)var->addr)[1], params);
631 					letter = *pp - '1';
632 					if (letter < count)
633 					{
634 						/* remove enclosing quotes on parameter */
635 						pars = params[letter];
636 						if (pars[0] == '"' && pars[estrlen(pars)-1] == '"')
637 						{
638 							pars[estrlen(pars)-1] = 0;
639 							pars++;
640 						}
641 
642 						/* add the parameter, removing quotes */
643 						for(; *pars != 0; pars++)
644 						{
645 							if (pars[0] == '"' && pars[1] == '"') pars++;
646 							addtoinfstr(infstr, *pars);
647 						}
648 
649 						/* skip the default clause, if any */
650 						if (pp[1] == '[')
651 							for(pp += 2; *pp != ']' && *pp != 0; pp++)
652 								;
653 						continue;
654 					}
655 				}
656 
657 				/* use the default clause, if any */
658 				if (pp[1] == '[')
659 					for(pp += 2; *pp != ']' && *pp != 0; pp++) addtoinfstr(infstr, *pp);
660 				continue;
661 			}
662 
663 			/* give up on substitution: leave the construct as is */
664 			addtoinfstr(infstr, *pp);
665 		}
666 		if (reallocstring(&tmpstring, returninfstr(infstr), el_tempcluster)) err = TRUE;
667 
668 		/* substitute any "$" variable references in the user command */
669 		for(infstr = initinfstr(), pp = tmpstring; *pp != 0; pp++)
670 		{
671 			/* handle escape character */
672 			if (*pp == '^')
673 			{
674 				addtoinfstr(infstr, *pp++);
675 				if (*pp != 0) addtoinfstr(infstr, *pp);
676 				continue;
677 			}
678 
679 			/* if not a variable character, just copy it */
680 			if (*pp != '$') { addtoinfstr(infstr, *pp);  continue; }
681 
682 			/* if variable expression is in parenthesis, determine extent */
683 			pp++;
684 			closeparen = 0;
685 			if (*pp == '(')
686 			{
687 				for(l=0; pp[l] != 0; l++) if (pp[l] == ')') break;
688 				if (pp[l] == ')')
689 				{
690 					closeparen = &pp[l];
691 					pp[l] = 0;
692 					pp++;
693 				}
694 			}
695 
696 			/* get index of variable (if specified) */
697 			aindex = -1;
698 			l = estrlen(pp);
699 			if (pp[l-1] == ']') for(l--; l >= 0; l--) if (pp[l] == '[')
700 			{
701 				aindex = myatoi(&pp[l+1]);
702 				break;
703 			}
704 			if (!us_evaluatevariable(pp, &objaddr, &objtype, &qual))
705 			{
706 				if (*qual != 0) var = getval(objaddr, objtype, -1, qual); else
707 				{
708 					localvar.addr = objaddr;
709 					localvar.type = objtype;
710 					TDCLEAR(localvar.textdescript);
711 					var = &localvar;
712 				}
713 				if (var != NOVARIABLE) addstringtoinfstr(infstr, describevariable(var, aindex, -1));
714 			}
715 			if (closeparen != 0)
716 			{
717 				*closeparen = ')';
718 				pp = closeparen;
719 			} else break;
720 		}
721 		if (reallocstring(&tmpstring, returninfstr(infstr), el_tempcluster)) err = TRUE;
722 
723 		/* remove any "^" escape references in the user command */
724 		for(infstr = initinfstr(), pp = tmpstring; *pp != 0; pp++)
725 		{
726 			if (*pp != '^') addtoinfstr(infstr, *pp); else
727 			{
728 				pp++;
729 				if (*pp == 0)
730 				{
731 					ttyputerr(_("HEY! '^' at end of line"));
732 					break;
733 				}
734 				chr = *pp;
735 
736 				/* check for numeric equivalent of the form "^010" */
737 				if (chr == '0')
738 				{
739 					pp++;
740 					chr = 0;
741 					while (*pp >= '0' && *pp <= '7')
742 					{
743 						chr = (chr * 8) + (*pp - '0');
744 						pp++;
745 					}
746 					pp--;
747 				}
748 				addtoinfstr(infstr, (CHAR)chr);
749 			}
750 		}
751 		if (allocstring(&ucnew->word[j], returninfstr(infstr), us_tool->cluster)) err = TRUE;
752 		efree(tmpstring);
753 	}
754 	if (err) ttyputnomemory();
755 	return(ucnew);
756 }
757 
758 /*
759  * routine to expand a variable path in the string "name" and return a full
760  * description of how to find that variable by setting "objaddr" and "objtype"
761  * to the address and type of the object containing the variable "qual".
762  * The routine returns true if the variable path is nonsensical.
763  */
us_evaluatevariable(CHAR * name,INTBIG * objaddr,INTBIG * objtype,CHAR ** qual)764 BOOLEAN us_evaluatevariable(CHAR *name, INTBIG *objaddr, INTBIG *objtype, CHAR **qual)
765 {
766 	REGISTER INTBIG i, len;
767 	INTBIG lx, hx, ly, hy, x, y;
768 	REGISTER CHAR *pp, save, *type;
769 	REGISTER NODEPROTO *np;
770 	REGISTER NODEINST *ni;
771 	REGISTER ARCINST *ai;
772 	REGISTER ARCPROTO *ap;
773 	REGISTER LIBRARY *lib;
774 	REGISTER PORTPROTO *port;
775 	REGISTER HIGHLIGHT *high;
776 	REGISTER TECHNOLOGY *tech;
777 	REGISTER VARIABLE *var, *highvar;
778 	REGISTER VIEW *view;
779 	REGISTER NETWORK *net;
780 	REGISTER WINDOWPART *win;
781 	GEOM *fromgeom, *togeom;
782 	PORTPROTO *fromport, *toport;
783 	HIGHLIGHT thishigh;
784 	REGISTER INTBIG varcount, *list;
785 	REGISTER void *infstr;
786 
787 	/* look for specifier with ":" */
788 	for(pp = name;
789 		*pp != 0 && *pp != ':' && *pp != '.' && *pp != ')' && *pp != '['; pp++)
790 			;
791 	if (*pp == ':')
792 	{
793 		i = pp - name;
794 		type = name;
795 		for(name = ++pp;
796 			*name != 0 && *name != '.' && *name != ')' && *name != '['; name++)
797 				;
798 		save = *name;    *name = 0;
799 		if (namesamen(type, x_("technology"), i) == 0 && i >= 1)
800 		{
801 			*objtype = VTECHNOLOGY;
802 			if (estrcmp(pp, x_("~")) == 0) tech = el_curtech; else
803 				tech = gettechnology(pp);
804 			*name = save;
805 			if (tech == NOTECHNOLOGY) return(TRUE);
806 			*objaddr = (INTBIG)tech;
807 		} else if (namesamen(type, x_("library"), i) == 0 && i >= 1)
808 		{
809 			*objtype = VLIBRARY;
810 			if (estrcmp(pp, x_("~")) == 0) lib = el_curlib; else lib = getlibrary(pp);
811 			*name = save;
812 			if (lib == NOLIBRARY) return(TRUE);
813 			*objaddr = (INTBIG)lib;
814 		} else if (namesamen(type, x_("tool"), i) == 0 && i >= 2)
815 		{
816 			*objtype = VTOOL;
817 			if (estrcmp(pp, x_("~")) == 0) i = us_tool->toolindex; else
818 				for(i=0; i<el_maxtools; i++)
819 					if (namesame(el_tools[i].toolname, pp) == 0) break;
820 			*name = save;
821 			if (i >= el_maxtools) return(TRUE);
822 			*objaddr = (INTBIG)&el_tools[i];
823 		} else if (namesamen(type, x_("arc"), i) == 0 && i >= 2)
824 		{
825 			*objtype = VARCPROTO;
826 			if (estrcmp(pp, x_("~")) == 0) ap = us_curarcproto; else
827 				for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
828 					if (namesame(ap->protoname, pp) == 0) break;
829 			*name = save;
830 			if (ap == NOARCPROTO) return(TRUE);
831 			*objaddr = (INTBIG)ap;
832 		} else if (namesamen(type, x_("node"), i) == 0 && i >= 2)
833 		{
834 			*objtype = VNODEPROTO;
835 			if (estrcmp(pp, x_("~")) == 0) np = us_curnodeproto; else
836 				np = getnodeproto(pp);
837 			*name = save;
838 			if (np == NONODEPROTO) return(TRUE);
839 			*objaddr = (INTBIG)np;
840 		} else if (namesamen(type, x_("primitive"), i) == 0 && i >= 1)
841 		{
842 			*objtype = VNODEPROTO;
843 			if (estrcmp(pp, x_("~")) == 0) np = us_curnodeproto; else
844 				np = getnodeproto(pp);
845 			if (np != NONODEPROTO && np->primindex == 0) np = NONODEPROTO;
846 			*name = save;
847 			if (np == NONODEPROTO) return(TRUE);
848 			*objaddr = (INTBIG)np;
849 		} else if (namesamen(type, x_("cell"), i) == 0 && i >= 1)
850 		{
851 			*objtype = VNODEPROTO;
852 			if (estrcmp(pp, x_("~")) == 0) np = getcurcell(); else
853 			{
854 				np = getnodeproto(pp);
855 				if (np != NONODEPROTO && np->primindex != 0) np = NONODEPROTO;
856 			}
857 			*name = save;
858 			if (np == NONODEPROTO) return(TRUE);
859 			*objaddr = (INTBIG)np;
860 		} else if (namesamen(type, x_("view"), i) == 0 && i >= 1)
861 		{
862 			*objtype = VVIEW;
863 			view = getview(pp);
864 			*name = save;
865 			if (view == NOVIEW) return(TRUE);
866 			*objaddr = (INTBIG)view;
867 		} else if (namesamen(type, x_("window"), i) == 0 && i >= 1)
868 		{
869 			*objtype = VWINDOWPART;
870 			if (estrcmp(pp, x_("~")) == 0) win = el_curwindowpart; else
871 			{
872 				for(win = el_topwindowpart; win != NOWINDOWPART; win = win->nextwindowpart)
873 					if (namesame(pp, win->location) == 0) break;
874 			}
875 			*name = save;
876 			if (win == NOWINDOWPART) return(TRUE);
877 			*objaddr = (INTBIG)win;
878 		} else if (namesamen(type, x_("net"), i) == 0 && i >= 2)
879 		{
880 			*objtype = VNETWORK;
881 			np = getcurcell();
882 			if (np == NONODEPROTO) return(TRUE);
883 			net = getnetwork(pp, np);
884 			*name = save;
885 			if (net == NONETWORK) return(TRUE);
886 			*objaddr = (INTBIG)net;
887 		} else
888 		{
889 			*name = save;
890 			return(TRUE);
891 		}
892 		if (*name == '.') name++;
893 	} else
894 	{
895 		if (*name == '~')
896 		{
897 			name++;
898 
899 			/* handle cases that do not need current selection */
900 			if (*name == 'x' || *name == 'y')
901 			{
902 				/* special case when evaluating cursor coordinates */
903 				if (us_demandxy(&x, &y)) return(TRUE);
904 				np = el_curlib->curnodeproto;
905 				gridalign(&x, &y, 1, np);
906 				*objtype = VINTEGER;
907 				if (*name == 'x') *objaddr = x; else *objaddr = y;
908 				name++;
909 			} else if (*name == 't')
910 			{
911 				/* figure out the current technology */
912 				*objtype = VSTRING;
913 				*objaddr = (INTBIG)x_("");
914 				np = el_curlib->curnodeproto;
915 				if (np != NONODEPROTO && (np->cellview->viewstate&TEXTVIEW) == 0)
916 					*objaddr = (INTBIG)us_techname(np);
917 				name++;
918 			} else if (*name == 'c')
919 			{
920 				list = us_getallhighlighted();
921 				for(i=0; list[i+1] != 0; i += 2) ;
922 				*objtype = VINTEGER;
923 				*objaddr = i / 2;
924 				name++;
925 			} else if (*name == 'h')
926 			{
927 				name++;
928 				if (us_getareabounds(&lx, &hx, &ly, &hy) == NONODEPROTO) return(TRUE);
929 				*objtype = VINTEGER;
930 				switch (*name)
931 				{
932 					case 'l': *objaddr = lx;   name++;   break;
933 					case 'r': *objaddr = hx;   name++;   break;
934 					case 'b': *objaddr = ly;   name++;   break;
935 					case 't': *objaddr = hy;   name++;   break;
936 					default:  *objtype = VUNKNOWN;       break;
937 				}
938 			} else if (*name == 'o')
939 			{
940 				name++;
941 				if (us_gettwoobjects(&fromgeom, &fromport, &togeom, &toport)) return(TRUE);
942 				*objaddr = (INTBIG)togeom->entryaddr.blind;
943 				if (togeom->entryisnode) *objtype = VNODEINST; else
944 					*objtype = VARCINST;
945 			} else if (namesamen(name, x_("nodes"), 5) == 0)
946 			{
947 				/* construct a list of the nodes in this cell */
948 				name += 5;
949 				np = getcurcell();
950 				if (np == NONODEPROTO) return(TRUE);
951 				varcount = 0;
952 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
953 				{
954 					if (varcount >= us_evaluatevarlimit)
955 						if (us_expandvarlist(&us_evaluatevarlist, &us_evaluatevarlimit)) return(TRUE);
956 					us_evaluatevarlist[varcount*2] = (INTBIG)ni;
957 					us_evaluatevarlist[varcount*2+1] = VNODEINST;
958 					varcount++;
959 				}
960 				*objaddr = (INTBIG)us_evaluatevarlist;
961 				*objtype = VGENERAL | VISARRAY | ((varcount*2) << VLENGTHSH) | VDONTSAVE;
962 			} else if (namesamen(name, x_("arcs"), 4) == 0)
963 			{
964 				/* construct a list of the arcs in this cell */
965 				name += 4;
966 				np = getcurcell();
967 				if (np == NONODEPROTO) return(TRUE);
968 				varcount = 0;
969 				for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
970 				{
971 					if (varcount >= us_evaluatevarlimit)
972 						if (us_expandvarlist(&us_evaluatevarlist, &us_evaluatevarlimit)) return(TRUE);
973 					us_evaluatevarlist[varcount*2] = (INTBIG)ai;
974 					us_evaluatevarlist[varcount*2+1] = VARCINST;
975 					varcount++;
976 				}
977 				*objaddr = (INTBIG)us_evaluatevarlist;
978 				*objtype = VGENERAL | VISARRAY | ((varcount*2) << VLENGTHSH) | VDONTSAVE;
979 			} else if (namesamen(name, x_("ports"), 5) == 0)
980 			{
981 				/* construct a list of the ports in this cell */
982 				name += 5;
983 				np = getcurcell();
984 				if (np == NONODEPROTO) return(TRUE);
985 				varcount = 0;
986 				for(port = np->firstportproto; port != NOPORTPROTO; port = port->nextportproto)
987 				{
988 					if (varcount >= us_evaluatevarlimit)
989 						if (us_expandvarlist(&us_evaluatevarlist, &us_evaluatevarlimit)) return(TRUE);
990 					us_evaluatevarlist[varcount*2] = (INTBIG)port;
991 					us_evaluatevarlist[varcount*2+1] = VPORTPROTO;
992 					varcount++;
993 				}
994 				*objaddr = (INTBIG)us_evaluatevarlist;
995 				*objtype = VGENERAL | VISARRAY | ((varcount*2) << VLENGTHSH) | VDONTSAVE;
996 			} else if (namesamen(name, x_("nets"), 4) == 0)
997 			{
998 				/* construct a list of the networks in this cell */
999 				name += 4;
1000 				np = getcurcell();
1001 				if (np == NONODEPROTO) return(TRUE);
1002 				varcount = 0;
1003 				for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1004 				{
1005 					if (varcount >= us_evaluatevarlimit)
1006 						if (us_expandvarlist(&us_evaluatevarlist, &us_evaluatevarlimit)) return(TRUE);
1007 					us_evaluatevarlist[varcount*2] = (INTBIG)net;
1008 					us_evaluatevarlist[varcount*2+1] = VNETWORK;
1009 					varcount++;
1010 				}
1011 				*objaddr = (INTBIG)us_evaluatevarlist;
1012 				*objtype = VGENERAL | VISARRAY | ((varcount*2) << VLENGTHSH) | VDONTSAVE;
1013 			} else if (namesamen(name, x_("cells"), 6) == 0)
1014 			{
1015 				/* construct a list of the cells in this library */
1016 				name += 6;
1017 				varcount = 0;
1018 				for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1019 				{
1020 					if (varcount >= us_evaluatevarlimit)
1021 						if (us_expandvarlist(&us_evaluatevarlist, &us_evaluatevarlimit)) return(TRUE);
1022 					us_evaluatevarlist[varcount*2] = (INTBIG)np;
1023 					us_evaluatevarlist[varcount*2+1] = VNODEPROTO;
1024 					varcount++;
1025 				}
1026 				*objaddr = (INTBIG)us_evaluatevarlist;
1027 				*objtype = VGENERAL | VISARRAY | ((varcount*2) << VLENGTHSH) | VDONTSAVE;
1028 			} else if (namesamen(name, x_("libs"), 4) == 0)
1029 			{
1030 				/* construct a list of the libraries */
1031 				name += 4;
1032 				varcount = 0;
1033 				for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1034 				{
1035 					if (varcount >= us_evaluatevarlimit)
1036 						if (us_expandvarlist(&us_evaluatevarlist, &us_evaluatevarlimit)) return(TRUE);
1037 					us_evaluatevarlist[varcount*2] = (INTBIG)lib;
1038 					us_evaluatevarlist[varcount*2+1] = VLIBRARY;
1039 					varcount++;
1040 				}
1041 				*objaddr = (INTBIG)us_evaluatevarlist;
1042 				*objtype = VGENERAL | VISARRAY | ((varcount*2) << VLENGTHSH) | VDONTSAVE;
1043 			} else
1044 			{
1045 				/* basic "~" with nothing after it requires the current selection, so get it */
1046 				list = us_getallhighlighted();
1047 
1048 				/* if there are no objects selected, stop now */
1049 				if (list[1] == 0) return(TRUE);
1050 
1051 				highvar = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1052 				if (highvar == NOVARIABLE) return(TRUE);
1053 				if (us_makehighlight(((CHAR **)highvar->addr)[0], &thishigh)) return(TRUE);
1054 				high = &thishigh;
1055 
1056 				/* copy the selected object to the parameters */
1057 				*objaddr = list[0];
1058 				*objtype = list[1];
1059 
1060 				/* get variable name if one is selected */
1061 				if ((high->status&HIGHTYPE) == HIGHTEXT && high->fromvar != NOVARIABLE)
1062 				{
1063 					*qual = makename(high->fromvar->key);
1064 					if (*name == 0 || *name == ')' || *name == '[') return(FALSE);
1065 					return(TRUE);
1066 				}
1067 			}
1068 			if (*name == '.') name++;
1069 		} else
1070 		{
1071 			np = getcurcell();
1072 			if (np == NONODEPROTO) return(TRUE);
1073 			*objaddr = (INTBIG)np;
1074 			*objtype = VNODEPROTO;
1075 		}
1076 	}
1077 
1078 	/* add in qualifiers */
1079 	save = *name;
1080 	for(pp = name; *name != 0;)
1081 	{
1082 		/* advance to the end of the next qualifying name */
1083 		while (*name != 0 && *name != '.' && *name != ')' && *name != '[') name++;
1084 
1085 		/* save the terminating character */
1086 		save = *name;   *name = 0;
1087 
1088 		/* special case if this is an array */
1089 		if (((*objtype) & VISARRAY) != 0 && ((*objtype)&VTYPE) == VGENERAL)
1090 		{
1091 			len = (((*objtype) & VLENGTH) >> VLENGTHSH) / 2;
1092 			for(i=0; i<len; i++)
1093 			{
1094 				/* climb down the context chain */
1095 				var = getval(((INTBIG *)*objaddr)[i*2], ((INTBIG *)*objaddr)[i*2+1], -1, pp);
1096 
1097 				/* if chain cannot be climbed, path is invalid */
1098 				if (var == NOVARIABLE) ((INTBIG *)*objaddr)[i*2+1] = VUNKNOWN; else
1099 				{
1100 					/* keep on going down the path */
1101 					((INTBIG *)*objaddr)[i*2] = var->addr;
1102 					((INTBIG *)*objaddr)[i*2+1] = var->type;
1103 				}
1104 			}
1105 			*name++ = save;
1106 		} else
1107 		{
1108 			/* if this is the end, return now */
1109 			if (save != '.') break;
1110 
1111 			/* climb down the context chain */
1112 			var = getval(*objaddr, *objtype, -1, pp);
1113 			*name++ = save;
1114 
1115 			/* if chain cannot be climbed, path is invalid */
1116 			if (var == NOVARIABLE) return(TRUE);
1117 
1118 			/* keep on going down the path */
1119 			*objaddr = var->addr;   *objtype = var->type;
1120 		}
1121 
1122 		pp = name;
1123 	}
1124 
1125 	/* get the final qualifying name */
1126 	if (((*objtype)&VTYPE) == VGENERAL) *qual = x_(""); else
1127 	{
1128 		infstr = initinfstr();
1129 		addstringtoinfstr(infstr, pp);
1130 		*qual = returninfstr(infstr);
1131 	}
1132 	*name = save;
1133 	return(FALSE);
1134 }
1135 
1136 /*
1137  * routine to maintain a static list of address/type pairs
1138  */
us_expandvarlist(INTBIG ** varlist,INTBIG * varlimit)1139 BOOLEAN us_expandvarlist(INTBIG **varlist, INTBIG *varlimit)
1140 {
1141 	INTBIG *newlist, newlimit, i;
1142 
1143 	newlimit = *varlimit * 2;
1144 	if (newlimit <= 0) newlimit = *varlimit + 10;
1145 	newlist = (INTBIG *)emalloc(newlimit * 2 * SIZEOFINTBIG, us_tool->cluster);
1146 	if (newlist == 0) return(TRUE);
1147 	for(i=0; i < (*varlimit)*2; i++) newlist[i] = (*varlist)[i];
1148 	if (*varlimit != 0) efree((CHAR *)*varlist);
1149 	*varlist = newlist;
1150 	*varlimit = newlimit;
1151 	return(FALSE);
1152 }
1153 
1154 /*
1155  * routine to ensure that the INTBIG arrays "addr" and "type" are at least "len"
1156  * long (current size is "limit").  Reallocates if not.  Returns true on error.
1157  */
us_expandaddrtypearray(INTBIG * limit,INTBIG ** addr,INTBIG ** type,INTBIG len)1158 BOOLEAN us_expandaddrtypearray(INTBIG *limit, INTBIG **addr, INTBIG **type, INTBIG len)
1159 {
1160 	if (len <= *limit) return(FALSE);
1161 
1162 	if (*limit > 0) { efree((CHAR *)*addr);   efree((CHAR *)*type); }
1163 	*limit = 0;
1164 	*addr = (INTBIG *)emalloc(len * SIZEOFINTBIG, us_tool->cluster);
1165 	if (*addr == 0) return(TRUE);
1166 	*type = (INTBIG *)emalloc(len * SIZEOFINTBIG, us_tool->cluster);
1167 	if (*type == 0) return(TRUE);
1168 	*limit = len;
1169 	return(FALSE);
1170 }
1171 
1172 /*
1173  * routine to execute popup menu "pm"
1174  */
us_dopopupmenu(POPUPMENU * pm)1175 void us_dopopupmenu(POPUPMENU *pm)
1176 {
1177 	REGISTER INTBIG i;
1178 	REGISTER POPUPMENUITEM *mi, *miret;
1179 	POPUPMENU *cpm;
1180 	REGISTER USERCOM *uc;
1181 	BOOLEAN butstate, verbose;
1182 	REGISTER void *infstr;
1183 
1184 	/* initialize the popup menu */
1185 	for(i=0; i<pm->total; i++)
1186 	{
1187 		mi = &pm->list[i];
1188 		if (mi->maxlen < 0) mi->value = 0; else
1189 		{
1190 			mi->value = (CHAR *)emalloc((mi->maxlen+1) * SIZEOFCHAR, el_tempcluster);
1191 			if (mi->value == 0)
1192 			{
1193 				ttyputnomemory();
1194 				return;
1195 			}
1196 			(void)estrcpy(mi->value, x_("*"));
1197 		}
1198 	}
1199 
1200 	/* display and select from the menu */
1201 	butstate = TRUE;
1202 	cpm = pm;
1203 	miret = us_popupmenu(&cpm, &butstate, TRUE, -1, -1, 0);
1204 
1205 	/* now analyze the results */
1206 	for(i=0; i<pm->total; i++)
1207 	{
1208 		mi = &pm->list[i];
1209 		if (mi->changed)
1210 		{
1211 			/* build the new command with the argument */
1212 			uc = mi->response;
1213 			infstr = initinfstr();
1214 			addstringtoinfstr(infstr, uc->comname);
1215 			us_appendargs(infstr, uc);
1216 			addtoinfstr(infstr, ' ');
1217 			addstringtoinfstr(infstr, mi->value);
1218 			uc = us_makecommand(returninfstr(infstr));
1219 			if (uc != NOUSERCOM)
1220 			{
1221 				if (miret != mi) verbose = TRUE; else
1222 					verbose = FALSE;
1223 				us_executesafe(uc, verbose, FALSE, FALSE);
1224 				us_freeusercom(uc);
1225 			}
1226 		}
1227 		if (mi->maxlen >= 0) efree(mi->value);
1228 	}
1229 
1230 	/* now execute the selected command if it wasn't already done */
1231 	if (miret == NOPOPUPMENUITEM || miret == 0) return;
1232 	if (miret->changed) return;
1233 	uc = miret->response;
1234 	if (uc == NOUSERCOM) return;
1235 	us_execute(uc, FALSE, FALSE, FALSE);
1236 }
1237 
1238 /*
1239  * routine to execute macro "mac" with parameters in the "count" entries of
1240  * array "pp"
1241  * DJY: Modified 10/87 to save old macro information before executing new macro
1242  * This is necessary if recursive macro calls are used.
1243  */
us_domacro(CHAR * mac,INTBIG count,CHAR * pp[])1244 void us_domacro(CHAR *mac, INTBIG count, CHAR *pp[])
1245 {
1246 	REGISTER INTBIG i, total;
1247 	BOOLEAN verbose;
1248 	REGISTER USERCOM *uc;
1249 	CHAR *runsave, *build[MAXPARS], *paramsave;
1250 	REGISTER CHAR *pt, **varmacroaddr;
1251 	REGISTER INTBIG len, varmacrokey;
1252 	REGISTER VARIABLE *varmacro, *varbuilding, *varrunning;
1253 	REGISTER void *infstr;
1254 
1255 	/* make sure the macro being executed is not currently being defined */
1256 	varbuilding = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrobuildingkey);
1257 	if (varbuilding != NOVARIABLE && namesame((CHAR *)varbuilding->addr, mac) == 0)
1258 	{
1259 		us_abortcommand(_("End macro definitions before executing them"));
1260 		return;
1261 	}
1262 
1263 	/* get the macro to be run */
1264 	varmacro = us_getmacro(mac);
1265 	if (varmacro == NOVARIABLE || (len = getlength(varmacro)) < 4)
1266 	{
1267 		us_abortcommand(_("Cannot find macro '%s'"), mac);
1268 		return;
1269 	}
1270 	varmacroaddr = (CHAR **)varmacro->addr;
1271 	varmacrokey = varmacro->key;
1272 
1273 	/* find out whether the macro should be verbose */
1274 	total = us_parsecommand(varmacroaddr[0], build);
1275 	verbose = FALSE;
1276 	for(i=0; i<total; i++) if (namesame(build[i], x_("verbose")) == 0) verbose = TRUE;
1277 
1278 	/* save former parameters to this macro, set new ones */
1279 	pt = varmacroaddr[1];
1280 	if (*pt != 0) (void)allocstring(&paramsave, pt, el_tempcluster); else
1281 		paramsave = 0;
1282 	infstr = initinfstr();
1283 	for(i=0; i<count; i++)
1284 	{
1285 		if (i != 0) addtoinfstr(infstr, ' ');
1286 		addtoinfstr(infstr, '"');
1287 		for(pt = pp[i]; *pt != 0; pt++)
1288 		{
1289 			if (*pt == '"') addtoinfstr(infstr, '^');
1290 			addtoinfstr(infstr, *pt);
1291 		}
1292 		addtoinfstr(infstr, '"');
1293 	}
1294 	nextchangequiet();
1295 	(void)setindkey((INTBIG)us_tool, VTOOL, varmacrokey, 1, (INTBIG)returninfstr(infstr));
1296 
1297 	/* save currently running macro, set this as current */
1298 	varrunning = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrorunningkey);
1299 	if (varrunning == NOVARIABLE) runsave = 0; else
1300 		(void)allocstring(&runsave, (CHAR *)varrunning->addr, el_tempcluster);
1301 	nextchangequiet();
1302 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_macrorunningkey, (INTBIG)mac, VSTRING|VDONTSAVE);
1303 
1304 	/* execute the macro */
1305 	us_state &= ~MACROTERMINATED;
1306 	for(i=3; i<len; i++)
1307 	{
1308 		uc = us_makecommand(varmacroaddr[i]);
1309 		if (uc == NOUSERCOM) continue;
1310 		us_executesafe(uc, verbose, FALSE, FALSE);
1311 		us_freeusercom(uc);
1312 		if ((us_state&MACROTERMINATED) != 0) break;
1313 	}
1314 	us_state &= ~MACROTERMINATED;
1315 
1316 	/* restore currently running macro */
1317 	if (runsave == 0)
1318 	{
1319 		nextchangequiet();
1320 		(void)delvalkey((INTBIG)us_tool, VTOOL, us_macrorunningkey);
1321 	} else
1322 	{
1323 		nextchangequiet();
1324 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_macrorunningkey, (INTBIG)runsave, VSTRING|VDONTSAVE);
1325 		efree(runsave);
1326 	}
1327 
1328 	/* restore the current macro parameters */
1329 	if (paramsave == 0)
1330 	{
1331 		nextchangequiet();
1332 		(void)setindkey((INTBIG)us_tool, VTOOL, varmacrokey, 1, (INTBIG)x_(""));
1333 	} else
1334 	{
1335 		nextchangequiet();
1336 		(void)setindkey((INTBIG)us_tool, VTOOL, varmacrokey, 1, (INTBIG)paramsave);
1337 		efree(paramsave);
1338 	}
1339 }
1340 
1341 /*
1342  * routine to execute the commands in the file pointed to by stream "infile".
1343  * If "verbose" is false, execute the commands silently.  "headerstring"
1344  * is the string that must exist at the start of every line of the command
1345  * file that is to be processed.
1346  */
us_docommands(FILE * infile,BOOLEAN verbose,CHAR * headerstring)1347 void us_docommands(FILE *infile, BOOLEAN verbose, CHAR *headerstring)
1348 {
1349 	REGISTER INTBIG headercount, lastquiet=0;
1350 	REGISTER CHAR *pp;
1351 	CHAR line[MAXLINE], *savemacro;
1352 	REGISTER USERCOM *uc, *savelastc;
1353 	REGISTER VARIABLE *varbuilding;
1354 
1355 	/* see how many characters are in the header string */
1356 	headercount = estrlen(headerstring);
1357 
1358 	/* shut-up the status terminal if requested */
1359 	if (!verbose) lastquiet = ttyquiet(1);
1360 
1361 	/* save iteration and macro state */
1362 	savelastc = us_lastcom;      us_lastcom = NOUSERCOM;
1363 	varbuilding = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrobuildingkey);
1364 	if (varbuilding != NOVARIABLE)
1365 	{
1366 		(void)allocstring(&savemacro, (CHAR *)varbuilding->addr, el_tempcluster);
1367 		nextchangequiet();
1368 		(void)delvalkey((INTBIG)us_tool, VTOOL, us_macrobuildingkey);
1369 	} else savemacro = 0;
1370 
1371 	/* loop through the command file */
1372 	for(;;)
1373 	{
1374 		if (stopping(STOPREASONCOMFILE)) break;
1375 		if (xfgets(line, MAXLINE, infile)) break;
1376 		pp = line;   while (*pp == ' ' || *pp == '\t') pp++;
1377 		if (namesamen(pp, headerstring, headercount) != 0) continue;
1378 		pp += headercount;
1379 
1380 		/* skip initial blanks and tabs */
1381 		while (*pp == ' ' || *pp == '\t') pp++;
1382 
1383 		/* ignore comment lines */
1384 		if (*pp == 0 || *pp == ';') continue;
1385 
1386 		/* parse the line into separate strings */
1387 		uc = us_makecommand(pp);
1388 		if (uc == NOUSERCOM) break;
1389 		us_executesafe(uc, verbose, TRUE, TRUE);
1390 		us_freeusercom(uc);
1391 	}
1392 
1393 	/* restore the world as it was */
1394 	if (us_lastcom != NOUSERCOM) us_freeusercom(us_lastcom);
1395 	us_lastcom = savelastc;
1396 	if (savemacro != 0)
1397 	{
1398 		nextchangequiet();
1399 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_macrobuildingkey, (INTBIG)savemacro, VSTRING|VDONTSAVE);
1400 		efree(savemacro);
1401 	}
1402 	if (!verbose) (void)ttyquiet(lastquiet);
1403 }
1404 
1405 /*
1406  * routine to parse the line in "pp" into space-separated parameters and
1407  * to store them in the array "build".  Returns the number of strings put
1408  * into "build".
1409  */
us_parsecommand(CHAR * pp,CHAR * build[])1410 INTBIG us_parsecommand(CHAR *pp, CHAR *build[])
1411 {
1412 	REGISTER CHAR *ppsave, c, *tstart, *tend, *ch, *initstring;
1413 	CHAR tempbuf[300];
1414 	REGISTER INTBIG count, inquote, tp;
1415 
1416 	/* parse the line into up to MAXPARS fields (command plus parameters) */
1417 	initstring = pp;
1418 	for(count=0; count<MAXPARS; count++)
1419 	{
1420 		/* skip the delimiters before the keyword */
1421 		while (*pp == ' ' || *pp == '\t') pp++;
1422 		if (*pp == 0) break;
1423 
1424 		/* remember the start of the keyword */
1425 		ppsave = pp;
1426 
1427 		/* scan to the end of the keyword (considering quotation) */
1428 		inquote = 0;
1429 		tstart = tend = 0;
1430 		for(;;)
1431 		{
1432 			if (*pp == 0) break;
1433 			if (*pp == '^' && pp[1] != 0)
1434 			{
1435 				pp += 2;
1436 				continue;
1437 			}
1438 			if (inquote == 0)
1439 			{
1440 				if (*pp == '"') inquote = 1; else
1441 				{
1442 					if (pp[0] == 'N' && pp[1] == '_' && pp[2] == '(' && pp[3] == '"')
1443 					{
1444 						inquote = 1;
1445 						tstart = pp;
1446 						pp += 3;
1447 					}
1448 				}
1449 			} else
1450 			{
1451 				if (*pp == '"')
1452 				{
1453 					inquote = 0;
1454 					if (tstart != 0 && pp[1] == ')')
1455 					{
1456 						tend = pp;
1457 						pp++;
1458 					}
1459 				}
1460 			}
1461 			if (inquote == 0 && (*pp == ' ' || *pp == '\t')) break;
1462 			pp++;
1463 		}
1464 
1465 		if (inquote != 0 || (tstart != 0 && tend == 0))
1466 			ttyputerr(_("Unbalanced quote in commandfile line '%s'"), initstring);
1467 
1468 		/* save the keyword */
1469 		c = *pp;   *pp = 0;
1470 		if (tstart != 0 && tend != 0)
1471 		{
1472 			tp = 0;
1473 			tempbuf[tp++] = '"';
1474 			for(ch = ppsave; ch != tstart; ch++) tempbuf[tp++] = *ch;
1475 			tstart += 4;
1476 			*tend = 0;
1477 			for(ch = TRANSLATE(tstart); *ch != 0; ch++) tempbuf[tp++] = *ch;
1478 			*tend = '"';
1479 			for(ch = tend+2; *ch != 0; ch++) tempbuf[tp++] = *ch;
1480 			tempbuf[tp++] = '"';
1481 			tempbuf[tp] = 0;
1482 			ppsave = tempbuf;
1483 		}
1484 		if (count > us_parsemaxownbuild)
1485 		{
1486 			(void)allocstring(&us_parseownbuild[count], ppsave, us_tool->cluster);
1487 			us_parsemaxownbuild = count;
1488 		} else (void)reallocstring(&us_parseownbuild[count], ppsave, us_tool->cluster);
1489 		build[count] = us_parseownbuild[count];
1490 		*pp = c;
1491 	}
1492 	return(count);
1493 }
1494 
1495 /*
1496  * routine to parse the string in "line" into a user command which is
1497  * allocated and returned (don't forget to free it when done).  Returns
1498  * NOUSERCOM upon error.
1499  */
us_buildcommand(INTBIG count,CHAR * par[])1500 USERCOM *us_buildcommand(INTBIG count, CHAR *par[])
1501 {
1502 	REGISTER USERCOM *uc;
1503 	REGISTER INTBIG i, inquote;
1504 	REGISTER CHAR *in, *out;
1505 	extern COMCOMP us_userp;
1506 
1507 	/* build the command structure */
1508 	i = parse(par[0], &us_userp, TRUE);
1509 	uc = us_allocusercom();
1510 	if (uc == NOUSERCOM) return(NOUSERCOM);
1511 	uc->active = i;
1512 	uc->menu = us_getpopupmenu(par[0]);
1513 	(void)allocstring(&uc->comname, par[0], us_tool->cluster);
1514 	uc->count = count-1;
1515 	for(i=1; i<count; i++)
1516 	{
1517 		if (allocstring(&uc->word[i-1], par[i], us_tool->cluster)) return(NOUSERCOM);
1518 
1519 		/* remove quotes from the keyword */
1520 		inquote = 0;
1521 		for(in = out = uc->word[i-1]; *in != 0; in++)
1522 		{
1523 			if (in[0] == '"')
1524 			{
1525 				if (inquote == 0)
1526 				{
1527 					inquote = 1;
1528 					continue;
1529 				}
1530 				if (in[1] == '"')
1531 				{
1532 					*out++ = '"';
1533 					in++;
1534 					continue;
1535 				}
1536 				inquote = 0;
1537 				continue;
1538 			}
1539 			*out++ = *in;
1540 		}
1541 		*out = 0;
1542 	}
1543 	return(uc);
1544 }
1545 
1546 /*
1547  * routine to parse the command in the string "line" and return a user
1548  * command object with that command.  This essentially combines
1549  * "us_parsecommand" and "us_buildcommand" into one routine.  Returns NOUSERCOM
1550  * if the command cannot be parsed.  The command object must be freed when done.
1551  */
us_makecommand(CHAR * line)1552 USERCOM *us_makecommand(CHAR *line)
1553 {
1554 	CHAR *build[MAXPARS];
1555 	REGISTER INTBIG count;
1556 	REGISTER USERCOM *uc;
1557 
1558 	count = us_parsecommand(line, build);
1559 	if (count <= 0) return(NOUSERCOM);
1560 	uc = us_buildcommand(count, build);
1561 	if (uc == NOUSERCOM) ttyputnomemory();
1562 	return(uc);
1563 }
1564 
1565 /*
1566  * routine to obtain the variable with the macro called "name".  Returns
1567  * NOVARIABLE if not found.
1568  */
us_getmacro(CHAR * name)1569 VARIABLE *us_getmacro(CHAR *name)
1570 {
1571 	REGISTER void *infstr;
1572 
1573 	infstr = initinfstr();
1574 	addstringtoinfstr(infstr, x_("USER_macro_"));
1575 	addstringtoinfstr(infstr, name);
1576 	return(getval((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, returninfstr(infstr)));
1577 }
1578 
1579 /*
1580  * routine to return the macro package named "name"
1581  */
us_getmacropack(CHAR * name)1582 MACROPACK *us_getmacropack(CHAR *name)
1583 {
1584 	REGISTER MACROPACK *pack;
1585 
1586 	for(pack = us_macropacktop; pack != NOMACROPACK; pack = pack->nextmacropack)
1587 		if (namesame(pack->packname, name) == 0) return(pack);
1588 	return(NOMACROPACK);
1589 }
1590 
1591 /*
1592  * routine to return address of popup menu whose name is "name"
1593  */
us_getpopupmenu(CHAR * name)1594 POPUPMENU *us_getpopupmenu(CHAR *name)
1595 {
1596 	REGISTER POPUPMENU *pm;
1597 
1598 	for(pm = us_firstpopupmenu; pm != NOPOPUPMENU; pm = pm->nextpopupmenu)
1599 		if (namesame(name, pm->name) == 0) return(pm);
1600 	return(NOPOPUPMENU);
1601 }
1602 
1603 /*
1604  * routine to append the parameters of user command "uc" to the infinite string.
1605  */
us_appendargs(void * infstr,USERCOM * uc)1606 void us_appendargs(void *infstr, USERCOM *uc)
1607 {
1608 	REGISTER INTBIG k;
1609 
1610 	for(k=0; k<uc->count; k++)
1611 	{
1612 		addtoinfstr(infstr, ' ');
1613 		addstringtoinfstr(infstr, uc->word[k]);
1614 	}
1615 }
1616 
1617 /*
1618  * routine to copy the string "str" to an infinite string and return it.
1619  * This is needed when a local string is being returned from a subroutine and
1620  * it will be destroyed on return.  It is also used to preserve strings from
1621  * dialogs which get destroyed when the dialog is closed.
1622  */
us_putintoinfstr(CHAR * str)1623 CHAR *us_putintoinfstr(CHAR *str)
1624 {
1625 	REGISTER void *infstr;
1626 
1627 	infstr = initinfstr();
1628 	addstringtoinfstr(infstr, str);
1629 	return(returninfstr(infstr));
1630 }
1631 
1632 /***************************** GENERAL DIALOG CONTROL *****************************/
1633 
1634 /*
1635  * Routine to declare a dialog routine in "routine" that will be called when
1636  * "ttygetparam()" is given the command-completion module "getlinecomcomp".
1637  * Also, if "terminputkeyword" is not zero, this is the keyword for the
1638  * "terminal input" command that invokes this dialog routine.
1639  */
DiaDeclareHook(CHAR * terminputkeyword,COMCOMP * getlinecomp,void (* routine)(void))1640 void DiaDeclareHook(CHAR *terminputkeyword, COMCOMP *getlinecomp, void (*routine)(void))
1641 {
1642 	DIALOGHOOK *dh;
1643 
1644 	dh = (DIALOGHOOK *)emalloc(sizeof (DIALOGHOOK), us_tool->cluster);
1645 	if (dh == 0) return;
1646 	if (terminputkeyword == 0) dh->terminputkeyword = 0; else
1647 		(void)allocstring(&dh->terminputkeyword, terminputkeyword, us_tool->cluster);
1648 	dh->getlinecomp = getlinecomp;
1649 	dh->routine = routine;
1650 	dh->nextdialoghook = us_firstdialoghook;
1651 	us_firstdialoghook = dh;
1652 }
1653 
1654 /*
1655  * Routine to find the command-completion object associated with the "terminal input"
1656  * keyword in "keyword".
1657  */
us_getcomcompfromkeyword(CHAR * keyword)1658 COMCOMP *us_getcomcompfromkeyword(CHAR *keyword)
1659 {
1660 	DIALOGHOOK *dh;
1661 
1662 	for(dh = us_firstdialoghook; dh != NODIALOGHOOK; dh = dh->nextdialoghook)
1663 	{
1664 		if (dh->terminputkeyword == 0) continue;
1665 		if (namesame(keyword, dh->terminputkeyword) == 0) return(dh->getlinecomp);
1666 	}
1667 	return(NOCOMCOMP);
1668 }
1669 
1670 /* List Dialog */
1671 static DIALOGITEM us_listdialogitems[] =
1672 {
1673  /*  1 */ {0, {160,216,184,280}, BUTTON, N_("OK")},
1674  /*  2 */ {0, {96,216,120,280}, BUTTON, N_("Cancel")},
1675  /*  3 */ {0, {56,8,200,206}, SCROLL, x_("")},
1676  /*  4 */ {0, {8,8,54,275}, MESSAGE, x_("")}
1677 };
1678 DIALOG us_listdialog = {{50,75,259,369}, x_(""), 0, 4, us_listdialogitems, 0, 0};
1679 
1680 /* special items for the "ttygetline" dialog: */
1681 #define DLST_LIST     3		/* line (scroll) */
1682 #define DLST_PROMPT   4		/* prompt (stat text) */
1683 
1684 /*
1685  * routine to get a string with "parameter" information (does command completion)
1686  */
ttygetparam(CHAR * prompt,COMCOMP * parameter,INTBIG keycount,CHAR * paramstart[])1687 INTBIG ttygetparam(CHAR *prompt, COMCOMP *parameter, INTBIG keycount, CHAR *paramstart[])
1688 {
1689 	INTBIG filetype, itemHit;
1690 	BOOLEAN multiplefiles;
1691 	REGISTER CHAR *pt, *next;
1692 	DIALOGHOOK *dh;
1693 	extern COMCOMP us_arrayxp, us_editcellp, us_spreaddp, us_artlookp,
1694 		us_defnodexsp, us_lambdachp, us_replacep, us_visiblelayersp, us_portlp,
1695 		us_copycellp, us_showp, us_gridalip, us_defarcsp, us_portep, us_menup,
1696 		us_yesnop, us_viewn1p, us_noyesp, us_colorpvaluep, us_viewfp, us_nodetptlp,
1697 		us_colorreadp, us_colorwritep, us_varvep, us_nodetp, us_showop, us_librarywp,
1698 		us_windowrnamep, us_technologyup, us_technologyedlp, us_librarydp, us_helpp,
1699 		us_technologyctdp, us_textdsp, us_librarywriteformatp, us_colorhighp,
1700 		us_showdp, us_renameop, us_renamenp, us_findnamep, us_librarynp, us_libraryrp,
1701 		us_nodetcaip, us_bindgkeyp, us_sizep, us_sizewp, us_defnodep, us_showup,
1702 		us_librarykp, us_findobjap, us_window3dp, us_gridp, us_technologytp, us_textfp,
1703 		us_renamecp, us_findnnamep, us_findexportp, us_noyesalwaysp, us_varop,
1704 		us_copycelldp, us_findnodep, us_technologycnnp, us_showep, us_purelayerp,
1705 		us_textsp, us_viewdp, us_interpretcp, us_findarcp, us_varvmp, us_showrp,
1706 		us_varbdp, us_portcp, us_showfp, us_varbs1p, us_findintp, us_viewc1p,
1707 		us_defnodenotp, us_nodetptmp;
1708 	REGISTER void *infstr, *dia;
1709 	Q_UNUSED( keycount );
1710 
1711 	/* is this necessary?  if not, us_pathiskey does not need to be global */
1712 	us_pathiskey = parameter->ifmatch;
1713 
1714 	for(dh = us_firstdialoghook; dh != NODIALOGHOOK; dh = dh->nextdialoghook)
1715 		if (parameter == dh->getlinecomp)
1716 	{
1717 		(*dh->routine)();
1718 		return(0);
1719 	}
1720 	if (parameter == &us_window3dp)           return(us_3ddepthdlog());
1721 	if (parameter == &us_showep)              return(us_aboutdlog());
1722 	if (parameter == &us_gridalip)            return(us_alignmentdlog());
1723 	if (parameter == &us_nodetcaip)           return(us_annularringdlog());
1724 	if (parameter == &us_sizewp)              return(us_arcsizedlog(paramstart));
1725 	if (parameter == &us_arrayxp)             return(us_arraydlog(paramstart));
1726 	if (parameter == &us_artlookp)            return(us_artlookdlog());
1727 	if (parameter == &us_varvmp)              return(us_attrenumdlog());
1728 	if (parameter == &us_varop)               return(us_attributesdlog());
1729 	if (parameter == &us_varbdp)              return(us_attrparamdlog());
1730 	if (parameter == &us_varbs1p)             return(us_attrreportdlog());
1731 	if (parameter == &us_copycellp)           return(us_copycelldlog(prompt));
1732 	if (parameter == &us_defnodenotp)         return(us_copyrightdlog());
1733 	if (parameter == &us_defarcsp)            return(us_defarcdlog());
1734 	if (parameter == &us_defnodexsp)          return(us_defnodedlog());
1735 	if (parameter == &us_textdsp)             return(us_deftextdlog(prompt));
1736 	if (parameter == &us_technologyedlp)      return(us_dependentlibdlog());
1737 	if (parameter == &us_editcellp)           return(us_editcelldlog(prompt));
1738 	if (parameter == &us_librarynp)           return(us_examineoptionsdlog());
1739 	if (parameter == &us_libraryrp)           return(us_findoptionsdlog());
1740 	if (parameter == &us_defnodep)            return(us_celldlog());
1741 	if (parameter == &us_showfp)              return(us_celllist());
1742 	if (parameter == &us_showdp)              return(us_cellselect(prompt, paramstart, 0));
1743 	if (parameter == &us_viewc1p)             return(us_cellselect(prompt, paramstart, 1));
1744 	if (parameter == &us_showup)              return(us_cellselect(_("Cell to delete"), paramstart, 2));
1745 	if (parameter == &us_textfp)              return(us_findtextdlog());
1746 	if (parameter == &us_viewfp)              return(us_frameoptionsdlog());
1747 	if (parameter == &us_showrp)              return(us_generaloptionsdlog());
1748 	if (parameter == &us_gridp)               return(us_griddlog());
1749 	if (parameter == &us_portcp)              return(us_globalsignaldlog());
1750 	if (parameter == &us_helpp)               return(us_helpdlog(prompt));
1751 	if (parameter == &us_colorhighp)          return(us_highlayerlog());
1752 	if (parameter == &us_copycelldp)          return(us_iconstyledlog());
1753 	if (parameter == &us_interpretcp)         return(us_javaoptionsdlog());
1754 	if (parameter == &us_lambdachp)           return(us_lambdadlog());
1755 	if (parameter == &us_librarydp)           return(us_librarypathdlog());
1756 	if (parameter == &us_technologycnnp)      return(us_libtotechnologydlog());
1757 	if (parameter == &us_textsp)              return(us_modtextsizedlog());
1758 	if (parameter == &us_menup)               return(us_menudlog(paramstart));
1759 	if (parameter == &us_viewn1p)             return(us_newviewdlog(paramstart));
1760 	if (parameter == &us_sizep)               return(us_nodesizedlog(paramstart));
1761 	if (parameter == &us_noyesp)              return(us_noyesdlog(prompt, paramstart));
1762 	if (parameter == &us_noyesalwaysp)        return(us_noyesalwaysdlog(prompt, paramstart));
1763 	if (parameter == &us_librarykp)           return(us_oldlibrarydlog());
1764 	if (parameter == &us_librarywp)           return(us_optionsavingdlog());
1765 	if (parameter == &us_colorpvaluep)        return(us_patterndlog());
1766 	if (parameter == &us_nodetptlp)           return(us_placetextdlog());
1767 	if (parameter == &us_librarywriteformatp) return(us_plotoptionsdlog());
1768 	if (parameter == &us_portlp)              return(us_portdisplaydlog());
1769 	if (parameter == &us_portep)              return(us_portdlog());
1770 	if (parameter == &us_bindgkeyp)           return(us_quickkeydlog());
1771 	if (parameter == &us_renameop)            return(us_renamedlog(VLIBRARY));
1772 	if (parameter == &us_renamenp)            return(us_renamedlog(VTECHNOLOGY));
1773 	if (parameter == &us_renamecp)            return(us_renamedlog(VPORTPROTO));
1774 	if (parameter == &us_findnamep)           return(us_renamedlog(VNODEPROTO));
1775 	if (parameter == &us_findintp)            return(us_renamedlog(VNETWORK));
1776 	if (parameter == &us_replacep)            return(us_replacedlog());
1777 	if (parameter == &us_nodetptmp)           return(us_romgendlog());
1778 	if (parameter == &us_findobjap)           return(us_selectoptdlog());
1779 	if (parameter == &us_findnnamep)          return(us_selectobjectdlog(0));
1780 	if (parameter == &us_findexportp)         return(us_selectobjectdlog(1));
1781 	if (parameter == &us_findnodep)           return(us_selectobjectdlog(2));
1782 	if (parameter == &us_findarcp)            return(us_selectobjectdlog(3));
1783 	if (parameter == &us_showp)               return(us_showdlog(FALSE));
1784 	if (parameter == &us_showop)              return(us_showdlog(TRUE));
1785 	if (parameter == &us_spreaddp)            return(us_spreaddlog());
1786 	if (parameter == &us_technologyup)        return(us_technologydlog(prompt, paramstart));
1787 	if (parameter == &us_technologytp)        return(us_techoptdlog());
1788 	if (parameter == &us_technologyctdp)      return(us_techvarsdlog());
1789 	if (parameter == &us_nodetp)              return(us_tracedlog());
1790 	if (parameter == &us_purelayerp)          return(us_purelayernodedlog(paramstart));
1791 	if (parameter == &us_varvep)              return(us_variablesdlog());
1792 	if (parameter == &us_viewdp)              return(us_viewdlog(1));
1793 	if (parameter == &us_visiblelayersp)      return(us_visiblelayersdlog(prompt));
1794 	if (parameter == &us_windowrnamep)        return(us_windowviewdlog());
1795 	if (parameter == &us_yesnop)              return(us_yesnodlog(prompt, paramstart));
1796 	if (parameter == &us_colorwritep || parameter == &us_colorreadp)
1797 	{
1798 		/* copy "prompt" to a temporary so that it can be modified */
1799 		infstr = initinfstr();
1800 		addstringtoinfstr(infstr, prompt);
1801 		prompt = returninfstr(infstr);
1802 
1803 		/* file dialog prompts have the form "type/prompt" */
1804 		filetype = el_filetypetext;
1805 		multiplefiles = FALSE;
1806 		for(pt = prompt; *pt != 0; pt++) if (*pt == '/') break;
1807 		if (*pt == '/')
1808 		{
1809 			*pt = 0;
1810 			if (namesamen(prompt, x_("multi-"), 6) == 0)
1811 			{
1812 				multiplefiles = TRUE;
1813 				prompt += 6;
1814 			}
1815 			filetype = getfiletype(prompt);
1816 			if (filetype == 0) filetype = el_filetypetext;
1817 			*pt++ = '/';
1818 			prompt = pt;
1819 		}
1820 		if (parameter == &us_colorwritep)
1821 		{
1822 			/* file output dialog prompts have the form "type/prompt|default" */
1823 			filetype |= FILETYPEWRITE;
1824 			pt = prompt;
1825 			while (*pt != 0 && *pt != '|') pt++;
1826 			if (*pt == 0)
1827 			{
1828 				next = (CHAR *)fileselect(prompt, filetype, x_(""));
1829 			} else
1830 			{
1831 				*pt = 0;
1832 				next = (CHAR *)fileselect(prompt, filetype, &pt[1]);
1833 				*pt = '|';
1834 			}
1835 			if (next == 0 || *next == 0) return(0);
1836 			setdefaultcursortype(WAITCURSOR);
1837 			paramstart[0] = next;
1838 			return(1);
1839 		} else
1840 		{
1841 			/* do dialog to get file name */
1842 			if (multiplefiles)
1843 			{
1844 				/* allow selection of multiple files */
1845 				next = multifileselectin(prompt, filetype);
1846 			} else
1847 			{
1848 				/* allow selection of one file */
1849 				next = (CHAR *)fileselect(prompt, filetype, x_(""));
1850 			}
1851 			if (next == 0 || *next == 0) return(0);
1852 			setdefaultcursortype(WAITCURSOR);
1853 			paramstart[0] = next;
1854 			return(1);
1855 		}
1856 	}
1857 
1858 	/* the general case: display the dialog box */
1859 	dia = DiaInitDialog(&us_listdialog);
1860 	if (dia == 0) return(0);
1861 	DiaInitTextDialog(dia, DLST_LIST, parameter->toplist, parameter->nextcomcomp, DiaNullDlogDone,
1862 		0, SCSELMOUSE|SCSELKEY|SCDOUBLEQUIT|SCHORIZBAR);
1863 	DiaSetText(dia, DLST_PROMPT, prompt);
1864 
1865 	for(;;)
1866 	{
1867 		itemHit = DiaNextHit(dia);
1868 		if (itemHit == OK || itemHit == CANCEL) break;
1869 	}
1870 	paramstart[0] = us_putintoinfstr(DiaGetScrollLine(dia, DLST_LIST, DiaGetCurLine(dia, DLST_LIST)));
1871 	DiaDoneDialog(dia);
1872 	if (itemHit == CANCEL) return(0);
1873 	return(1);
1874 }
1875 
1876 /***************************** GET FULL COMMAND *****************************/
1877 
1878 /* Full Input Dialog */
1879 static DIALOGITEM us_ttyfulldialogitems[] =
1880 {
1881  /*  1 */ {0, {160,328,184,392}, BUTTON, N_("OK")},
1882  /*  2 */ {0, {104,328,128,392}, BUTTON, N_("Cancel")},
1883  /*  3 */ {0, {24,8,56,408}, EDITTEXT, x_("")},
1884  /*  4 */ {0, {3,8,19,408}, MESSAGE, x_("")},
1885  /*  5 */ {0, {88,8,212,294}, SCROLL, x_("")},
1886  /*  6 */ {0, {72,56,88,270}, MESSAGE, N_("Type '?' for a list of options")}
1887 };
1888 static DIALOG us_ttyfulldialog = {{50,75,271,493}, N_("Command Completion"), 0, 6, us_ttyfulldialogitems, 0, 0};
1889 
1890 /* special items for the "ttygetline" dialog: */
1891 #define DGTF_LINE     3		/* line (edit text) */
1892 #define DGTF_PROMPT   4		/* prompt (stat text) */
1893 #define DGTF_OPTIONS  5		/* options (scroll) */
1894 
1895 /*
1896  * Routine to get a string with "parameter" information (does command completion).
1897  * Returns the number of strings parsed into "paramstart" (-1 if cancelled or
1898  * on error).
1899  */
ttygetfullparam(CHAR * prompt,COMCOMP * parameter,INTBIG keycount,CHAR * paramstart[])1900 INTBIG ttygetfullparam(CHAR *prompt, COMCOMP *parameter, INTBIG keycount,
1901 	CHAR *paramstart[])
1902 {
1903 	INTBIG i, itemHit;
1904 	CHAR *line;
1905 	REGISTER void *infstr, *dia;
1906 
1907 	/* initialize for command completion */
1908 	us_expandttybuffers(80);
1909 	us_pacurchar = 0;
1910 	us_pattyline[0] = 0;
1911 	us_paparamstart[us_paparamcount = 0] = us_pattyline;
1912 	us_paparamtype[us_paparamcount] = parameter;
1913 	us_paparamtype[us_paparamcount+1] = &us_panullcomcomp;
1914 	us_paparamtotal = 2;
1915 	us_painquote = FALSE;
1916 
1917 	/* display the dialog box */
1918 	dia = DiaInitDialog(&us_ttyfulldialog);
1919 	if (dia == 0) return(-1);
1920 	DiaInitTextDialog(dia, DGTF_OPTIONS, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1, 0);
1921 
1922 	/* load header message */
1923 	infstr = initinfstr();
1924 	if (*parameter->noise != 0)
1925 	{
1926 		addstringtoinfstr(infstr, parameter->noise);
1927 		if (parameter->def != 0)
1928 			formatinfstr(infstr, x_(" (%s)"), parameter->def);
1929 	} else addstringtoinfstr(infstr, prompt);
1930 	DiaSetText(dia, DGTF_PROMPT, returninfstr(infstr));
1931 
1932 	for(;;)
1933 	{
1934 		itemHit = DiaNextHit(dia);
1935 		if (itemHit == OK || itemHit == CANCEL) break;
1936 
1937 		if (itemHit == DGTF_LINE)
1938 		{
1939 			line = DiaGetText(dia, DGTF_LINE);
1940 			for(i=0; line[i] == us_pattyline[i] && line[i] != 0; i++);
1941 			if (us_pattyline[i] != 0) us_pabackup(i);
1942 			for(; line[i] != 0; i++) us_pahandlechar(dia, line[i]);
1943 			if (estrcmp(us_pattyline, line) != 0) DiaSetText(dia, DGTF_LINE, us_pattyline);
1944 		}
1945 	}
1946 
1947 	/* parse the line if not cancelled */
1948 	if (itemHit == CANCEL) us_paparamcount = -1; else
1949 	{
1950 		us_paparamcount++;
1951 		for(i=1; i<us_paparamcount; i++) (us_paparamstart[i])[-1] = 0;
1952 		if (*us_paparamstart[us_paparamcount-1] == 0) us_paparamcount--;
1953 		if(us_paparamcount>keycount) us_paparamcount = keycount;
1954 		for(i=0; i<us_paparamcount; i++) paramstart[i] = us_paparamstart[i];
1955 	}
1956 	DiaDoneDialog(dia);
1957 	return(us_paparamcount);
1958 }
1959 
1960 /*
1961  * Routine to handle next char
1962  */
us_pahandlechar(void * dia,INTBIG c)1963 static BOOLEAN us_pahandlechar(void *dia, INTBIG c)
1964 {
1965 	REGISTER INTBIG i, j, k, nofill, noshoall, isbreak, nmatch;
1966 	REGISTER BOOLEAN topval;
1967 	REGISTER INTBIG (*setparams)(CHAR*, COMCOMP*[], CHAR);
1968 	REGISTER BOOLEAN (*toplist)(CHAR**);
1969 	REGISTER CHAR *initialline, *pt, realc, *breakch, *(*nextinlist)(void);
1970 	CHAR *compare;
1971 	REGISTER COMCOMP *thiscomcomp;
1972 	COMCOMP *nextparams[MAXKEYWORD];
1973 	REGISTER void *infstr;
1974 
1975 	/* continue parsing word number "us_paparamcount" */
1976 	thiscomcomp = us_paparamtype[us_paparamcount];
1977 	initialline = us_paparamstart[us_paparamcount];
1978 
1979 	if ((thiscomcomp->interpret&NOSHOALL) != 0) noshoall = 1; else
1980 		noshoall = 0;
1981 	if ((thiscomcomp->interpret&NOFILL) != 0) nofill = 1; else
1982 		nofill = 0;
1983 	us_pathiskey = thiscomcomp->ifmatch;
1984 	if (*initialline == '$')
1985 	{
1986 		/* special case for variables */
1987 		toplist = us_topofvars;
1988 		nextinlist = us_nextvars;
1989 	} else
1990 	{
1991 		toplist = thiscomcomp->toplist;
1992 		nextinlist = thiscomcomp->nextcomcomp;
1993 	}
1994 	setparams = thiscomcomp->params;
1995 	breakch = thiscomcomp->breakchrs;
1996 
1997 	/* provide help if requested */
1998 	if (c == '?' && !us_painquote)
1999 	{
2000 		/* initialize scrolled list of choices */
2001 		DiaLoadTextDialog(dia, 5, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
2002 
2003 		compare = initialline;
2004 		topval = (*toplist)(&compare);
2005 		if (*thiscomcomp->noise != 0)
2006 		{
2007 			infstr = initinfstr();
2008 			addstringtoinfstr(infstr, thiscomcomp->noise);
2009 			if (thiscomcomp->def != 0)
2010 			{
2011 				addstringtoinfstr(infstr, x_(" ("));
2012 				addstringtoinfstr(infstr, thiscomcomp->def);
2013 				addtoinfstr(infstr, ')');
2014 			}
2015 			if (topval) addtoinfstr(infstr, ':');
2016 			DiaStuffLine(dia, 5, returninfstr(infstr));
2017 		}
2018 
2019 		if (*compare != 0 || noshoall == 0)
2020 		{
2021 			for(i=0; (pt = (*nextinlist)()); )
2022 			{
2023 				j = stringmatch(pt, compare);
2024 				if (j == -1) continue;
2025 				if (j == -2) j = estrlen(pt);
2026 				if (j > i) i = j;
2027 			}
2028 			if (i == 0 && *compare != 0) ttybeep(SOUNDBEEP, TRUE); else
2029 			{
2030 				compare = initialline;
2031 				for((void)(*toplist)(&compare); (pt = (*nextinlist)()); )
2032 				{
2033 					j = stringmatch(pt, compare);
2034 					if (j == -1) continue;
2035 					if (j == i || j == -2) DiaStuffLine(dia, 5, pt);
2036 				}
2037 			}
2038 		}
2039 		DiaSelectLine(dia, 5, -1);
2040 		return(FALSE);
2041 	}
2042 
2043 	/* check for quoted strings */
2044 	if (c == '"') us_painquote = !us_painquote;
2045 
2046 	/* see if this is a break character */
2047 	isbreak = 0;
2048 	realc = 0;
2049 	if (!us_painquote)
2050 		for(pt = breakch; *pt != 0; pt++)
2051 			if (c == *pt) { isbreak++;  break; }
2052 	if (isbreak != 0) { realc = (CHAR)c;   c = ' '; }
2053 
2054 	/* ignore break characters at the start of a keyword */
2055 	if ((c == ESCKEY || isbreak != 0) && *initialline == 0) return(FALSE);
2056 
2057 	/* fill out keyword if a break character is reached */
2058 	if (c == ESCKEY || isbreak != 0 || c == '\n' || c == '\r')
2059 	{
2060 		compare = initialline;
2061 		if (*compare != 0)
2062 		{
2063 			i = nmatch = 0;
2064 			us_paextra[0] = 0;
2065 			for((void)(*toplist)(&compare); (pt = (*nextinlist)());)
2066 			{
2067 				j = stringmatch(pt, compare);
2068 				if (j == -1) continue;
2069 				if (j == -2)
2070 				{
2071 					us_paextra[0] = 0;
2072 					i = estrlen(pt);
2073 					nmatch = 1;
2074 					break;
2075 				}
2076 				if (j > i)
2077 				{
2078 					if ((INTBIG)estrlen(&pt[j]) >= us_patruelength)
2079 						us_expandttybuffers(estrlen(&pt[j])+10);
2080 					estrcpy(us_paextra, &pt[j]);
2081 					i = j;
2082 					nmatch = 1;
2083 				} else if (j == i)
2084 				{
2085 					for(j=0; us_paextra[j]; j++) if (pt[i+j] != us_paextra[j]) us_paextra[j] = 0;
2086 					nmatch++;
2087 				}
2088 			}
2089 
2090 			/* fill out the keyword if possible */
2091 			if ((nofill == 0 || c == ESCKEY) && us_paextra[0] != 0)
2092 			{
2093 				if (us_pacurchar+(INTBIG)estrlen(us_paextra) >= us_patruelength)
2094 					us_expandttybuffers(us_pacurchar+estrlen(us_paextra)+10);
2095 				(void)estrcat(&us_pattyline[us_pacurchar], us_paextra);
2096 				us_pacurchar += estrlen(us_paextra);
2097 			}
2098 
2099 			/* print an error bell if there is ambiguity */
2100 			if (nmatch != 1 && nofill == 0 && c != ESCKEY) ttybeep(SOUNDBEEP, TRUE);
2101 		};
2102 
2103 		/* if an escape was typed, stop after filling in the keyword */
2104 		if (c == ESCKEY) return(FALSE);
2105 
2106 		/* if normal break character was typed, advance to next keyword */
2107 		if (isbreak != 0)
2108 		{
2109 			/* find out number of parameters to this keyword */
2110 			k = (*setparams)(initialline, nextparams, realc);
2111 
2112 			/* clip to the number of allowable parameters */
2113 			if (k+us_paparamtotal > MAXKEYWORD)
2114 			{
2115 				ttyputmsg(_("Full number of parameters is more than %d"), MAXKEYWORD);
2116 				k = MAXKEYWORD - us_paparamcount;
2117 			}
2118 
2119 			/* spread open the list */
2120 			for(j=us_paparamtotal-1; j > us_paparamcount; j--)
2121 				us_paparamtype[j+k] = us_paparamtype[j];
2122 			us_paparamtotal += k;
2123 
2124 			/* fill in the parameter types */
2125 			for(j = 0; j < k; j++)
2126 				us_paparamtype[us_paparamcount+j+1] = nextparams[j];
2127 			us_paparamadded[us_paparamcount] = k;
2128 			us_paparamcount++;
2129 
2130 			pt = &us_pattyline[us_pacurchar];
2131 			if (us_pacurchar >= us_patruelength)
2132 				us_expandttybuffers(us_pacurchar+10);
2133 			*pt = realc;   pt[1] = 0;
2134 			us_pacurchar++;
2135 			us_paparamstart[us_paparamcount] = &us_pattyline[us_pacurchar];
2136 			return(FALSE);
2137 		}
2138 
2139 		/* if this is the end of the line, signal so */
2140 		if (c == '\n' || c == '\r') return(TRUE);
2141 	}
2142 
2143 	/* normal character: add it to the input string */
2144 	if (us_pacurchar >= us_patruelength) us_expandttybuffers(us_pacurchar+10);
2145 	pt = &us_pattyline[us_pacurchar];
2146 	*pt = (CHAR)c;   pt[1] = 0;
2147 	us_pacurchar++;
2148 
2149 	return(FALSE);
2150 }
2151 
2152 /*
2153  * Routine to return to previous state when number of matching chars diminishes to "to_curchar"
2154  */
us_pabackup(INTBIG to_curchar)2155 static void us_pabackup(INTBIG to_curchar)
2156 {
2157 	REGISTER INTBIG j, k;
2158 
2159 	while (us_pacurchar > to_curchar) {
2160 		/* back up one character */
2161 		if (us_pattyline[--us_pacurchar] == '"') us_painquote = !us_painquote;
2162 		us_pattyline[us_pacurchar] = 0;
2163 
2164 		/* special case if just backed up over a word boundary */
2165 		if (&us_pattyline[us_pacurchar] < us_paparamstart[us_paparamcount])
2166 		{
2167 			/* remove any added parameters from the last keyword */
2168 			k = us_paparamadded[us_paparamcount-1];
2169 			us_paparamtotal -= k;
2170 			for(j=us_paparamcount; j < us_paparamtotal; j++) us_paparamtype[j] = us_paparamtype[j+k];
2171 
2172 			us_paparamcount--;
2173 		}
2174 	}
2175 }
2176 
2177 /*
2178  * Routine to expand the buffers "us_pattyline" and "us_paextra" to "amt" long
2179  */
us_expandttybuffers(INTBIG amt)2180 static void us_expandttybuffers(INTBIG amt)
2181 {
2182 	REGISTER CHAR *newline, *newextra;
2183 	REGISTER INTBIG i;
2184 
2185 	/* stop now if request is already satisfied */
2186 	if (amt <= us_patruelength) return;
2187 
2188 	/* allocate new buffers */
2189 	newline = (CHAR *)emalloc((amt+1) * SIZEOFCHAR, us_tool->cluster);
2190 	if (newline == 0) return;
2191 	newextra = (CHAR *)emalloc((amt+1) * SIZEOFCHAR, us_tool->cluster);
2192 	if (newextra == 0) return;
2193 
2194 	/* preserve any old buffers */
2195 	if (us_pattyline != 0)
2196 	{
2197 		for(i=0; i<us_patruelength; i++)
2198 		{
2199 			newline[i] = us_pattyline[i];
2200 			newextra[i] = us_paextra[i];
2201 		}
2202 		if (us_paparamstart != 0)
2203 			for(i=0; i<=us_paparamcount; i++)
2204 				us_paparamstart[i] = us_paparamstart[i] - us_pattyline + newline;
2205 		efree(us_pattyline);
2206 		efree(us_paextra);
2207 	}
2208 
2209 	/* set the new buffers */
2210 	us_pattyline = newline;
2211 	us_paextra = newextra;
2212 	us_patruelength = amt;
2213 }
2214 
2215 /*
2216  * internal routines to search keyword lists for command completion:
2217  */
us_patoplist(CHAR ** a)2218 BOOLEAN us_patoplist(CHAR **a)
2219 {
2220 	Q_UNUSED( a );
2221 
2222 	us_pathisind = 0;
2223 	if (us_pathiskey == NOKEYWORD) return(FALSE);
2224 	if (us_pathiskey[0].name == 0) return(FALSE);
2225 	return(TRUE);
2226 }
2227 
us_panextinlist(void)2228 CHAR *us_panextinlist(void)
2229 {
2230 	if (us_pathiskey == NOKEYWORD) return(0);
2231 	return(us_pathiskey[us_pathisind++].name);
2232 }
2233 
us_paparams(CHAR * word,COMCOMP * arr[],CHAR breakc)2234 INTBIG us_paparams(CHAR *word, COMCOMP *arr[], CHAR breakc)
2235 {
2236 	REGISTER INTBIG i, count, ind;
2237 	Q_UNUSED( breakc );
2238 
2239 	if (*word == 0 || us_pathiskey == NOKEYWORD) return(0);
2240 	for(ind=0; us_pathiskey[ind].name != 0; ind++)
2241 		if (namesame(word, us_pathiskey[ind].name) == 0) break;
2242 	if (us_pathiskey[ind].name == 0) return(0);
2243 	count = us_pathiskey[ind].params;
2244 	for(i=0; i<count; i++) arr[i] = us_pathiskey[ind].par[i];
2245 	return(count);
2246 }
2247