removed some warnings
[dyninst.git] / paradyn / src / UIthread / paradyn.tcl.C
1 /* paradyn.tcl.C
2
3    This code implements the tcl "paradyn" command.  See the README file for 
4    command descriptions.
5
6 */
7 /* $Log: paradyn.tcl.C,v $
8 /* Revision 1.59  1995/12/08 05:50:05  tamches
9 /* removed some warnings
10 /*
11  * Revision 1.58  1995/12/01 06:39:18  tamches
12  * removed some warnings
13  *
14  * Revision 1.57  1995/11/28 15:49:36  naim
15  * Adding boolean parameter to getAvailableMetric - naim
16  *
17  * Revision 1.56  1995/11/08  06:25:22  tamches
18  * removed some warnings
19  *
20  * Revision 1.55  1995/11/08 05:11:10  tamches
21  * no longer prints a msg when a tunable constant value is changed
22  *
23  * Revision 1.54  1995/11/07 03:11:31  tamches
24  * allowed blank directory names in paradynProcessCmd, fixing a bug of last commit
25  *
26  * Revision 1.53  1995/11/07 01:31:45  tamches
27  * directory names in the "start a process" dialog box can now begin
28  * with ~ or ~some-user-name.  This solution was modeled after
29  * Tcl_TildeSubst (in the tcl source code)
30  *
31  * Revision 1.52  1995/11/06 19:27:17  tamches
32  * removed a lot of warnings under g++ 2.7.0
33  *
34  * Revision 1.51  1995/11/03 21:19:55  naim
35  * Adding paradyn exit command - naim
36  *
37  * Revision 1.50  1995/10/30  23:07:07  naim
38  * Minor fix: eliminating error message from status_line destructor by relocating
39  * object declarations to a better place in the code. "static" declarations were
40  * also changed to global declarations, so we use "new" the first time were we
41  * reference them - naim
42  *
43  * Revision 1.49  1995/10/17  20:54:56  tamches
44  * class abstractions is no longer templated
45  *
46  * Revision 1.48  1995/10/13 19:37:26  naim
47  * Minor change for handling PAUSE and RUN buttons when a process is created
48  * from a MDL file - naim
49  *
50  * Revision 1.47  1995/10/06  19:53:32  naim
51  * Fixing bug: pressing RUN while defining a process produces a core dump. Now,
52  * the RUN and PAUSE keys are disabled while a process is being defined - naim
53  *
54  * Revision 1.46  1995/10/05  04:33:07  karavan
55  * changes to paradyn search and paradyn shg commands to support new igen
56  * interface.
57  * deleted commented obsolete code.
58  *
59  * Revision 1.45  1995/09/18  22:32:45  mjrg
60  * Added directory command.
61  *
62  * Revision 1.44  1995/08/07  00:01:31  tamches
63  * Added waSetAbstraction, waSelect, and waUnselect
64  *
65  * Revision 1.43  1995/08/01  02:18:31  newhall
66  * changes to support phase interface
67  *
68  * Revision 1.42  1995/06/26  19:40:39  tamches
69  * Removed references to tunable constant print member function;
70  * we now print manually
71  *
72  * Revision 1.41  1995/06/02  20:50:43  newhall
73  * made code compatable with new DM interface
74  *
75  * Revision 1.40  1995/02/27  18:56:48  tamches
76  * Changes to reflect the new TCthread.
77  *
78  * Revision 1.39  1995/02/16  08:20:52  markc
79  * Changed Boolean to bool
80  * Changed wait loop code for igen messages
81  *
82  * Revision 1.38  1995/02/07  21:52:54  newhall
83  * changed parameters to VMCreateVisi call
84  *
85  * Revision 1.37  1995/01/26  17:59:04  jcargill
86  * Changed igen-generated include files to new naming convention; fixed
87  * some bugs compiling with gcc-2.6.3.
88  *
89  * Revision 1.36  1994/12/21  07:39:51  tamches
90  * Removed uses of tunableConstant::allConstants, which became a private
91  * class variable.
92  *
93  * Revision 1.35  1994/12/21  00:43:14  tamches
94  * used the new findTunableConstant() method function, instead of doing it
95  * by looking into tc's data members (which is no longer allowed).
96  *
97  * Revision 1.34  1994/11/11  15:12:35  rbi
98  * causing serious illness to debugging printf()
99  *
100  * Revision 1.33  1994/11/10  17:35:57  rbi
101  * physical illness and possible death in the family
102  *
103  * Revision 1.32  1994/11/07  08:25:14  jcargill
104  * Added ability to suppress search on children of a resource, rather than
105  * the resource itself.
106  *
107  * Revision 1.31  1994/11/04  16:29:08  rbi
108  * Added paradyn daemon command
109  *
110  * Revision 1.30  1994/11/03  20:25:08  krisna
111  * added status_lines for application name and application status
112  *
113  * Revision 1.29  1994/11/01  05:42:35  karavan
114  * some minor performance and warning fixes
115  *
116  * Revision 1.28  1994/09/25  01:54:12  newhall
117  * updated to support changes in VM, and UI interface
118  *
119  * Revision 1.27  1994/09/22  01:17:53  markc
120  * Cast stringHandles to char*s in printf statements
121  *
122  * Revision 1.26  1994/08/22  15:55:29  markc
123  * Added extra argument to addExecutable call.
124  *
125  * Revision 1.25  1994/08/13  20:55:33  newhall
126  * changed call to VMCreateVisi
127  *
128  * Revision 1.24  1994/08/08  20:15:25  hollings
129  * added suppress instrumentation command.
130  *
131  * Revision 1.23  1994/08/05  16:04:28  hollings
132  * more consistant use of stringHandle vs. char *.
133  *
134  * Revision 1.22  1994/08/03  19:10:25  hollings
135  * split tunable constant into boolean and float types.
136  *
137  * Revision 1.21  1994/07/25  14:58:15  hollings
138  * added suppress resource option.
139  *
140  * Revision 1.20  1994/07/07  03:27:36  markc
141  * Changed expected result of call to dataMgr->addExecutable
142  *
143  * Revision 1.19  1994/07/03  05:00:24  karavan
144  * bug fix: removed call to delete name returned from getCanonicalName()
145  *
146  * Revision 1.18  1994/07/02  01:44:13  markc
147  * Removed aggregation operator from enableDataCollection call.
148  *
149  * Revision 1.17  1994/06/14  15:20:17  markc
150  * Added extra arg to enableDataCollection call.  This is probably temporaray
151  * since the data manager or configuration language will specify this info.
152  *
153  * Revision 1.16  1994/05/31  19:11:49  hollings
154  * Changes to permit direct access to resources and resourceLists.
155  *
156  * Revision 1.15  1994/05/26  21:26:10  karavan
157  * corrected return value for Process command, to return TCL_ERROR if call
158  * to Add_Executable fails.
159  *
160  * Revision 1.14  1994/05/18  00:50:12  hollings
161  * added pid argument to core command.
162  *
163  * Revision 1.13  1994/05/12  23:34:16  hollings
164  * made path to paradyn.h relative.
165  *
166  * Revision 1.12  1994/05/09  20:59:27  hollings
167  * Changed paradyn shg start to clearSHG not init it.
168  *
169  * Revision 1.11  1994/05/06  06:40:06  karavan
170  * added shg start command
171  *
172  * Revision 1.10  1994/05/05  02:13:29  karavan
173  * moved CmdTabEntry definition from paradyn.tcl.C to UIglobals.h
174  *
175  * Revision 1.9  1994/05/02  20:38:31  hollings
176  * added search pause command and shg commands.
177  *
178  * Revision 1.8  1994/04/27  22:55:09  hollings
179  * Merged refine auto and search.
180  *
181  * Revision 1.7  1994/04/21  23:24:51  hollings
182  * added process command.
183  *
184  * Revision 1.6  1994/04/19  22:09:14  rbi
185  * Added new tcl commands and updated "enable" to return met id
186  *
187  * Revision 1.5  1994/04/10  19:12:12  newhall
188  * added visi command
189  *
190  * Revision 1.4  1994/04/09  18:37:20  hollings
191  * Fixed paramter to tunable constant to work.
192  *
193  * Revision 1.3  1994/04/06  22:40:15  markc
194  * Included assert.h.
195  *
196  * Revision 1.2  1994/04/05  23:49:25  rbi
197  * Fixed a bunch of tcl related stuff.
198  *
199  * Revision 1.1  1994/04/05  04:42:38  karavan
200  * initial version of UI thread code and tcl paradyn command
201  * */
202
203 /*
204  * Copyright (c) 1993, 1994 Barton P. Miller, Jeff Hollingsworth,
205  *     Bruce Irvin, Jon Cargille, Krishna Kunchithapadam, Karen
206  *     Karavanic, Tia Newhall, Mark Callaghan.  All rights reserved.
207  * 
208  * This software is furnished under the condition that it may not be
209  * provided or otherwise made available to, or used by, any other
210  * person, except as provided for by the terms of applicable license
211  * agreements.  No title to or ownership of the software is hereby
212  * transferred.  The name of the principals may not be used in any
213  * advertising or publicity related to this software without specific,
214  * written prior authorization.  Any use of this software must include
215  * the above copyright notice.
216  *
217  */
218
219 #include <string.h>
220
221 #include "tclclean.h"
222 #include "tkclean.h"
223
224 #include "UIglobals.h"
225 #include "paradyn/src/DMthread/DMinclude.h"
226 #include "../TCthread/tunableConst.h"
227 #include "VM.thread.CLNT.h"
228 #include "thread/h/thread.h"
229 #include "../pdMain/paradyn.h"
230 #include "abstractions.h"
231 #include "whereAxisTcl.h"
232
233 #include <assert.h>
234 #include <stdlib.h>
235 #include <pwd.h>
236
237 #include "Status.h"
238
239 extern bool detachApplication(bool);
240
241 extern appState PDapplicState;
242
243 status_line *app_name=NULL;
244
245 int ParadynPauseCmd(ClientData,
246                 Tcl_Interp *,
247                 int,
248                 char **)
249 {
250   dataMgr->pauseApplication();
251   return TCL_OK;
252 }
253
254 int ParadynContCmd(ClientData,
255                 Tcl_Interp *,
256                 int,
257                 char **)
258 {
259   dataMgr->continueApplication();
260   return TCL_OK;
261 }
262
263 int ParadynStatusCmd(ClientData,
264                 Tcl_Interp *,
265                 int,
266                 char **)
267 {
268   dataMgr->printStatus();
269   return TCL_OK;
270 }
271
272 int ParadynMetricsCmd(ClientData,
273                         Tcl_Interp *,
274                         int,
275                         char **)
276 {
277   vector<string> *ml = dataMgr->getAvailableMetrics(false);
278   for (unsigned i=0; i < ml->size(); i++)
279     Tcl_AppendElement(interp, (*ml)[i].string_of());
280   delete ml;
281   return TCL_OK;
282 }
283
284
285 int ParadynDaemonsCmd(ClientData,
286                       Tcl_Interp *interp, 
287                       int,
288                       char **)
289 {
290   vector<string> *dl = dataMgr->getAvailableDaemons();
291   for (unsigned i=0; i < dl->size(); i++)
292     Tcl_AppendElement(interp, (*dl)[i].string_of());
293   delete dl;
294   return TCL_OK;
295 }
296
297
298 int ParadynResourcesCmd(ClientData,
299                         Tcl_Interp *,
300                         int,
301                         char **)
302 {
303   dataMgr->printResources();
304   return TCL_OK;
305 }
306
307 int ParadynListCmd(ClientData,
308                 Tcl_Interp *,
309                 int,
310                 char **)
311 {
312   dataMgr->printResources();
313
314   vector<string> *ml = dataMgr->getAvailableMetrics(false);
315   for (unsigned i=0; i < ml->size(); i++) {
316     cout << ((*ml)[i]).string_of() << endl;
317   }
318
319   cout << "CONSTANTS" << endl;
320
321   vector<tunableBooleanConstant> allBoolConstants = tunableConstantRegistry::getAllBoolTunableConstants();
322   for (unsigned boollcv = 0; boollcv < allBoolConstants.size(); boollcv++) {
323      tunableBooleanConstant &tbc = allBoolConstants[boollcv];
324      cout << tbc.getName() << " = ";
325      if (tbc.getValue())
326         cout << "true" << endl;
327      else
328         cout << "false" << endl;
329   }
330
331   vector<tunableFloatConstant> allFloatConstants = tunableConstantRegistry::getAllFloatTunableConstants();
332   for (unsigned floatlcv = 0; floatlcv < allFloatConstants.size(); floatlcv++) {
333      tunableFloatConstant &tfc = allFloatConstants[floatlcv];
334
335      cout << tfc.getName() << " = " << tfc.getValue() << endl;
336   }
337
338   cout << "bucketWidth " << dataMgr->getCurrentBucketWidth() << endl;
339   cout << "number of buckets = " << dataMgr->getMaxBins() << endl;
340   dataMgr->printDaemons();
341   return TCL_OK;
342 }
343
344 int ParadynDetachCmd (ClientData,
345                       Tcl_Interp *,
346                       int,
347                       char **)
348 {
349   dataMgr->detachApplication(true);
350   return TCL_OK;
351 }
352
353 metricHandle *
354 StrToMetHandle (char *mstr)
355 {
356   metricHandle *mh = new metricHandle;
357   if (sscanf (mstr, "%u", mh) <= 0) {
358     delete mh;
359     return (metricHandle *) NULL;
360   }
361   else return mh;
362 }
363
364 char *
365 MetHandleToStr (metricHandle mh)
366 {
367   char *result = new char[12];
368   sprintf (result, "%u", mh);
369   return result;
370 }
371
372 int ParadynGetTotalCmd (ClientData,
373                      Tcl_Interp *,
374                      int argc,
375                      char *argv[])
376 {
377   metricHandle *met;
378   metricInstInfo *mi;
379   float val;
380
381   if (argc < 2) {
382     sprintf(interp->result, "USAGE: gettotal <metid>");
383     return TCL_ERROR;
384   }
385
386   if (!(met = dataMgr->findMetric (argv[1]))) {
387     Tcl_AppendElement (interp, "invalid metric identifier");
388     return TCL_ERROR;
389   }
390   
391   mi = uim_enabled.find((void *) *met);
392   if (!mi) {
393     Tcl_AppendResult (interp, "unable to find metric ", MetHandleToStr(*met),
394                       (char *)NULL);
395     delete met;
396     return TCL_ERROR;
397   }
398   else {
399     val = dataMgr->getTotValue(mi->mi_id);
400     sprintf(interp->result, "%g", val);
401     delete met;
402   }  
403   return TCL_OK;
404 }
405
406 int ParadynPrintCmd (ClientData,
407                      Tcl_Interp *,
408                      int,
409                      char *argv[])
410 {
411   if (argv[1][0] == 'm') {   // print metric
412     float val;
413     metricInstInfo *mi;
414     metricHandle *met;
415
416     if (! (met = dataMgr->findMetric (argv[2]))) {
417       Tcl_AppendElement (interp, "Invalid metric");
418       return TCL_ERROR;
419     }
420     mi = uim_enabled.find((void *) *met);
421
422     if (!mi) {
423       sprintf (interp->result, "unable to find metric %s\n", 
424                argv[2]);
425       delete met;
426       return TCL_ERROR;
427      } else {
428       val = dataMgr->getMetricValue(mi->mi_id);
429       printf ("metric %s, val = %f\n", 
430                (char*)dataMgr->getMetricName(*met), val);
431     }
432   } else if (argv[1][0] == 's') {     //print shg
433       perfConsult->printSHGList();
434   } else if (argv[1][0] == 'r') {     // print refine
435     int i;
436     searchHistoryNode *currentSHGNode;
437     SHNptr_Array currentRefinementList;
438         
439     currentSHGNode = perfConsult->getCurrentRefinement();
440     currentRefinementList = perfConsult-> getAllRefinements (currentSHGNode);
441
442     for (i=0; i < currentRefinementList.count; i++) {
443       currentSHGNode = currentRefinementList.data[i];
444       perfConsult->printSHGNode(currentSHGNode);
445       printf ("\n");
446     }
447   } else {
448     sprintf (interp->result, "Unknown option: paradyn print %s\n", argv[1]);
449     return TCL_ERROR;
450   }
451   return TCL_OK;
452 }
453
454 void processUsage()
455 {
456   printf("USAGE: process <-user user> <-machine machine> <-daemon> daemon> <-dir> directory \"command\"\n");
457 }
458
459 void disablePAUSEandRUN()
460 {
461   string msg = string("Tcl interpreter failed in routine changeApplicState: ");
462   if (Tcl_VarEval(interp,"changeApplicState 2",0)==TCL_ERROR) {
463     msg += string((const char *) interp->result);
464     uiMgr->showError(83, P_strdup(msg.string_of()));
465   }
466 }
467
468 void enablePAUSEorRUN()
469 {
470   string msg = string("Tcl interpreter failed in routine changeApplicState: ");
471   if (PDapplicState==appRunning) {
472     if (Tcl_VarEval(interp,"changeApplicState 1",0)==TCL_ERROR) {
473       msg += string((const char *) interp->result);
474       uiMgr->showError(83, P_strdup(msg.string_of()));
475     }   
476   }
477   else {
478     if (Tcl_VarEval(interp,"changeApplicState 0",0)==TCL_ERROR) {
479       msg += string((const char *) interp->result);
480       uiMgr->showError(83, P_strdup(msg.string_of()));
481     }
482   }
483 }
484
485 /****
486  * Process
487  * Calls data manager service "addExecutable".  
488  * Returns TCL_OK or TCL_ERROR
489  */
490 int ParadynProcessCmd(ClientData,
491                       Tcl_Interp *,
492                       int argc,
493                       char *argv[])
494 {
495   char *user = NULL;
496   char *machine = NULL;
497   char *paradynd = NULL;
498   string dir;
499   static bool firstProcess=true;
500   
501   for (int i=1; i < argc-1; i++) {
502     if (!strcmp("-user", argv[i])) {
503       if (i+1 == argc) {
504         processUsage();
505         return TCL_ERROR;
506       }
507       user = argv[++i];
508     } else if (!strcmp("-machine", argv[i])) {
509       if (i+1 == argc) {
510         processUsage();
511         return TCL_ERROR;
512       }
513       machine = argv[++i];
514     } else if (!strcmp("-daemon", argv[i])) {
515       if (i+1 == argc) {
516         processUsage();
517         return TCL_ERROR;
518       }
519       paradynd = argv[++i];
520     } else if (!strcmp("-dir", argv[i])) {
521       if (i+1 == argc) {
522         processUsage();
523         return TCL_ERROR;
524       }
525       dir = argv[++i];
526     } else if (argv[i][0] != '-') {
527       break;
528     } else {
529       processUsage();
530       return TCL_ERROR;
531     }
532   }
533
534   if (!app_name) {
535     app_name = new status_line("Application name");
536   }
537   static char tmp_buf[1024];
538   sprintf(tmp_buf, "program: %s, machine: %s, user: %s, daemon: %s",
539           argv[i], machine?machine:"(local)", user?user:"(self)",
540           paradynd?paradynd:"(default)");
541   app_name->message(tmp_buf);
542   
543   vector<string> av;
544   unsigned ve=i;
545   while (argv[ve]) {
546     av += argv[ve];
547     ve++;
548   }
549
550   // We disabled PAUSE and RUN buttons to avoid problems. If any of these
551   // keys is pressed while defining a process, we end in a deadlock - naim
552   disablePAUSEandRUN();
553
554   // At this point, we take a look at "dir"; if it starts with ~some_user_name,
555   // then we alter "dir".  In the spirit of Tcl_TildeSubst (tclGlob.c).
556   // The only reason we don't use Tcl_TildeSubst is because it uses Tcl_DStringFree,
557   // etc., where we much prefer to use Krishna's string class  --Ari
558
559   // for debugging (temporary):
560 //  cout << dir << " maps to ";
561
562   if (dir.length() == 0)
563      ; // do nothing; leave "dir" the empty string
564   else {
565      const char *dir_cstr = dir.string_of();
566      if (dir_cstr[0] == '~') {
567         // two possibilities: a tilde by itself e.g. ~/x/y, or tilde followed by a username
568         if (dir_cstr[1] == '/' || dir_cstr[1] == '\0') {
569            // it's the first possibility.  We need to find the environment vrble HOME
570            // and use that result.  If HOME env vrble doesn't exist (it always does)
571            // than I have no idea what to do.  I guess I'll just leave "dir" unchanged
572            // in that case.
573            char *home_dir = getenv("HOME");
574            if (home_dir != NULL) {
575               // Now let dir=home_dir + dir_cstr(starting at [1 or 2])
576               // If home_dir ends in a '/' then we start dir_cstr at 2.  Else, 1
577               if (home_dir[strlen(home_dir)-1] == '/')
578                  dir = string(home_dir) + &dir_cstr[2];
579               else
580                  dir = string(home_dir) + &dir_cstr[1];
581            }
582         } // ~ without a user-name
583         else {
584            // we need to collect the user name.  It starts at dir_cstr[1]
585            // and ends at (but not including) the first '/' or '\0'
586            const char *ptr=strchr(&dir_cstr[1], '/');
587    
588            string user_name;
589            if (ptr != NULL) {
590               char user_name_buffer[200];
591               unsigned user_name_len = ptr - &dir_cstr[1];
592    
593               for (unsigned j=0; j < user_name_len; j++)
594                  user_name_buffer[j] = dir_cstr[1+j];
595               user_name_buffer[user_name_len] = '\0';
596    
597               user_name = user_name_buffer;
598            }
599            else
600               user_name = string(&dir_cstr[1]);
601
602            struct passwd *pwPtr = getpwnam(user_name.string_of());
603            if (pwPtr == NULL) {
604               endpwent();
605               // something better needed...
606               //cerr << "Sorry, user \"" << user_name << "\" doesn't exist" << endl;
607            }
608            else {
609               dir = string(pwPtr->pw_dir) + string(ptr);
610               endpwent();
611            }
612         } // ~user-name
613      } // first char is a squiggle
614   } // "dir" is not the empty string
615
616   // temporary (for debugging):
617 //  cout << dir << endl;
618
619   if (dataMgr->addExecutable(machine, user, paradynd, dir.string_of(),
620                              &av) == false)
621   {
622     enablePAUSEorRUN();
623     return TCL_ERROR;
624   }
625   else {
626     // When the very first process is created...
627     // RUN is now enabled. PDapplicState is set to appRunning, because we
628     // need a previous state of appRunning if we want to pause the application
629     if (firstProcess) {
630       firstProcess=false;
631       if (PDapplicState==appRunning) { 
632         // A previous process has been started from a mdl file
633         PDapplicState=appPaused;
634         dataMgr->continueApplication();
635       }
636       else {
637         PDapplicState=appRunning;
638         dataMgr->pauseApplication();
639       }
640     }
641     else {
642       if (PDapplicState==appRunning) {
643         PDapplicState=appPaused;
644         dataMgr->continueApplication();
645       }
646       else {
647         PDapplicState=appRunning;
648         dataMgr->pauseApplication();
649       }
650     }
651     return TCL_OK;
652   }
653 }
654
655 //
656 //  disable  <metid>
657 //
658 int ParadynDisableCmd (ClientData,
659                       Tcl_Interp *interp,
660                       int argc,
661                       char *argv[])
662 {
663   metricHandle *met;
664   metricInstInfo *mi;
665
666   // Hold Everything!
667   dataMgr->pauseApplication ();
668
669   if (argc < 2) {
670     sprintf(interp->result, "USAGE: disable <metid>");
671     return TCL_ERROR;
672   }
673
674   if (! (met = dataMgr->findMetric(argv[1]))) {
675     sprintf(interp->result, "Invalid metric %s", argv[1]);
676     return TCL_ERROR;
677   }
678
679   mi = uim_enabled.find((void *) *met);
680
681   if (!mi) {
682     sprintf (interp->result, "unable to find metric %s\n", 
683              MetHandleToStr(*met)); 
684     delete met;
685     return TCL_ERROR;
686   }
687   else {
688     // TODO: phase type should be entered as a command arg 
689     dataMgr->disableDataCollection (uim_ps_handle, mi->mi_id,GlobalPhase);
690     delete met;
691   }
692   return TCL_OK;
693 }
694
695 //
696 //  enable <metric> ?<resource>? ...
697 //    returns metric id
698 //
699 int ParadynEnableCmd (ClientData,
700                       Tcl_Interp *interp,
701                       int argc,
702                       char *argv[])
703 {
704   metricHandle *met;
705   metricInstInfo *mi;
706   vector<resourceHandle> *resList;
707
708   // Hold Everything!
709   dataMgr->pauseApplication ();
710
711   // Build a resource list from the tcl list
712   if (argc == 2)
713     resList = dataMgr->getRootResources();
714   else {
715     char **argsv;
716     int argsc;
717     resourceHandle *res;
718
719     if (Tcl_SplitList(interp, argv[2], &argsc, &argsv) != TCL_OK) {
720       printf("Error parsing resource list '%s'", argv[2]);
721       return TCL_ERROR;
722     }
723
724     resList = new vector<resourceHandle>;
725     cout << "enable request for ";
726     for (int i = 0; i < argsc; i++) {
727       res = dataMgr->findResource(argsv[i]);
728       cout << argsv[i] << " ";
729       resList += *res;
730     }
731     cout << endl;
732     free(argsv);
733   }
734
735   // Now check the metric
736   met = dataMgr->findMetric (argv[1]);
737   if (!met) {
738     sprintf (interp->result, "metric %s is not defined\n", argv[1]);
739     delete resList;
740     return TCL_ERROR;
741   }
742   else {
743     // Finally enable the data collection
744     // TODO: phaseType, and persistent flags should be command args
745     mi = dataMgr->enableDataCollection (uim_ps_handle, resList, *met,
746                                         GlobalPhase,0,0);
747     if (mi) {
748       uim_enabled.add(mi, (void *)mi->mi_id);
749       sprintf(interp->result, MetHandleToStr (mi->mi_id));
750       printf ("metric %s, id = %s\n", argv[1], MetHandleToStr(mi->mi_id));
751     } else {
752       sprintf (interp->result, "can't enable metric %s for focus \n", argv[1]);
753       return TCL_ERROR;
754     }
755   }
756   return TCL_OK;
757 }
758
759 int ParadynCoreCmd (ClientData,
760                     Tcl_Interp *,
761                     int argc,
762                     char *argv[])
763 {
764   int pid;
765
766   if (argc != 2) {
767     printf("usage: paradyn core <pid>\n");
768     return TCL_ERROR;
769   }
770   if (sscanf(argv[1],"%d",&pid) != 1) {
771     printf("usage: paradyn core <pid>\n");
772     return TCL_ERROR;
773   }
774
775   dataMgr->coreProcess(pid);
776   return TCL_OK;
777 }
778
779 int ParadynSetCmd (ClientData,
780                     Tcl_Interp *interp,
781                     int argc,
782                     char *argv[])
783 {
784   if (argc != 3) {
785     sprintf(interp->result,"USAGE: %s <variable> <value>", argv[0]);
786     return TCL_ERROR;
787   }
788
789   if (!tunableConstantRegistry::existsTunableConstant(argv[1])) {
790      cout << "Tunable constant " << argv[1] << " does not exist; cannot set its value to " << argv[2] << endl;
791      return TCL_ERROR;
792   }
793   
794   if (tunableConstantRegistry::getTunableConstantType(argv[1]) == tunableBoolean) {
795      int boolVal;
796      if (TCL_ERROR == Tcl_GetBoolean(interp, argv[2], &boolVal))
797         return TCL_ERROR;
798      else {
799         tunableConstantRegistry::setBoolTunableConstant(argv[1], (bool)boolVal);
800 //        cout << "tunable boolean constant " << argv[1] << " set to " << boolVal << endl;
801      }
802   }
803   else {
804      double doubleVal;
805      if (TCL_ERROR == Tcl_GetDouble(interp, argv[2], &doubleVal))
806         return TCL_ERROR;
807      else {
808         tunableConstantRegistry::setFloatTunableConstant(argv[1], (float)doubleVal);
809 //        cout << "tunable float constant " << argv[1] << " set to " << doubleVal << endl;
810      }
811   }
812
813   return TCL_OK;
814 }
815
816 // new argument: perfConsult calls now take phase-related arguments
817 // paradyn search pause <put-searchType-here>
818 // paradyn search <false|true> <put-searchType-here> <put-limit-here>
819  
820 int ParadynSearchCmd (ClientData,
821                       Tcl_Interp *interp,
822                       int argc,
823                       char *argv[])
824 {
825   int limit;
826
827   if (argc == 3 && !strcmp(argv[1], "pause")) {
828     // stop the search
829     if (!strcmp(argv[2], "current"))
830       perfConsult->pauseSearch(CurrentPhase);
831     else 
832       perfConsult->pauseSearch(GlobalPhase);
833     return TCL_OK;
834   } else if (argc == 4) {
835     if (Tcl_GetInt (interp, argv[3], &limit) == TCL_ERROR) 
836       return TCL_ERROR;
837   } else if (argc == 3) {
838     limit = -1;
839   } else {
840     printf("Usage: paradyn search <false|true> <global|current> <int>\n");
841     printf("       paradyn search pause <global|current>\n");
842     return TCL_ERROR;
843   }
844
845   if (dataMgr->applicationDefined() != true) {
846     sprintf (interp->result, "no program defined, can't search\n");
847     return TCL_ERROR;
848   } else {
849     perfConsult->search(true, limit, 0);
850     return TCL_OK;
851   }
852 }
853
854
855 int ParadynSHGCmd (ClientData,
856                    Tcl_Interp *interp,
857                    int argc,
858                    char *argv[])
859 {
860   int node;
861
862   if (argc == 2 && !strcmp(argv[1], "get")) {
863     node = perfConsult->getCurrentNodeId();
864     sprintf(interp->result, "%d", node);
865     return(TCL_OK);
866   } else if (argc == 2 && !strcmp(argv[1], "reset")) {
867     perfConsult->resetRefinement();
868     sprintf(interp->result, "1");
869     return(TCL_OK);
870   } else if (argc == 3 && 
871              !strcmp(argv[1], "set") && 
872              (node = atoi(argv[2]) > 0)) {
873     sprintf(interp->result, "%d", perfConsult->setCurrentSHGnode(node));
874     return TCL_OK;
875   } else if (argc == 3 && !strcmp(argv[1], "start")) {
876     if (!strcmp(argv[2], "global"))
877       perfConsult->newSearch(GlobalPhase);
878     else 
879       perfConsult->newSearch(CurrentPhase);
880     return TCL_OK;
881   } else {
882     printf("Usage: paradyn shg set <int>\n");
883     printf("       paradyn shg get\n");
884     printf("       paradyn shg reset\n");
885     printf("       paradyn shg start <current|global>\n");
886     return TCL_ERROR;
887   }
888 }
889
890 extern abstractions *theAbstractions;
891 int ParadynWaSetAbstraction(ClientData, Tcl_Interp *interp,
892                             int argc, char **argv) {
893    if (argc != 2) {
894       cerr << "ParadynWaSetAbstraction: wrong # args" << endl;
895       return TCL_ERROR;
896    }
897    
898    assert(0==strcmp(argv[0], "waSetAbstraction"));
899    string absName = string(argv[1]);
900
901    int menuIndex = theAbstractions->name2index(absName);
902       // -1 if not found
903
904    if (menuIndex == -1) {
905       cout << "paradyn waSetAbstraction: could not change the abstraction to \"" << absName << "\" because it does not (yet?) exist" << endl;
906       return TCL_ERROR;
907    }
908
909    menuIndex++; // tcl menus are base 1 (0 is reserved for tearoff)
910
911    string commandStr = theAbstractions->getAbsMenuName() + " invoke " +
912                        string(menuIndex);
913    cout << "invoking menu item " << menuIndex << endl;
914
915    if (TCL_OK != Tcl_Eval(interp, commandStr.string_of())) {
916       cerr << interp->result << endl;
917       exit(5);
918    }
919
920    return TCL_OK;
921 }
922
923 int ParadynWaSelectUnselect(Tcl_Interp *interp,
924                             const char *name,
925                             bool selectFlag) {
926    if (!theAbstractions->existsCurrent())
927       return TCL_ERROR;
928
929    const bool found = theAbstractions->getCurrent().
930                       selectUnSelectFromFullPathName(name, selectFlag);
931    if (!found) {
932       if (selectFlag)
933          cout << "paradyn waSelect: ";
934       else
935          cout << "paradyn waUnselect: ";
936       cout << "could not find the item: " << name << endl;
937    }
938    else
939       initiateWhereAxisRedraw(interp, true); // whereAxisTcl.C
940
941    return TCL_OK;
942 }
943
944 int ParadynWaSelect(ClientData, Tcl_Interp *interp,
945                     int argc, char **argv) {
946    if (argc != 2) {
947       cerr << "ParadynWaSelect: too many arguments" << endl;
948       return TCL_ERROR;
949    }
950
951    assert(0==strcmp(argv[0], "waSelect"));
952    return ParadynWaSelectUnselect(interp, argv[1], true);
953 }
954
955 int ParadynWaUnSelect(ClientData, Tcl_Interp *interp,
956                     int argc, char **argv) {
957    if (argc != 2) {
958       cerr << "ParadynWaUnselect: too many arguments" << endl;
959       return TCL_ERROR;
960    }
961
962    assert(0==strcmp(argv[0], "waUnselect"));
963    return ParadynWaSelectUnselect(interp, argv[1], false);
964 }
965
966 int ParadynSuppressCmd (ClientData,
967                        Tcl_Interp *interp,
968                        int argc,
969                        char *argv[])
970 {
971   bool suppressInst, suppressChildren;
972
973   if (argc != 3) {
974     printf("Usage: paradyn suppress <search|inst|searchChildren> <resource list>\n");
975     return TCL_ERROR;
976   }
977   if (!strcmp(argv[1], "search")) {
978     suppressInst = false;
979     suppressChildren = false;
980   } else if (!strcmp(argv[1], "inst")) {
981     suppressInst = true;
982   } else if (!strcmp(argv[1], "searchChildren")) {
983     suppressInst = false;
984     suppressChildren = true;
985   } else {
986     printf("Usage: paradyn suppress <search|inst|searchChildren> <resource list>\n");
987     return TCL_ERROR;
988   }
989
990   {
991     char **argsv;
992     int argsc;
993     resourceHandle *res;
994     
995     if (Tcl_SplitList(interp, argv[2], &argsc, &argsv) != TCL_OK) {
996       printf("Error parsing resource list '%s'", argv[2]);
997       return TCL_ERROR;
998     }
999     
1000     cout << "suppress request for ";
1001     for (int i = 0; i < argsc; i++) {
1002       res = dataMgr->findResource (argsv[i]);
1003       cout << argsv[i];
1004
1005       if (res == NULL) {
1006          cerr << "sorry, data manager could not findResource" << endl;
1007          return TCL_ERROR;
1008       }
1009
1010       if (suppressInst) {
1011         dataMgr->setResourceInstSuppress(*res, true);
1012       } else {
1013         if (suppressChildren)
1014           dataMgr->setResourceSearchChildrenSuppress(*res, true);
1015         else
1016           dataMgr->setResourceSearchSuppress(*res, true);
1017       }
1018       delete res;
1019     }
1020     cout << endl;
1021     free(argsv);
1022     return TCL_OK;
1023   }
1024 }
1025
1026 int ParadynVisiCmd (ClientData,
1027                     Tcl_Interp *interp,
1028                     int argc,
1029                     char *argv[])
1030 {
1031 //
1032 //  @begin(barf)
1033 //    This should be automated with a visi command 
1034 //    dictionary or at least a switch statement.  --rbi
1035 //  @end(barf)
1036 //
1037   if (argc < 2) {
1038     sprintf(interp->result,
1039             "USAGE: visi [kill <ivalue>|create <ivalue>|info|active<cmd>]");
1040     return TCL_ERROR;
1041   }
1042   if (argv[1][0] == 'a') {
1043     vector<VM_activeVisiInfo> *temp;
1044
1045     temp = vmMgr->VMActiveVisis();
1046     for (unsigned i=0; i < temp->size(); i++) {
1047       printf("active_info %d: name %s TypeId %d visiNum = %d\n",i,
1048              ((*temp)[i]).name.string_of(),
1049              ((*temp)[i]).visiTypeId,((*temp)[i]).visiNum);
1050     }
1051     delete temp;
1052   }
1053   else if (argv[1][0] == 'i') {
1054       vector<VM_visiInfo> *visi_info;
1055
1056       visi_info = vmMgr->VMAvailableVisis();
1057       for (unsigned i=0; i < visi_info->size();i++) {
1058         printf("visi %d: name %s visiTypeId %d\n",i,
1059                ((*visi_info)[i]).name.string_of(), 
1060                ((*visi_info)[i]).visiTypeId);
1061       }
1062       delete visi_info;
1063     } 
1064   else if (argv[1][0] == 'c') {
1065     int ok, i;
1066     int j;
1067     if (Tcl_GetInt (interp, argv[2], &i) != TCL_OK) 
1068       return TCL_ERROR;
1069     if (Tcl_GetInt (interp, argv[3], &j) != TCL_OK) 
1070       return TCL_ERROR;
1071     if(j == 1){
1072         ok = vmMgr->VMCreateVisi(1,-1,i,CurrentPhase,NULL); 
1073     }
1074     else {
1075         ok = vmMgr->VMCreateVisi(1,-1,i,GlobalPhase,NULL); 
1076     }
1077   } 
1078   else if (argv[1][0] == 'k') {
1079     int i;
1080     if (Tcl_GetInt (interp, argv[2], &i) != TCL_OK) 
1081       return TCL_ERROR;
1082     vmMgr->VMDestroyVisi(i);
1083   } 
1084   else {
1085     sprintf(interp->result,
1086             "USAGE: visi [kill <ivalue>|create <ivalue>|info|active<cmd>]");
1087     return TCL_ERROR;
1088   }
1089   return TCL_OK;
1090 }
1091
1092 int ParadynExitCmd (ClientData,
1093                     Tcl_Interp *,
1094                     int, char **)
1095 {
1096   exit(0);
1097 }
1098
1099 static struct cmdTabEntry Pd_Cmds[] = {
1100   {"pause", ParadynPauseCmd},
1101   {"cont", ParadynContCmd},
1102   {"status", ParadynStatusCmd},
1103   {"list", ParadynListCmd},
1104   {"daemons", ParadynDaemonsCmd},
1105   {"detach", ParadynDetachCmd},
1106   {"disable", ParadynDisableCmd},
1107   {"enable", ParadynEnableCmd},
1108   {"gettotal", ParadynGetTotalCmd},
1109   {"metrics", ParadynMetricsCmd},
1110   {"print", ParadynPrintCmd},
1111   {"process", ParadynProcessCmd},
1112   {"resources", ParadynResourcesCmd},
1113   {"set", ParadynSetCmd},
1114   {"core", ParadynCoreCmd},
1115   {"search", ParadynSearchCmd},
1116   {"shg", ParadynSHGCmd},
1117   {"suppress", ParadynSuppressCmd},
1118   {"visi", ParadynVisiCmd},
1119   {"waSetAbstraction", ParadynWaSetAbstraction},
1120   {"waSelect", ParadynWaSelect},
1121   {"waUnselect", ParadynWaUnSelect},
1122   {"exit",ParadynExitCmd},
1123   {NULL, NULL}
1124 };
1125
1126 int ParadynCmd(ClientData clientData, 
1127                 Tcl_Interp *interp, 
1128                 int argc, 
1129                 char *argv[])
1130 {
1131   int i;
1132
1133   if (argc < 2) {
1134     sprintf(interp->result,"USAGE: %s <cmd>", argv[0]);
1135     return TCL_ERROR;
1136   }
1137
1138   for (i = 0; Pd_Cmds[i].cmdname; i++) {
1139     if (strcmp(Pd_Cmds[i].cmdname,argv[1]) == 0) {
1140       return ((Pd_Cmds[i].func)(clientData,interp,argc-1,argv+1));      
1141       }
1142   }
1143
1144   sprintf(interp->result,"unknown paradyn cmd '%s'",argv[1]);
1145   return TCL_ERROR;  
1146 }