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(¶msave, 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