xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/gp-display-text.cc (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "config.h"
22 #include <unistd.h>     // isatty
23 #include <errno.h>
24 
25 #include "gp-print.h"
26 #include "ipcio.h"
27 #include "Command.h"
28 #include "Dbe.h"
29 #include "DbeApplication.h"
30 #include "DbeSession.h"
31 #include "Experiment.h"
32 #include "Emsg.h"
33 #include "DbeView.h"
34 #include "DataObject.h"
35 #include "Function.h"
36 #include "Hist_data.h"
37 #include "PathTree.h"
38 #include "LoadObject.h"
39 #include "Function.h"
40 #include "FilterSet.h"
41 #include "Filter.h"
42 #include "MetricList.h"
43 #include "MemorySpace.h"
44 #include "Module.h"
45 #include "util.h"
46 #include "i18n.h"
47 #include "StringBuilder.h"
48 #include "debug.h"
49 #include "UserLabel.h"
50 
51 static char *exe_name;
52 static char **new_argv;
53 
54 void
55 reexec ()
56 {
57   if (dbeSession != NULL)
58     dbeSession->unlink_tmp_files ();
59   execvp (exe_name, new_argv);
60   fprintf (stderr, GTXT ("Error: reexec() failed (%d: %s)\n"), errno,
61 	   STR(strerror (errno)));
62   fflush (stderr);
63   exit (1);
64 }
65 
66 /**
67  * Run application under enhance if the following requirements are satisfied:
68  * 1. Environment variable GPROFNG_ENHANCE is not set to "no"
69  * 2. Standard input is terminal
70  * 3. Standard output is terminal
71  * 4. /bin/enhance exists and can work on this system
72  */
73 static void
74 reexec_enhance (int argc, char *argv[])
75 {
76   char *gp_enhance = getenv ("GPROFNG_ENHANCE");
77   if (NULL != gp_enhance && 0 == strcasecmp (gp_enhance, "no"))
78     return; // Do not enhance
79   // Verify that input and output are tty
80   if (!isatty (fileno (stdin)))     // stdin is not a terminal
81     return; // Do not enhance
82   if (!isatty (fileno (stdout)))    // stdout is not a terminal
83     return; // Do not enhance
84   char *enhance_name = NTXT ("/bin/enhance");
85   struct stat sbuf;
86   int res = stat (enhance_name, &sbuf); // Check if enhance exists
87   if (res == 0)
88     res = system (NTXT ("/bin/enhance /bin/true")); // Check if enhance can work
89   if (res != 0)
90     {
91       fflush (stdout);
92       printf (GTXT ("Warning: History and command editing is not supported on this system.\n"));
93       fflush (stdout);
94       return;
95     }
96   else
97     {
98       printf (GTXT ("Note: History and command editing is supported on this system.\n"));
99       fflush (stdout);
100     }
101   char **nargv = new char*[argc + 2];
102   for (int i = 0; i < argc; i++)
103     nargv[i + 1] = argv[i];
104   nargv[0] = enhance_name;
105   nargv[argc + 1] = NULL;
106   putenv (NTXT ("GPROFNG_ENHANCE=no")); // prevent recursion
107   execv (enhance_name, nargv);
108   // execv failed. Continue to run the program
109   delete[] nargv;
110 }
111 
112 int
113 main (int argc, char *argv[])
114 {
115   er_print *erprint;
116   int ind = 1;
117   if (argc > ind && *argv[ind] == '-')
118     {
119       int arg_count, cparam;
120       if (Command::get_command (argv[ind] + 1, arg_count, cparam) == WHOAMI)
121 	ind = ind + 1 + arg_count;
122     }
123   if (argc > ind && argv[ind] != NULL && *argv[ind] != '-')
124     reexec_enhance (argc, argv);
125 
126   // Save argv for reexec())
127   exe_name = argv[0];
128   new_argv = argv;
129 
130   if (argc > ind && argv[ind] != NULL && strcmp (argv[ind], "-IPC") == 0)
131     {
132       putenv (NTXT ("LC_NUMERIC=C")); // Use non-localized numeric data in IPC packets
133       erprint = new er_print (argc, argv);
134       theDbeApplication->rdtMode = false;
135       ipc_mainLoop (argc, argv);
136     }
137   else
138     {
139       erprint = new er_print (argc, argv);
140       erprint->start (argc, argv);
141     }
142 
143   dbeSession->unlink_tmp_files ();
144   if (DUMP_CALL_STACK)
145     {
146       extern long total_calls_add_stack, total_stacks, total_nodes, call_stack_size[201];
147       fprintf (stderr, NTXT ("total_calls_add_stack=%lld\ntotal_stacks=%lld\ntotal_nodes=%lld\n"),
148 	       (long long) total_calls_add_stack, (long long) total_stacks, (long long) total_nodes);
149       for (int i = 0; i < 201; i++)
150 	if (call_stack_size[i] != 0)
151 	    fprintf (stderr, NTXT ("   call_stack_size[%d] = %6lld\n"), i,
152 		     (long long) call_stack_size[i]);
153     }
154 #if defined(DEBUG)
155   delete erprint;
156 #endif
157   return 0;
158 }
159 
160 er_print::er_print (int argc, char *argv[])
161 : DbeApplication (argc, argv)
162 {
163   out_fname = GTXT ("<stdout>");
164   inp_file = stdin;
165   out_file = stdout;
166   dis_file = stdout;
167   cov_string = NULL;
168   limit = 0;
169   cstack = new Vector<Histable*>();
170   was_QQUIT = false;
171 }
172 
173 er_print::~er_print ()
174 {
175   free (cov_string);
176   delete cstack;
177   if (inp_file != stdin)
178     fclose (inp_file);
179 }
180 
181 void
182 er_print::start (int argc, char *argv[])
183 {
184   Vector<String> *res = theDbeApplication->initApplication (NULL, NULL, NULL);
185   res->destroy ();
186   delete res;
187 
188   // Create a view on the session
189   dbevindex = dbeSession->createView (0, -1);
190   dbev = dbeSession->getView (dbevindex);
191   limit = dbev->get_limit ();
192   (void) check_args (argc, argv);
193   int ngood = dbeSession->ngoodexps ();
194   if (ngood == 0)
195     {
196       fprintf (stderr, GTXT ("No valid experiments loaded; exiting\n"));
197       return;
198     }
199   dbeDetectLoadMachineModel (dbevindex);
200   run (argc, argv);
201 }
202 
203 bool
204 er_print::free_memory_before_exit ()
205 {
206   return was_QQUIT;
207 }
208 
209 void
210 er_print::usage ()
211 {
212 
213 /*
214   Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
215   end of the long option list.
216 */
217   printf ( GTXT (
218     "Usage: gprofng display text [OPTION(S)] [COMMAND(S)] [-script <script_file>] EXPERIMENT(S)\n"));
219 
220   printf ( GTXT (
221     "\n"
222     "Print a plain text version of the various displays supported by gprofng.\n"
223     "\n"
224     "Options:\n"
225     "\n"
226     " --version           print the version number and exit.\n"
227     " --help              print usage information and exit.\n"
228     " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
229     "\n"
230     " -script <script-file>  execute the commands stored in the script file;\n"
231     "                        this feature may be combined with commands specified\n"
232     "                        at the command line.\n"
233     "\n"
234     "Commands:\n"
235     "\n"
236     "This tool supports a rich set of commands to control the display of the\n"
237     "data; instead of, or in addition to, including these commands in a script\n"
238     "file, it is also allowed to include such commands at the command line;\n"
239     "in this case, the commands need to be prepended with the \"-\" symbol; the\n"
240     "commands are processed and interpreted left from right, so the order matters;\n"
241     "The gprofng manual documents the commands that are supported.\n"
242     "\n"
243     "If this tool is invoked without options, commands, or a script file, it starts\n"
244     "in interpreter mode. The user can then issue the commands interactively; the\n"
245     "session is terminated with the \"exit\" command in the interpreter.\n"
246     "\n"
247     "Documentation:\n"
248     "\n"
249     "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
250     "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
251     "should give you access to this document.\n"
252     "\n"
253     "See also:\n"
254     "\n"
255     "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1)\n"));
256 }
257 
258 int // returns count of experiments read
259 er_print::check_args (int argc, char *argv[])
260 {
261   CmdType cmd_type;
262   int arg_count;
263   int cparam;
264   int exp_no;
265   error_msg = NULL;
266 
267   Emsg *rcmsg = fetch_comments ();
268   while (rcmsg != NULL)
269     {
270       fprintf (stderr, NTXT ("%s: %s\n"), prog_name, rcmsg->get_msg ());
271       rcmsg = rcmsg->next;
272     }
273   delete_comments ();
274 
275   // Set up the list of experiments to add after checking the args
276   Vector<Vector<char*>*> *exp_list = new Vector<Vector<char*>*>();
277 
278   // Prescan the command line arguments, processing only a few
279   for (int i = 1; i < argc; i++)
280     {
281       if (*argv[i] != '-')
282 	{
283 	  // we're at the end -- get the list of experiments
284 	  //  Build the list of experiments, and set the searchpath
285 	  Vector<char*> *list = dbeSession->get_group_or_expt (argv[i]);
286 	  if (list->size () > 0)
287 	    {
288 	      for (int j = 0, list_sz = list->size (); j < list_sz; j++)
289 		{
290 		  char *path = list->fetch (j);
291 		  if (strlen (path) == 0 || strcmp (path, NTXT ("\\")) == 0)
292 		    continue;
293 		  char *p = strrchr (path, '/');
294 		  if (p)
295 		    {
296 		      // there's a directory in front of the name; add it to search path
297 		      *p = '\0';
298 		      dbeSession->set_search_path (path, false);
299 		    }
300 		}
301 	      list->destroy ();
302 	      list->append (dbe_strdup (argv[i]));
303 	      exp_list->append (list);
304 	    }
305 	  else
306 	    delete list;
307 	  continue;
308 	}
309 
310       // Not at the end yet, treat the next argument as a command
311       switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
312 	{
313 	case WHOAMI:
314 	  whoami = argv[i] + 1 + cparam;
315 	  break;
316 	case HELP:
317 	  if (i + 1 + arg_count == argc)
318 	    {
319 	      usage();
320 	      exit (0);
321 	    }
322 	  break;
323 	case HHELP:
324 	  Command::print_help (whoami, true, false, stdout);
325 	  fprintf (stdout, "\n");
326 	  indxo_list (false, stdout);
327 	  fprintf (stdout, "\n");
328 	  mo_list (false, stdout);
329 	  if (!getenv ("_BUILDING_MANPAGE"))
330 	    fprintf (stdout, GTXT ("\nSee gprofng(1) for more details\n"));
331 	  exit (0);
332 	case ADD_EXP:
333 	case DROP_EXP:
334 	case OPEN_EXP:
335 	  printf (GTXT ("Error: command %s can not appear on the command line\n"), argv[i]);
336 	  exit (2);
337 	case VERSION_cmd:
338 	  Application::print_version_info ();
339 	  exit (0);
340 	case AMBIGUOUS_CMD:
341 	  fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), argv[i]);
342 	  exit (2);
343 	case UNKNOWN_CMD:
344 	  fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), argv[i]);
345 	  exit (2);
346 	  // it's a plausible argument; see if we process now or later
347 	case SOURCE:
348 	case DISASM:
349 	case CSINGLE:
350 	case CPREPEND:
351 	case CAPPEND:
352 	case FSINGLE:
353 	case SAMPLE_DETAIL:
354 	case STATISTICS:
355 	case HEADER:
356 	  //skip the arguments to that command
357 	  i += arg_count;
358 	  if (i >= argc || end_command (argv[i]))
359 	    i--;
360 	  break;
361 	case PRINTMODE:
362 	case INDXOBJDEF:
363 	case ADDPATH:
364 	case SETPATH:
365 	case PATHMAP:
366 	case OBJECT_SHOW:
367 	case OBJECT_HIDE:
368 	case OBJECT_API:
369 	case OBJECTS_DEFAULT:
370 	case EN_DESC:
371 	  // these are processed in the initial pass over the arguments
372 	  proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
373 		    (arg_count > 1) ? argv[i + 2] : NULL,
374 		    (arg_count > 2) ? argv[i + 3] : NULL,
375 		    (arg_count > 3) ? argv[i + 4] : NULL);
376 	  i += arg_count;
377 	  break;
378 	default:
379 	  // any others, we skip for now
380 	  i += arg_count;
381 	  break;
382 	}
383     }
384 
385   // Make sure some experiments were specified
386   exp_no = exp_list->size ();
387   if (exp_no == 0)
388     { // no experiment name
389       fprintf (stderr, GTXT ("%s: Missing experiment directory (use the --help option to get a usage overview)\n"), whoami);
390       exit (1);
391     }
392 
393   // add the experiments to the session
394   char *errstr = dbeOpenExperimentList (0, exp_list, false);
395   for (long i = 0; i < exp_list->size (); i++)
396     {
397       Vector<char*>* p = exp_list->get (i);
398       Destroy (p);
399     }
400   delete exp_list;
401   if (errstr != NULL)
402     {
403       fprintf (stderr, NTXT ("%s"), errstr);
404       free (errstr);
405     }
406 
407   return exp_no;
408 }
409 
410 int
411 er_print::is_valid_seg_name (char *lo_name, int prev)
412 {
413   // prev is the loadobject segment index that was last returned
414   // search starts following that loadobject
415   int index;
416   LoadObject *lo;
417   char *p_lo_name = lo_name;
418   char *name = NULL;
419 
420   // strip angle brackets from all but <Unknown> and <Total>
421   if (strcmp (lo_name, "<Unknown>") && strcmp (lo_name, "<Total>"))
422     {
423       if (*lo_name == '<')
424 	{
425 	  name = dbe_strdup (lo_name + 1);
426 	  p_lo_name = name;
427 	  char *p = strchr (name, '>');
428 	  if (p)
429 	    *p = '\0';
430 	}
431     }
432 
433   // get the load object list from the session
434   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
435   Vec_loop (LoadObject*, lobjs, index, lo)
436   {
437     if (prev > 0)
438       {
439 	if (lo->seg_idx == prev)    // this is where we left off
440 	  prev = -1;
441 	continue;
442       }
443 
444     // does this one match?
445     if (cmp_seg_name (lo->get_pathname (), p_lo_name))
446       {
447 	delete lobjs;
448 	free (name);
449 	size_t len = strlen (lo_name);
450 	if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
451 	    (len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
452 	  {
453 	    fprintf (stderr, GTXT ("Error: Java class `%s' is not selectable\n"), lo_name);
454 	    return -1;
455 	  }
456 	return lo->seg_idx;
457       }
458   }
459   delete lobjs;
460   free (name);
461   return -1;
462 }
463 
464 int
465 er_print::cmp_seg_name (char *full_name, char *lo_name)
466 {
467   char *cmp_name;
468   if (!strchr (lo_name, '/') && (cmp_name = strrchr (full_name, '/')))
469     cmp_name++; // basename
470   else
471     cmp_name = full_name; // full path name
472   return !strcmp (lo_name, cmp_name);
473 }
474 
475 // processing object_select
476 //	Note that this does not affect the strings in Settings,
477 //	unlike object_show, object_hide, and object_api
478 int
479 er_print::process_object_select (char *names)
480 {
481   int index;
482   LoadObject *lo;
483   int no_lobj = 0;
484   bool got_err = false;
485   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
486   if ((names == NULL) || !strcasecmp (names, Command::ALL_CMD))
487     { // full coverage
488       Vec_loop (LoadObject*, lobjs, index, lo)
489       {
490 	dbev->set_lo_expand (lo->seg_idx, LIBEX_SHOW);
491       }
492     }
493   else
494     { // parsing coverage
495       // first, hide functions from all loadobjects
496       // except the java ones
497       Vec_loop (LoadObject*, lobjs, index, lo)
498       {
499 	char *lo_name = lo->get_name ();
500 	if (lo_name != NULL)
501 	  {
502 	    size_t len = strlen (lo_name);
503 	    if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
504 		(len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
505 	      continue;
506 	  }
507 	dbev->set_lo_expand (lo->seg_idx, LIBEX_HIDE);
508       }
509 
510       Vector <char *> *tokens = split_str (names, ',');
511       for (long j = 0, sz = VecSize (tokens); j < sz; j++)
512 	{
513 	  // loop over the provided names
514 	  char *lo_name = tokens->get (j);
515 	  int seg_idx = -1;
516 	  seg_idx = is_valid_seg_name (lo_name, seg_idx);
517 	  while (seg_idx != -1)
518 	    {
519 	      dbev->set_lo_expand (seg_idx, LIBEX_SHOW);
520 	      no_lobj++;
521 	      seg_idx = is_valid_seg_name (lo_name, seg_idx);
522 	    }
523 	  if (no_lobj == 0)
524 	    {
525 	      got_err = true;
526 	      fprintf (stderr, GTXT ("Error: Unknown load object: `%s'\n"), lo_name);
527 	    }
528 	  free (lo_name);
529 	}
530       delete tokens;
531     }
532 
533   if (!got_err)
534     { // good coverage string
535       free (cov_string);
536       cov_string = strdup (names);
537     }
538   else
539     { // bad, restore original coverage
540       no_lobj = -1;
541       process_object_select (cov_string);
542     }
543   delete lobjs;
544   return no_lobj;
545 }
546 
547 int
548 er_print::set_libexpand (char *cov, enum LibExpand expand)
549 {
550   bool changed = dbev->set_libexpand (cov, expand);
551   if (changed == true)
552     dbev->update_lo_expands ();
553   return 0;
554 }
555 
556 int
557 er_print::set_libdefaults ()
558 {
559   dbev->set_libdefaults ();
560   return 0;
561 }
562 
563 bool
564 er_print::end_command (char *cmd)
565 {
566   if (cmd == NULL || *cmd == '-')
567     return true;
568   size_t len = strlen (cmd);
569   if (cmd[len - 1] == '/')
570     len--;
571   if ((len > 3 && !strncmp (&cmd[len - 3], NTXT (".er"), 3)) ||
572       (len > 4 && !strncmp (&cmd[len - 4], NTXT (".erg"), 4)))
573     return true;
574   return false;
575 }
576 
577 // Now actually start processing the arguments
578 void
579 er_print::run (int argc, char *argv[])
580 {
581   CmdType cmd_type;
582   int arg_count, cparam, i;
583   bool got = false;
584   char *arg1, *arg2;
585   for (i = 1; i < argc; i++)
586     {
587       if (*argv[i] != '-') // open experiment pointer files
588 	continue;
589       switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
590 	{
591 	case WHOAMI:
592 	  whoami = argv[i] + 1 + cparam;
593 	  break;
594 	case SCRIPT:
595 	  got = true;
596 	  inp_file = fopen (argv[++i], "r");
597 	  if (inp_file == NULL)
598 	    {
599 	      fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), argv[i]);
600 	      exit (3);
601 	    }
602 	  proc_script ();
603 	  break;
604 	case STDIN:
605 	  got = true;
606 	  inp_file = stdin;
607 	  proc_script ();
608 	  break;
609 	case SOURCE: // with option arg_count == 2
610 	case DISASM:
611 	  got = true;
612 	  i += arg_count;
613 	  if ((i >= argc) || end_command (argv[i]))
614 	    {
615 	      i--;
616 	      arg1 = argv[i];
617 	      arg2 = NTXT ("");
618 	    }
619 	  else
620 	    {
621 	      arg1 = argv[i - 1];
622 	      arg2 = argv[i];
623 	    }
624 	  proc_cmd (cmd_type, cparam, arg1, arg2, NULL, NULL, true);
625 	  break;
626 	case CSINGLE:
627 	case CPREPEND:
628 	case CAPPEND:
629 	case FSINGLE:
630 	  got = true;
631 	  i += arg_count;
632 	  if ((i >= argc) || end_command (argv[i]))
633 	    {
634 	      i--;
635 	      proc_cmd (cmd_type, cparam, argv[i], NTXT ("1"));
636 	    }
637 	  else
638 	    proc_cmd (cmd_type, cparam, argv[i - 1], argv[i]);
639 	  break;
640 	case SAMPLE_DETAIL: // with option arg_count == 1
641 	case STATISTICS:
642 	case HEADER:
643 	  got = true;
644 	  // now fall through to process the command
645 	case COMPARE:
646 	  got = true;
647 	  i += arg_count;
648 	  if ((i >= argc) || end_command (argv[i]))
649 	    {
650 	      i--;
651 	      proc_cmd (cmd_type, cparam, NULL, NULL);
652 	    }
653 	  else
654 	    proc_cmd (cmd_type, cparam, argv[i], NULL);
655 	  break;
656 	case PRINTMODE:
657 	case INDXOBJDEF:
658 	case ADDPATH:
659 	case SETPATH:
660 	case PATHMAP:
661 	case OBJECT_SHOW:
662 	case OBJECT_HIDE:
663 	case OBJECT_API:
664 	case OBJECTS_DEFAULT:
665 	case EN_DESC:
666 	  got = true;
667 	  // these have been processed already
668 	  i += arg_count;
669 	  break;
670 	case LIMIT:
671 	  got = true;
672 	  proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
673 		    (arg_count > 1) ? argv[i + 2] : NULL);
674 	  i += arg_count;
675 	  break;
676 	default:
677 	  got = true;
678 	  proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
679 		    (arg_count > 1) ? argv[i + 2] : NULL);
680 	  i += arg_count;
681 	  break;
682 	}
683     }
684   if (!got) // no command has been specified
685     proc_script ();
686 }
687 
688 #define MAXARGS 20
689 
690 void
691 er_print::proc_script ()
692 {
693   CmdType cmd_type;
694   int arg_count, cparam;
695   char *cmd, *end_cmd;
696   char *script = NULL;
697   char *arglist[MAXARGS];
698   char *line = NULL;
699   int lineno = 0;
700   while (!feof (inp_file))
701     {
702       if (inp_file == stdin)
703 	printf (NTXT ("(%s) "), get_basename (prog_name));
704       free (script);
705       script = read_line (inp_file);
706       if (script == NULL)
707 	continue;
708       free (line);
709       line = dbe_strdup (script);
710       lineno++;
711       for (int i = 0; i < MAXARGS; i++)
712 	arglist[i] = NULL;
713 
714       // ensure it's terminated by a \n, and remove that character
715       strtok (script, NTXT ("\n"));
716 
717       // extract the command
718       cmd = strtok (script, NTXT (" \t"));
719       if (cmd == NULL)
720 	continue;
721       if (*cmd == '#')
722 	{
723 	  fprintf (stderr, NTXT ("%s"), line);
724 	  continue;
725 	}
726       if (*cmd == '\n')
727 	continue;
728 
729       char *remainder = strtok (NULL, NTXT ("\n"));
730       // now extract the arguments
731       int nargs = 0;
732       for (;;)
733 	{
734 	  end_cmd = NULL;
735 	  if (nargs >= MAXARGS)
736 	    fprintf (stderr, GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
737 		     MAXARGS, cmd, lineno);
738 	  char *nextarg = strtok (remainder, NTXT ("\n"));
739 	  if ((nextarg == NULL) || (*nextarg == '#'))
740 	    // either the end of the line, or a comment indicator
741 	    break;
742 	  if (nargs >= MAXARGS)
743 	    {
744 	      parse_qstring (nextarg, &end_cmd);
745 	      nargs++;
746 	    }
747 	  else
748 	    arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
749 	  remainder = end_cmd;
750 	  if (remainder == NULL)
751 	    break;
752 	  // skip any blanks or tabs to get to next argument
753 	  while (*remainder == ' ' || *remainder == '\t')
754 	    remainder++;
755 	}
756 
757       cmd_type = Command::get_command (cmd, arg_count, cparam);
758 
759       // check for extra arguments
760       if (cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF && nargs > arg_count)
761 	fprintf (stderr, GTXT ("Warning: extra arguments to %s command, line %d\n"),
762 		 cmd, lineno);
763       switch (cmd_type)
764 	{
765 	case SOURCE:
766 	case DISASM:
767 	  // ignore any third parameter
768 	  // if there was, we have written a warning
769 	  proc_cmd (cmd_type, cparam, arglist[0], arglist[1], NULL, NULL,
770 		    (inp_file != stdin));
771 	  break;
772 	case QUIT:
773 	  free (script);
774 	  free (line);
775 	  exit (0);
776 	case QQUIT:
777 	  was_QQUIT = true;
778 	  free (script);
779 	  free (line);
780 	  return;
781 	case STDIN:
782 	  break;
783 	case COMMENT:
784 	  fprintf (dis_file, NTXT ("%s"), line);
785 	  break;
786 	case AMBIGUOUS_CMD:
787 	  fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), cmd);
788 	  break;
789 	case UNKNOWN_CMD:
790 	  if (*cmd != '\n')
791 	    fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), cmd);
792 	  break;
793 	default:
794 	  proc_cmd (cmd_type, cparam, arglist[0], arglist[1]);
795 	  break;
796 	}
797     }
798   // free up the input line
799   free (script);
800   free (line);
801 }
802 
803 void
804 er_print::proc_cmd (CmdType cmd_type, int cparam,
805 		    char *arg1, char *arg2, char *arg3, char *arg4, bool xdefault)
806 {
807   er_print_common_display *cd;
808   FILE *ck_file, *save_file;
809   char *name;
810   int bgn_index, end_index, index;
811   Cmd_status status;
812   char *scratch, *scratch1;
813   switch (cmd_type)
814     {
815     case FUNCS:
816       print_func (Histable::FUNCTION, MODE_LIST,
817 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
818       break;
819     case FDETAIL:
820       print_func (Histable::FUNCTION, MODE_DETAIL,
821 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
822       break;
823     case FSINGLE:
824       print_func (Histable::FUNCTION, MODE_DETAIL,
825 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL),
826 		  arg1, arg2);
827       break;
828     case HOTPCS:
829       print_func (Histable::INSTR, MODE_LIST,
830 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
831       break;
832     case PDETAIL:
833       print_func (Histable::INSTR, MODE_DETAIL,
834 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
835       break;
836     case HOTLINES:
837       print_func (Histable::LINE, MODE_LIST,
838 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
839       break;
840     case LDETAIL:
841       print_func (Histable::LINE, MODE_DETAIL,
842 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
843       break;
844     case OBJECTS:
845       print_objects ();
846       break;
847     case OVERVIEW_NEW:
848       print_overview ();
849       break;
850     case LOADOBJECT:
851       print_segments ();
852       break;
853     case GPROF:
854       print_func (Histable::FUNCTION, MODE_GPROF,
855 		  dbev->get_metric_list (MET_CALL), dbev->get_metric_list (MET_NORMAL));
856       break;
857     case CALLTREE:
858       if (dbev->comparingExperiments ())
859 	{
860 	  fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
861 	  break;
862 	}
863       print_ctree (cmd_type);
864       break;
865     case CSINGLE:
866     case CPREPEND:
867     case CAPPEND:
868     case CRMFIRST:
869     case CRMLAST:
870       print_gprof (cmd_type, arg1, arg2);
871       break;
872     case EXP_LIST:
873       exp_list ();
874       break;
875     case DESCRIBE:
876       describe ();
877       break;
878     case SCOMPCOM:
879       status = dbev->proc_compcom (arg1, true, false);
880       if (status != CMD_OK)
881 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
882       break;
883     case STHRESH:
884       status = dbev->proc_thresh (arg1, true, false);
885       if (status != CMD_OK)
886 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
887       break;
888     case DCOMPCOM:
889       status = dbev->proc_compcom (arg1, false, false);
890       if (status != CMD_OK)
891 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
892       break;
893     case COMPCOM:
894       status = dbev->proc_compcom (arg1, true, false);
895       if (status != CMD_OK)
896 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
897       status = dbev->proc_compcom (arg1, false, false);
898       if (status != CMD_OK)
899 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
900       break;
901     case DTHRESH:
902       status = dbev->proc_thresh (arg1, false, false);
903       if (status != CMD_OK)
904 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
905       break;
906     case SOURCE:
907     case DISASM:
908       {
909 	if (arg3 != NULL)
910 	  abort ();
911 	if (arg1 == NULL)
912 	  {
913 	    fprintf (stderr, GTXT ("Error: Invalid function/file setting: \n"));
914 	    break;
915 	  }
916 	char *fcontext = NULL;
917 	char *arg = parse_fname (arg1, &fcontext);
918 	if (arg == NULL)
919 	  {
920 	    fprintf (stderr, GTXT ("Error: Invalid function/file setting: %s\n"), arg1);
921 	    free (fcontext);
922 	    break;
923 	  }
924 	if (arg2 && (strlen (arg2) == 0))
925 	  arg2 = NULL;
926 	print_anno_file (arg, arg2, fcontext, cmd_type == DISASM,
927 			 dis_file, inp_file, out_file, dbev, xdefault);
928 	free (arg);
929 	free (fcontext);
930 	break;
931       }
932     case METRIC_LIST:
933       proc_cmd (METRICS, cparam, NULL, NULL);
934       dbev->get_metric_ref (MET_NORMAL)->print_metric_list (dis_file,
935 							    GTXT ("Available metrics:\n"), false);
936       break;
937     case METRICS:
938       if (arg1)
939 	{
940 	  char *ret = dbev->setMetrics (arg1, false);
941 	  if (ret != NULL)
942 	    {
943 	      fprintf (stderr, GTXT ("Error: %s\n"), ret);
944 	      proc_cmd (METRIC_LIST, cparam, NULL, NULL);
945 	      break;
946 	    }
947 	}
948       scratch = dbev->get_metric_list (MET_NORMAL)->get_metrics ();
949       fprintf (dis_file, GTXT ("Current metrics: %s\n"), scratch);
950       free (scratch);
951       proc_cmd (SORT, cparam, NULL, NULL);
952       break;
953     case GMETRIC_LIST:
954       scratch = dbev->get_metric_list (MET_CALL)->get_metrics ();
955       fprintf (dis_file, GTXT ("Current caller-callee metrics: %s\n"), scratch);
956       free (scratch);
957       fprintf (dis_file, GTXT ("Current caller-callee sort Metric: %s\n"),
958 	       dbev->getSort (MET_DATA));
959       break;
960     case INDX_METRIC_LIST:
961       scratch = dbev->get_metric_list (MET_INDX)->get_metrics ();
962       fprintf (dis_file, GTXT ("Current index-object metrics: %s\n"), scratch);
963       free (scratch);
964       scratch = dbev->getSort (MET_INDX);
965       fprintf (dis_file, GTXT ("Current index-object sort Metric: %s\n"), scratch);
966       free (scratch);
967       break;
968     case SORT:
969       if (arg1)
970 	{
971 	  char *ret = dbev->setSort (arg1, MET_NORMAL, false);
972 	  if (ret != NULL)
973 	    {
974 	      fprintf (stderr, GTXT ("Error: %s\n"), ret);
975 	      proc_cmd (METRICS, cparam, NULL, NULL);
976 	      break;
977 	    }
978 	  dbev->setSort (arg1, MET_SRCDIS, false);
979 	  dbev->setSort (arg1, MET_CALL, false);
980 	  dbev->setSort (arg1, MET_DATA, false);
981 	  dbev->setSort (arg1, MET_INDX, false);
982 	  dbev->setSort (arg1, MET_CALL_AGR, false);
983 	  dbev->setSort (arg1, MET_IO, false);
984 	  dbev->setSort (arg1, MET_HEAP, false);
985 	}
986       scratch = dbev->getSort (MET_NORMAL);
987       scratch1 = dbev->getSortCmd (MET_NORMAL);
988       fprintf (dis_file,
989 	       GTXT ("Current Sort Metric: %s ( %s )\n"), scratch, scratch1);
990       free (scratch1);
991       free (scratch);
992       break;
993     case OBJECT_SHOW:
994       if (arg1)
995 	set_libexpand (arg1, LIBEX_SHOW);
996       obj_list ();
997       break;
998     case OBJECT_HIDE:
999       if (arg1)
1000 	set_libexpand (arg1, LIBEX_HIDE);
1001       obj_list ();
1002       break;
1003     case OBJECT_API:
1004       if (arg1)
1005 	set_libexpand (arg1, LIBEX_API);
1006       obj_list ();
1007       break;
1008     case OBJECTS_DEFAULT:
1009       set_libdefaults ();
1010       obj_list ();
1011       break;
1012     case OBJECT_LIST:
1013       obj_list ();
1014       break;
1015     case OBJECT_SELECT:
1016       if (arg1)
1017 	{
1018 	  if (process_object_select (arg1) != -1)
1019 	    proc_cmd (OBJECT_LIST, cparam, NULL, NULL);
1020 	  else
1021 	    fprintf (stderr, GTXT ("Error: Type \"object_list\" for a list of all load objects.\n"));
1022 	}
1023       else
1024 	fprintf (stderr, GTXT ("Error: No load object has been specified.\n"));
1025       break;
1026     case LOADOBJECT_LIST:
1027       seg_list ();
1028       break;
1029     case LOADOBJECT_SELECT:
1030       if (arg1)
1031 	{
1032 	  if (process_object_select (arg1) != -1)
1033 	    proc_cmd (LOADOBJECT_LIST, cparam, NULL, NULL);
1034 	  else
1035 	    fprintf (stderr, GTXT ("Error: Type \"segment_list\" for a list of all segments.\n"));
1036 	}
1037       else
1038 	fprintf (stderr, GTXT ("Error: No segment has been specified.\n"));
1039       break;
1040     case SAMPLE_LIST:
1041       filter_list (SAMPLE_LIST);
1042       break;
1043     case SAMPLE_SELECT:
1044       if (arg1 && !dbev->set_pattern (SAMPLE_FILTER_IDX, arg1))
1045 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1046       proc_cmd (SAMPLE_LIST, cparam, NULL, NULL);
1047       break;
1048     case THREAD_LIST:
1049       filter_list (THREAD_LIST);
1050       break;
1051     case THREAD_SELECT:
1052       if (arg1 && !dbev->set_pattern (THREAD_FILTER_IDX, arg1))
1053 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1054       proc_cmd (THREAD_LIST, cparam, NULL, NULL);
1055       break;
1056     case LWP_LIST:
1057       filter_list (LWP_LIST);
1058       break;
1059     case LWP_SELECT:
1060       if (arg1 && !dbev->set_pattern (LWP_FILTER_IDX, arg1))
1061 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1062       proc_cmd (LWP_LIST, cparam, NULL, NULL);
1063       break;
1064     case CPU_LIST:
1065       filter_list (CPU_LIST);
1066       break;
1067     case CPU_SELECT:
1068       if (arg1 && !dbev->set_pattern (CPU_FILTER_IDX, arg1))
1069 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1070       proc_cmd (CPU_LIST, cparam, NULL, NULL);
1071       break;
1072     case FILTERS:
1073       if (arg1 != NULL)
1074 	{
1075 	  if (strcmp (arg1, NTXT ("True")) == 0)
1076 	    scratch = dbev->set_filter (NULL);
1077 	  else
1078 	    scratch = dbev->set_filter (arg1);
1079 	  if (scratch != NULL)
1080 	    fprintf (stderr, GTXT ("Error: %s\n"), scratch);
1081 	}
1082       scratch = dbev->get_filter ();
1083       fprintf (dis_file, GTXT ("current filter setting: \"%s\"\n"),
1084 	       scratch == NULL ? GTXT ("<none>") : scratch);
1085       break;
1086     case OUTFILE:
1087       if (arg1)
1088 	{
1089 	  set_outfile (arg1, out_file, false);
1090 	  if (inp_file != stdin)
1091 	    dis_file = out_file;
1092 	}
1093       break;
1094     case APPENDFILE:
1095       if (arg1)
1096 	{
1097 	  set_outfile (arg1, out_file, true);
1098 	  if (inp_file != stdin)
1099 	    dis_file = out_file;
1100 	}
1101       break;
1102     case LIMIT:
1103       if (arg1)
1104 	{
1105 	  limit = (int) strtol (arg1, (char **) NULL, 10);
1106 	  char *res = dbeSetPrintLimit (dbevindex, limit);
1107 	  if (res != NULL)
1108 	    fprintf (stderr, NTXT ("%s\n"), res);
1109 	}
1110 
1111       limit = dbeGetPrintLimit (dbevindex);
1112       fprintf (stderr, GTXT ("Print limit set to %d\n"), limit);
1113       break;
1114     case NAMEFMT:
1115       if (arg1)
1116 	{
1117 	  status = dbev->set_name_format (arg1);
1118 	  if (status != CMD_OK)
1119 	    fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
1120 	}
1121       else
1122 	fprintf (stderr, GTXT ("Error: No format has been specified.\n"));
1123       break;
1124     case VIEWMODE:
1125       {
1126 	if (arg1)
1127 	  {
1128 	    status = dbev->set_view_mode (arg1, false);
1129 	    if (status != CMD_OK)
1130 	      fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
1131 	  }
1132 	const char *vname = "unknown";
1133 	int vm = dbev->get_view_mode ();
1134 	switch (vm)
1135 	  {
1136 	  case VMODE_USER:
1137 	    vname = "user";
1138 	    break;
1139 	  case VMODE_EXPERT:
1140 	    vname = "expert";
1141 	    break;
1142 	  case VMODE_MACHINE:
1143 	    vname = "machine";
1144 	    break;
1145 	  }
1146 	fprintf (stderr, GTXT ("Viewmode set to %s\n"), vname);
1147       }
1148       break;
1149 
1150       // EN_DESC does not make sense after experiments are read, but it does make sense on the command line,
1151       //	processed before the experiments are read.
1152     case EN_DESC:
1153       if (arg1)
1154 	{
1155 	  status = dbev->set_en_desc (arg1, false);
1156 	  if (status != CMD_OK)
1157 	    fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
1158 	}
1159       else
1160 	fprintf (stderr, GTXT ("Error: No descendant processing has been specified.\n"));
1161       break;
1162     case SETPATH:
1163     case ADDPATH:
1164       if (arg1)
1165 	dbeSession->set_search_path (arg1, (cmd_type == SETPATH));
1166       fprintf (dis_file, GTXT ("search path:\n"));
1167       Vec_loop (char*, dbeSession->get_search_path (), index, name)
1168       {
1169 	fprintf (dis_file, NTXT ("\t%s\n"), name);
1170       }
1171       break;
1172     case PATHMAP:
1173       {
1174 	Vector<pathmap_t*> *pathMaps = dbeSession->get_pathmaps ();
1175 	if (arg1 != NULL)
1176 	  {
1177 	    if (arg2 == NULL)
1178 	      {
1179 		fprintf (stderr, GTXT ("Error: No replacement path prefix has been specified.\n"));
1180 		break;
1181 	      }
1182 	    // add this mapping to the session
1183 	    char *err = Settings::add_pathmap (pathMaps, arg1, arg2);
1184 	    if (err != NULL)
1185 	      {
1186 		fprintf (stderr, NTXT ("%s"), err);
1187 		free (err);
1188 	      }
1189 	  }
1190 	fprintf (dis_file, GTXT ("Path mappings: from -> to\n"));
1191 	for (int i = 0, sz = pathMaps->size (); i < sz; i++)
1192 	  {
1193 	    pathmap_t *thismap = pathMaps->get (i);
1194 	    fprintf (dis_file, NTXT ("\t`%s' -> `%s'\n"), thismap->old_prefix, thismap->new_prefix);
1195 	  }
1196       }
1197       break;
1198     case SAMPLE_DETAIL:
1199       if (get_exp_id (arg1, bgn_index, end_index) != -1)
1200 	{
1201 	  cd = new er_print_experiment (dbev, bgn_index, end_index, false,
1202 					false, false, true, true);
1203 	  print_cmd (cd);
1204 	  delete cd;
1205 	}
1206       break;
1207     case STATISTICS:
1208       if (get_exp_id (arg1, bgn_index, end_index) != -1)
1209 	{
1210 	  cd = new er_print_experiment (dbev, bgn_index, end_index, false,
1211 					false, true, true, false);
1212 	  print_cmd (cd);
1213 	  delete cd;
1214 	}
1215       break;
1216     case PRINTMODE:
1217       {
1218 	if (arg1 == NULL)
1219 	  {
1220 	    fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
1221 	    break;
1222 	  }
1223 	char *s = dbeSetPrintMode (dbevindex, arg1);
1224 	if (s != NULL)
1225 	  {
1226 	    fprintf (stderr, NTXT ("%s\n"), s);
1227 	    break;
1228 	  }
1229 	fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
1230       }
1231       break;
1232     case HEADER:
1233       if (get_exp_id (arg1, bgn_index, end_index) != -1)
1234 	{
1235 	  cd = new er_print_experiment (dbev, bgn_index, end_index, false,
1236 					true, false, false, false);
1237 	  print_cmd (cd);
1238 	  delete cd;
1239 	}
1240       break;
1241     case COMPARE:
1242       if (arg1 == NULL)
1243 	{
1244 	  fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
1245 	  break;
1246 	}
1247       else
1248 	{
1249 	  int cmp;
1250 	  if (strcasecmp (arg1, NTXT ("OFF")) == 0 || strcmp (arg1, NTXT ("0")) == 0)
1251 	    cmp = CMP_DISABLE;
1252 	  else if (strcasecmp (arg1, NTXT ("ON")) == 0 || strcmp (arg1, NTXT ("1")) == 0)
1253 	    cmp = CMP_ENABLE;
1254 	  else if (strcasecmp (arg1, NTXT ("DELTA")) == 0)
1255 	    cmp = CMP_DELTA;
1256 	  else if (strcasecmp (arg1, NTXT ("RATIO")) == 0)
1257 	    cmp = CMP_RATIO;
1258 	  else
1259 	    {
1260 	      fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
1261 	      break;
1262 	    }
1263 	  int oldMode = dbev->get_compare_mode ();
1264 	  dbev->set_compare_mode (cmp);
1265 	  if (oldMode != cmp)
1266 	    {
1267 	      dbev->reset_data (false);
1268 	      dbeSession->reset_data ();
1269 	    }
1270 	}
1271       break;
1272     case LEAKS:
1273       if (!dbeSession->is_leaklist_available ())
1274 	{
1275 	  fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
1276 	  break;
1277 	}
1278       if (dbev->comparingExperiments ())
1279 	{ // XXXX show warning for compare
1280 	  fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
1281 	  break;
1282 	}
1283       cd = new er_print_leaklist (dbev, true, false, dbev->get_limit ());
1284       print_cmd (cd);
1285       delete cd;
1286       break;
1287     case ALLOCS:
1288       if (!dbeSession->is_leaklist_available ())
1289 	{
1290 	  fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
1291 	  break;
1292 	}
1293       cd = new er_print_leaklist (dbev, false, true, dbev->get_limit ());
1294       print_cmd (cd);
1295       delete cd;
1296       break;
1297     case HEAP:
1298       if (!dbeSession->is_heapdata_available ())
1299 	{
1300 	  fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
1301 	  break;
1302 	}
1303       cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, false, dbev->get_limit ());
1304       print_cmd (cd);
1305       delete cd;
1306       break;
1307     case HEAPSTAT:
1308       if (!dbeSession->is_heapdata_available ())
1309 	{
1310 	  fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
1311 	  break;
1312 	}
1313       cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, true, dbev->get_limit ());
1314       print_cmd (cd);
1315       delete cd;
1316       break;
1317     case IOACTIVITY:
1318       if (!dbeSession->is_iodata_available ())
1319 	{
1320 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1321 	  break;
1322 	}
1323       if (dbev->comparingExperiments ())
1324 	{ // XXXX show warning for compare
1325 	  fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
1326 	  break;
1327 	}
1328       cd = new er_print_ioactivity (dbev, Histable::IOACTFILE, false, dbev->get_limit ());
1329       print_cmd (cd);
1330       delete cd;
1331       break;
1332     case IOVFD:
1333       if (!dbeSession->is_iodata_available ())
1334 	{
1335 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1336 	  break;
1337 	}
1338       cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, false, dbev->get_limit ());
1339       print_cmd (cd);
1340       delete cd;
1341       break;
1342     case IOCALLSTACK:
1343       if (!dbeSession->is_iodata_available ())
1344 	{
1345 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1346 	  break;
1347 	}
1348       cd = new er_print_ioactivity (dbev, Histable::IOCALLSTACK, false, dbev->get_limit ());
1349       print_cmd (cd);
1350       delete cd;
1351       break;
1352     case IOSTAT:
1353       if (!dbeSession->is_iodata_available ())
1354 	{
1355 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1356 	  break;
1357 	}
1358       cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, true, dbev->get_limit ());
1359       print_cmd (cd);
1360       delete cd;
1361       break;
1362     case HELP:
1363       Command::print_help(whoami, false, true, out_file);
1364       break;
1365     case VERSION_cmd:
1366       Application::print_version_info ();
1367       break;
1368     case SCRIPT:
1369       if (arg1)
1370 	{
1371 	  ck_file = fopen (arg1, NTXT ("r"));
1372 	  if (ck_file == NULL)
1373 	    fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), arg1);
1374 	  else
1375 	    {
1376 	      save_file = inp_file;
1377 	      inp_file = ck_file;
1378 	      proc_script ();
1379 	      inp_file = save_file;
1380 	    }
1381 	}
1382       else
1383 	fprintf (stderr, GTXT ("Error: No filename has been specified.\n"));
1384       break;
1385     case QUIT:
1386       exit (0);
1387       break;
1388 
1389       // commands relating to index Objects
1390     case INDXOBJ:
1391       if ((cparam == -1) && (arg1 == NULL))
1392 	{
1393 	  fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
1394 	  break;
1395 	}
1396       // automatically load machine model if applicable
1397       dbeDetectLoadMachineModel (dbevindex);
1398       indxobj (arg1, cparam);
1399       break;
1400     case INDXOBJLIST:
1401       // automatically load machine model if applicable
1402       dbeDetectLoadMachineModel (dbevindex);
1403       indxo_list (false, out_file);
1404       break;
1405 
1406       // define a new IndexObject type
1407     case INDXOBJDEF:
1408       if (arg1 == NULL)
1409 	{
1410 	  fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
1411 	  break;
1412 	}
1413       if (arg2 == NULL)
1414 	{
1415 	  fprintf (stderr, GTXT ("Error: No index-expr has been specified.\n"));
1416 	  break;
1417 	}
1418       indxo_define (arg1, arg2, arg3, arg4);
1419       break;
1420 
1421       // the commands following this are unsupported/hidden
1422     case IFREQ:
1423       if (!dbeSession->is_ifreq_available ())
1424 	{
1425 	  fprintf (out_file, GTXT ("\nInstruction frequency data was not requested when recording experiments\n\n"));
1426 	  break;
1427 	}
1428       ifreq ();
1429       break;
1430     case DUMPNODES:
1431       dump_nodes ();
1432       break;
1433     case DUMPSTACKS:
1434       dump_stacks ();
1435       break;
1436     case DUMPUNK:
1437       dump_unk_pcs ();
1438       break;
1439     case DUMPFUNC:
1440       dump_funcs (arg1);
1441       break;
1442     case DUMPDOBJS:
1443       dump_dataobjects (arg1);
1444       break;
1445     case DUMPMAP:
1446       dump_map ();
1447       break;
1448     case DUMPENTITIES:
1449       dump_entities ();
1450       break;
1451     case DUMP_PROFILE:
1452       dbev->dump_profile (out_file);
1453       break;
1454     case DUMP_SYNC:
1455       dbev->dump_sync (out_file);
1456       break;
1457     case DUMP_HWC:
1458       dbev->dump_hwc (out_file);
1459       break;
1460     case DUMP_HEAP:
1461       if (!dbeSession->is_leaklist_available ())
1462 	{
1463 	  fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
1464 	  break;
1465 	}
1466       dbev->dump_heap (out_file);
1467       break;
1468     case DUMP_IOTRACE:
1469       if (!dbeSession->is_iodata_available ())
1470 	{
1471 	  fprintf (out_file, GTXT ("\nI/O trace information was not requested when recording experiments\n\n"));
1472 	  break;
1473 	}
1474       dbev->dump_iotrace (out_file);
1475       break;
1476     case DMEM:
1477       if (arg1 == NULL)
1478 	fprintf (stderr, GTXT ("Error: No sample has been specified.\n"));
1479       else
1480 	{
1481 	  Experiment *exp = dbeSession->get_exp (0);
1482 	  if (exp != NULL)
1483 	    exp->DBG_memuse (arg1);
1484 	}
1485       break;
1486     case DUMP_GC:
1487       if (!dbeSession->has_java ())
1488 	{
1489 	  fprintf (out_file, GTXT ("\nJava garbage collection information was not requested when recording experiments\n\n"));
1490 	  break;
1491 	}
1492       dbev->dump_gc_events (out_file);
1493       break;
1494     case DKILL:
1495       {
1496 	if (arg1 == NULL)
1497 	  {
1498 	    fprintf (stderr, GTXT ("Error: No process has been specified.\n"));
1499 	    break;
1500 	  }
1501 	if (arg2 == NULL)
1502 	  {
1503 	    fprintf (stderr, GTXT ("Error: No signal has been specified.\n"));
1504 	    break;
1505 	  }
1506 	pid_t p = (pid_t) atoi (arg1);
1507 	int signum = atoi (arg2);
1508 	char *ret = dbeSendSignal (p, signum);
1509 	if (ret != NULL)
1510 	  fprintf (stderr, GTXT ("Error: %s"), ret);
1511       }
1512       break;
1513     case PROCSTATS:
1514       dump_stats ();
1515       break;
1516     case ADD_EXP:
1517     case OPEN_EXP:
1518       if (arg1 == NULL)
1519 	fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
1520       else
1521 	{
1522 	  Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*>(1);
1523 	  Vector<char*> *list = new Vector<char*>(1);
1524 	  list->append (arg1);
1525 	  groups->append (list);
1526 	  char *res = dbeOpenExperimentList (dbevindex, groups, cmd_type == OPEN_EXP);
1527 	  if (cmd_type == OPEN_EXP)
1528 	    fprintf (stderr, GTXT ("Previously loaded experiment have been dropped.\n"));
1529 	  if (res != NULL)
1530 	    fprintf (stderr, NTXT ("%s"), res);
1531 	  else
1532 	    fprintf (stderr, GTXT ("Experiment %s has been loaded\n"), arg1);
1533 	  free (res);
1534 	  delete list;
1535 	  delete groups;
1536 	}
1537       break;
1538     case DROP_EXP:
1539       {
1540 	if (arg1 == NULL)
1541 	  fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
1542 	else
1543 	  {
1544 	    int exp_index = dbeSession->find_experiment (arg1);
1545 	    if (exp_index < 0)
1546 	      fprintf (stderr, GTXT ("Error: experiment %s has not been opened.\n"), arg1);
1547 	    else
1548 	      {
1549 		Vector<int> *expid = new Vector<int> (1);
1550 		expid->append (exp_index);
1551 		char *res = dbeDropExperiment (dbevindex, expid);
1552 		if (res != NULL)
1553 		  fprintf (stderr, NTXT ("%s"), res);
1554 		else
1555 		  fprintf (stderr, GTXT ("Experiment %s has been dropped\n"), arg1);
1556 		delete expid;
1557 		free (res);
1558 	      }
1559 	  }
1560       }
1561       break;
1562     case HHELP:
1563       // automatically load machine model if applicable
1564       dbeDetectLoadMachineModel (dbevindex);
1565       Command::print_help (whoami, false, false, out_file);
1566       fprintf (out_file, NTXT ("\n"));
1567       indxo_list (false, out_file);
1568       fprintf (out_file, NTXT ("\n"));
1569       mo_list (false, out_file);
1570       if (!getenv ("_BUILDING_MANPAGE"))
1571 	fprintf (out_file, GTXT ("\nSee gprofng(1) for more details\n"));
1572       break;
1573     case QQUIT:
1574       was_QQUIT = true;
1575       return;
1576     default:
1577       fprintf (stderr, GTXT ("Error: Invalid option\n"));
1578       break;
1579     }
1580 
1581   // check for any processing error messages
1582   dump_proc_warnings ();
1583   fflush (out_file);
1584 }
1585 
1586 #define MAX_NUM_HEADER      4
1587 
1588 void
1589 er_print::disp_list (int num_header, int size, int align[], char *header[],
1590 		     char **lists[])
1591 {
1592   size_t maxlen[MAX_NUM_HEADER];
1593   char fmt[MAX_NUM_HEADER][64];
1594   if (num_header > MAX_NUM_HEADER)
1595     abort ();
1596   for (int i = 0; i < num_header; i++)
1597     {
1598       maxlen[i] = strlen (header[i]);
1599       for (int j = 0; j < size; j++)
1600 	{
1601 	  size_t len = strlen (lists[i][j]);
1602 	  if (maxlen[i] < len)
1603 	    maxlen[i] = len;
1604 	}
1605 
1606       // get format string
1607       if ((align[i] == -1) && (i == num_header - 1))
1608 	snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%s "));
1609       else
1610 	snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%%ds "), (int) (align[i] * maxlen[i]));
1611 
1612       // write header
1613       fprintf (out_file, fmt[i], header[i]);
1614     }
1615   putc ('\n', out_file);
1616 
1617   // write separator "==="
1618   size_t np = 0;
1619   for (int i = 0; (i < num_header) && (np < 132); i++)
1620     {
1621       size_t nc = maxlen[i];
1622       if (nc + np > 132)
1623 	nc = 132 - np;
1624       for (size_t j = 0; j < nc; j++)
1625 	putc ('=', out_file);
1626       putc (' ', out_file);
1627       np += nc + 1;
1628     }
1629   putc ('\n', out_file);
1630 
1631   // write lists
1632   for (int j = 0; j < size; j++)
1633     {
1634       for (int i = 0; i < num_header; i++)
1635 	fprintf (out_file, fmt[i], lists[i][j]);
1636       putc ('\n', out_file);
1637     }
1638 }
1639 
1640 void
1641 er_print::exp_list ()
1642 {
1643   int size, index;
1644   int align[MAX_NUM_HEADER];
1645   char *header[MAX_NUM_HEADER];
1646   char **lists[MAX_NUM_HEADER];
1647 
1648   align[0] = 1;     // right-justify
1649   align[1] = 1;     // right-justify
1650   align[2] = 1;     // right-justify
1651   align[3] = -1;    // left-justify
1652   header[0] = GTXT ("ID");
1653   header[1] = GTXT ("Sel");
1654   header[2] = GTXT ("PID");
1655   header[3] = GTXT ("Experiment");
1656 
1657   size = dbeSession->nexps ();
1658   lists[0] = new char*[size];
1659   lists[1] = new char*[size];
1660   lists[2] = new char*[size];
1661   lists[3] = new char*[size];
1662   for (index = 0; index < size; index++)
1663     {
1664       lists[0][index] = dbe_sprintf (NTXT ("%d"), index + 1);
1665       lists[1][index] = strdup (dbev->get_exp_enable (index) ? GTXT ("yes") : GTXT ("no"));
1666       lists[2][index] = dbe_sprintf (NTXT ("%d"), dbeSession->get_exp (index)->getPID ());
1667       lists[3][index] = strdup (dbeSession->get_exp (index)->get_expt_name ());
1668     }
1669   disp_list (4, size, align, header, lists);
1670   for (int i = 0; i < 4; i++)
1671     {
1672       for (int j = 0; j < size; j++)
1673 	free (lists[i][j]);
1674       delete[] lists[i];
1675     }
1676 }
1677 
1678 void
1679 er_print::describe ()
1680 {
1681   Vector<void*> *res = dbeGetFilterKeywords (dbev->vindex);
1682   if (res == NULL)
1683     return;
1684   Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
1685   Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
1686   Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
1687   Vector <char*> *kwDescrip = (Vector<char*>*) res->fetch (5);
1688   Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
1689   String sectionFormat = NTXT ("\n------ %s ------\n");
1690   String categoryFormat = NTXT ("\n%s\n");
1691   String keywordFormat = NTXT ("   %-20s  %s\n");
1692   String empty = NTXT ("");
1693   String previousCategory = empty;
1694 
1695   for (int i = 0; i < kwKeyword->size (); i++)
1696     {
1697       if (kwKeyword->fetch (i) == NULL)
1698 	{
1699 	  fprintf (dis_file, sectionFormat, kwCategoryI18N->fetch (i));
1700 	  continue;
1701 	}
1702       String cat = kwCategoryI18N->fetch (i);
1703       if (dbe_strcmp (previousCategory, cat) != 0)
1704 	fprintf (dis_file, categoryFormat, cat);
1705       previousCategory = cat;
1706       Vector <String> *enumDescs = (Vector <String> *) kwEnumDescs->fetch (i);
1707       String keyword = kwKeyword->fetch (i);
1708       if (kwDescrip->fetch (i) != NULL)
1709 	{
1710 	  fprintf (dis_file, keywordFormat, keyword, kwDescrip->fetch (i));
1711 	  keyword = empty;
1712 	}
1713       if (kwFormula->fetch (i) != NULL)
1714 	{
1715 	  fprintf (dis_file, keywordFormat, keyword, kwFormula->fetch (i));
1716 	  keyword = empty;
1717 	  continue;
1718 	}
1719       int numEnums = enumDescs != NULL ? enumDescs->size () : 0;
1720       for (int jj = 0; jj < numEnums; jj++)
1721 	{
1722 	  fprintf (dis_file, keywordFormat, keyword, enumDescs->fetch (jj));
1723 	  keyword = empty;
1724 	}
1725     }
1726   destroy (res);
1727 }
1728 
1729 void
1730 er_print::obj_list ()
1731 {
1732   LoadObject *lo;
1733   int index;
1734   int align[MAX_NUM_HEADER];
1735   char *header[MAX_NUM_HEADER];
1736   char **lists[MAX_NUM_HEADER];
1737   Vector<LoadObject*> *text_segments = dbeSession->get_text_segments ();
1738   if (text_segments->size () == 0)
1739     {
1740       fprintf (dis_file, GTXT ("There are no load objects in this experiment\n"));
1741       return;
1742     }
1743   align[0] = -1; // left-justify
1744   align[1] = -1; // left-justify
1745   align[2] = -1; // left-justify
1746   align[3] = -1; // left-justify
1747   header[0] = GTXT ("Sel");
1748   header[1] = GTXT ("Load Object");
1749   header[2] = GTXT ("Index");
1750   header[3] = GTXT ("Path");
1751 
1752   int size = text_segments->size ();
1753   lists[0] = new char*[size];
1754   lists[1] = new char*[size];
1755   lists[2] = new char*[size];
1756   lists[3] = new char*[size];
1757 
1758   char *lo_name;
1759   int new_index = 0;
1760   Vec_loop (LoadObject*, text_segments, index, lo)
1761   {
1762     lo_name = lo->get_name ();
1763     if (lo_name != NULL)
1764       {
1765 	size_t len = strlen (lo_name);
1766 	if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
1767 	  continue;
1768       }
1769     LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
1770     switch (expand)
1771       {
1772       case LIBEX_SHOW:
1773 	lists[0][new_index] = dbe_strdup (GTXT ("show"));
1774 	break;
1775       case LIBEX_HIDE:
1776 	lists[0][new_index] = dbe_strdup (GTXT ("hide"));
1777 	break;
1778       case LIBEX_API:
1779 	lists[0][new_index] = dbe_strdup (GTXT ("API-only"));
1780 	break;
1781       }
1782     lists[1][new_index] = dbe_strdup (lo_name);
1783     lists[2][new_index] = dbe_sprintf (NTXT ("%d"), lo->seg_idx);
1784     lists[3][new_index] = dbe_strdup (lo->get_pathname ());
1785     new_index++;
1786   }
1787   disp_list (4, new_index, align, header, lists);
1788   for (int i = 0; i < 4; i++)
1789     {
1790       for (int j = 0; j < new_index; j++)
1791 	free (lists[i][j]);
1792       delete[] lists[i];
1793     }
1794   delete text_segments;
1795 }
1796 
1797 void
1798 er_print::seg_list ()
1799 {
1800   LoadObject *lo;
1801   int index;
1802   int align[MAX_NUM_HEADER];
1803   char *header[MAX_NUM_HEADER];
1804   char **lists[MAX_NUM_HEADER];
1805 
1806   // XXX seg_list only prints text segments; should extend to all
1807   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
1808   if (lobjs->size () == 0)
1809     {
1810       fprintf (dis_file, GTXT ("There are no segments in this experiment\n"));
1811       return;
1812     }
1813   align[0] = -1; // left-justify
1814   align[1] = 1;  // right-justify
1815   align[2] = -1; // left-justify
1816   header[0] = GTXT ("Sel");
1817   header[1] = GTXT ("Size");
1818   header[2] = GTXT ("Segment");
1819 
1820   int size = lobjs->size ();
1821   lists[0] = new char*[size];
1822   lists[1] = new char*[size];
1823   lists[2] = new char*[size];
1824 
1825   char *lo_name;
1826   int new_index = 0;
1827   Vec_loop (LoadObject*, lobjs, index, lo)
1828   {
1829     lo_name = lo->get_name ();
1830     if (lo_name != NULL)
1831       {
1832 	size_t len = strlen (lo_name);
1833 	if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
1834 	  continue;
1835       }
1836     bool expand = dbev->get_lo_expand (lo->seg_idx);
1837     lists[0][new_index] = strdup (expand ? GTXT ("yes") : GTXT ("no"));
1838     lists[1][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) lo->get_size ());
1839     lists[2][new_index] = strdup (lo->get_pathname ());
1840     new_index++;
1841   }
1842 
1843   disp_list (3, new_index, align, header, lists);
1844   for (int i = 0; i < 4; i++)
1845     {
1846       for (int j = 0; j < new_index; j++)
1847 	free (lists[i][j]);
1848       delete[] lists[i];
1849     }
1850   delete lobjs;
1851 }
1852 
1853 void
1854 er_print::filter_list (CmdType cmd_type)
1855 {
1856   FilterNumeric *select;
1857   int index;
1858   int align[MAX_NUM_HEADER];
1859   char *header[MAX_NUM_HEADER];
1860   char **lists[MAX_NUM_HEADER];
1861   char *pattern;
1862 
1863   // first ensure that the data has been read
1864   MetricList *mlist = dbev->get_metric_list (MET_INDX);
1865   Hist_data *data = dbev->get_hist_data (mlist, Histable::INDEXOBJ, 0, Hist_data::ALL);
1866   delete data;
1867 
1868   align[0] = 1;  // right-justify
1869   align[1] = -1; // left-justify
1870   align[2] = 1;  // right-justify
1871   align[3] = 1;  // right-justify
1872   header[0] = GTXT ("Exp");
1873   header[1] = GTXT ("Sel");
1874   header[2] = GTXT ("Total");
1875   header[3] = GTXT ("Status");
1876 
1877   int size = dbeSession->nexps ();
1878   lists[0] = new char*[size];
1879   lists[1] = new char*[size];
1880   lists[2] = new char*[size];
1881   lists[3] = new char*[size];
1882   int new_index = 0;
1883   for (index = 0; index < size; index++)
1884     {
1885       switch (cmd_type)
1886 	{
1887 	case SAMPLE_LIST:
1888 	  select = dbev->get_FilterNumeric (index, SAMPLE_FILTER_IDX);
1889 	  break;
1890 	case THREAD_LIST:
1891 	  select = dbev->get_FilterNumeric (index, THREAD_FILTER_IDX);
1892 	  break;
1893 	case LWP_LIST:
1894 	  select = dbev->get_FilterNumeric (index, LWP_FILTER_IDX);
1895 	  break;
1896 	case CPU_LIST:
1897 	  select = dbev->get_FilterNumeric (index, CPU_FILTER_IDX);
1898 	  break;
1899 	default:
1900 	  abort (); // internal error
1901 	}
1902       if (select == NULL)
1903 	continue;
1904       lists[0][new_index] = dbe_sprintf (NTXT ("%d"), index + 1);
1905       pattern = dbev->get_exp_enable (index) ? select->get_pattern () : NULL;
1906       lists[1][new_index] = strdup (pattern && *pattern ? pattern : GTXT ("none"));
1907       lists[2][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) select->nelem ());
1908       lists[3][new_index] = select->get_status ();
1909       new_index++;
1910     }
1911   disp_list (3, size, align, header, lists);
1912   for (int i = 0; i < 4; i++)
1913     {
1914       for (int j = 0; j < new_index; j++)
1915 	free (lists[i][j]);
1916       delete[] lists[i];
1917     }
1918 }
1919 
1920 int
1921 er_print::check_exp_id (int exp_id, char *sel)
1922 {
1923   if (exp_id < 0 || exp_id >= dbeSession->nexps ())
1924     {
1925       fprintf (stderr, GTXT ("Error: Invalid number entered: %s\nType \"exp_list\" for a list of all experiments.\n"),
1926 	       sel);
1927       return -1;
1928     }
1929   return exp_id;
1930 }
1931 
1932 int
1933 er_print::get_exp_id (char *sel, int &bgn_index, int &end_index)
1934 {
1935   int id, exp_id;
1936   if (sel == NULL || strcmp (sel, NTXT ("all")) == 0)
1937     {
1938       // loop over all experiments
1939       bgn_index = 0;
1940       end_index = dbeSession->nexps () - 1;
1941     }
1942   else
1943     {
1944       id = (int) strtol (sel, (char **) NULL, 10) - 1;
1945       exp_id = check_exp_id (id, sel);
1946      if (exp_id == -1)
1947 	return -1;
1948       bgn_index = end_index = exp_id;
1949     }
1950   return 0;
1951 }
1952 
1953 void
1954 er_print::print_objects ()
1955 {
1956   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
1957   char *msg = pr_load_objects (lobjs, NTXT (""));
1958   delete lobjs;
1959   fprintf (out_file, NTXT ("%s\n"), msg);
1960   free (msg);
1961 }
1962 
1963 void
1964 er_print::print_overview ()
1965 {
1966   //fprintf(out_file, NTXT("%s\n"), GTXT("Not implemented yet."));//YXXX
1967   Vector<char*> *status = dbeGetOverviewText (dbevindex);
1968   StringBuilder sb;
1969   sb.append (GTXT ("Experiment(s):\n\n"));
1970   for (int i = 0; i < status->size (); i++)
1971     sb.appendf (NTXT ("%s\n"), status->fetch (i));
1972   sb.append (GTXT ("Metrics:\n"));
1973   sb.toFile (out_file);
1974 
1975   Vector<void*> *data = dbeGetRefMetricTree (dbevindex, false);
1976   Vector<char *> *metric_cmds = new Vector<char *>();
1977   Vector<char *> *non_metric_cmds = new Vector<char *>();
1978   print_overview_nodes (data, 0, metric_cmds, non_metric_cmds);
1979   Vector<void*> *values = dbeGetRefMetricTreeValues (0, metric_cmds, non_metric_cmds);
1980   print_overview_tree (data, 0, values, metric_cmds, non_metric_cmds);
1981 
1982   StringBuilder sb2;
1983   sb2.append (GTXT ("\nNotes: '*' indicates hot metrics, '[X]' indicates currently enabled metrics.\n"));
1984   sb2.append (GTXT ("       The metrics command can be used to change selections. The metric_list command lists all available metrics.\n"));
1985   sb2.toFile (out_file);
1986 }
1987 
1988 void
1989 er_print::print_overview_nodes (Vector<void*> * data, int level, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
1990 {
1991   Vector<void*> *fields = (Vector<void*> *) data->fetch (0);
1992   Vector<void*> *children = (Vector<void*> *) data->fetch (1);
1993   char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
1994   int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
1995   bool has_value = ((Vector<bool>*) fields->fetch (10))->fetch (0);
1996   bool selectable = (vstyles_capable != 0) ? true : false;
1997   if (selectable)
1998     metric_cmds->append (name);
1999   else if (has_value)
2000     non_metric_cmds->append (name);
2001 
2002   level++;
2003   for (int i = 0; i < children->size (); i++)
2004     print_overview_nodes ((Vector<void*> *)(children->fetch (i)), level, metric_cmds, non_metric_cmds);
2005 }
2006 
2007 void
2008 er_print::print_overview_tree (Vector<void*> * data, int level, Vector<void*> * values, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
2009 {
2010   Vector<void*> * fields = (Vector<void*> *) data->fetch (0);
2011   Vector<void*> * children = (Vector<void*> *) data->fetch (1);
2012   char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
2013   char *username = ((Vector<char*> *)fields->fetch (1))->fetch (0);
2014   int flavors = ((Vector<int>*) fields->fetch (3))->fetch (0); //bitmask e.g. EXCLUSIVE
2015   int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
2016   //    bool aggregation = ((Vector<bool>*) fields->fetch(9))->fetch(0);
2017   //    bool has_value = ((Vector<bool>*) fields->fetch(10))->fetch(0);
2018   char *unit = ((Vector<char*> *) fields->fetch (11))->fetch (0);
2019 
2020   StringBuilder sb;
2021   for (int i = 0; i < level * 2; i++)
2022     sb.append (NTXT (" ")); // NOI18N
2023 
2024   bool selectable = (vstyles_capable != 0) ? true : false;
2025   if (selectable)
2026     {
2027       bool isSelected = dbev->get_metric_list (MET_NORMAL)->find_metric_by_name (name) == NULL ? false : true;
2028       if (isSelected)
2029 	sb.append (NTXT ("[X]"));
2030       else
2031 	sb.append (NTXT ("[ ]"));
2032     }
2033   if ((unit != NULL && dbe_strcmp (unit, UNIT_SECONDS) == 0)
2034       || (unit == NULL && vstyles_capable & VAL_TIMEVAL))
2035     unit = GTXT ("Seconds");
2036 
2037   bool isHiddenInOverview = ((flavors & BaseMetric::STATIC) != 0);
2038   if (name != NULL && dbe_strcmp (name, L1_STATIC) == 0)
2039     isHiddenInOverview = true;
2040   if (!dbeSession->has_java () && name != NULL && dbe_strcmp (name, L1_GCDURATION) == 0)
2041     isHiddenInOverview = true;
2042   if (isHiddenInOverview)
2043     return;
2044 
2045   sb.append (username == NULL ? NTXT ("") : username); // NOI18N
2046   int show = 0;
2047   if (name == NULL)
2048     show = 0;
2049   else if (strstr (name, NTXT ("PROFDATA_TYPE_")) == NULL)
2050     show = 1;
2051 
2052   if (show)
2053     {
2054       sb.append (username == NULL ? NTXT ("") : NTXT (" - ")); // NOI18N
2055       sb.append (name == NULL ? NTXT ("") : name); // NOI18N
2056     }
2057 
2058   // "Bugs 16624403 and 19539622" (leave this string intact for searches)
2059   // add an extra condition for now
2060   // once we have proper fixes, eliminate test on Bug16624402_extra_condition
2061   int Bug16624402_extra_condition = 1;
2062   if (username)
2063     {
2064       if (strcmp (username, NTXT ("Block Covered %")) == 0) Bug16624402_extra_condition = 0;
2065       if (strcmp (username, NTXT ("Instr Covered %")) == 0) Bug16624402_extra_condition = 0;
2066     }
2067   if (Bug16624402_extra_condition > 0 && values->size () > 0)
2068     {
2069       Vector<void*> * valueColumns = (Vector<void*> *)values->fetch (0);
2070       Vector<void*> * highlightColumns = (Vector<void*> *)values->fetch (1);
2071       int jj = 0;
2072       int found = 0;
2073       for (jj = 0; jj < valueColumns->size (); jj++)
2074 	{
2075 	  const char *value_name = "";
2076 	  if (jj < metric_cmds->size ())
2077 	    value_name = metric_cmds->fetch (jj);
2078 	  else
2079 	    value_name = non_metric_cmds->fetch (jj - metric_cmds->size ());
2080 	  if (dbe_strcmp (value_name, name) != 0)
2081 	    continue;
2082 	  else
2083 	    {
2084 	      found = 1;
2085 	      break;
2086 	    }
2087 	}
2088       if (found)
2089 	{
2090 	  Vector<void*> * valueVec = (Vector<void*> *)valueColumns->fetch (jj);
2091 	  Vector<bool> * highlights = (Vector<bool> *)highlightColumns->fetch (jj);
2092 	  for (int kk = 0; kk < valueVec->size (); kk++)
2093 	    {
2094 	      char * value_str;
2095 	      int show_value = 0;
2096 	      switch (valueVec->type ())
2097 		{
2098 		case VEC_INTEGER:
2099 		  value_str = dbe_sprintf (NTXT ("%ld"), (long) (((Vector<int> *)valueVec)->fetch (kk)));
2100 		  show_value = 1;
2101 		  break;
2102 		case VEC_DOUBLE:
2103 		  value_str = dbe_sprintf (NTXT ("%.3f"), (double) (((Vector<double> *)valueVec)->fetch (kk)));
2104 		  show_value = 1;
2105 		  break;
2106 		case VEC_LLONG:
2107 		  value_str = dbe_sprintf (NTXT ("%lld"), (long long) (((Vector<long> *)valueVec)->fetch (kk)));
2108 		  show_value = 1;
2109 		  break;
2110 		case VEC_STRING:
2111 		  value_str = NTXT ("");
2112 		  break;
2113 		default:
2114 		  value_str = NTXT ("");
2115 		}
2116 	      if (show_value)
2117 		{
2118 		  if (kk == 0)
2119 		    {
2120 		      sb.append (unit == NULL ? NTXT ("") : NTXT (" ("));
2121 		      sb.append (unit == NULL ? NTXT ("") : unit);
2122 		      sb.append (unit == NULL ? NTXT ("") : NTXT (")"));
2123 		      sb.append (NTXT (":"));
2124 		    }
2125 		  bool highlight = highlights->fetch (kk);
2126 		  const char * hilite = highlight ? NTXT ("*") : NTXT ("");
2127 		  sb.append (NTXT (" ["));
2128 		  sb.append (hilite);
2129 		  sb.append (value_str);
2130 		  sb.append (NTXT ("]"));
2131 		}
2132 	    }
2133 	}
2134     }
2135   sb.append (NTXT ("\n"));
2136   sb.toFile (out_file);
2137   level++;
2138   for (int i = 0; i < children->size (); i++)
2139     print_overview_tree ((Vector<void*> *)(children->fetch (i)), level, values, metric_cmds, non_metric_cmds);
2140 }
2141 
2142 void
2143 er_print::print_segments ()
2144 {
2145   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
2146   char *msg = pr_load_objects (lobjs, NTXT (""));
2147   delete lobjs;
2148   fprintf (dis_file, NTXT ("Not implemented yet!\n"));
2149   free (msg);
2150 }
2151 
2152 void
2153 er_print::print_dobj (Print_mode mode, MetricList *mlist1,
2154 		      char *dobj_name, char *sel)
2155 {
2156   Hist_data *hist_data = NULL;
2157   char *errstr;
2158   er_print_common_display *cd;
2159   int list_limit = limit;
2160   Histable *sobj = NULL;
2161   Dprintf (DEBUG_DATAOBJ, NTXT ("er_print::print_dobj(mode=%d,dobj=%s,sel=%s)\n"),
2162 	   mode, (dobj_name == NULL) ? NTXT ("0") : dobj_name, (sel == NULL) ? NTXT ("0") : sel);
2163   char *name = dbev->getSort (MET_DATA);
2164   switch (mode)
2165     {
2166     case MODE_LIST:
2167       hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
2168       break;
2169     case MODE_DETAIL:
2170       // if specified, find the dataobject from the name
2171       if (dobj_name && strcmp (dobj_name, NTXT ("<All>")))
2172 	{
2173 	  if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
2174 				     sel, Histable::DOBJECT, (inp_file != stdin)))
2175 	    return;
2176 	  if (sobj == NULL)
2177 	    { // dataobject/segment not found
2178 	      hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
2179 	      if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
2180 					 sel, Histable::DOBJECT, (inp_file != stdin)))
2181 		return;
2182 	      if (sobj == NULL)
2183 		{ // dataobject/segment not found
2184 		  fprintf (stderr, GTXT ("Error: No dataobject with given name `%s' found.\n"),
2185 			   dobj_name);
2186 		  return;
2187 		}
2188 	    }
2189 
2190 	  list_limit = 1;
2191 	}
2192       if (!hist_data)
2193 	hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
2194       break;
2195     case MODE_ANNOTATED:
2196       hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::LAYOUT);
2197       break;
2198     default: // MODE_GPROF is not relevant for DataObjects
2199       abort ();
2200     }
2201 
2202   if (hist_data->get_status () != Hist_data::SUCCESS)
2203     {
2204       // XXXX is this error message adequate?
2205       errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
2206       if (errstr)
2207 	{
2208 	  fprintf (stderr, GTXT ("Error: %s\n"), errstr);
2209 	  free (errstr);
2210 	}
2211       delete hist_data;
2212       return;
2213     }
2214   cd = (er_print_common_display *) new er_print_histogram (dbev, hist_data,
2215 							   hist_data->get_metric_list (), mode, list_limit, name, sobj, false, false);
2216   free (name);
2217   print_cmd (cd);
2218 
2219   delete hist_data;
2220   delete cd;
2221 }
2222 
2223 void
2224 er_print::print_func (Histable::Type type, Print_mode mode, MetricList *mlist1,
2225 		      MetricList *mlist2, char *func_name, char *sel)
2226 {
2227   Hist_data *hist_data;
2228   Hist_data::HistItem *hitem;
2229   int index;
2230   char *errstr;
2231   int list_limit = limit;
2232   Histable *sobj = NULL;
2233   MetricList *mlist;
2234   StringBuilder sb;
2235   char *sname = dbev->getSort (MET_NORMAL);
2236   sb.append (sname);
2237   free (sname);
2238 
2239   switch (mode)
2240     {
2241     case MODE_DETAIL:
2242       {
2243 	// The first metric list, mlist1, is only used to pick out the sort
2244 	//    mlist2 is the one used to generate the data
2245 	char *prevsort = NULL;
2246 	// if specified, find the function from the function name
2247 	if (func_name && strcmp (func_name, NTXT ("<All>")))
2248 	  {
2249 	    if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2250 					sel, Histable::FUNCTION, (inp_file != stdin)) || (sobj == NULL)) &&
2251 		!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2252 				       sel, Histable::LOADOBJECT, (inp_file != stdin)))
2253 	      return;
2254 	    if (sobj == NULL)
2255 	      { // function/segment object not found
2256 		fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
2257 			 func_name);
2258 		return;
2259 	      }
2260 	    list_limit = 1;
2261 	  }
2262 	else
2263 	  {
2264 	    // find the sort metric from the reference list
2265 	    prevsort = mlist2->get_sort_cmd ();
2266 
2267 	    // find the current sort metric from the current list
2268 	    char *cursort = mlist1->get_sort_cmd ();
2269 
2270 	    // find the corresponding metric in the reference list
2271 	    (void) mlist2->set_sort (cursort, false);
2272 	    free (cursort);
2273 	    // if it fails, nothing is needed
2274 	  }
2275 	hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
2276 
2277 	// restore
2278 	if (sobj == NULL)
2279 	  {
2280 	    if (prevsort == NULL)
2281 	      abort ();
2282 	    (void) mlist2->set_sort (prevsort, false);
2283 	  }
2284 	mlist = mlist2;
2285 	free (prevsort);
2286 	break;
2287       }
2288     case MODE_GPROF:
2289       // if specified, find the function from the function name
2290       if (func_name && strcmp (func_name, NTXT ("<All>")))
2291 	{
2292 	  if (!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2293 				     sel, Histable::FUNCTION, (inp_file != stdin)))
2294 	    return;
2295 	  if (sobj == NULL)
2296 	    { // function/segment object not found
2297 	      fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
2298 		       func_name);
2299 	      return;
2300 	    }
2301 	  list_limit = 1;
2302 	  sb.setLength (0);
2303 	}
2304       sb.append (GTXT ("\nCallers and callees sorted by metric: "));
2305       sname = dbev->getSort (MET_CALL);
2306       sb.append (sname);
2307       free (sname);
2308 
2309       // Use mlist2 to generate the sort order.
2310       // mlist1 is used to generate the data.
2311       hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
2312       mlist = mlist1;
2313       break;
2314     default:
2315       hist_data = dbev->get_hist_data (mlist1, type, 0, Hist_data::ALL);
2316       mlist = mlist1;
2317     }
2318 
2319   if (hist_data->get_status () != Hist_data::SUCCESS)
2320     {
2321       errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
2322       if (errstr)
2323 	{
2324 	  fprintf (stderr, GTXT ("Error: %s\n"), errstr);
2325 	  free (errstr);
2326 	}
2327       delete hist_data;
2328       return;
2329     }
2330 
2331   if (type == Histable::FUNCTION)
2332     {
2333       for (index = 0; index < hist_data->size (); index++)
2334 	{
2335 	  hitem = hist_data->fetch (index);
2336 	  if (hitem->obj->get_type () == Histable::FUNCTION)
2337 	    // fetch the name, since that will force a format conversion
2338 	    ((Function *) hitem->obj)->get_name ();
2339 	}
2340     }
2341 
2342   char *name = sb.toString ();
2343   er_print_histogram *cd = new er_print_histogram (dbev, hist_data,
2344 						   mlist, mode, list_limit, name, sobj, false, false);
2345   print_cmd (cd);
2346   delete hist_data;
2347   free (name);
2348   delete cd;
2349 }
2350 
2351 void
2352 er_print::print_gprof (CmdType cmd_type, char *func_name, char *sel)
2353 {
2354   Histable *sobj = NULL;
2355   if (func_name != NULL)
2356     {
2357       if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2358 				  sel, Histable::FUNCTION, (inp_file != stdin))
2359 	   || sobj == NULL)
2360 	  && !dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2361 				    sel, Histable::LOADOBJECT, (inp_file != stdin)))
2362 	return;
2363       if (sobj == NULL)
2364 	{ // function/segment object not found
2365 	  fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
2366 		   func_name);
2367 	  return;
2368 	}
2369     }
2370   if (cmd_type == CPREPEND)
2371     {
2372       if (sobj == NULL)
2373 	{
2374 	  fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
2375 	  return;
2376 	}
2377       cstack->insert (0, sobj);
2378     }
2379   else if (cmd_type == CAPPEND)
2380     {
2381       if (sobj == NULL)
2382 	{
2383 	  fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
2384 	  return;
2385 	}
2386       cstack->append (sobj);
2387     }
2388   else if (cmd_type == CSINGLE)
2389     {
2390       if (sobj != NULL)
2391 	{
2392 	  cstack->reset ();
2393 	  cstack->append (sobj);
2394 	}
2395       else if (cstack->size () == 0)
2396 	{
2397 	  fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
2398 	  return;
2399 	}
2400     }
2401   else if (cmd_type == CRMFIRST)
2402     {
2403       if (cstack->size () <= 1)
2404 	{
2405 	  fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
2406 	  return;
2407 	}
2408       cstack->remove (0);
2409     }
2410   else if (cmd_type == CRMLAST)
2411     {
2412       if (cstack->size () <= 1)
2413 	{
2414 	  fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
2415 	  return;
2416 	}
2417       cstack->remove (cstack->size () - 1);
2418     }
2419 
2420   er_print_gprof *cd = new er_print_gprof (dbev, cstack);
2421   print_cmd (cd);
2422   delete cd;
2423 }
2424 
2425 /*
2426  * Method print_ctree() prints Functions Call Tree.
2427  */
2428 void
2429 er_print::print_ctree (CmdType cmd_type)
2430 {
2431   if (cmd_type != CALLTREE)
2432     {
2433       fprintf (stderr, GTXT ("Error: Invalid command type: %d\n"), cmd_type);
2434       return;
2435     }
2436 
2437   Histable *sobj = dbeSession->get_Total_Function ();
2438   Vector<Histable*> *ctree_cstack = new Vector<Histable*>();
2439   ctree_cstack->reset ();
2440   er_print_ctree *cd = new er_print_ctree (dbev, ctree_cstack, sobj, limit);
2441   print_cmd (cd);
2442   delete ctree_cstack;
2443   delete cd;
2444 }
2445 
2446 void
2447 er_print::memobj (char *name, int cparam)
2448 {
2449   int type;
2450   if (name != NULL)
2451     {
2452       // find the memory object index for the name
2453       MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
2454       if (mot == NULL)
2455 	{
2456 	  // unknown type, report the error
2457 	  fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
2458 	  return;
2459 	}
2460       type = mot->type;
2461     }
2462   else
2463     {
2464       MemObjType_t *mot = MemorySpace::findMemSpaceByIndex (cparam);
2465       if (mot == NULL)
2466 	{
2467 	  // unknown type, report the error
2468 	  fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
2469 	  return;
2470 	}
2471       type = cparam;
2472     }
2473   dbePrintData (0, DSP_MEMOBJ, type, NULL, NULL, out_file);
2474 }
2475 
2476 void
2477 er_print::mo_define (char *moname, char *mo_index_exp, char *machmodel, char *short_desc, char *long_desc)
2478 {
2479   char *ret = MemorySpace::mobj_define (moname, mo_index_exp, machmodel, short_desc, long_desc);
2480   if (ret != NULL)
2481     fprintf (stderr, GTXT ("mobj_define for %s failed: %s\n"), moname, ret);
2482 }
2483 
2484 void
2485 er_print::mo_list (bool showtab, FILE *outf)
2486 {
2487   Vector<bool> *mtab = NULL;
2488   Vector<void*>*res = MemorySpace::getMemObjects ();
2489   if (showtab)
2490     mtab = dbev->get_MemTabState ();
2491   if (res == NULL)
2492     // Since we checked already, this is an internal error
2493     abort ();
2494 
2495   // unpack the return
2496   // Vector<char*> *index = (Vector<int> *)res->fetch(0);  // not used
2497   Vector<char*> *mo_names = (Vector<char*> *)res->fetch (1);
2498   // Vector<char*> *mnemonic = (Vector<char> *)res->fetch(2);  // not used
2499   Vector<char*> *mo_expr = (Vector<char*> *)res->fetch (3);
2500   Vector<char*> *mo_mach_m = (Vector<char*> *)res->fetch (4);
2501   // Vector<char*> *tmpOrder = (Vector<int> *)res->fetch(5);  // not used
2502 
2503   int size = mo_names->size ();
2504   if (size == 0)
2505     {
2506       if (!getenv ("_BUILDING_MANPAGE"))
2507 	fprintf (outf, GTXT (" No Memory Object Types Defined\n"));
2508     }
2509   else
2510     {
2511       if (!getenv ("_BUILDING_MANPAGE"))
2512 	fprintf (outf, GTXT (" Memory Object Types Available:\n"));
2513       else
2514 	fprintf (outf, GTXT ("*Memory Object Types*\n"));
2515       for (int i = 0; i < size; i++)
2516 	{
2517 	  if (mtab)
2518 	    fprintf (outf, NTXT ("  %c %s\n"), mtab->fetch (i) ? 'T' : 'F',
2519 		     mo_names->fetch (i));
2520 	  else
2521 	    {
2522 	      if (mo_mach_m->fetch (i) != NULL)
2523 		fprintf (outf, NTXT ("  %s\t\t\"%s\"\t\t(machinemodel: %s)\n"),
2524 			 mo_names->fetch (i), mo_expr->fetch (i), mo_mach_m->fetch (i));
2525 	      else
2526 		fprintf (outf, NTXT ("  %s\t\t\"%s\"\n"),
2527 			 mo_names->fetch (i), mo_expr->fetch (i));
2528 	    }
2529 	}
2530     }
2531   delete mo_names;
2532   delete mo_expr;
2533   delete mo_mach_m;
2534   delete res;
2535 }
2536 
2537 void
2538 er_print::indxobj (char *name, int cparam)
2539 {
2540   int type;
2541   if (name != NULL)
2542     {
2543       // find the index object index for the name
2544       type = dbeSession->findIndexSpaceByName (name);
2545       if (type < 0)
2546 	{
2547 	  // unknown type, report the error
2548 	  fprintf (stderr, GTXT ("Error: Unknown Index Object type: %s\n"), name);
2549 	  return;
2550 	}
2551     }
2552   else
2553     {
2554       char *indxname = dbeSession->getIndexSpaceName (cparam);
2555       if (indxname == NULL)
2556 	{
2557 	  // unknown type, report the error
2558 	  fprintf (stderr, GTXT ("Error: Unknown Index Object type: %d\n"), cparam);
2559 	  return;
2560 	}
2561       type = cparam;
2562     }
2563   dbePrintData (0, DSP_INDXOBJ, type, NULL, NULL, out_file);
2564 }
2565 
2566 void
2567 er_print::indxo_define (char *ioname, char *io_index_exp, char *sdesc, char *ldesc)
2568 {
2569   char *ret = dbeDefineIndxObj (ioname, io_index_exp, sdesc, ldesc);
2570   if (ret != NULL)
2571     fprintf (stderr, GTXT ("indxobj_define for %s failed: %s\n"), ioname, ret);
2572 }
2573 
2574 void
2575 er_print::indxo_list (bool showtab, FILE *outf)
2576 {
2577   Vector<bool> *indxtab = NULL;
2578   char *name;
2579   char *i18n_name;
2580   if (!getenv ("_BUILDING_MANPAGE"))
2581     fprintf (outf, GTXT (" Index Object Types Available:\n"));
2582   else
2583     fprintf (outf, GTXT ("*Index Object Types*\n"));
2584   Vector<void*>*res = dbeGetIndxObjDescriptions (0);
2585   if (showtab)
2586     indxtab = dbev->get_IndxTabState ();
2587   if (res == NULL)  // If none is defined
2588     return;
2589   Vector<char*> *indxo_names = (Vector<char*> *)res->fetch (1);
2590   Vector<char*> *indxo_i18nnames = (Vector<char*> *)res->fetch (3);
2591   Vector<char*> *indxo_exprlist = (Vector<char*> *)res->fetch (5);
2592   int size = indxo_names->size ();
2593   for (int i = 0; i < size; i++)
2594     {
2595       name = indxo_names->fetch (i);
2596       i18n_name = indxo_i18nnames->fetch (i);
2597       if (indxtab)
2598 	{
2599 	  if ((i18n_name != NULL) && (strcmp (i18n_name, name) != 0))
2600 	    fprintf (outf, NTXT ("  %c %s (%s)\n"), indxtab->fetch (i) ? 'T' : 'F',
2601 		     i18n_name, name);
2602 	  else
2603 	    fprintf (outf, NTXT ("  %c %s\n"), indxtab->fetch (i) ? 'T' : 'F', name);
2604 	}
2605       else
2606 	{
2607 	  if (i18n_name != NULL && strcmp (i18n_name, indxo_names->fetch (i)) != 0)
2608 	    fprintf (outf, NTXT ("  %s (%s)"), i18n_name, name);
2609 	  else
2610 	    fprintf (outf, NTXT ("  %s"), name);
2611 	}
2612       char *exprs = indxo_exprlist->fetch (i);
2613       if (exprs != NULL)
2614 	fprintf (outf, NTXT (" \t%s\n"), exprs);
2615       else
2616 	fprintf (outf, NTXT ("\n"));
2617     }
2618   delete indxo_names;
2619   if (showtab)
2620     delete res;
2621 }
2622 
2623 void
2624 er_print::ifreq ()
2625 {
2626   dbev->ifreq (out_file);
2627 }
2628 
2629 void
2630 er_print::dump_nodes ()
2631 {
2632   dbev->dump_nodes (out_file);
2633 }
2634 
2635 void
2636 er_print::dump_stacks ()
2637 {
2638   dbeSession->dump_stacks (out_file);
2639 }
2640 
2641 void
2642 er_print::dump_unk_pcs ()
2643 {
2644   // Dump the nodes associated with the <Unknown> function
2645   dbev->get_path_tree ()->dumpNodes (out_file, dbeSession->get_Unknown_Function ());
2646 
2647   // Dump the nodes associated with the <no Java callstack recorded> function
2648   Vector<Function *> *matches = dbeSession->match_func_names ("<no Java callstack recorded>", dbev->get_name_format ());
2649   if (matches == NULL || matches->size () == 0)
2650     fprintf (out_file, GTXT ("No %s functions found\n"), "<no Java callstack recorded>");
2651   else
2652     {
2653       Function *fitem;
2654       int index;
2655       Vec_loop (Function*, matches, index, fitem)
2656       {
2657 	dbev->get_path_tree ()->dumpNodes (out_file, fitem);
2658       }
2659       delete matches;
2660     }
2661 }
2662 
2663 void
2664 er_print::dump_funcs (char *arg1)
2665 {
2666   if (arg1 == NULL || strlen (arg1) == 0)
2667     dbeSession->dump_segments (out_file);
2668   else
2669     {
2670       Vector<Function *> *matches = dbeSession->match_func_names (arg1, dbev->get_name_format ());
2671       if (matches == NULL)
2672 	{
2673 	  fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
2674 	  return;
2675 	}
2676       fprintf (out_file, GTXT ("%d Function's match `%s'\n"), (int) matches->size (), arg1);
2677       Function *fitem;
2678       int index;
2679       Vec_loop (Function*, matches, index, fitem)
2680       {
2681 	fprintf (out_file, NTXT (" %5lld -- %s (%s) [%s]\n"),
2682 		 (ll_t) fitem->id, fitem->get_name (),
2683 		 (fitem->module ? fitem->module->file_name : NTXT ("<unknown>")),
2684 		 ((fitem->module && fitem->module->loadobject) ?
2685 		  get_basename (fitem->module->loadobject->get_name ()) : NTXT ("<unknown>")));
2686       }
2687       delete matches;
2688     }
2689 }
2690 
2691 void
2692 er_print::dump_dataobjects (char *arg1)
2693 {
2694   // Force computation of data objects, to update master table; discard it
2695   MetricList *mlist1 = dbev->get_metric_list (MET_DATA);
2696   Hist_data *data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
2697   delete data;
2698 
2699   if (arg1 == NULL || strlen (arg1) == 0)
2700     dbeSession->dump_dataobjects (out_file);
2701   else
2702     {
2703       Vector<DataObject *> *matches = dbeSession->match_dobj_names (arg1);
2704       if (matches == NULL)
2705 	{
2706 	  fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
2707 	  return;
2708 	}
2709       fprintf (out_file, GTXT ("%d DataObject's match `%s'\n"), (int) matches->size (), arg1);
2710       DataObject *ditem;
2711       int index;
2712       Vec_loop (DataObject*, matches, index, ditem)
2713       {
2714 	fprintf (out_file, NTXT (" %5lld -- %s\n"), (ll_t) ditem->id, ditem->get_name ());
2715       }
2716       delete matches;
2717     }
2718 }
2719 
2720 void
2721 er_print::dump_map ()
2722 {
2723   dbeSession->dump_map (out_file);
2724 }
2725 
2726 void
2727 er_print::dump_entities ()
2728 {
2729   int ent_prop_ids[] = {PROP_THRID, PROP_LWPID, PROP_CPUID, PROP_EXPID, -1};
2730 
2731   // loop over experiments
2732   for (int exp_id = 0; exp_id < dbeSession->nexps (); exp_id++)
2733     {
2734       Experiment *exp = dbeSession->get_exp (exp_id);
2735       fprintf (out_file, GTXT ("Experiment %d (%s)\n"),
2736 	       exp_id, exp->get_expt_name ());
2737 
2738       for (int kk = 0; ent_prop_ids[kk] != -1; kk++)
2739 	{
2740 	  int ent_prop_id = ent_prop_ids[kk];
2741 	  Vector<void*> *elist = dbeGetEntities (0, exp_id, ent_prop_id);
2742 	  if (!elist)
2743 	    continue;
2744 	  Vector<int> *entity_vals = (Vector<int> *) elist->fetch (0);
2745 	  Vector<char*> *jthr_names = (Vector<char*> *)elist->fetch (1);
2746 	  Vector<char*> *jthr_g_names = (Vector<char*> *)elist->fetch (2);
2747 	  Vector<char*> *jthr_p_names = (Vector<char*> *)elist->fetch (3);
2748 	  Vector<char*> *entity_name = (Vector<char*> *)elist->fetch (4);
2749 	  int nent = entity_vals->size ();
2750 	  char *entName = entity_name->fetch (0);
2751 	  if (!entName)
2752 	    entName = NTXT ("<unknown>");
2753 	  fprintf (out_file, GTXT ("  %s\n"), entName);
2754 	  for (int i = 0; i < nent; i++)
2755 	      fprintf (out_file, GTXT ("    %s=%d: %s, %s, %s\n"),
2756 		       entName, entity_vals->fetch (i),
2757 		       jthr_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"),
2758 		       jthr_g_names->fetch (i) != NULL ? jthr_g_names->fetch (i) : NTXT ("N/A"),
2759 		       jthr_p_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"));
2760 	  destroy (elist);
2761 	}
2762     }
2763 }
2764 
2765 void
2766 er_print::dump_stats ()
2767 {
2768   Emsg *m = dbev->get_path_tree ()->fetch_stats ();
2769   while (m != NULL)
2770     {
2771       fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
2772       m = m->next;
2773     }
2774   dbev->get_path_tree ()->delete_stats ();
2775 }
2776 
2777 void
2778 er_print::dump_proc_warnings ()
2779 {
2780   PathTree *p = dbev->get_path_tree ();
2781   if (p == NULL)
2782     return;
2783   Emsg *m = p->fetch_warnings ();
2784   while (m != NULL)
2785     {
2786       fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
2787       m = m->next;
2788     }
2789   dbev->get_path_tree ()->delete_warnings ();
2790 }
2791 
2792 void
2793 er_print::print_cmd (er_print_common_display *cd)
2794 {
2795   cd->set_out_file (out_file);
2796   cd->data_dump ();
2797 }
2798 
2799 FILE *
2800 er_print::set_outfile (char *cmd, FILE *&set_file, bool append)
2801 {
2802   FILE *new_file;
2803   char *home;
2804   if (!strcasecmp (cmd, NTXT ("-")))
2805     {
2806       new_file = stdout;
2807       out_fname = NTXT ("<stdout>");
2808     }
2809   else if (!strcasecmp (cmd, NTXT ("--")))
2810     {
2811       new_file = stderr;
2812       out_fname = NTXT ("<stderr>");
2813     }
2814   else
2815     {
2816       char *fname;
2817       char *path = NULL;
2818       // Handle ~ in file names
2819       home = getenv (NTXT ("HOME"));
2820       if ((fname = strstr (cmd, NTXT ("~/"))) != NULL && home != NULL)
2821 	path = dbe_sprintf (NTXT ("%s/%s"), home, fname + 2);
2822       else if ((fname = strstr (cmd, NTXT ("~"))) != NULL && home != NULL)
2823 	path = dbe_sprintf (NTXT ("/home/%s"), fname + 1);
2824       else
2825 	path = strdup (cmd);
2826       new_file = fopen (path, append ? NTXT ("a") : NTXT ("w"));
2827       if (new_file == NULL)
2828 	{
2829 	  fprintf (stderr, GTXT ("Error: Unable to open file: %s\n"), cmd);
2830 	  free (path);
2831 	  return NULL;
2832 	}
2833       out_fname = path;
2834     }
2835   if (set_file && set_file != stdout)
2836     fclose (set_file);
2837   set_file = new_file;
2838   return set_file;
2839 }
2840