1/* Copyright (C) 2021 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 <string.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <sys/param.h>
26
27#include "enums.h"
28#include "Settings.h"
29#include "DbeSession.h"
30#include "Command.h"
31#include "Application.h"
32#include "MemorySpace.h"
33#include "StringBuilder.h"
34#include "Table.h"
35#include "Emsg.h"
36#include "util.h"
37#include "i18n.h"
38
39// Commands for compiler commentary
40static const char *comp_cmd[] = {
41  NTXT ("basic"),
42  NTXT ("version"),
43  NTXT ("warn"),
44  NTXT ("parallel"),
45  NTXT ("query"),
46  NTXT ("loop"),
47  NTXT ("pipe"),
48  NTXT ("inline"),
49  NTXT ("memops"),
50  NTXT ("fe"),
51  NTXT ("codegen"),
52  NTXT ("src"),
53  NTXT ("asrc"),
54  NTXT ("nosrc"),
55  NTXT ("hex"),
56  NTXT ("nohex"),
57  NTXT ("threshold"),
58  NTXT ("cf")
59};
60
61static const int comp_vis[] = {
62  CCMV_BASIC,
63  CCMV_VER,
64  CCMV_WARN,
65  CCMV_PAR,
66  CCMV_QUERY,
67  CCMV_LOOP,
68  CCMV_PIPE,
69  CCMV_INLINE,
70  CCMV_MEMOPS,
71  CCMV_FE,
72  CCMV_CG,
73  COMP_SRC,
74  COMP_SRC_METRIC,
75  COMP_NOSRC,
76  COMP_HEX,
77  COMP_NOHEX,
78  COMP_THRESHOLD,
79  COMP_CMPLINE
80};
81
82const int comp_size = sizeof (comp_cmd) / sizeof (char *);
83
84// Commands for timeline
85typedef enum
86{
87  TLCMD_INVALID,
88  TLCMD_ENTITY_MODE,
89  TLCMD_ALIGN,
90  TLCMD_DEPTH
91} TLModeSubcommand;
92
93typedef struct
94{
95  const char * cmdText;
96  TLModeSubcommand cmdType;
97  int cmdId;
98} TLModeCmd;
99static const TLModeCmd tlmode_cmd[] = {
100  // MODE commands
101  {NTXT ("lwp"),        TLCMD_ENTITY_MODE, PROP_LWPID},
102  {NTXT ("thread"),     TLCMD_ENTITY_MODE, PROP_THRID},
103  {NTXT ("cpu"),        TLCMD_ENTITY_MODE, PROP_CPUID},
104  {NTXT ("experiment"), TLCMD_ENTITY_MODE, PROP_EXPID},
105  // ALIGN commands
106  {NTXT ("root"),       TLCMD_ALIGN, TLSTACK_ALIGN_ROOT},
107  {NTXT ("leaf"),       TLCMD_ALIGN, TLSTACK_ALIGN_LEAF},
108  // DEPTH commands
109  {NTXT ("depth"),      TLCMD_DEPTH, 0 /* don't care */}
110};
111
112static const int tlmode_size = sizeof (tlmode_cmd) / sizeof (TLModeCmd);
113
114// Constructor
115
116Settings::Settings (Application *_app)
117{
118  // Remember the application
119  app = _app;
120
121  // Clear all default strings
122  str_vmode = NULL;
123  str_en_desc = NULL;
124  str_datamode = NULL;
125  str_scompcom = NULL;
126  str_sthresh = NULL;
127  str_dcompcom = NULL;
128  str_dthresh = NULL;
129  str_dmetrics = NULL;
130  str_dsort = NULL;
131  str_tlmode = NULL;
132  str_tldata = NULL;
133  str_tabs = NULL;
134  str_rtabs = NULL;
135  str_search_path = NULL;
136  str_name_format = NULL;
137  str_limit = NULL;
138  str_printmode = NULL;
139  str_compare = NULL;
140  preload_libdirs = NULL;
141  pathmaps = new Vector<pathmap_t*>;
142  lo_expands = new Vector<lo_expand_t*>;
143  lo_expand_default = LIBEX_SHOW;
144  is_loexpand_default = true;
145  tabs_processed = false;
146
147  // set default-default values
148  name_format = Histable::NA;
149  view_mode = VMODE_USER;
150  en_desc = false;
151  en_desc_cmp = NULL;
152  en_desc_usr = NULL;
153  src_compcom = 2147483647;
154  dis_compcom = 2147483647;
155#define DEFAULT_SRC_DIS_THRESHOLD 75
156  threshold_src = DEFAULT_SRC_DIS_THRESHOLD;
157  threshold_dis = DEFAULT_SRC_DIS_THRESHOLD;
158  src_visible = true;
159  srcmetric_visible = false;
160  hex_visible = false;
161  cmpline_visible = true;
162  funcline_visible = true;
163  tldata = NULL;
164  tlmode = 0;
165  stack_align = 0;
166  stack_depth = 0;
167  limit = 0;
168  // print mode is initialized after the .rc files are read
169  print_delim = ',';
170  compare_mode = CMP_DISABLE;
171  machinemodel = NULL;
172  ignore_no_xhwcprof = false;
173  ignore_fs_warn = false;
174
175  // construct the master list of tabs
176  buildMasterTabList ();
177
178  indx_tab_state = new Vector<bool>;
179  indx_tab_order = new Vector<int>;
180  mem_tab_state = new Vector<bool>;
181  mem_tab_order = new Vector<int>;
182
183  // note that the .rc files are not read here, but later
184}
185
186// Constructor for duplicating an existing Settings class
187
188Settings::Settings (Settings * _settings)
189{
190  int index;
191  app = _settings->app;
192
193  // Copy all default strings
194  str_vmode = dbe_strdup (_settings->str_vmode);
195  str_en_desc = dbe_strdup (_settings->str_en_desc);
196  str_datamode = dbe_strdup (_settings->str_datamode);
197  str_scompcom = dbe_strdup (_settings->str_scompcom);
198  str_sthresh = dbe_strdup (_settings->str_sthresh);
199  str_dcompcom = dbe_strdup (_settings->str_dcompcom);
200  str_dthresh = dbe_strdup (_settings->str_dthresh);
201  str_dmetrics = dbe_strdup (_settings->str_dmetrics);
202  str_dsort = dbe_strdup (_settings->str_dsort);
203  str_tlmode = dbe_strdup (_settings->str_tlmode);
204  str_tldata = dbe_strdup (_settings->str_tldata);
205  str_tabs = dbe_strdup (_settings->str_tabs);
206  str_rtabs = dbe_strdup (_settings->str_rtabs);
207  str_search_path = dbe_strdup (_settings->str_search_path);
208  str_name_format = dbe_strdup (_settings->str_name_format);
209  str_limit = dbe_strdup (_settings->str_limit);
210  str_printmode = dbe_strdup (_settings->str_printmode);
211  str_compare = dbe_strdup (_settings->str_compare);
212  preload_libdirs = dbe_strdup (_settings->preload_libdirs);
213
214  // replicate the pathmap vector
215  pathmap_t *thismap;
216  pathmap_t *newmap;
217  pathmaps = new Vector<pathmap_t*>;
218
219  Vec_loop (pathmap_t*, _settings->pathmaps, index, thismap)
220  {
221    newmap = new pathmap_t;
222    newmap->old_prefix = dbe_strdup (thismap->old_prefix);
223    newmap->new_prefix = dbe_strdup (thismap->new_prefix);
224    pathmaps->append (newmap);
225  }
226
227  // replicate the lo_expand vector and default
228  lo_expand_t *this_lo_ex;
229  lo_expand_t *new_lo_ex;
230  lo_expand_default = _settings->lo_expand_default;
231  is_loexpand_default = _settings->is_loexpand_default;
232  lo_expands = new Vector<lo_expand_t*>;
233
234  Vec_loop (lo_expand_t*, _settings->lo_expands, index, this_lo_ex)
235  {
236    new_lo_ex = new lo_expand_t;
237    new_lo_ex->libname = dbe_strdup (this_lo_ex->libname);
238    new_lo_ex->expand = this_lo_ex->expand;
239    lo_expands->append (new_lo_ex);
240  }
241  tabs_processed = _settings->tabs_processed;
242
243  // Copy the various values from the _settings instance
244  name_format = _settings->name_format;
245  view_mode = _settings->view_mode;
246  en_desc = false;
247  en_desc_cmp = NULL;
248  en_desc_usr = NULL;
249  if (_settings->en_desc_usr)
250    set_en_desc (_settings->en_desc_usr, true);
251  src_compcom = _settings->src_compcom;
252  dis_compcom = _settings->dis_compcom;
253  threshold_src = _settings->threshold_src;
254  threshold_dis = _settings->threshold_dis;
255  src_visible = _settings->src_visible;
256  srcmetric_visible = _settings->srcmetric_visible;
257  hex_visible = _settings->hex_visible;
258  cmpline_visible = _settings->cmpline_visible;
259  funcline_visible = _settings->funcline_visible;
260  tldata = dbe_strdup (_settings->tldata);
261  tlmode = _settings->tlmode;
262  stack_align = _settings->stack_align;
263  stack_depth = _settings->stack_depth;
264  limit = _settings->limit;
265  print_mode = _settings->print_mode;
266  print_delim = _settings->print_delim;
267  compare_mode = _settings->compare_mode;
268  machinemodel = dbe_strdup (_settings->machinemodel);
269  ignore_no_xhwcprof = _settings->ignore_no_xhwcprof;
270  ignore_fs_warn = _settings->ignore_fs_warn;
271
272  // copy the tab list, too
273  tab_list = new Vector<DispTab*>;
274  DispTab *dsptab;
275
276  Vec_loop (DispTab*, _settings->tab_list, index, dsptab)
277  {
278    DispTab *ntab;
279    ntab = new DispTab (dsptab->type, dsptab->order, dsptab->visible, dsptab->cmdtoken);
280    ntab->setAvailability (dsptab->available);
281    tab_list->append (ntab);
282  }
283
284  // construct the master list of memory tabs & copy order
285  index = _settings->mem_tab_state->size ();
286  mem_tab_state = new Vector<bool>(index);
287  mem_tab_order = new Vector<int>(index);
288  for (int i = 0; i < index; i++)
289    {
290      mem_tab_state->append (false);
291      mem_tab_order->append (_settings->mem_tab_order->fetch (i));
292    }
293
294  // construct the master list of index tabs & copy order
295  index = _settings->indx_tab_state->size ();
296  indx_tab_state = new Vector<bool>(index);
297  indx_tab_order = new Vector<int>(index);
298  for (int i = 0; i < index; i++)
299    indx_tab_order->append (_settings->indx_tab_order->fetch (i));
300  set_IndxTabState (_settings->indx_tab_state);
301}
302
303Settings::~Settings ()
304{
305  for (int i = 0; i < pathmaps->size (); ++i)
306    {
307      pathmap_t *pmap = pathmaps->fetch (i);
308      free (pmap->old_prefix);
309      free (pmap->new_prefix);
310      delete pmap;
311    }
312  delete pathmaps;
313
314  for (int i = 0; i < lo_expands->size (); ++i)
315    {
316      lo_expand_t *lo_ex = lo_expands->fetch (i);
317      free (lo_ex->libname);
318      delete lo_ex;
319    }
320  delete lo_expands;
321
322  tab_list->destroy ();
323  delete tab_list;
324  delete indx_tab_state;
325  delete indx_tab_order;
326  delete mem_tab_state;
327  delete mem_tab_order;
328
329  free (str_vmode);
330  free (str_en_desc);
331  free (str_datamode);
332  free (str_scompcom);
333  free (str_sthresh);
334  free (str_dcompcom);
335  free (str_dthresh);
336  free (str_dmetrics);
337  free (str_dsort);
338  free (str_tlmode);
339  free (str_tldata);
340  free (str_tabs);
341  free (str_rtabs);
342  free (str_search_path);
343  free (str_name_format);
344  free (str_limit);
345  free (str_compare);
346  free (str_printmode);
347  free (preload_libdirs);
348  free (tldata);
349  free (en_desc_usr);
350  if (en_desc_cmp)
351    {
352      regfree (en_desc_cmp);
353      delete en_desc_cmp;
354    }
355}
356
357/**
358 * Read .er.rc file from the specified location
359 * @param path
360 * @return
361 */
362char *
363Settings::read_rc (char *path)
364{
365  StringBuilder sb;
366  Emsgqueue *commentq = new Emsgqueue (NTXT ("setting_commentq"));
367
368  // Check file name
369  if (NULL == path)
370    return dbe_strdup (GTXT ("Error: empty file name"));
371  bool override = true;
372  set_rc (path, true, commentq, override);
373  Emsg *msg = commentq->fetch ();
374  while (msg != NULL)
375    {
376      char *str = msg->get_msg ();
377      sb.append (str);
378      msg = msg->next;
379    }
380  return sb.toString ();
381}
382
383void
384Settings::read_rc (bool ipc_or_rdt_mode)
385{
386  bool override = false;
387
388  // Read file from the current working directory
389  char *rc_path = realpath (NTXT ("./.gprofng.rc"), NULL);
390  if (rc_path)
391    set_rc (rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode);
392
393  // Read file from the user's home directory
394  char *home = getenv (NTXT ("HOME"));
395  if (home)
396    {
397      char *strbuf = dbe_sprintf (NTXT ("%s/.gprofng.rc"), home);
398      char *home_rc_path = realpath (strbuf, NULL);
399      if (home_rc_path)
400	{
401	  if (rc_path == NULL || strcmp (rc_path, home_rc_path) != 0)
402	    set_rc (home_rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode);
403	  free (home_rc_path);
404	}
405      free (strbuf);
406    }
407  free (rc_path);
408
409  // Read system-wide file
410  const char *sysconfdir = getenv("GPROFNG_SYSCONFDIR");
411  if (sysconfdir == NULL)
412    sysconfdir = SYSCONFDIR;
413  rc_path = dbe_sprintf (NTXT ("%s/gprofng.rc"), sysconfdir);
414  if (access (rc_path, R_OK | F_OK) != 0)
415    {
416      StringBuilder sb;
417      sb.sprintf (GTXT ("Warning: Default gprofng.rc file (%s) missing; configuration error "), rc_path);
418      Emsg *m = new Emsg (CMSG_COMMENT, sb);
419      app->get_comments_queue ()->append (m);
420    }
421  else
422    set_rc (rc_path, false, app->get_comments_queue (), override);
423  free (rc_path);
424  is_loexpand_default = true;
425  if (str_printmode == NULL)
426    {
427      // only if there's none set
428      print_mode = PM_TEXT;
429      str_printmode = dbe_strdup (NTXT ("text"));
430    }
431}
432
433
434//  Handle various settings from reading the name .rc file
435//	This function is called for each .rc file read, and, for
436//	some settings, it accumulates the strings from the files.
437//	For others, it accepts the first appearance for a setting in a
438//	.rc file, and ignores subsequent appearances from other files.
439//  Error messages are appended to the Emsgqueue specified by the caller
440
441#define MAXARGS 20
442
443void
444Settings::set_rc (const char *path, bool msg, Emsgqueue *commentq,
445		  bool override, bool ipc_or_rdt_mode)
446{
447  CmdType cmd_type;
448  int arg_count, cparam;
449  char *cmd, *end_cmd, *strbuf;
450  char *arglist[MAXARGS];
451  StringBuilder sb;
452
453  FILE *fptr = fopen (path, NTXT ("r"));
454  if (fptr == NULL)
455    return;
456
457  if (msg)
458    {
459      sb.sprintf (GTXT ("Processed %s for default settings"), path);
460      Emsg *m = new Emsg (CMSG_COMMENT, sb);
461      commentq->append (m);
462    }
463  int line_no = 0;
464  end_cmd = NULL;
465  while (!feof (fptr))
466    {
467      char *script = read_line (fptr);
468      if (script == NULL)
469	continue;
470      line_no++;
471      strtok (script, NTXT ("\n"));
472
473      // extract the command
474      cmd = strtok (script, NTXT (" \t"));
475      if (cmd == NULL || *cmd == '#' || *cmd == '\n')
476	{
477	  free (script);
478	  continue;
479	}
480      char *remainder = strtok (NULL, NTXT ("\n"));
481      // now extract the arguments
482      int nargs = 0;
483      for (;;)
484	{
485	  if (nargs >= MAXARGS)
486	    {
487	      if (!msg)
488		{
489		  msg = true; // suppress repeats of header
490		  Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
491		  commentq->append (m);
492		}
493	      sb.sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
494			  MAXARGS, cmd, line_no);
495	      Emsg *m = new Emsg (CMSG_COMMENT, sb);
496	      commentq->append (m);
497	      break;
498	    }
499
500	  char *nextarg = strtok (remainder, NTXT ("\n"));
501	  if (nextarg == NULL || *nextarg == '#')
502	    break;
503	  arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
504	  remainder = end_cmd;
505	  if (remainder == NULL)
506	    break;
507	  // skip any blanks or tabs to get to next argument
508	  while (*remainder == ' ' || *remainder == '\t')
509	    remainder++;
510	}
511      cmd_type = Command::get_command (cmd, arg_count, cparam);
512      // check for extra arguments
513      if ((cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF) && (nargs > arg_count))
514	{
515	  if (!msg)
516	    {
517	      msg = true; // suppress repeats of header
518	      Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
519	      commentq->append (m);
520	    }
521	  sb.sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"), cmd, line_no);
522	  Emsg *m = new Emsg (CMSG_COMMENT, sb);
523	  commentq->append (m);
524	}
525      if (nargs < arg_count)
526	{
527	  if (!msg)
528	    {
529	      msg = true; // suppress repeats of header
530	      Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
531	      commentq->append (m);
532	    }
533	  sb.sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"),
534		      cmd, line_no);
535	  Emsg *m = new Emsg (CMSG_COMMENT, sb);
536	  commentq->append (m);
537
538	  // ignore this command
539	  free (script);
540	  continue;
541	}
542      if (ipc_or_rdt_mode && (cmd_type != ADDPATH) && (cmd_type != PATHMAP))
543	{
544	  free (script);
545	  continue;
546	}
547      switch (cmd_type)
548	{
549	case SCOMPCOM:
550	  if (!str_scompcom || override)
551	    {
552	      str_scompcom = dbe_strdup (arglist[0]);
553	      proc_compcom (arglist[0], true, true);
554	    }
555	  break;
556	case STHRESH:
557	  if (!str_sthresh || override)
558	    {
559	      str_sthresh = dbe_strdup (arglist[0]);
560	      proc_thresh (arglist[0], true, true);
561	      break;
562	    }
563	  break;
564	case DCOMPCOM:
565	  if (!str_dcompcom || override)
566	    {
567	      str_dcompcom = dbe_strdup (arglist[0]);
568	      proc_compcom (arglist[0], false, true);
569	    }
570	  break;
571	case COMPCOM:
572	  // process as if it were for both source and disassembly
573	  //	note that if it is set, subsequent SCOMPCOM and DCOMPCOM
574	  //	will be ignored
575	  if (!str_scompcom || override)
576	    {
577	      str_scompcom = dbe_strdup (arglist[0]);
578	      proc_compcom (arglist[0], true, true);
579	    }
580	  if (!str_dcompcom || override)
581	    {
582	      str_dcompcom = dbe_strdup (arglist[0]);
583	      proc_compcom (arglist[0], false, true);
584	    }
585	  break;
586	case DTHRESH:
587	  if (!str_dthresh || override)
588	    {
589	      str_dthresh = dbe_strdup (arglist[0]);
590	      proc_thresh (arglist[0], false, true);
591	    }
592	  break;
593	case DMETRICS:
594	  // append new settings to old, if necessary
595	  if (str_dmetrics)
596	    {
597	      char *name = strstr (str_dmetrics, ":name");
598	      if (name == NULL)
599		strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]);
600	      else
601		{
602		  char * next = strstr (name + 1, ":");
603		  if (next == NULL)
604		    {
605		      name[0] = '\0';
606		      strbuf = dbe_sprintf ("%s:%s:name", str_dmetrics, arglist[0]);
607		    }
608		  else
609		    strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]);
610		}
611	      free (str_dmetrics);
612	      str_dmetrics = strbuf;
613	    }
614	  else
615	    str_dmetrics = dbe_strdup (arglist[0]);
616	  break;
617	case DSORT:
618	  // append new settings to old, if necessary
619	  if (str_dsort)
620	    {
621	      strbuf = dbe_sprintf (NTXT ("%s:%s"), str_dsort, arglist[0]);
622	      free (str_dsort);
623	      str_dsort = strbuf;
624	    }
625	  else
626	    str_dsort = dbe_strdup (arglist[0]);
627	  break;
628	case TLMODE:
629	  if (!str_tlmode || override)
630	    {
631	      str_tlmode = dbe_strdup (arglist[0]);
632	      proc_tlmode (arglist[0], true);
633	    }
634	  break;
635	case TLDATA:
636	  if (!str_tldata || override)
637	    {
638	      str_tldata = dbe_strdup (arglist[0]);
639	      proc_tldata (arglist[0], true);
640	    }
641	  break;
642	case TABS:
643	  if (!str_tabs || override)
644	    // the string is processed later, after all .rc files are read
645	    str_tabs = dbe_strdup (arglist[0]);
646	  break;
647	case RTABS:
648	  if (!str_rtabs || override)
649	    // the string is processed later, after all .rc files are read
650	    str_rtabs = dbe_strdup (arglist[0]);
651	  break;
652	case ADDPATH:
653	  if (str_search_path)
654	    {
655	      strbuf = dbe_sprintf (NTXT ("%s:%s"), str_search_path, arglist[0]);
656	      free (str_search_path);
657	      str_search_path = strbuf;
658	    }
659	  else
660	    str_search_path = dbe_strdup (arglist[0]);
661	  break;
662	case PATHMAP:
663	  {
664	    char *err = add_pathmap (pathmaps, arglist[0], arglist[1]);
665	    free (err);     // XXX error is not reported
666	    break;
667	  }
668	case LIBDIRS:
669	  if (preload_libdirs == NULL)
670	    preload_libdirs = dbe_strdup (arglist[0]);
671	  break;
672	case NAMEFMT:
673	  if (name_format == Histable::NA)
674	    set_name_format (arglist[0]);
675	  break;
676	case VIEWMODE:
677	  if (!str_vmode || override)
678	    {
679	      str_vmode = dbe_strdup (arglist[0]);
680	      set_view_mode (arglist[0], true);
681	    }
682	  break;
683	case EN_DESC:
684	  if (!str_en_desc || override)
685	    {
686	      str_en_desc = dbe_strdup (arglist[0]);
687	      set_en_desc (arglist[0], true);
688	    }
689	  break;
690	case LIMIT:
691	  if (!str_limit || override)
692	    {
693	      str_limit = dbe_strdup (arglist[0]);
694	      set_limit (arglist[0], true);
695	    }
696	  break;
697	case PRINTMODE:
698	  if (!str_printmode || override)
699	    set_printmode (arglist[0]);
700	  break;
701	case COMPARE:
702	  if (!str_compare || override)
703	    {
704	      char *s = arglist[0];
705	      if (s)
706		str_compare = dbe_strdup (s);
707	      else
708		s = NTXT ("");
709	      if (strcasecmp (s, NTXT ("OFF")) == 0
710		  || strcmp (s, NTXT ("0")) == 0)
711		set_compare_mode (CMP_DISABLE);
712	      else if (strcasecmp (s, NTXT ("ON")) == 0
713		       || strcmp (s, NTXT ("1")) == 0)
714		set_compare_mode (CMP_ENABLE);
715	      else if (strcasecmp (s, NTXT ("DELTA")) == 0)
716		set_compare_mode (CMP_DELTA);
717	      else if (strcasecmp (s, NTXT ("RATIO")) == 0)
718		set_compare_mode (CMP_RATIO);
719	      else
720		{
721		  sb.sprintf (GTXT ("   .er.rc:%d The argument of 'compare' should be 'on', 'off', 'delta', or 'ratio'"),
722			      (int) line_no);
723		  Emsg *m = new Emsg (CMSG_COMMENT, sb);
724		  commentq->append (m);
725		}
726	    }
727	  break;
728
729	case INDXOBJDEF:
730	  {
731	    char *ret = dbeSession->indxobj_define (arglist[0], NULL, arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL, (nargs >= 4) ? PTXT (arglist[3]) : NULL);
732	    if (ret != NULL)
733	      {
734		sb.sprintf (GTXT ("   %s: line %d `%s %s %s'\n"),
735			    ret, line_no, cmd, arglist[0], arglist[1]);
736		Emsg *m = new Emsg (CMSG_COMMENT, sb);
737		commentq->append (m);
738	      }
739	    break;
740	  }
741#ifdef sparc
742	  //XXX: should be conditional on the experiment ARCH, not dbe ARCH
743	case IGNORE_NO_XHWCPROF:
744	  // ignore absence of -xhwcprof info for dataspace profiling
745	  set_ignore_no_xhwcprof (true);
746	  break;
747#endif // sparc
748	case IGNORE_FS_WARN:
749	  // ignore file system warning in experiments
750	  set_ignore_fs_warn (true);
751	  break;
752	case OBJECT_SHOW:
753	  // Add the named libraries to the lib_expands array
754	  set_libexpand (arglist[0], LIBEX_SHOW, true);
755	  break;
756	case OBJECT_HIDE:
757	  // Add the named libraries to the lib_expands array
758	  set_libexpand (arglist[0], LIBEX_HIDE, true);
759	  break;
760	case OBJECT_API:
761	  // Add the named libraries to the lib_expands array
762	  set_libexpand (arglist[0], LIBEX_API, true);
763	  break;
764	case COMMENT:
765	  // ignore the line
766	  break;
767	default:
768	  {
769	    // unexpected command in an rc file
770	    if (!msg)
771	      {
772		// if quiet, can remain so no longer
773		msg = true;
774		Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
775		commentq->append (m);
776	      }
777	    sb.sprintf (GTXT ("   Unrecognized .gprofng.rc command on line %d: `%.64s'"),
778			line_no, cmd);
779	    Emsg *m = new Emsg (CMSG_COMMENT, sb);
780	    commentq->append (m);
781	    break;
782	  }
783	}
784      free (script);
785    }
786  fclose (fptr);
787}
788
789Cmd_status
790Settings::set_view_mode (char *arg, bool rc)
791{
792  if (!strcasecmp (arg, NTXT ("user")))
793    view_mode = VMODE_USER;
794  else if (!strcasecmp (arg, NTXT ("expert")))
795    view_mode = VMODE_EXPERT;
796  else if (!strcasecmp (arg, NTXT ("machine")))
797    view_mode = VMODE_MACHINE;
798  else if (!rc)
799    return CMD_BAD_ARG;
800  return CMD_OK;
801}
802
803Cmd_status
804Settings::set_en_desc (char *arg, bool rc)
805{
806  regex_t *regex_desc = NULL;
807
808  // cases below should be similar to Coll_Ctrl::set_follow_mode() cases
809  if (!strcasecmp (arg, NTXT ("on")))
810    en_desc = true;
811  else if (!strcasecmp (arg, NTXT ("off")))
812    en_desc = false;
813  else if (arg[0] == '=' && arg[1] != 0)
814    {
815      // user has specified a string matching specification
816      int ercode;
817      { // compile regex_desc
818	char * str = dbe_sprintf (NTXT ("^%s$"), arg + 1);
819	regex_desc = new regex_t;
820	memset (regex_desc, 0, sizeof (regex_t));
821	ercode = regcomp (regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
822	free (str);
823      }
824      if (ercode)
825	{
826	  // syntax error in parsing string
827	  delete regex_desc;
828	  if (!rc)
829	    return CMD_BAD_ARG;
830	  return CMD_OK;
831	}
832      en_desc = true;
833    }
834  else
835    {
836      if (!rc)
837	return CMD_BAD_ARG;
838      return CMD_OK;
839    }
840  free (en_desc_usr);
841  en_desc_usr = dbe_strdup (arg);
842  if (en_desc_cmp)
843    {
844      regfree (en_desc_cmp);
845      delete en_desc_cmp;
846    }
847  en_desc_cmp = regex_desc;
848  return CMD_OK;
849}
850
851// See if a descendant matches either the lineage or the executable name
852bool
853Settings::check_en_desc (const char *lineage, const char *targname)
854{
855  bool rc;
856  if (en_desc_cmp == NULL)
857    return en_desc;     // no specification was set, use the binary on/off value
858  if (lineage == NULL)  // user doesn't care about specification
859    return en_desc;     // use the binary on/off specification
860  if (!regexec (en_desc_cmp, lineage, 0, NULL, 0))
861    rc = true;          // this one matches user specification
862  else if (targname == NULL)
863    rc = false;         //a NULL name does not match any expression
864  else if (!regexec (en_desc_cmp, targname, 0, NULL, 0))
865    rc = true;          // this one matches the executable name
866  else
867    rc = false;
868  return rc;
869}
870
871char *
872Settings::set_limit (char *arg, bool)
873{
874  limit = (int) strtol (arg, (char **) NULL, 10);
875  return NULL;
876}
877
878char *
879Settings::set_printmode (char *arg)
880{
881  if (arg == NULL)
882    return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"),
883			NTXT ("printmode"), NTXT ("text"), NTXT ("html"));
884  if (strlen (arg) == 1)
885    {
886      print_mode = PM_DELIM_SEP_LIST;
887      print_delim = arg[0];
888    }
889  else if (!strcasecmp (arg, NTXT ("text")))
890    print_mode = PM_TEXT;
891  else if (!strcasecmp (arg, NTXT ("html")))
892    print_mode = PM_HTML;
893  else
894    return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"),
895			NTXT ("printmode"), NTXT ("text"), NTXT ("html"));
896  free (str_printmode);
897  str_printmode = dbe_strdup (arg);
898  return NULL;
899}
900
901Cmd_status
902Settings::proc_compcom (const char *cmd, bool isSrc, bool rc)
903{
904  int ck_compcom_bits, ck_threshold;
905  bool ck_hex_visible = false;
906  bool ck_src_visible = false;
907  bool ck_srcmetric_visible = false;
908  bool got_compcom_bits, got_threshold, got_src_visible, got_srcmetric_visible;
909  bool got_hex_visible, got;
910  int len, i;
911  char *mcmd, *param;
912  int flag, value = 0;
913  Cmd_status status;
914  char buf[BUFSIZ], *list;
915
916  if (cmd == NULL)
917    return CMD_BAD;
918  ck_compcom_bits = 0;
919  ck_threshold = 0;
920  got_compcom_bits = got_threshold = got_src_visible = false;
921  got_srcmetric_visible = got_hex_visible = false;
922  snprintf (buf, sizeof (buf), NTXT ("%s"), cmd);
923  list = buf;
924  while ((mcmd = strtok (list, NTXT (":"))) != NULL)
925    {
926      list = NULL;
927      // if "all" or "none"
928      if (!strcasecmp (mcmd, Command::ALL_CMD))
929	{
930	  got_compcom_bits = true;
931	  ck_compcom_bits = CCMV_ALL;
932	  continue;
933	}
934      else if (!strcasecmp (mcmd, Command::NONE_CMD))
935	{
936	  got_compcom_bits = true;
937	  ck_compcom_bits = 0;
938	  continue;
939	}
940
941      // Find parameter after '='
942      param = strchr (mcmd, '=');
943      if (param)
944	{
945	  *param = '\0';
946	  param++;
947	}
948      status = CMD_OK;
949      got = false;
950      flag = 0;
951      len = (int) strlen (mcmd);
952      for (i = 0; status == CMD_OK && i < comp_size; i++)
953	if (!strncasecmp (mcmd, comp_cmd[i], len))
954	  {
955	    if (got) // Ambiguous comp_com command
956	      status = CMD_AMBIGUOUS;
957	    else
958	      {
959		got = true;
960		flag = comp_vis[i];
961		// Check argument
962		if (flag == COMP_THRESHOLD)
963		  {
964		    if (param == NULL)
965		      status = CMD_BAD_ARG;
966		    else
967		      {
968			value = (int) strtol (param, &param, 10);
969			if (value < 0 || value > 100)
970			  status = CMD_OUTRANGE;
971		      }
972		  }
973		else if (param != NULL)
974		  status = CMD_BAD_ARG;
975	      }
976	  }
977
978      // Not valid comp_com command
979      if (!got)
980	status = CMD_INVALID;
981      if (status != CMD_OK)
982	{
983	  if (!rc)
984	    return status;
985	  continue;
986	}
987
988      // Set bits
989      switch (flag)
990	{
991	case COMP_CMPLINE:
992	  cmpline_visible = true;
993	  break;
994	case COMP_FUNCLINE:
995	  funcline_visible = true;
996	  break;
997	case COMP_THRESHOLD:
998	  got_threshold = true;
999	  ck_threshold = value;
1000	  break;
1001	case COMP_SRC:
1002	  got_src_visible = true;
1003	  ck_src_visible = true;
1004	  break;
1005	case COMP_SRC_METRIC:
1006	  got_srcmetric_visible = true;
1007	  ck_srcmetric_visible = true;
1008	  got_src_visible = true;
1009	  ck_src_visible = true;
1010	  break;
1011	case COMP_NOSRC:
1012	  got_src_visible = true;
1013	  ck_src_visible = false;
1014	  break;
1015	case COMP_HEX:
1016	  got_hex_visible = true;
1017	  ck_hex_visible = true;
1018	  break;
1019	case COMP_NOHEX:
1020	  got_hex_visible = true;
1021	  ck_hex_visible = false;
1022	  break;
1023	case CCMV_BASIC:
1024	  got_compcom_bits = true;
1025	  ck_compcom_bits = CCMV_BASIC;
1026	  break;
1027	default:
1028	  got_compcom_bits = true;
1029	  ck_compcom_bits |= flag;
1030	}
1031    }
1032
1033  // No error, update
1034  if (got_compcom_bits)
1035    {
1036      if (isSrc)
1037	src_compcom = ck_compcom_bits;
1038      else
1039	dis_compcom = ck_compcom_bits;
1040    }
1041  if (got_threshold)
1042    {
1043      if (isSrc)
1044	threshold_src = ck_threshold;
1045      else
1046	threshold_dis = ck_threshold;
1047    }
1048  if (got_src_visible)
1049      src_visible = ck_src_visible;
1050  if (got_srcmetric_visible)
1051      srcmetric_visible = ck_srcmetric_visible;
1052  if (got_hex_visible)
1053      hex_visible = ck_hex_visible;
1054  return CMD_OK;
1055}
1056
1057// Process a threshold setting
1058Cmd_status
1059Settings::proc_thresh (char *cmd, bool isSrc, bool rc)
1060{
1061  int value;
1062  if (cmd == NULL)
1063    value = DEFAULT_SRC_DIS_THRESHOLD; // the default
1064  else
1065    value = (int) strtol (cmd, &cmd, 10);
1066  if (value < 0 || value > 100)
1067    {
1068      if (!rc)
1069	return CMD_OUTRANGE;
1070      value = DEFAULT_SRC_DIS_THRESHOLD;
1071    }
1072  if (isSrc)
1073    threshold_src = value;
1074  else
1075    threshold_dis = value;
1076  return CMD_OK;
1077}
1078
1079// return any error string from processing visibility settings
1080char *
1081Settings::get_compcom_errstr (Cmd_status status, const char *cmd)
1082{
1083  int i;
1084  StringBuilder sb;
1085  switch (status)
1086    {
1087    case CMD_BAD:
1088      sb.append (GTXT ("No commentary classes has been specified."));
1089      break;
1090    case CMD_AMBIGUOUS:
1091      sb.append (GTXT ("Ambiguous commentary classes: "));
1092      break;
1093    case CMD_BAD_ARG:
1094      sb.append (GTXT ("Invalid argument for commentary classes: "));
1095      break;
1096    case CMD_OUTRANGE:
1097      sb.append (GTXT ("Out of range commentary classes argument: "));
1098      break;
1099    case CMD_INVALID:
1100      sb.append (GTXT ("Invalid commentary classes: "));
1101      break;
1102    case CMD_OK:
1103      break;
1104    }
1105  if (cmd)
1106    sb.append (cmd);
1107  sb.append (GTXT ("\nAvailable commentary classes: "));
1108  for (i = 0; i < comp_size; i++)
1109    {
1110      sb.append (comp_cmd[i]);
1111      if (i == comp_size - 1)
1112	sb.append (NTXT ("=#\n"));
1113      else
1114	sb.append (NTXT (":"));
1115    }
1116  return sb.toString ();
1117}
1118
1119// Process a timeline-mode setting
1120Cmd_status
1121Settings::proc_tlmode (char *cmd, bool rc)
1122{
1123  bool got_tlmode, got_stack_align, got_stack_depth, got;
1124  int ck_tlmode = 0, ck_stack_align = 0, ck_stack_depth = 0;
1125  int len, i;
1126  char *mcmd, *param;
1127  int cmd_id, value = 0;
1128  TLModeSubcommand cmd_type;
1129  Cmd_status status;
1130  char buf[BUFSIZ], *list;
1131  if (cmd == NULL)
1132    return CMD_BAD;
1133  got_tlmode = got_stack_align = got_stack_depth = false;
1134  snprintf (buf, sizeof (buf), NTXT ("%s"), cmd);
1135  list = buf;
1136  while ((mcmd = strtok (list, NTXT (":"))) != NULL)
1137    {
1138      list = NULL;
1139
1140      // Find parameter after '='
1141      param = strchr (mcmd, '=');
1142      if (param)
1143	{
1144	  *param = '\0';
1145	  param++;
1146	}
1147      status = CMD_OK;
1148      got = false;
1149      cmd_id = 0;
1150      cmd_type = TLCMD_INVALID;
1151      len = (int) strlen (mcmd);
1152      for (i = 0; status == CMD_OK && i < tlmode_size; i++)
1153	{
1154	  if (!strncasecmp (mcmd, tlmode_cmd[i].cmdText, len))
1155	    {
1156	      if (got) // Ambiguous timeline mode
1157		status = CMD_AMBIGUOUS;
1158	      else
1159		{
1160		  got = true;
1161		  cmd_type = tlmode_cmd[i].cmdType;
1162		  cmd_id = tlmode_cmd[i].cmdId;
1163
1164		  // Check argument
1165		  if (cmd_type == TLCMD_DEPTH)
1166		    {
1167		      if (param == NULL)
1168			status = CMD_BAD_ARG;
1169		      else
1170			{
1171			  value = (int) strtol (param, &param, 10);
1172			  if (value <= 0 || value > 256)
1173			    status = CMD_OUTRANGE;
1174			}
1175		    }
1176		  else if (param != NULL)
1177		    status = CMD_BAD_ARG;
1178		}
1179	    }
1180	}
1181
1182      // Not valid timeline mode
1183      if (!got)
1184	status = CMD_INVALID;
1185      if (status != CMD_OK)
1186	{
1187	  if (!rc)
1188	    return status;
1189	  continue;
1190	}
1191
1192      // Set bits
1193      switch (cmd_type)
1194	{
1195	case TLCMD_ENTITY_MODE:
1196	  got_tlmode = true;
1197	  ck_tlmode = cmd_id;
1198	  break;
1199	case TLCMD_ALIGN:
1200	  got_stack_align = true;
1201	  ck_stack_align = cmd_id;
1202	  break;
1203	case TLCMD_DEPTH:
1204	  got_stack_depth = true;
1205	  ck_stack_depth = value;
1206	  break;
1207	default:
1208	  break;
1209	}
1210    }
1211
1212  // No error, update
1213  if (got_tlmode)
1214    tlmode = ck_tlmode;
1215  if (got_stack_align)
1216    stack_align = ck_stack_align;
1217  if (got_stack_depth)
1218    stack_depth = ck_stack_depth;
1219  return CMD_OK;
1220}
1221
1222// Process timeline data specification
1223Cmd_status
1224Settings::proc_tldata (const char *cmd, bool /* if true, ignore any error */)
1225{
1226  free (tldata);
1227  tldata = dbe_strdup (cmd); // let GUI parse it
1228  return CMD_OK;
1229}
1230
1231void
1232Settings::set_tldata (const char* _tldata_str)
1233{
1234  free (tldata);
1235  tldata = dbe_strdup (_tldata_str);
1236}
1237
1238char*
1239Settings::get_tldata ()
1240{
1241  return dbe_strdup (tldata);
1242}
1243
1244Cmd_status
1245Settings::set_name_format (char *arg)
1246{
1247  char *colon = strchr (arg, ':');
1248  size_t arg_len = (colon) ? (colon - arg) : strlen (arg);
1249  Histable::NameFormat fname_fmt = Histable::NA;
1250  if (!strncasecmp (arg, NTXT ("long"), arg_len))
1251    fname_fmt = Histable::LONG;
1252  else if (!strncasecmp (arg, NTXT ("short"), arg_len))
1253    fname_fmt = Histable::SHORT;
1254  else if (!strncasecmp (arg, NTXT ("mangled"), arg_len))
1255    fname_fmt = Histable::MANGLED;
1256  else
1257    return CMD_BAD_ARG;
1258
1259  bool soname_fmt = false;
1260  if (colon && (colon + 1))
1261    {
1262      colon++;
1263      if (!strcasecmp (colon, NTXT ("soname")))
1264	soname_fmt = true;
1265      else if (!strcasecmp (colon, NTXT ("nosoname")))
1266	soname_fmt = false;
1267      else
1268	return CMD_BAD_ARG;
1269    }
1270  name_format = Histable::make_fmt (fname_fmt, soname_fmt);
1271  return CMD_OK;
1272}
1273
1274void
1275Settings::buildMasterTabList ()
1276{
1277  tab_list = new Vector<DispTab*>;
1278  int i = -1;
1279
1280  // Add tabs for all the known reports
1281  tab_list->append (new DispTab (DSP_DEADLOCKS, i, false, DEADLOCK_EVNTS));
1282  tab_list->append (new DispTab (DSP_FUNCTION, i, false, FUNCS));
1283  tab_list->append (new DispTab (DSP_TIMELINE, i, false, TIMELINE));
1284  tab_list->append (new DispTab (DSP_CALLTREE, i, false, CALLTREE));
1285  tab_list->append (new DispTab (DSP_CALLFLAME, i, false, CALLFLAME));
1286  tab_list->append (new DispTab (DSP_DUALSOURCE, i, false, DUALSOURCE));
1287  tab_list->append (new DispTab (DSP_SOURCE_DISASM, i, false, SOURCEDISAM));
1288  tab_list->append (new DispTab (DSP_SOURCE, i, false, SOURCE));
1289  tab_list->append (new DispTab (DSP_LINE, i, false, HOTLINES));
1290  tab_list->append (new DispTab (DSP_DISASM, i, false, DISASM));
1291  tab_list->append (new DispTab (DSP_PC, i, false, HOTPCS));
1292  tab_list->append (new DispTab (DSP_LEAKLIST, i, false, LEAKS));
1293  tab_list->append (new DispTab (DSP_IOACTIVITY, i, false, IOACTIVITY));
1294  tab_list->append (new DispTab (DSP_HEAPCALLSTACK, i, false, HEAP));
1295  tab_list->append (new DispTab (DSP_IFREQ, i, false, IFREQ));
1296  tab_list->append (new DispTab (DSP_CALLER, i, false, GPROF));
1297  tab_list->append (new DispTab (DSP_STATIS, i, false, STATISTICS));
1298  tab_list->append (new DispTab (DSP_EXP, i, false, HEADER));
1299}
1300
1301// Update tablist based on data availability
1302void
1303Settings::updateTabAvailability ()
1304{
1305  int index;
1306  DispTab *dsptab;
1307
1308  Vec_loop (DispTab*, tab_list, index, dsptab)
1309  {
1310    if (dsptab->type == DSP_DATAOBJ)
1311      dsptab->setAvailability (dbeSession->is_datamode_available ());
1312    else if (dsptab->type == DSP_DLAYOUT)
1313      dsptab->setAvailability (dbeSession->is_datamode_available ());
1314    else if (dsptab->type == DSP_LEAKLIST)
1315      dsptab->setAvailability (false);
1316    else if (dsptab->type == DSP_IOACTIVITY)
1317      dsptab->setAvailability (dbeSession->is_iodata_available ());
1318    else if (dsptab->type == DSP_HEAPCALLSTACK)
1319      dsptab->setAvailability (dbeSession->is_heapdata_available ());
1320    else if (dsptab->type == DSP_TIMELINE)
1321      dsptab->setAvailability (dbeSession->is_timeline_available ());
1322    else if (dsptab->type == DSP_IFREQ)
1323      dsptab->setAvailability (dbeSession->is_ifreq_available ());
1324    else if (dsptab->type == DSP_RACES)
1325      dsptab->setAvailability (dbeSession->is_racelist_available ());
1326    else if (dsptab->type == DSP_DEADLOCKS)
1327      dsptab->setAvailability (dbeSession->is_deadlocklist_available ());
1328    else if (dsptab->type == DSP_DUALSOURCE)
1329      dsptab->setAvailability (dbeSession->is_racelist_available ()
1330			       || dbeSession->is_deadlocklist_available ());
1331  }
1332}
1333
1334// Process a tab setting
1335Cmd_status
1336Settings::proc_tabs (bool _rdtMode)
1337{
1338  int arg_cnt, cparam;
1339  int count = 0;
1340  int index;
1341  DispTab *dsptab;
1342  char *cmd;
1343  if (tabs_processed == true)
1344    return CMD_OK;
1345  tabs_processed = true;
1346  if (_rdtMode == true)
1347    {
1348      if (str_rtabs == NULL)
1349	str_rtabs = strdup ("header");
1350      cmd = str_rtabs;
1351    }
1352  else
1353    {
1354      if (str_tabs == NULL)
1355	str_tabs = strdup ("header");
1356      cmd = str_tabs;
1357    }
1358  if (strcmp (cmd, NTXT ("none")) == 0)
1359    return CMD_OK;
1360  Vector <char *> *tokens = split_str (cmd, ':');
1361  for (long j = 0, sz = VecSize (tokens); j < sz; j++)
1362    {
1363      char *tabname = tokens->get (j);
1364      // search for this tab command token
1365      CmdType c = Command::get_command (tabname, arg_cnt, cparam);
1366      if (c == INDXOBJ)
1367	{
1368	  // set the bit for this subtype
1369	  indx_tab_state->store (cparam, true);
1370	  indx_tab_order->store (cparam, count++);
1371	}
1372      else
1373	{
1374	  // search for this tab type in the regular tabs
1375	  Vec_loop (DispTab*, tab_list, index, dsptab)
1376	  {
1377	    if (dsptab->cmdtoken == c)
1378	      {
1379		dsptab->visible = true;
1380		dsptab->order = count++;
1381		break;
1382	      }
1383	  }
1384	}
1385      free (tabname);
1386    }
1387  delete tokens;
1388  return CMD_OK;
1389}
1390
1391void
1392Settings::set_MemTabState (Vector<bool>*selected)
1393{
1394  if (selected->size () == 0)
1395    return;
1396  for (int j = 0; j < mem_tab_state->size (); j++)
1397    mem_tab_state->store (j, selected->fetch (j));
1398}
1399
1400// define a new memory object type
1401
1402void
1403Settings::mobj_define (MemObjType_t */* mobj */, bool state)
1404{
1405  if (mem_tab_state->size () == 0)
1406    state = true;
1407  mem_tab_state->append (state);
1408  mem_tab_order->append (-1);
1409}
1410
1411void
1412Settings::set_IndxTabState (Vector<bool>*selected)
1413{
1414  for (int j = 0; j < selected->size (); j++)
1415    indx_tab_state->store (j, selected->fetch (j));
1416}
1417
1418// define a new index object type
1419void
1420Settings::indxobj_define (int type, bool state)
1421{
1422  indx_tab_state->store (type, state);
1423  indx_tab_order->store (type, -1);
1424}
1425
1426void
1427Settings::set_pathmaps (Vector<pathmap_t*> *newPathMap)
1428{
1429  if (pathmaps)
1430    {
1431      pathmaps->destroy ();
1432      delete pathmaps;
1433    }
1434  pathmaps = newPathMap;
1435}
1436
1437static char *
1438get_canonical_name (const char *fname)
1439{
1440  char *nm = dbe_strdup (fname);
1441  for (size_t len = strlen (nm); (len > 0) && (nm[len - 1] == '/'); len--)
1442    nm[len - 1] = 0;
1443  return nm;
1444}
1445
1446char *
1447Settings::add_pathmap (Vector<pathmap_t*> *v, const char *from, const char *to)
1448{
1449  // Check for errors
1450  if (from == NULL || to == NULL)
1451    return dbe_strdup (GTXT ("Pathmap can have neither from nor to as NULL\n"));
1452  if (strcmp (from, to) == 0)
1453    return dbe_strdup (GTXT ("Pathmap from must differ from to\n"));
1454  char *old_prefix = get_canonical_name (from);
1455  char *new_prefix = get_canonical_name (to);
1456
1457  // Check the pathmap list
1458  for (int i = 0, sz = v->size (); i < sz; i++)
1459    {
1460      pathmap_t *pmp = v->get (i);
1461      if ((strcmp (pmp->old_prefix, old_prefix) == 0) &&(strcmp (pmp->new_prefix, new_prefix) == 0))
1462	{
1463	  char *s = dbe_sprintf (GTXT ("Pathmap from `%s' to `%s' already exists\n"), old_prefix, new_prefix);
1464	  free (old_prefix);
1465	  free (new_prefix);
1466	  return s;
1467	}
1468    }
1469  // construct a map for this pair
1470  pathmap_t *thismap = new pathmap_t;
1471  thismap->old_prefix = old_prefix;
1472  thismap->new_prefix = new_prefix;
1473  v->append (thismap);
1474  return NULL;
1475}
1476
1477// Set all shared object expands back to .rc file defaults,
1478//	as stored in the DbeSession Settings
1479bool
1480Settings::set_libdefaults ()
1481{
1482  // See if this is unchanged
1483  if (is_loexpand_default == true)
1484    return false; // no change
1485
1486  // replicate the DbeSession's lo_expand vector and default settings
1487  lo_expand_t *this_lo_ex;
1488  lo_expand_t *new_lo_ex;
1489  int index;
1490  lo_expand_default = dbeSession->get_settings ()->lo_expand_default;
1491  lo_expands = new Vector<lo_expand_t*>;
1492  Vec_loop (lo_expand_t*, dbeSession->get_settings ()->lo_expands, index, this_lo_ex)
1493  {
1494    new_lo_ex = new lo_expand_t;
1495    new_lo_ex->libname = dbe_strdup (this_lo_ex->libname);
1496    new_lo_ex->expand = this_lo_ex->expand;
1497    lo_expands->append (new_lo_ex);
1498  }
1499  is_loexpand_default = true;
1500  return true;
1501}
1502
1503bool
1504Settings::set_libexpand (char *cov, enum LibExpand expand, bool rc)
1505{
1506  int index;
1507  lo_expand_t *loe;
1508  bool change = false;
1509  if (cov == NULL || !strcasecmp (cov, Command::ALL_CMD))
1510    { // set all libraries
1511      // set the default
1512      if (lo_expand_default != expand)
1513	{
1514	  lo_expand_default = expand;
1515	  change = true;
1516	  is_loexpand_default = false;
1517	}
1518
1519      // and force any explicit settings to match, too
1520      Vec_loop (lo_expand_t*, lo_expands, index, loe)
1521      {
1522	if (loe->expand != expand)
1523	  {
1524	    loe->expand = expand;
1525	    change = true;
1526	    is_loexpand_default = false;
1527	  }
1528      }
1529
1530    }
1531  else
1532    { // parsing coverage
1533      Vector <char *> *tokens = split_str (cov, ',');
1534      for (long j = 0, sz = VecSize (tokens); j < sz; j++)
1535	{
1536	  char *lo_name = tokens->get (j);
1537	  char *newname = get_basename (lo_name);
1538	  bool found = false;
1539	  Vec_loop (lo_expand_t*, lo_expands, index, loe)
1540	  {
1541	    if (strcmp (loe->libname, newname) == 0)
1542	      {
1543		if (loe->expand != expand)
1544		  {
1545		    if (rc == false)
1546		      {
1547			loe->expand = expand;
1548			change = true;
1549			is_loexpand_default = false;
1550		      }
1551		  }
1552		found = true;
1553		break;
1554	      }
1555	  }
1556
1557	  if (found == false)
1558	    {
1559	      // construct a map for this pair
1560	      lo_expand_t *thisloe;
1561	      thisloe = new lo_expand_t;
1562	      thisloe->libname = dbe_strdup (newname);
1563	      thisloe->expand = expand;
1564	      change = true;
1565	      is_loexpand_default = false;
1566
1567	      // add it to the vector
1568	      lo_expands->append (thisloe);
1569	    }
1570	  free (lo_name);
1571	}
1572      delete tokens;
1573    }
1574  return change;
1575}
1576
1577enum LibExpand
1578Settings::get_lo_setting (char *name)
1579{
1580  int index;
1581  lo_expand_t *loe;
1582  char *lo_name = get_basename (name);
1583  Vec_loop (lo_expand_t*, lo_expands, index, loe)
1584  {
1585    if (strcmp (loe->libname, lo_name) == 0)
1586      return loe->expand;
1587  }
1588  return lo_expand_default;
1589}
1590