1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12 #include <sys/types.h>
13
14 #if defined(HAVE_ERRNO_H)
15 #include <errno.h>
16 #endif
17
18 #if defined(HAVE_DIRENT_H)
19 #include <dirent.h>
20 #endif
21
22 #if defined(HAVE_IO_H)
23 #include <io.h>
24 #endif
25
26 #if defined(HAVE_SYS_STAT_H)
27 #include <sys/stat.h>
28 #endif
29
30 #include <stdio.h>
31
32 #define Ark Ark
33 #include <dx/arch.h>
34 #undef Ark
35
36 #include "lex.h"
37 #include "MacroDefinition.h"
38 #include "MacroNode.h"
39 #include "ListIterator.h"
40 #include "DXApplication.h"
41 #include "Network.h"
42 #include "ErrorDialogManager.h"
43 #include "WarningDialogManager.h"
44 #include "ParseMDF.h"
45 #include "ParameterDefinition.h"
46 #include "ToolSelector.h"
47 #include "EditorWindow.h"
48 #include "SaveMacroCommand.h"
49
50 #define OLD_DUMMY_DESCRIPTION_STRING "Generated dummy input"
51
52 #if HAVE_REGCOMP && HAVE_REGEX_H
53 /* prefer POSIX style regcomp(3) over obsolete versions */
54 extern "C" {
55 #include <regex.h>
56 }
57 #undef HAVE_RE_COMP
58 #undef HAVE_FINDFIRST
59 #elif defined(HAVE_RE_COMP)
60 #undef HAVE_REGCMP
61 #undef HAVE_REGCOMP
62 #undef HAVE__FINDFIRST
63 extern "C" char *re_comp(char *s);
64 extern "C" int re_exec(char *);
65 #elif defined(HAVE_REGCMP)
66 #undef HAVE_REGCOMP
67 #undef HAVE__FINDFIRST
68 extern "C" char *regcmp(...);
69 extern "C" char *regex(char *, char *, ...);
70 #elif HAVE_REGCOMP && HAVE_REGEXP_H
71 extern "C" {
72 #include <regexp.h>
73 }
74 #undef HAVE_RE_COMP
75 #undef HAVE__FINDFIRST
76 #elif defined(HAVE_RE_COMP)
77 #undef HAVE__FINDFIRST
78 extern "C" char *re_comp(char *s);
79 extern "C" int re_exec(char *);
80 #endif
81
MacroDefinition(boolean system)82 MacroDefinition::MacroDefinition(boolean system) :
83 NodeDefinition()
84 {
85 this->systemMacro = system;
86 this->fileName = NULL;
87 this->body = NULL;
88 this->initialRead = FALSE;
89 this->updatingServer = FALSE;
90 this->category = 0;
91 if (!system)
92 this->saveCmd = new SaveMacroCommand("saveMacroCommand",
93 theDXApplication->getCommandScope(),
94 TRUE,
95 this);
96 }
~MacroDefinition()97 MacroDefinition::~MacroDefinition()
98 {
99 if (this->saveCmd) delete this->saveCmd;
100
101 if (this->body)
102 {
103 this->body->setDefinition(NULL);
104 theDXApplication->macroList.removeElement(this->body);
105 if (!this->body->isDeleted())
106 delete this->body;
107 this->body = NULL;
108 }
109 if (this->fileName)
110 delete[] this->fileName;
111 }
112
finishDefinition()113 void MacroDefinition::finishDefinition()
114 {
115 }
116
117
newNode(Network * net,int instance)118 Node *MacroDefinition::newNode(Network *net, int instance)
119 {
120 MacroNode *d = new MacroNode(this, net, instance);
121 return d;
122 }
123
reference(MacroNode * n)124 void MacroDefinition::reference(MacroNode *n)
125 {
126 ListIterator li(this->referencingNodes);
127 Node *listNode;
128 while ( (listNode = (MacroNode*)li.getNext()) )
129 if (n == listNode)
130 return;
131 this->referencingNodes.appendElement(n);
132 }
133
dereference(MacroNode * n)134 void MacroDefinition::dereference(MacroNode *n)
135 {
136 ListIterator li(this->referencingNodes);
137 Node *listNode;
138 while ( (listNode = (MacroNode*)li.getNext()) )
139 {
140 if (n == listNode)
141 {
142 this->referencingNodes.deleteElement(li.getPosition()-1);
143 break;
144 }
145 }
146 // if (this->referencingNodes.getSize() == 0 && this->body != NULL)
147 // {
148 // theDXApplication->macroList.removeElement(this->body);
149 // delete this->body;
150 // this->body = NULL;
151 // }
152 }
153
printNetworkBody(FILE * f,PrintType ptype)154 boolean MacroDefinition::printNetworkBody(FILE *f, PrintType ptype)
155 {
156 if (!this->loadNetworkBody())
157 return FALSE;
158 return this->body->printNetwork(f,ptype);
159 }
loadNetworkBody()160 boolean MacroDefinition::loadNetworkBody()
161 {
162 if (this->body == NULL)
163 {
164 this->body = theDXApplication->newNetwork();
165 this->body->setDefinition(this);
166 this->initialRead = TRUE;
167 boolean r = this->body->readNetwork(this->fileName);
168 this->initialRead = FALSE;
169 if (!r) {
170 this->body->setDefinition(NULL);
171 Network *n = this->body;
172 this->body = NULL;
173 delete n;
174 return FALSE;
175 } else {
176 theDXApplication->macroList.appendElement(this->body);
177 }
178 }
179 return TRUE;
180 }
updateServer()181 boolean MacroDefinition::updateServer()
182 {
183 if (!this->loadNetworkBody())
184 return FALSE;
185
186 if (this->body && !this->updatingServer) {
187 //
188 // There is a recursive loop between DXExecCtl::updateMacros(),
189 // Network::sendValues(), MacroNode::sendValues() and
190 // this->updateServer() that we try and avoid here.
191 //
192 this->updatingServer = TRUE;
193 theDXApplication->getExecCtl()->updateMacros(FALSE);
194 this->updatingServer = FALSE;
195 }
196 return (this->body != NULL);
197 }
198
setNodeDefinitions(MacroDefinition * newDef)199 boolean MacroDefinition::setNodeDefinitions(MacroDefinition *newDef)
200 {
201 ListIterator li(this->referencingNodes);
202 MacroNode *n;
203
204 while ( (n = (MacroNode*)li.getNext()) )
205 {
206 n->setDefinition(newDef);
207 n->updateDefinition();
208 if (newDef != this)
209 newDef->reference(n);
210 }
211
212 return TRUE;
213 }
214
setFileName(const char * n)215 void MacroDefinition::setFileName(const char *n)
216 {
217 char *fileName = DuplicateString(n);
218 if (this->fileName)
219 delete[] this->fileName;
220 this->fileName = fileName;
221 }
222
LoadMacroFile(FILE * f,const char * fileName,boolean replace,boolean * wasMacro,boolean asSystemMacro)223 boolean MacroDefinition::LoadMacroFile(FILE *f,
224 const char *fileName,
225 boolean replace,
226 boolean *wasMacro,
227 boolean asSystemMacro)
228 {
229
230 if (theDXApplication->inDebugMode())
231 printf("read macro from %s\n", fileName);
232
233 char *p, line[1000];
234 boolean inMDF = FALSE;
235 int lineNo = 0;
236 MacroDefinition *md = NULL;
237 NodeDefinition *nd = NULL;
238 MacroDefinition *oldMd = NULL;
239 SymbolManager *symbolManager = theNodeDefinitionDictionary->
240 getSymbolManager();
241 // statefull-ness. Remember which INPUT was added most recently so
242 // that the OPTIONS keyword can associate with it. Ensure the
243 // most_recent_param is set to NULL if INPUT isn't followed
244 // by an OPTIONS keyword.
245 ParameterDefinition* most_recent_param = NULL;
246
247 #define EQUAL_STRING_SECOND_LEN(s1,s2) (EqualSubstring((s1), (s2), STRLEN(s2)))
248 while(fgets(line, sizeof(line), f) == line)
249 {
250 // Convert possible dos-land carriage returns (ctrl-M) to white space
251 int len = STRLEN(line);
252 if (len > 1 && line[len-2] == '\15')
253 {
254 line[len-2] = line[len-1];
255 line[len-1] = '\0';
256 len--;
257 }
258 lineNo++;
259 if (EQUAL_STRING_SECOND_LEN(line, "// Begin MDF"))
260 {
261 inMDF = TRUE;
262 }
263 else if (inMDF && EQUAL_STRING_SECOND_LEN(line, "// End MDF"))
264 {
265 inMDF = FALSE;
266 break;
267 }
268 else if (!inMDF && EQUAL_STRING_SECOND_LEN(line, "// MODULE"))
269 {
270 if (theDXApplication->inDebugMode())
271 printf("Macro rejected\n");
272 if (wasMacro)
273 *wasMacro = FALSE;
274 goto error;
275 }
276 else if (inMDF && EQUAL_STRING_SECOND_LEN(line, "// MODULE"))
277 {
278 if (wasMacro)
279 *wasMacro = TRUE;
280
281 char name[1000];
282 int items_parsed = sscanf(line, "// MODULE %[^\n]", name);
283 if (items_parsed != 1)
284 {
285 ErrorMessage("Invalid MODULE comment at line %d of %s.",
286 lineNo, fileName);
287 goto error;
288 }
289
290 int index = 0;
291 if (!IsRestrictedIdentifier(name, index) ||
292 (index != STRLEN(name) && !IsWhiteSpace(name, index)))
293 {
294 ErrorMessage("Invalid macro name: %s must start with a letter "
295 "and contain only letters and numbers "
296 "at line %d of %s.",
297 name, lineNo, fileName);
298 goto error;
299 }
300
301 if (EqualString("main", name))
302 {
303 ErrorMessage("The macro name must not be \"main\" "
304 "at line %d of %s.", lineNo, fileName);
305 goto error;
306 }
307
308 nd =
309 (NodeDefinition*)theNodeDefinitionDictionary->
310 findDefinition(name);
311 if (nd)
312 {
313 if (!nd->isDerivedFromMacro())
314 {
315 ErrorMessage("Standard module \"%s\" cannot be redefined.\n"
316 "Macro file \"%s\" not loaded.",
317 name, fileName);
318 goto error;
319 }
320 else if (!replace)
321 {
322 // WarningMessage("Macro \"%s\" is already defined.\n"
323 // "Macro file \"%s\" not loaded.",
324 // name, fileName);
325 goto error;
326 }
327 oldMd = (MacroDefinition*)nd;
328 }
329 md = new MacroDefinition(asSystemMacro);
330 md->setName(name);
331 md->setFileName(fileName);
332 if (nd)
333 md->setNextInstance(nd->newInstanceNumber());
334 }
335 else if (inMDF && EQUAL_STRING_SECOND_LEN(line, "// CATEGORY"))
336 {
337 char cat[1000];
338 int items_parsed = sscanf(line, "// CATEGORY %[^\n]", cat);
339 if (items_parsed != 1)
340 {
341 ErrorMessage("Invalid CATEGORY comment at line %d of %s.",
342 lineNo, fileName);
343 goto error;
344 }
345 md->setCategory(symbolManager->registerSymbol(cat));
346 }
347 else if (inMDF && EQUAL_STRING_SECOND_LEN(line, "// DESCRIPTION"))
348 {
349 char desc[1000];
350 int items_parsed = sscanf(line, "// DESCRIPTION %[^\n]", desc);
351 if (items_parsed != 1)
352 {
353 ErrorMessage("Invalid DESCRIPTION comment at line %d of %s.",
354 lineNo, fileName);
355 goto error;
356 }
357 md->setDescription(desc);
358 }
359 else if (inMDF && EQUAL_STRING_SECOND_LEN(line, "// INPUT"))
360 {
361 char name[1000];
362 char types[1000];
363 char deflt[1000];
364 char descr[1000];
365 int items_parsed = sscanf(line,
366 "// INPUT %[^;]; %[^;]; %[^;]; %[^\n]",
367 name, types, deflt, descr);
368 if (items_parsed != 3 && items_parsed != 4)
369 {
370 ErrorMessage("Invalid INPUT comment at line %d of %s.",
371 lineNo, fileName);
372 goto error;
373 }
374
375 int index = 0;
376 // ... to avoid millions of purify umrs
377 int len = STRLEN(name);
378 name[len] = name[len+1] = '\0';
379 if (!IsIdentifier(name, index) ||
380 (index != STRLEN(name) && !IsWhiteSpace(name, index) &&
381 name[index] != '['))
382 {
383 ErrorMessage("Invalid parameter name at line %d of %s.",
384 lineNo, fileName);
385 goto error;
386 }
387 name[index++] = '\0';
388 int visattr = 1;
389 if ( (p = strstr(&name[index],"visible:")) ) {
390 p += strlen("visible:");
391 visattr = atoi(p);
392 }
393
394 ParameterDefinition *pd = new
395 ParameterDefinition(symbolManager->registerSymbol(name));
396 if (items_parsed == 4) {
397 if (strstr(descr,DUMMY_DESCRIPTION_STRING) ||
398 strstr(descr,OLD_DUMMY_DESCRIPTION_STRING))
399 pd->setDummy(TRUE);
400 else
401 pd->setDescription(descr);
402 }
403 switch (visattr) {
404 case 0: pd->setDefaultVisibility(FALSE); break;
405 case 1: pd->setDefaultVisibility(TRUE); break;
406 case 2: pd->setViewability(FALSE); break;
407 }
408 pd->markAsInput();
409 if (!ParseMDFTypes(pd, types, lineNo))
410 {
411 delete pd;
412 goto error;
413 }
414
415 if (*deflt == '(')
416 {
417 pd->setDescriptiveValue(deflt);
418 if (EqualString(deflt,"(none)"))
419 pd->setRequired();
420 }
421 else if (!pd->setDefaultValue(deflt))
422 {
423 ErrorMessage(
424 "Invalid default parameter value at line %d of %s.",
425 lineNo, fileName);
426
427 delete pd;
428 pd = NULL;
429 goto error;
430 }
431 md->addInput(pd);
432 most_recent_param = pd;
433 }
434 else if (most_recent_param && EQUAL_STRING_SECOND_LEN(line, "// OPTIONS"))
435 {
436 // must convert trailing \n to whitespace because
437 // ParseMDFOptions expects it that way.
438 int len = STRLEN(line);
439 if (line[len-1] == '\n') line[len-1] = '\0';
440 if (!ParseMDFOptions (most_recent_param, &line[11])) {
441 ErrorMessage(
442 "Invalid parameter options values at line %d of %s.",
443 lineNo, fileName);
444 }
445 }
446 else if (inMDF && EQUAL_STRING_SECOND_LEN(line, "// OUTPUT"))
447 {
448 char name[1000];
449 char types[1000];
450 char descr[1000];
451 int items_parsed = sscanf(line,
452 "// OUTPUT %[^;]; %[^;]; %[^\n]",
453 name, types, descr);
454 if (items_parsed != 2 && items_parsed != 3)
455 {
456 ErrorMessage("Invalid OUTPUT comment at line %d of %s.",
457 lineNo, fileName);
458 goto error;
459 }
460
461 int index = 0;
462 // ... to avoid millions of purify umrs
463 int len = STRLEN(name);
464 name[len] = name[len+1] = '\0';
465 if (!IsIdentifier(name, index) ||
466 (index != STRLEN(name) && !IsWhiteSpace(name, index) &&
467 name[index] != '['))
468 {
469 ErrorMessage("Invalid parameter name at line %d of %s.",
470 lineNo, fileName);
471 goto error;
472 }
473
474 name[index++]='\0';
475 int visattr = 1;
476 if ( (p = strstr(&name[index],"visible:")) ) {
477 p += strlen("visible:");
478 visattr = atoi(p);
479 }
480
481 ParameterDefinition *pd = new
482 ParameterDefinition(symbolManager->registerSymbol(name));
483 if (items_parsed == 3) {
484 if (strstr(descr,DUMMY_DESCRIPTION_STRING) ||
485 strstr(descr,OLD_DUMMY_DESCRIPTION_STRING))
486 pd->setDummy(TRUE);
487 else
488 pd->setDescription(descr);
489 }
490 switch (visattr) {
491 case 0: pd->setDefaultVisibility(FALSE); break;
492 case 1: pd->setDefaultVisibility(TRUE); break;
493 case 2: pd->setViewability(FALSE); break;
494 }
495 pd->markAsOutput();
496 if (!ParseMDFTypes(pd, types, lineNo))
497 {
498 delete pd;
499 goto error;
500 }
501
502 md->addOutput(pd);
503 }
504 else if (inMDF)
505 {
506 WarningMessage("Encountered unrecognized MDF line "
507 "at line %d of `%s', ignored.",
508 lineNo, fileName);
509 }
510 if (!EQUAL_STRING_SECOND_LEN(line, "// INPUT")) {
511 most_recent_param = NULL;
512 }
513 }
514
515 if (!md)
516 goto error;
517
518 md->completeDefinition();
519
520 if (!asSystemMacro) {
521 if (oldMd)
522 {
523 oldMd->setNodeDefinitions(md);
524 ToolSelector::RemoveTool(oldMd->getCategorySymbol(),
525 oldMd->getNameSymbol());
526 //
527 // Check if the macro is changed.
528 //
529 if (oldMd->body &&oldMd->saveCmd &&
530 oldMd->body->saveToFileRequired())
531 {
532 ((SaveMacroCommand*)oldMd->saveCmd)->setNext(NULL);
533 oldMd->saveCmd->execute();
534 }
535 else
536 delete oldMd;
537 }
538 }
539
540 theNodeDefinitionDictionary->replaceDefinition(md->getNameString(), md);
541
542 if (!asSystemMacro) {
543 ToolSelector::AddTool(md->getCategorySymbol(),
544 md->getNameSymbol(),
545 (void *)md);
546 ToolSelector::UpdateCategoryListWidget();
547 }
548
549
550 if (theDXApplication->inDebugMode())
551 printf("Macro %s accepted\n", md->getNameString());
552
553 return TRUE;
554
555 error:
556 if (md)
557 delete md;
558 return FALSE;
559 }
560
561 //
562 // Load all .net files in the given directory that are macros.
563 // If replace is TRUE, then replace any current definitions with the
564 // new one, otherwise ignore the .net file.
565 // If errmsg is not NULL and an error occurs then, no error messages are
566 // posted, and instead a string buffer is allocated to hold the error
567 // message that would have been posted and returned. The returned
568 // string must be freed by the caller.
569 //
LoadMacroDirectories(const char * path,boolean replace,char ** errmsg,boolean asSystemMacro)570 boolean MacroDefinition::LoadMacroDirectories(const char *path,
571 boolean replace, char **errmsg,
572 boolean asSystemMacro)
573 {
574 boolean wasEncoded;
575 boolean return_code = TRUE;
576
577 if (path == NULL)
578 return TRUE;
579
580 #ifndef DXD_NON_UNIX_ENV_SEPARATOR
581 #define SEP_CHAR ':'
582 #else
583 #define SEP_CHAR ';'
584 #endif
585
586 char *originalString = DuplicateString(path);
587 char *sptr = originalString;
588
589 if (errmsg)
590 *errmsg = NULL;
591
592 while(sptr)
593 {
594 char *nsptr = sptr;
595 char *sep = strchr(nsptr, SEP_CHAR);
596 if (sep)
597 {
598 *sep = '\0';
599 sptr = sep + 1;
600 }
601 else
602 {
603 sptr = NULL;
604 }
605
606 #if defined(HAVE_OPENDIR) && defined(HAVE_DIRENT_H)
607 DIR* d = opendir(nsptr);
608 if (!d)
609 #elif defined(HAVE_SYS_STAT_H)
610 struct STATSTRUCT b;
611 int d = STATFUNC(nsptr, &b);
612 if (d == -1)
613 #else
614 No directory tools?
615 #endif
616
617 {
618 char *errtxt = "Failed opening directory %s: %s";
619 if (errmsg) {
620 int size = STRLEN(errtxt) + STRLEN(nsptr) + 256;
621 char *p;
622 if (!*errmsg) {
623 *errmsg = (char*)MALLOC(size);
624 p = *errmsg;
625 } else {
626 int errmsg_size = STRLEN(*errmsg);
627 *errmsg = (char*)REALLOC(*errmsg,errmsg_size + size + 2);
628 p = *errmsg + errmsg_size;
629 *p = '\n';
630 p++;
631 }
632 sprintf(p,errtxt,nsptr, strerror(errno));
633 } else {
634 ErrorMessage(errtxt, nsptr, strerror(errno));
635 }
636 return_code = FALSE;
637 }
638 else
639 {
640 #if defined(HAVE_REGCOMP) && defined(HAVE_REGEX_H)
641
642 regex_t net_file;
643 ASSERT(regcomp(&net_file, ".[.]*\\.net$", REG_NOSUB) == 0);
644
645 struct dirent *entry;
646 while ( (entry = readdir(d)) )
647 {
648 boolean exists = regexec(&net_file, entry->d_name, 0, NULL, 0);
649 if (exists == 0)
650
651 #elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H)
652
653 char *net_file = (char *)regcomp(".[.]*\\.net$");
654 ASSERT(net_file != NULL);
655
656 struct dirent *entry;
657 while (entry = readdir(d))
658 {
659 boolean exists = regexec((regexp *)net_file, entry->d_name);
660 if (exists)
661
662 #elif defined(HAVE_REGCMP)
663
664 char *net_file = regcmp(".[.]*\\.net$", NULL);
665 ASSERT(net_file != NULL);
666
667 struct dirent *entry;
668 while (entry = readdir(d))
669 {
670 boolean exists = regex(net_file, entry->d_name) != NULL;
671 if (exists)
672
673 #elif defined(HAVE_RE_COMP)
674
675 char *net_file = re_comp(".[.]*\\.net$");
676 ASSERT(net_file == NULL);
677
678 struct dirent *entry;
679 while (entry = readdir(d))
680 {
681 boolean exists = re_exec(entry->d_name) > 0;
682 if (exists)
683
684 #elif defined(HAVE__FINDFIRST)
685
686 char *srch_string2 = new char[STRLEN(nsptr) + 10];
687 strcpy(srch_string2,nsptr);
688 if (strlen(srch_string2)>0) {
689 char c = srch_string2[strlen(srch_string2)-1];
690 if (c != '/' && c != '\\' && c != ':')
691 strcat(srch_string2, "/");
692 }
693 strcat(srch_string2, "*.net");
694
695 struct _finddata_t entry;
696 long handle = _findfirst(srch_string2,&entry);
697 int exists = (handle == -1L) ? -1: 0;
698 while (exists == 0)
699 #endif
700 {
701 char path[1000];
702 strcpy(path, nsptr);
703 strcat(path, "/");
704
705 #if defined(HAVE__FINDFIRST)
706 strcat(path, entry.name);
707 #else
708 strcat(path, entry->d_name);
709 #endif
710
711 char *ignore = NULL;
712 FILE *f = Network::OpenNetworkFILE(path, &wasEncoded, &ignore);
713 if (ignore) delete[] ignore;
714 if (f == NULL)
715 {
716 char *errtxt = "Failed to load macro file %s: %s";
717 if (errmsg) {
718 int size = STRLEN(errtxt) + STRLEN(path) + 256;
719 char *p;
720 if (!*errmsg) {
721 *errmsg = (char*)MALLOC(size);
722 p = *errmsg;
723 } else {
724 int errmsg_size = STRLEN(*errmsg);
725 *errmsg = (char*)REALLOC(*errmsg,
726 errmsg_size + size + 2);
727 p = *errmsg + errmsg_size;
728 *p = '\n';
729 p++;
730 }
731 sprintf(p,errtxt,path, strerror(errno));
732 } else {
733 ErrorMessage(errtxt, path, strerror(errno));
734 }
735 return_code = FALSE;
736 }
737 else
738 {
739 MacroDefinition::LoadMacroFile(f, path,
740 replace, NULL, asSystemMacro);
741 Network::CloseNetworkFILE(f, wasEncoded);
742 }
743 #if defined(HAVE__FINDFIRST)
744 exists=_findnext(handle,&entry);
745 }
746 _findclose(handle);
747 delete[] srch_string2;
748 #elif defined(HAVE_REGCOMP) && defined(HAVE_REGEX_H)
749 }
750 }
751 closedir(d);
752 regfree(&net_file);
753 #elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H)
754 }
755 }
756 closedir(d);
757 #elif defined(HAVE_RE_COMP)
758 }
759 }
760 closedir(d);
761 #elif defined(HAVE_REGCMP)
762 }
763 }
764 closedir(d);
765 #elif defined(HAVE_REGCMP)
766 }
767 }
768 free(net_file);
769 closedir(d);
770 #endif
771 }
772 }
773
774 delete[] originalString;
775 return return_code;
776 }
777
778 //
779 // If errmsg is not NULL and an error occurs then, no error messages are
780 // posted, and instead a string buffer is allocated to hold the error
781 // message that would have been posted and returned. The returned
782 // string must be freed by the caller.
783 //
784 boolean MacroDefinition::LoadMacro(const char *fileName, char **errmsg,
785 boolean asSystemMacro)
786 {
787 char *netFile = Network::FilenameToNetname(fileName);
788 boolean return_code = TRUE;
789 boolean wasEncoded;
790
791 if (errmsg)
792 *errmsg = NULL;
793
794 FILE *f = Network::OpenNetworkFILE(netFile, &wasEncoded, errmsg);
795
796
797 if (f == NULL) {
798 return_code = FALSE;
799 } else {
800 boolean wasMacro;
801 MacroDefinition::LoadMacroFile(f, netFile, TRUE,
802 &wasMacro, asSystemMacro);
803 Network::CloseNetworkFILE(f, wasEncoded);
804 if (!wasMacro) {
805 char *errtxt = "File %s doesn't contain a macro and was not loaded";
806 if (errmsg) {
807 *errmsg = new char[STRLEN(errtxt) + STRLEN(netFile)];
808 sprintf(*errmsg,errtxt,netFile);
809 } else {
810 ErrorMessage(errtxt, netFile);
811 }
812 return_code = FALSE;
813 }
814 }
815 delete netFile;
816
817 return return_code;
818 }
819
820 void MacroDefinition::openMacro()
821 {
822 if (this->updateServer()) {
823 EditorWindow *e = this->body->getEditor();
824 if (e == NULL)
825 e = theDXApplication->newNetworkEditor(this->body);
826 if (e) {
827 e->manage();
828 XMapRaised(XtDisplay(e->getRootWidget()),
829 XtWindow(e->getRootWidget()));
830 }
831 }
832 }
833
834 boolean MacroDefinition::removeIODef(List *l, ParameterDefinition *pd)
835 {
836 boolean result = l->removeElement((void*)pd);
837 if (!this->initialRead)
838 this->setNodeDefinitions(this);
839 return result;
840 }
841 boolean MacroDefinition::addIODef(List *l, ParameterDefinition *pd)
842 {
843 boolean result = TRUE;
844 if (!this->initialRead) {
845 result = this->NodeDefinition::addIODef(l, pd) &&
846 this->setNodeDefinitions(this);
847 }
848 return result;
849 }
850 boolean MacroDefinition::replaceIODef(List *l,
851 ParameterDefinition *newPd,
852 ParameterDefinition *pd)
853 {
854 int position = l->getPosition((void*)pd);
855 if (position == 0)
856 return FALSE;
857 boolean result = l->removeElement((void*)pd);
858 if (result)
859 {
860 result = l->insertElement((void*)newPd, position);
861 }
862
863 int i;
864 //
865 // Remove trailing DUMMY parameters.
866 //
867 if (result) {
868 for (i = l->getSize(); (i > 0); i--)
869 {
870 pd = (ParameterDefinition*)l->getElement(i);
871 if (pd->isDummy()) {
872 if (l->removeElement((void*)pd))
873 delete pd;
874 } else
875 break;
876 }
877 }
878 if (!this->initialRead)
879 this->setNodeDefinitions(this);
880
881 return result;
882 }
883
884 //
885 // Get the Nth input that is not a dummy parameter definition.
886 //
887 ParameterDefinition *MacroDefinition::getNonDummyIODefinition(List *l, int n)
888 {
889 ASSERT(n > 0);
890 ASSERT(l);
891
892 ParameterDefinition *pd=NULL;
893 ListIterator iterator(*l);
894 int count = 0;
895
896 while ((count != n) &&
897 (pd = (ParameterDefinition*)iterator.getNext())) {
898 if (!pd->isDummy())
899 count++;
900 }
901 if (count != n)
902 pd = NULL;
903
904 return pd;
905 }
906 //
907 // Find the first available spot to place a new parameter in the given
908 // list (expected to be either inputDefs or outputDefs). If there are dummy
909 // parameters in the list, then the index of the first dummy is returned.
910 // If no dummies, then N+1 is returned, where N is the current number of
911 // items in the list.
912 //
913 int MacroDefinition::getFirstAvailableIOPosition(List *l)
914 {
915 ASSERT(l);
916
917 ParameterDefinition *pd;
918 ListIterator iterator(*l);
919 int n = 0;
920 boolean found_dummy = FALSE;
921
922 while ((pd = (ParameterDefinition*)iterator.getNext())) {
923 n++;
924 if (pd->isDummy()) {
925 found_dummy = TRUE;
926 break;
927 }
928 }
929 if (!found_dummy)
930 n++;
931
932 ASSERT(n>0);
933 return n;
934 }
935
936 boolean MacroDefinition::setNetwork(Network *net)
937 {
938 this->body = net;
939 this->initialRead = FALSE;
940
941 return TRUE;
942 }
943
944