| /* Copyright (C) 2021-2024 Free Software Foundation, Inc. |
| Contributed by Oracle. |
| |
| This file is part of GNU Binutils. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, 51 Franklin Street - Fifth Floor, Boston, |
| MA 02110-1301, USA. */ |
| |
| #include "config.h" |
| #include <string.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <sys/param.h> |
| |
| #include "enums.h" |
| #include "Settings.h" |
| #include "DbeSession.h" |
| #include "Command.h" |
| #include "Application.h" |
| #include "MemorySpace.h" |
| #include "StringBuilder.h" |
| #include "Table.h" |
| #include "Emsg.h" |
| #include "util.h" |
| #include "i18n.h" |
| |
| // Commands for compiler commentary |
| static const char *comp_cmd[] = { |
| NTXT ("basic"), |
| NTXT ("version"), |
| NTXT ("warn"), |
| NTXT ("parallel"), |
| NTXT ("query"), |
| NTXT ("loop"), |
| NTXT ("pipe"), |
| NTXT ("inline"), |
| NTXT ("memops"), |
| NTXT ("fe"), |
| NTXT ("codegen"), |
| NTXT ("src"), |
| NTXT ("asrc"), |
| NTXT ("nosrc"), |
| NTXT ("hex"), |
| NTXT ("nohex"), |
| NTXT ("threshold"), |
| NTXT ("cf") |
| }; |
| |
| static const int comp_vis[] = { |
| CCMV_BASIC, |
| CCMV_VER, |
| CCMV_WARN, |
| CCMV_PAR, |
| CCMV_QUERY, |
| CCMV_LOOP, |
| CCMV_PIPE, |
| CCMV_INLINE, |
| CCMV_MEMOPS, |
| CCMV_FE, |
| CCMV_CG, |
| COMP_SRC, |
| COMP_SRC_METRIC, |
| COMP_NOSRC, |
| COMP_HEX, |
| COMP_NOHEX, |
| COMP_THRESHOLD, |
| COMP_CMPLINE |
| }; |
| |
| const int comp_size = sizeof (comp_cmd) / sizeof (char *); |
| |
| // Commands for timeline |
| typedef enum |
| { |
| TLCMD_INVALID, |
| TLCMD_ENTITY_MODE, |
| TLCMD_ALIGN, |
| TLCMD_DEPTH |
| } TLModeSubcommand; |
| |
| typedef struct |
| { |
| const char * cmdText; |
| TLModeSubcommand cmdType; |
| int cmdId; |
| } TLModeCmd; |
| static const TLModeCmd tlmode_cmd[] = { |
| // MODE commands |
| {NTXT ("lwp"), TLCMD_ENTITY_MODE, PROP_LWPID}, |
| {NTXT ("thread"), TLCMD_ENTITY_MODE, PROP_THRID}, |
| {NTXT ("cpu"), TLCMD_ENTITY_MODE, PROP_CPUID}, |
| {NTXT ("experiment"), TLCMD_ENTITY_MODE, PROP_EXPID}, |
| // ALIGN commands |
| {NTXT ("root"), TLCMD_ALIGN, TLSTACK_ALIGN_ROOT}, |
| {NTXT ("leaf"), TLCMD_ALIGN, TLSTACK_ALIGN_LEAF}, |
| // DEPTH commands |
| {NTXT ("depth"), TLCMD_DEPTH, 0 /* don't care */} |
| }; |
| |
| static const int tlmode_size = sizeof (tlmode_cmd) / sizeof (TLModeCmd); |
| |
| // Constructor |
| |
| Settings::Settings (Application *_app) |
| { |
| // Remember the application |
| app = _app; |
| |
| // Clear all default strings |
| str_vmode = NULL; |
| str_en_desc = NULL; |
| str_datamode = NULL; |
| str_scompcom = NULL; |
| str_sthresh = NULL; |
| str_dcompcom = NULL; |
| str_dthresh = NULL; |
| str_dmetrics = NULL; |
| str_dsort = NULL; |
| str_tlmode = NULL; |
| str_tldata = NULL; |
| str_tabs = NULL; |
| str_rtabs = NULL; |
| str_search_path = NULL; |
| str_name_format = NULL; |
| str_limit = NULL; |
| str_printmode = NULL; |
| str_compare = NULL; |
| preload_libdirs = NULL; |
| pathmaps = new Vector<pathmap_t*>; |
| lo_expands = new Vector<lo_expand_t*>; |
| lo_expand_default = LIBEX_SHOW; |
| is_loexpand_default = true; |
| tabs_processed = false; |
| |
| // set default-default values |
| name_format = Histable::NA; |
| view_mode = VMODE_USER; |
| en_desc = false; |
| en_desc_cmp = NULL; |
| en_desc_usr = NULL; |
| src_compcom = 2147483647; |
| dis_compcom = 2147483647; |
| #define DEFAULT_SRC_DIS_THRESHOLD 75 |
| threshold_src = DEFAULT_SRC_DIS_THRESHOLD; |
| threshold_dis = DEFAULT_SRC_DIS_THRESHOLD; |
| src_visible = true; |
| srcmetric_visible = false; |
| hex_visible = false; |
| cmpline_visible = true; |
| funcline_visible = true; |
| tldata = NULL; |
| tlmode = 0; |
| stack_align = 0; |
| stack_depth = 0; |
| limit = 0; |
| // print mode is initialized after the .rc files are read |
| print_delim = ','; |
| compare_mode = CMP_DISABLE; |
| machinemodel = NULL; |
| ignore_no_xhwcprof = false; |
| ignore_fs_warn = false; |
| |
| // construct the master list of tabs |
| buildMasterTabList (); |
| |
| indx_tab_state = new Vector<bool>; |
| indx_tab_order = new Vector<int>; |
| mem_tab_state = new Vector<bool>; |
| mem_tab_order = new Vector<int>; |
| |
| // note that the .rc files are not read here, but later |
| } |
| |
| // Constructor for duplicating an existing Settings class |
| |
| Settings::Settings (Settings * _settings) |
| { |
| int index; |
| app = _settings->app; |
| |
| // Copy all default strings |
| str_vmode = dbe_strdup (_settings->str_vmode); |
| str_en_desc = dbe_strdup (_settings->str_en_desc); |
| str_datamode = dbe_strdup (_settings->str_datamode); |
| str_scompcom = dbe_strdup (_settings->str_scompcom); |
| str_sthresh = dbe_strdup (_settings->str_sthresh); |
| str_dcompcom = dbe_strdup (_settings->str_dcompcom); |
| str_dthresh = dbe_strdup (_settings->str_dthresh); |
| str_dmetrics = dbe_strdup (_settings->str_dmetrics); |
| str_dsort = dbe_strdup (_settings->str_dsort); |
| str_tlmode = dbe_strdup (_settings->str_tlmode); |
| str_tldata = dbe_strdup (_settings->str_tldata); |
| str_tabs = dbe_strdup (_settings->str_tabs); |
| str_rtabs = dbe_strdup (_settings->str_rtabs); |
| str_search_path = dbe_strdup (_settings->str_search_path); |
| str_name_format = dbe_strdup (_settings->str_name_format); |
| str_limit = dbe_strdup (_settings->str_limit); |
| str_printmode = dbe_strdup (_settings->str_printmode); |
| str_compare = dbe_strdup (_settings->str_compare); |
| preload_libdirs = dbe_strdup (_settings->preload_libdirs); |
| |
| // replicate the pathmap vector |
| pathmap_t *thismap; |
| pathmap_t *newmap; |
| pathmaps = new Vector<pathmap_t*>; |
| |
| Vec_loop (pathmap_t*, _settings->pathmaps, index, thismap) |
| { |
| newmap = new pathmap_t; |
| newmap->old_prefix = dbe_strdup (thismap->old_prefix); |
| newmap->new_prefix = dbe_strdup (thismap->new_prefix); |
| pathmaps->append (newmap); |
| } |
| |
| // replicate the lo_expand vector and default |
| lo_expand_t *this_lo_ex; |
| lo_expand_t *new_lo_ex; |
| lo_expand_default = _settings->lo_expand_default; |
| is_loexpand_default = _settings->is_loexpand_default; |
| lo_expands = new Vector<lo_expand_t*>; |
| |
| Vec_loop (lo_expand_t*, _settings->lo_expands, index, this_lo_ex) |
| { |
| new_lo_ex = new lo_expand_t; |
| new_lo_ex->libname = dbe_strdup (this_lo_ex->libname); |
| new_lo_ex->expand = this_lo_ex->expand; |
| lo_expands->append (new_lo_ex); |
| } |
| tabs_processed = _settings->tabs_processed; |
| |
| // Copy the various values from the _settings instance |
| name_format = _settings->name_format; |
| view_mode = _settings->view_mode; |
| en_desc = false; |
| en_desc_cmp = NULL; |
| en_desc_usr = NULL; |
| if (_settings->en_desc_usr) |
| set_en_desc (_settings->en_desc_usr, true); |
| src_compcom = _settings->src_compcom; |
| dis_compcom = _settings->dis_compcom; |
| threshold_src = _settings->threshold_src; |
| threshold_dis = _settings->threshold_dis; |
| src_visible = _settings->src_visible; |
| srcmetric_visible = _settings->srcmetric_visible; |
| hex_visible = _settings->hex_visible; |
| cmpline_visible = _settings->cmpline_visible; |
| funcline_visible = _settings->funcline_visible; |
| tldata = dbe_strdup (_settings->tldata); |
| tlmode = _settings->tlmode; |
| stack_align = _settings->stack_align; |
| stack_depth = _settings->stack_depth; |
| limit = _settings->limit; |
| print_mode = _settings->print_mode; |
| print_delim = _settings->print_delim; |
| compare_mode = _settings->compare_mode; |
| machinemodel = dbe_strdup (_settings->machinemodel); |
| ignore_no_xhwcprof = _settings->ignore_no_xhwcprof; |
| ignore_fs_warn = _settings->ignore_fs_warn; |
| |
| // copy the tab list, too |
| tab_list = new Vector<DispTab*>; |
| DispTab *dsptab; |
| |
| Vec_loop (DispTab*, _settings->tab_list, index, dsptab) |
| { |
| DispTab *ntab; |
| ntab = new DispTab (dsptab->type, dsptab->order, dsptab->visible, dsptab->cmdtoken); |
| ntab->setAvailability (dsptab->available); |
| tab_list->append (ntab); |
| } |
| |
| // construct the master list of memory tabs & copy order |
| index = _settings->mem_tab_state->size (); |
| mem_tab_state = new Vector<bool>(index); |
| mem_tab_order = new Vector<int>(index); |
| for (int i = 0; i < index; i++) |
| { |
| mem_tab_state->append (false); |
| mem_tab_order->append (_settings->mem_tab_order->fetch (i)); |
| } |
| |
| // construct the master list of index tabs & copy order |
| index = _settings->indx_tab_state->size (); |
| indx_tab_state = new Vector<bool>(index); |
| indx_tab_order = new Vector<int>(index); |
| for (int i = 0; i < index; i++) |
| indx_tab_order->append (_settings->indx_tab_order->fetch (i)); |
| set_IndxTabState (_settings->indx_tab_state); |
| } |
| |
| Settings::~Settings () |
| { |
| for (int i = 0; i < pathmaps->size (); ++i) |
| { |
| pathmap_t *pmap = pathmaps->fetch (i); |
| free (pmap->old_prefix); |
| free (pmap->new_prefix); |
| delete pmap; |
| } |
| delete pathmaps; |
| |
| for (int i = 0; i < lo_expands->size (); ++i) |
| { |
| lo_expand_t *lo_ex = lo_expands->fetch (i); |
| free (lo_ex->libname); |
| delete lo_ex; |
| } |
| delete lo_expands; |
| |
| tab_list->destroy (); |
| delete tab_list; |
| delete indx_tab_state; |
| delete indx_tab_order; |
| delete mem_tab_state; |
| delete mem_tab_order; |
| |
| free (str_vmode); |
| free (str_en_desc); |
| free (str_datamode); |
| free (str_scompcom); |
| free (str_sthresh); |
| free (str_dcompcom); |
| free (str_dthresh); |
| free (str_dmetrics); |
| free (str_dsort); |
| free (str_tlmode); |
| free (str_tldata); |
| free (str_tabs); |
| free (str_rtabs); |
| free (str_search_path); |
| free (str_name_format); |
| free (str_limit); |
| free (str_compare); |
| free (str_printmode); |
| free (preload_libdirs); |
| free (tldata); |
| free (en_desc_usr); |
| if (en_desc_cmp) |
| { |
| regfree (en_desc_cmp); |
| delete en_desc_cmp; |
| } |
| } |
| |
| /** |
| * Read .er.rc file from the specified location |
| * @param path |
| * @return |
| */ |
| char * |
| Settings::read_rc (char *path) |
| { |
| StringBuilder sb; |
| Emsgqueue *commentq = new Emsgqueue (NTXT ("setting_commentq")); |
| |
| // Check file name |
| if (NULL == path) |
| return dbe_strdup (GTXT ("Error: empty file name")); |
| bool override = true; |
| set_rc (path, true, commentq, override); |
| Emsg *msg = commentq->fetch (); |
| while (msg != NULL) |
| { |
| char *str = msg->get_msg (); |
| sb.append (str); |
| msg = msg->next; |
| } |
| return sb.toString (); |
| } |
| |
| void |
| Settings::read_rc (bool ipc_or_rdt_mode) |
| { |
| bool override = false; |
| |
| // Read file from the current working directory |
| char *rc_path = realpath (NTXT ("./.gprofng.rc"), NULL); |
| if (rc_path) |
| set_rc (rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode); |
| |
| // Read file from the user's home directory |
| char *home = getenv (NTXT ("HOME")); |
| if (home) |
| { |
| char *strbuf = dbe_sprintf (NTXT ("%s/.gprofng.rc"), home); |
| char *home_rc_path = realpath (strbuf, NULL); |
| if (home_rc_path) |
| { |
| if (rc_path == NULL || strcmp (rc_path, home_rc_path) != 0) |
| set_rc (home_rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode); |
| free (home_rc_path); |
| } |
| free (strbuf); |
| } |
| free (rc_path); |
| |
| // Read system-wide file |
| const char *sysconfdir = getenv("GPROFNG_SYSCONFDIR"); |
| if (sysconfdir == NULL) |
| sysconfdir = SYSCONFDIR; |
| rc_path = dbe_sprintf (NTXT ("%s/gprofng.rc"), sysconfdir); |
| if (access (rc_path, R_OK | F_OK) != 0) |
| { |
| StringBuilder sb; |
| sb.sprintf (GTXT ("Warning: Default gprofng.rc file (%s) missing; configuration error "), rc_path); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| app->get_comments_queue ()->append (m); |
| } |
| else |
| set_rc (rc_path, false, app->get_comments_queue (), override); |
| free (rc_path); |
| is_loexpand_default = true; |
| if (str_printmode == NULL) |
| { |
| // only if there's none set |
| print_mode = PM_TEXT; |
| str_printmode = dbe_strdup (NTXT ("text")); |
| } |
| } |
| |
| |
| // Handle various settings from reading the name .rc file |
| // This function is called for each .rc file read, and, for |
| // some settings, it accumulates the strings from the files. |
| // For others, it accepts the first appearance for a setting in a |
| // .rc file, and ignores subsequent appearances from other files. |
| // Error messages are appended to the Emsgqueue specified by the caller |
| |
| #define MAXARGS 20 |
| |
| void |
| Settings::set_rc (const char *path, bool msg, Emsgqueue *commentq, |
| bool override, bool ipc_or_rdt_mode) |
| { |
| CmdType cmd_type; |
| int arg_count, cparam; |
| char *cmd, *end_cmd, *strbuf; |
| char *arglist[MAXARGS]; |
| StringBuilder sb; |
| |
| FILE *fptr = fopen (path, NTXT ("r")); |
| if (fptr == NULL) |
| return; |
| |
| if (msg) |
| { |
| sb.sprintf (GTXT ("Processed %s for default settings"), path); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| commentq->append (m); |
| } |
| int line_no = 0; |
| end_cmd = NULL; |
| while (!feof (fptr)) |
| { |
| char *script = read_line (fptr); |
| if (script == NULL) |
| continue; |
| line_no++; |
| strtok (script, NTXT ("\n")); |
| |
| // extract the command |
| cmd = strtok (script, NTXT (" \t")); |
| if (cmd == NULL || *cmd == '#' || *cmd == '\n') |
| { |
| free (script); |
| continue; |
| } |
| char *remainder = strtok (NULL, NTXT ("\n")); |
| // now extract the arguments |
| int nargs = 0; |
| for (;;) |
| { |
| if (nargs >= MAXARGS) |
| { |
| if (!msg) |
| { |
| msg = true; // suppress repeats of header |
| Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); |
| commentq->append (m); |
| } |
| sb.sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"), |
| MAXARGS, cmd, line_no); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| commentq->append (m); |
| break; |
| } |
| |
| char *nextarg = strtok (remainder, NTXT ("\n")); |
| if (nextarg == NULL || *nextarg == '#') |
| break; |
| arglist[nargs++] = parse_qstring (nextarg, &end_cmd); |
| remainder = end_cmd; |
| if (remainder == NULL) |
| break; |
| // skip any blanks or tabs to get to next argument |
| while (*remainder == ' ' || *remainder == '\t') |
| remainder++; |
| } |
| cmd_type = Command::get_command (cmd, arg_count, cparam); |
| // check for extra arguments |
| if ((cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF) && (nargs > arg_count)) |
| { |
| if (!msg) |
| { |
| msg = true; // suppress repeats of header |
| Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); |
| commentq->append (m); |
| } |
| sb.sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"), cmd, line_no); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| commentq->append (m); |
| } |
| if (nargs < arg_count) |
| { |
| if (!msg) |
| { |
| msg = true; // suppress repeats of header |
| Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); |
| commentq->append (m); |
| } |
| sb.sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"), |
| cmd, line_no); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| commentq->append (m); |
| |
| // ignore this command |
| free (script); |
| continue; |
| } |
| if (ipc_or_rdt_mode && (cmd_type != ADDPATH) && (cmd_type != PATHMAP)) |
| { |
| free (script); |
| continue; |
| } |
| switch (cmd_type) |
| { |
| case SCOMPCOM: |
| if (!str_scompcom || override) |
| { |
| str_scompcom = dbe_strdup (arglist[0]); |
| proc_compcom (arglist[0], true, true); |
| } |
| break; |
| case STHRESH: |
| if (!str_sthresh || override) |
| { |
| str_sthresh = dbe_strdup (arglist[0]); |
| proc_thresh (arglist[0], true, true); |
| break; |
| } |
| break; |
| case DCOMPCOM: |
| if (!str_dcompcom || override) |
| { |
| str_dcompcom = dbe_strdup (arglist[0]); |
| proc_compcom (arglist[0], false, true); |
| } |
| break; |
| case COMPCOM: |
| // process as if it were for both source and disassembly |
| // note that if it is set, subsequent SCOMPCOM and DCOMPCOM |
| // will be ignored |
| if (!str_scompcom || override) |
| { |
| str_scompcom = dbe_strdup (arglist[0]); |
| proc_compcom (arglist[0], true, true); |
| } |
| if (!str_dcompcom || override) |
| { |
| str_dcompcom = dbe_strdup (arglist[0]); |
| proc_compcom (arglist[0], false, true); |
| } |
| break; |
| case DTHRESH: |
| if (!str_dthresh || override) |
| { |
| str_dthresh = dbe_strdup (arglist[0]); |
| proc_thresh (arglist[0], false, true); |
| } |
| break; |
| case DMETRICS: |
| // append new settings to old, if necessary |
| if (str_dmetrics) |
| { |
| char *name = strstr (str_dmetrics, ":name"); |
| if (name == NULL) |
| strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]); |
| else |
| { |
| char * next = strstr (name + 1, ":"); |
| if (next == NULL) |
| { |
| name[0] = '\0'; |
| strbuf = dbe_sprintf ("%s:%s:name", str_dmetrics, arglist[0]); |
| } |
| else |
| strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]); |
| } |
| free (str_dmetrics); |
| str_dmetrics = strbuf; |
| } |
| else |
| str_dmetrics = dbe_strdup (arglist[0]); |
| break; |
| case DSORT: |
| // append new settings to old, if necessary |
| if (str_dsort) |
| { |
| strbuf = dbe_sprintf (NTXT ("%s:%s"), str_dsort, arglist[0]); |
| free (str_dsort); |
| str_dsort = strbuf; |
| } |
| else |
| str_dsort = dbe_strdup (arglist[0]); |
| break; |
| case TLMODE: |
| if (!str_tlmode || override) |
| { |
| str_tlmode = dbe_strdup (arglist[0]); |
| proc_tlmode (arglist[0], true); |
| } |
| break; |
| case TLDATA: |
| if (!str_tldata || override) |
| { |
| str_tldata = dbe_strdup (arglist[0]); |
| proc_tldata (arglist[0], true); |
| } |
| break; |
| case TABS: |
| if (!str_tabs || override) |
| // the string is processed later, after all .rc files are read |
| str_tabs = dbe_strdup (arglist[0]); |
| break; |
| case RTABS: |
| if (!str_rtabs || override) |
| // the string is processed later, after all .rc files are read |
| str_rtabs = dbe_strdup (arglist[0]); |
| break; |
| case ADDPATH: |
| if (str_search_path) |
| { |
| strbuf = dbe_sprintf (NTXT ("%s:%s"), str_search_path, arglist[0]); |
| free (str_search_path); |
| str_search_path = strbuf; |
| } |
| else |
| str_search_path = dbe_strdup (arglist[0]); |
| break; |
| case PATHMAP: |
| { |
| char *err = add_pathmap (pathmaps, arglist[0], arglist[1]); |
| free (err); // XXX error is not reported |
| break; |
| } |
| case LIBDIRS: |
| if (preload_libdirs == NULL) |
| preload_libdirs = dbe_strdup (arglist[0]); |
| break; |
| case NAMEFMT: |
| if (name_format == Histable::NA) |
| set_name_format (arglist[0]); |
| break; |
| case VIEWMODE: |
| if (!str_vmode || override) |
| { |
| str_vmode = dbe_strdup (arglist[0]); |
| set_view_mode (arglist[0], true); |
| } |
| break; |
| case EN_DESC: |
| if (!str_en_desc || override) |
| { |
| str_en_desc = dbe_strdup (arglist[0]); |
| set_en_desc (arglist[0], true); |
| } |
| break; |
| case LIMIT: |
| if (!str_limit || override) |
| { |
| str_limit = dbe_strdup (arglist[0]); |
| set_limit (arglist[0], true); |
| } |
| break; |
| case PRINTMODE: |
| if (!str_printmode || override) |
| set_printmode (arglist[0]); |
| break; |
| case COMPARE: |
| if (!str_compare || override) |
| { |
| char *s = arglist[0]; |
| if (s) |
| str_compare = dbe_strdup (s); |
| else |
| s = NTXT (""); |
| if (strcasecmp (s, NTXT ("OFF")) == 0 |
| || strcmp (s, NTXT ("0")) == 0) |
| set_compare_mode (CMP_DISABLE); |
| else if (strcasecmp (s, NTXT ("ON")) == 0 |
| || strcmp (s, NTXT ("1")) == 0) |
| set_compare_mode (CMP_ENABLE); |
| else if (strcasecmp (s, NTXT ("DELTA")) == 0) |
| set_compare_mode (CMP_DELTA); |
| else if (strcasecmp (s, NTXT ("RATIO")) == 0) |
| set_compare_mode (CMP_RATIO); |
| else |
| { |
| sb.sprintf (GTXT (" .er.rc:%d The argument of 'compare' should be 'on', 'off', 'delta', or 'ratio'"), |
| (int) line_no); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| commentq->append (m); |
| } |
| } |
| break; |
| |
| case INDXOBJDEF: |
| { |
| char *ret = dbeSession->indxobj_define (arglist[0], NULL, arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL, (nargs >= 4) ? PTXT (arglist[3]) : NULL); |
| if (ret != NULL) |
| { |
| sb.sprintf (GTXT (" %s: line %d `%s %s %s'\n"), |
| ret, line_no, cmd, arglist[0], arglist[1]); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| commentq->append (m); |
| } |
| break; |
| } |
| #ifdef sparc |
| //XXX: should be conditional on the experiment ARCH, not dbe ARCH |
| case IGNORE_NO_XHWCPROF: |
| // ignore absence of -xhwcprof info for dataspace profiling |
| set_ignore_no_xhwcprof (true); |
| break; |
| #endif // sparc |
| case IGNORE_FS_WARN: |
| // ignore file system warning in experiments |
| set_ignore_fs_warn (true); |
| break; |
| case OBJECT_SHOW: |
| // Add the named libraries to the lib_expands array |
| set_libexpand (arglist[0], LIBEX_SHOW, true); |
| break; |
| case OBJECT_HIDE: |
| // Add the named libraries to the lib_expands array |
| set_libexpand (arglist[0], LIBEX_HIDE, true); |
| break; |
| case OBJECT_API: |
| // Add the named libraries to the lib_expands array |
| set_libexpand (arglist[0], LIBEX_API, true); |
| break; |
| case COMMENT: |
| // ignore the line |
| break; |
| default: |
| { |
| // unexpected command in an rc file |
| if (!msg) |
| { |
| // if quiet, can remain so no longer |
| msg = true; |
| Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings")); |
| commentq->append (m); |
| } |
| sb.sprintf (GTXT (" Unrecognized .gprofng.rc command on line %d: `%.64s'"), |
| line_no, cmd); |
| Emsg *m = new Emsg (CMSG_COMMENT, sb); |
| commentq->append (m); |
| break; |
| } |
| } |
| free (script); |
| } |
| fclose (fptr); |
| } |
| |
| Cmd_status |
| Settings::set_view_mode (char *arg, bool rc) |
| { |
| if (!strcasecmp (arg, NTXT ("user"))) |
| view_mode = VMODE_USER; |
| else if (!strcasecmp (arg, NTXT ("expert"))) |
| view_mode = VMODE_EXPERT; |
| else if (!strcasecmp (arg, NTXT ("machine"))) |
| view_mode = VMODE_MACHINE; |
| else if (!rc) |
| return CMD_BAD_ARG; |
| return CMD_OK; |
| } |
| |
| Cmd_status |
| Settings::set_en_desc (char *arg, bool rc) |
| { |
| regex_t *regex_desc = NULL; |
| |
| // cases below should be similar to Coll_Ctrl::set_follow_mode() cases |
| if (!strcasecmp (arg, NTXT ("on"))) |
| en_desc = true; |
| else if (!strcasecmp (arg, NTXT ("off"))) |
| en_desc = false; |
| else if (arg[0] == '=' && arg[1] != 0) |
| { |
| // user has specified a string matching specification |
| int ercode; |
| { // compile regex_desc |
| char * str = dbe_sprintf (NTXT ("^%s$"), arg + 1); |
| regex_desc = new regex_t; |
| memset (regex_desc, 0, sizeof (regex_t)); |
| ercode = regcomp (regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); |
| free (str); |
| } |
| if (ercode) |
| { |
| // syntax error in parsing string |
| delete regex_desc; |
| if (!rc) |
| return CMD_BAD_ARG; |
| return CMD_OK; |
| } |
| en_desc = true; |
| } |
| else |
| { |
| if (!rc) |
| return CMD_BAD_ARG; |
| return CMD_OK; |
| } |
| free (en_desc_usr); |
| en_desc_usr = dbe_strdup (arg); |
| if (en_desc_cmp) |
| { |
| regfree (en_desc_cmp); |
| delete en_desc_cmp; |
| } |
| en_desc_cmp = regex_desc; |
| return CMD_OK; |
| } |
| |
| // See if a descendant matches either the lineage or the executable name |
| bool |
| Settings::check_en_desc (const char *lineage, const char *targname) |
| { |
| bool rc; |
| if (en_desc_cmp == NULL) |
| return en_desc; // no specification was set, use the binary on/off value |
| if (lineage == NULL) // user doesn't care about specification |
| return en_desc; // use the binary on/off specification |
| if (!regexec (en_desc_cmp, lineage, 0, NULL, 0)) |
| rc = true; // this one matches user specification |
| else if (targname == NULL) |
| rc = false; //a NULL name does not match any expression |
| else if (!regexec (en_desc_cmp, targname, 0, NULL, 0)) |
| rc = true; // this one matches the executable name |
| else |
| rc = false; |
| return rc; |
| } |
| |
| char * |
| Settings::set_limit (char *arg, bool) |
| { |
| limit = (int) strtol (arg, (char **) NULL, 10); |
| return NULL; |
| } |
| |
| char * |
| Settings::set_printmode (char *arg) |
| { |
| if (arg == NULL) |
| return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"), |
| NTXT ("printmode"), NTXT ("text"), NTXT ("html")); |
| if (strlen (arg) == 1) |
| { |
| print_mode = PM_DELIM_SEP_LIST; |
| print_delim = arg[0]; |
| } |
| else if (!strcasecmp (arg, NTXT ("text"))) |
| print_mode = PM_TEXT; |
| else if (!strcasecmp (arg, NTXT ("html"))) |
| print_mode = PM_HTML; |
| else |
| return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"), |
| NTXT ("printmode"), NTXT ("text"), NTXT ("html")); |
| free (str_printmode); |
| str_printmode = dbe_strdup (arg); |
| return NULL; |
| } |
| |
| Cmd_status |
| Settings::proc_compcom (const char *cmd, bool isSrc, bool rc) |
| { |
| int ck_compcom_bits, ck_threshold; |
| bool ck_hex_visible = false; |
| bool ck_src_visible = false; |
| bool ck_srcmetric_visible = false; |
| bool got_compcom_bits, got_threshold, got_src_visible, got_srcmetric_visible; |
| bool got_hex_visible, got; |
| int len, i; |
| char *mcmd, *param; |
| int flag, value = 0; |
| Cmd_status status; |
| char buf[BUFSIZ], *list; |
| |
| if (cmd == NULL) |
| return CMD_BAD; |
| ck_compcom_bits = 0; |
| ck_threshold = 0; |
| got_compcom_bits = got_threshold = got_src_visible = false; |
| got_srcmetric_visible = got_hex_visible = false; |
| snprintf (buf, sizeof (buf), NTXT ("%s"), cmd); |
| list = buf; |
| while ((mcmd = strtok (list, NTXT (":"))) != NULL) |
| { |
| list = NULL; |
| // if "all" or "none" |
| if (!strcasecmp (mcmd, Command::ALL_CMD)) |
| { |
| got_compcom_bits = true; |
| ck_compcom_bits = CCMV_ALL; |
| continue; |
| } |
| else if (!strcasecmp (mcmd, Command::NONE_CMD)) |
| { |
| got_compcom_bits = true; |
| ck_compcom_bits = 0; |
| continue; |
| } |
| |
| // Find parameter after '=' |
| param = strchr (mcmd, '='); |
| if (param) |
| { |
| *param = '\0'; |
| param++; |
| } |
| status = CMD_OK; |
| got = false; |
| flag = 0; |
| len = (int) strlen (mcmd); |
| for (i = 0; status == CMD_OK && i < comp_size; i++) |
| if (!strncasecmp (mcmd, comp_cmd[i], len)) |
| { |
| if (got) // Ambiguous comp_com command |
| status = CMD_AMBIGUOUS; |
| else |
| { |
| got = true; |
| flag = comp_vis[i]; |
| // Check argument |
| if (flag == COMP_THRESHOLD) |
| { |
| if (param == NULL) |
| status = CMD_BAD_ARG; |
| else |
| { |
| value = (int) strtol (param, ¶m, 10); |
| if (value < 0 || value > 100) |
| status = CMD_OUTRANGE; |
| } |
| } |
| else if (param != NULL) |
| status = CMD_BAD_ARG; |
| } |
| } |
| |
| // Not valid comp_com command |
| if (!got) |
| status = CMD_INVALID; |
| if (status != CMD_OK) |
| { |
| if (!rc) |
| return status; |
| continue; |
| } |
| |
| // Set bits |
| switch (flag) |
| { |
| case COMP_CMPLINE: |
| cmpline_visible = true; |
| break; |
| case COMP_FUNCLINE: |
| funcline_visible = true; |
| break; |
| case COMP_THRESHOLD: |
| got_threshold = true; |
| ck_threshold = value; |
| break; |
| case COMP_SRC: |
| got_src_visible = true; |
| ck_src_visible = true; |
| break; |
| case COMP_SRC_METRIC: |
| got_srcmetric_visible = true; |
| ck_srcmetric_visible = true; |
| got_src_visible = true; |
| ck_src_visible = true; |
| break; |
| case COMP_NOSRC: |
| got_src_visible = true; |
| ck_src_visible = false; |
| break; |
| case COMP_HEX: |
| got_hex_visible = true; |
| ck_hex_visible = true; |
| break; |
| case COMP_NOHEX: |
| got_hex_visible = true; |
| ck_hex_visible = false; |
| break; |
| case CCMV_BASIC: |
| got_compcom_bits = true; |
| ck_compcom_bits = CCMV_BASIC; |
| break; |
| default: |
| got_compcom_bits = true; |
| ck_compcom_bits |= flag; |
| } |
| } |
| |
| // No error, update |
| if (got_compcom_bits) |
| { |
| if (isSrc) |
| src_compcom = ck_compcom_bits; |
| else |
| dis_compcom = ck_compcom_bits; |
| } |
| if (got_threshold) |
| { |
| if (isSrc) |
| threshold_src = ck_threshold; |
| else |
| threshold_dis = ck_threshold; |
| } |
| if (got_src_visible) |
| src_visible = ck_src_visible; |
| if (got_srcmetric_visible) |
| srcmetric_visible = ck_srcmetric_visible; |
| if (got_hex_visible) |
| hex_visible = ck_hex_visible; |
| return CMD_OK; |
| } |
| |
| // Process a threshold setting |
| Cmd_status |
| Settings::proc_thresh (char *cmd, bool isSrc, bool rc) |
| { |
| int value; |
| if (cmd == NULL) |
| value = DEFAULT_SRC_DIS_THRESHOLD; // the default |
| else |
| value = (int) strtol (cmd, &cmd, 10); |
| if (value < 0 || value > 100) |
| { |
| if (!rc) |
| return CMD_OUTRANGE; |
| value = DEFAULT_SRC_DIS_THRESHOLD; |
| } |
| if (isSrc) |
| threshold_src = value; |
| else |
| threshold_dis = value; |
| return CMD_OK; |
| } |
| |
| // return any error string from processing visibility settings |
| char * |
| Settings::get_compcom_errstr (Cmd_status status, const char *cmd) |
| { |
| int i; |
| StringBuilder sb; |
| switch (status) |
| { |
| case CMD_BAD: |
| sb.append (GTXT ("No commentary classes has been specified.")); |
| break; |
| case CMD_AMBIGUOUS: |
| sb.append (GTXT ("Ambiguous commentary classes: ")); |
| break; |
| case CMD_BAD_ARG: |
| sb.append (GTXT ("Invalid argument for commentary classes: ")); |
| break; |
| case CMD_OUTRANGE: |
| sb.append (GTXT ("Out of range commentary classes argument: ")); |
| break; |
| case CMD_INVALID: |
| sb.append (GTXT ("Invalid commentary classes: ")); |
| break; |
| case CMD_OK: |
| break; |
| } |
| if (cmd) |
| sb.append (cmd); |
| sb.append (GTXT ("\nAvailable commentary classes: ")); |
| for (i = 0; i < comp_size; i++) |
| { |
| sb.append (comp_cmd[i]); |
| if (i == comp_size - 1) |
| sb.append (NTXT ("=#\n")); |
| else |
| sb.append (NTXT (":")); |
| } |
| return sb.toString (); |
| } |
| |
| // Process a timeline-mode setting |
| Cmd_status |
| Settings::proc_tlmode (char *cmd, bool rc) |
| { |
| bool got_tlmode, got_stack_align, got_stack_depth, got; |
| int ck_tlmode = 0, ck_stack_align = 0, ck_stack_depth = 0; |
| int len, i; |
| char *mcmd, *param; |
| int cmd_id, value = 0; |
| TLModeSubcommand cmd_type; |
| Cmd_status status; |
| char buf[BUFSIZ], *list; |
| if (cmd == NULL) |
| return CMD_BAD; |
| got_tlmode = got_stack_align = got_stack_depth = false; |
| snprintf (buf, sizeof (buf), NTXT ("%s"), cmd); |
| list = buf; |
| while ((mcmd = strtok (list, NTXT (":"))) != NULL) |
| { |
| list = NULL; |
| |
| // Find parameter after '=' |
| param = strchr (mcmd, '='); |
| if (param) |
| { |
| *param = '\0'; |
| param++; |
| } |
| status = CMD_OK; |
| got = false; |
| cmd_id = 0; |
| cmd_type = TLCMD_INVALID; |
| len = (int) strlen (mcmd); |
| for (i = 0; status == CMD_OK && i < tlmode_size; i++) |
| { |
| if (!strncasecmp (mcmd, tlmode_cmd[i].cmdText, len)) |
| { |
| if (got) // Ambiguous timeline mode |
| status = CMD_AMBIGUOUS; |
| else |
| { |
| got = true; |
| cmd_type = tlmode_cmd[i].cmdType; |
| cmd_id = tlmode_cmd[i].cmdId; |
| |
| // Check argument |
| if (cmd_type == TLCMD_DEPTH) |
| { |
| if (param == NULL) |
| status = CMD_BAD_ARG; |
| else |
| { |
| value = (int) strtol (param, ¶m, 10); |
| if (value <= 0 || value > 256) |
| status = CMD_OUTRANGE; |
| } |
| } |
| else if (param != NULL) |
| status = CMD_BAD_ARG; |
| } |
| } |
| } |
| |
| // Not valid timeline mode |
| if (!got) |
| status = CMD_INVALID; |
| if (status != CMD_OK) |
| { |
| if (!rc) |
| return status; |
| continue; |
| } |
| |
| // Set bits |
| switch (cmd_type) |
| { |
| case TLCMD_ENTITY_MODE: |
| got_tlmode = true; |
| ck_tlmode = cmd_id; |
| break; |
| case TLCMD_ALIGN: |
| got_stack_align = true; |
| ck_stack_align = cmd_id; |
| break; |
| case TLCMD_DEPTH: |
| got_stack_depth = true; |
| ck_stack_depth = value; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| // No error, update |
| if (got_tlmode) |
| tlmode = ck_tlmode; |
| if (got_stack_align) |
| stack_align = ck_stack_align; |
| if (got_stack_depth) |
| stack_depth = ck_stack_depth; |
| return CMD_OK; |
| } |
| |
| // Process timeline data specification |
| Cmd_status |
| Settings::proc_tldata (const char *cmd, bool /* if true, ignore any error */) |
| { |
| free (tldata); |
| tldata = dbe_strdup (cmd); // let GUI parse it |
| return CMD_OK; |
| } |
| |
| void |
| Settings::set_tldata (const char* _tldata_str) |
| { |
| free (tldata); |
| tldata = dbe_strdup (_tldata_str); |
| } |
| |
| char* |
| Settings::get_tldata () |
| { |
| return dbe_strdup (tldata); |
| } |
| |
| Cmd_status |
| Settings::set_name_format (char *arg) |
| { |
| char *colon = strchr (arg, ':'); |
| size_t arg_len = (colon) ? (colon - arg) : strlen (arg); |
| Histable::NameFormat fname_fmt = Histable::NA; |
| if (!strncasecmp (arg, NTXT ("long"), arg_len)) |
| fname_fmt = Histable::LONG; |
| else if (!strncasecmp (arg, NTXT ("short"), arg_len)) |
| fname_fmt = Histable::SHORT; |
| else if (!strncasecmp (arg, NTXT ("mangled"), arg_len)) |
| fname_fmt = Histable::MANGLED; |
| else |
| return CMD_BAD_ARG; |
| |
| bool soname_fmt = false; |
| if (colon) |
| { |
| colon++; |
| if (!strcasecmp (colon, NTXT ("soname"))) |
| soname_fmt = true; |
| else if (!strcasecmp (colon, NTXT ("nosoname"))) |
| soname_fmt = false; |
| else |
| return CMD_BAD_ARG; |
| } |
| name_format = Histable::make_fmt (fname_fmt, soname_fmt); |
| return CMD_OK; |
| } |
| |
| void |
| Settings::buildMasterTabList () |
| { |
| tab_list = new Vector<DispTab*>; |
| int i = -1; |
| |
| // Add tabs for all the known reports |
| tab_list->append (new DispTab (DSP_DEADLOCKS, i, false, DEADLOCK_EVNTS)); |
| tab_list->append (new DispTab (DSP_FUNCTION, i, false, FUNCS)); |
| tab_list->append (new DispTab (DSP_TIMELINE, i, false, TIMELINE)); |
| tab_list->append (new DispTab (DSP_CALLTREE, i, false, CALLTREE)); |
| tab_list->append (new DispTab (DSP_CALLFLAME, i, false, CALLFLAME)); |
| tab_list->append (new DispTab (DSP_DUALSOURCE, i, false, DUALSOURCE)); |
| tab_list->append (new DispTab (DSP_SOURCE_DISASM, i, false, SOURCEDISAM)); |
| tab_list->append (new DispTab (DSP_SOURCE, i, false, SOURCE)); |
| tab_list->append (new DispTab (DSP_LINE, i, false, HOTLINES)); |
| tab_list->append (new DispTab (DSP_DISASM, i, false, DISASM)); |
| tab_list->append (new DispTab (DSP_PC, i, false, HOTPCS)); |
| tab_list->append (new DispTab (DSP_LEAKLIST, i, false, LEAKS)); |
| tab_list->append (new DispTab (DSP_IOACTIVITY, i, false, IOACTIVITY)); |
| tab_list->append (new DispTab (DSP_HEAPCALLSTACK, i, false, HEAP)); |
| tab_list->append (new DispTab (DSP_IFREQ, i, false, IFREQ)); |
| tab_list->append (new DispTab (DSP_CALLER, i, false, GPROF)); |
| tab_list->append (new DispTab (DSP_STATIS, i, false, STATISTICS)); |
| tab_list->append (new DispTab (DSP_EXP, i, false, HEADER)); |
| } |
| |
| // Update tablist based on data availability |
| void |
| Settings::updateTabAvailability () |
| { |
| int index; |
| DispTab *dsptab; |
| |
| Vec_loop (DispTab*, tab_list, index, dsptab) |
| { |
| if (dsptab->type == DSP_DATAOBJ) |
| dsptab->setAvailability (dbeSession->is_datamode_available ()); |
| else if (dsptab->type == DSP_DLAYOUT) |
| dsptab->setAvailability (dbeSession->is_datamode_available ()); |
| else if (dsptab->type == DSP_LEAKLIST) |
| dsptab->setAvailability (false); |
| else if (dsptab->type == DSP_IOACTIVITY) |
| dsptab->setAvailability (dbeSession->is_iodata_available ()); |
| else if (dsptab->type == DSP_HEAPCALLSTACK) |
| dsptab->setAvailability (dbeSession->is_heapdata_available ()); |
| else if (dsptab->type == DSP_TIMELINE) |
| dsptab->setAvailability (dbeSession->is_timeline_available ()); |
| else if (dsptab->type == DSP_IFREQ) |
| dsptab->setAvailability (dbeSession->is_ifreq_available ()); |
| else if (dsptab->type == DSP_RACES) |
| dsptab->setAvailability (dbeSession->is_racelist_available ()); |
| else if (dsptab->type == DSP_DEADLOCKS) |
| dsptab->setAvailability (dbeSession->is_deadlocklist_available ()); |
| else if (dsptab->type == DSP_DUALSOURCE) |
| dsptab->setAvailability (dbeSession->is_racelist_available () |
| || dbeSession->is_deadlocklist_available ()); |
| } |
| } |
| |
| // Process a tab setting |
| Cmd_status |
| Settings::proc_tabs (bool _rdtMode) |
| { |
| int arg_cnt, cparam; |
| int count = 0; |
| int index; |
| DispTab *dsptab; |
| char *cmd; |
| if (tabs_processed == true) |
| return CMD_OK; |
| tabs_processed = true; |
| if (_rdtMode == true) |
| { |
| if (str_rtabs == NULL) |
| str_rtabs = strdup ("header"); |
| cmd = str_rtabs; |
| } |
| else |
| { |
| if (str_tabs == NULL) |
| str_tabs = strdup ("header"); |
| cmd = str_tabs; |
| } |
| if (strcmp (cmd, NTXT ("none")) == 0) |
| return CMD_OK; |
| Vector <char *> *tokens = split_str (cmd, ':'); |
| for (long j = 0, sz = VecSize (tokens); j < sz; j++) |
| { |
| char *tabname = tokens->get (j); |
| // search for this tab command token |
| CmdType c = Command::get_command (tabname, arg_cnt, cparam); |
| if (c == INDXOBJ) |
| { |
| // set the bit for this subtype |
| indx_tab_state->store (cparam, true); |
| indx_tab_order->store (cparam, count++); |
| } |
| else |
| { |
| // search for this tab type in the regular tabs |
| Vec_loop (DispTab*, tab_list, index, dsptab) |
| { |
| if (dsptab->cmdtoken == c) |
| { |
| dsptab->visible = true; |
| dsptab->order = count++; |
| break; |
| } |
| } |
| } |
| free (tabname); |
| } |
| delete tokens; |
| return CMD_OK; |
| } |
| |
| void |
| Settings::set_MemTabState (Vector<bool>*selected) |
| { |
| if (selected->size () == 0) |
| return; |
| for (int j = 0; j < mem_tab_state->size (); j++) |
| mem_tab_state->store (j, selected->fetch (j)); |
| } |
| |
| // define a new memory object type |
| |
| void |
| Settings::mobj_define (MemObjType_t */* mobj */, bool state) |
| { |
| if (mem_tab_state->size () == 0) |
| state = true; |
| mem_tab_state->append (state); |
| mem_tab_order->append (-1); |
| } |
| |
| void |
| Settings::set_IndxTabState (Vector<bool>*selected) |
| { |
| for (int j = 0; j < selected->size (); j++) |
| indx_tab_state->store (j, selected->fetch (j)); |
| } |
| |
| // define a new index object type |
| void |
| Settings::indxobj_define (int type, bool state) |
| { |
| indx_tab_state->store (type, state); |
| indx_tab_order->store (type, -1); |
| } |
| |
| void |
| Settings::set_pathmaps (Vector<pathmap_t*> *newPathMap) |
| { |
| if (pathmaps) |
| { |
| pathmaps->destroy (); |
| delete pathmaps; |
| } |
| pathmaps = newPathMap; |
| } |
| |
| static char * |
| get_canonical_name (const char *fname) |
| { |
| char *nm = dbe_strdup (fname); |
| for (size_t len = strlen (nm); (len > 0) && (nm[len - 1] == '/'); len--) |
| nm[len - 1] = 0; |
| return nm; |
| } |
| |
| char * |
| Settings::add_pathmap (Vector<pathmap_t*> *v, const char *from, const char *to) |
| { |
| // Check for errors |
| if (from == NULL || to == NULL) |
| return dbe_strdup (GTXT ("Pathmap can have neither from nor to as NULL\n")); |
| if (strcmp (from, to) == 0) |
| return dbe_strdup (GTXT ("Pathmap from must differ from to\n")); |
| char *old_prefix = get_canonical_name (from); |
| char *new_prefix = get_canonical_name (to); |
| |
| // Check the pathmap list |
| for (int i = 0, sz = v->size (); i < sz; i++) |
| { |
| pathmap_t *pmp = v->get (i); |
| if ((strcmp (pmp->old_prefix, old_prefix) == 0) &&(strcmp (pmp->new_prefix, new_prefix) == 0)) |
| { |
| char *s = dbe_sprintf (GTXT ("Pathmap from `%s' to `%s' already exists\n"), old_prefix, new_prefix); |
| free (old_prefix); |
| free (new_prefix); |
| return s; |
| } |
| } |
| // construct a map for this pair |
| pathmap_t *thismap = new pathmap_t; |
| thismap->old_prefix = old_prefix; |
| thismap->new_prefix = new_prefix; |
| v->append (thismap); |
| return NULL; |
| } |
| |
| // Set all shared object expands back to .rc file defaults, |
| // as stored in the DbeSession Settings |
| bool |
| Settings::set_libdefaults () |
| { |
| // See if this is unchanged |
| if (is_loexpand_default == true) |
| return false; // no change |
| |
| // replicate the DbeSession's lo_expand vector and default settings |
| lo_expand_t *this_lo_ex; |
| lo_expand_t *new_lo_ex; |
| int index; |
| lo_expand_default = dbeSession->get_settings ()->lo_expand_default; |
| lo_expands = new Vector<lo_expand_t*>; |
| Vec_loop (lo_expand_t*, dbeSession->get_settings ()->lo_expands, index, this_lo_ex) |
| { |
| new_lo_ex = new lo_expand_t; |
| new_lo_ex->libname = dbe_strdup (this_lo_ex->libname); |
| new_lo_ex->expand = this_lo_ex->expand; |
| lo_expands->append (new_lo_ex); |
| } |
| is_loexpand_default = true; |
| return true; |
| } |
| |
| bool |
| Settings::set_libexpand (char *cov, enum LibExpand expand, bool rc) |
| { |
| int index; |
| lo_expand_t *loe; |
| bool change = false; |
| if (cov == NULL || !strcasecmp (cov, Command::ALL_CMD)) |
| { // set all libraries |
| // set the default |
| if (lo_expand_default != expand) |
| { |
| lo_expand_default = expand; |
| change = true; |
| is_loexpand_default = false; |
| } |
| |
| // and force any explicit settings to match, too |
| Vec_loop (lo_expand_t*, lo_expands, index, loe) |
| { |
| if (loe->expand != expand) |
| { |
| loe->expand = expand; |
| change = true; |
| is_loexpand_default = false; |
| } |
| } |
| |
| } |
| else |
| { // parsing coverage |
| Vector <char *> *tokens = split_str (cov, ','); |
| for (long j = 0, sz = VecSize (tokens); j < sz; j++) |
| { |
| char *lo_name = tokens->get (j); |
| char *newname = get_basename (lo_name); |
| bool found = false; |
| Vec_loop (lo_expand_t*, lo_expands, index, loe) |
| { |
| if (strcmp (loe->libname, newname) == 0) |
| { |
| if (loe->expand != expand) |
| { |
| if (rc == false) |
| { |
| loe->expand = expand; |
| change = true; |
| is_loexpand_default = false; |
| } |
| } |
| found = true; |
| break; |
| } |
| } |
| |
| if (found == false) |
| { |
| // construct a map for this pair |
| lo_expand_t *thisloe; |
| thisloe = new lo_expand_t; |
| thisloe->libname = dbe_strdup (newname); |
| thisloe->expand = expand; |
| change = true; |
| is_loexpand_default = false; |
| |
| // add it to the vector |
| lo_expands->append (thisloe); |
| } |
| free (lo_name); |
| } |
| delete tokens; |
| } |
| return change; |
| } |
| |
| enum LibExpand |
| Settings::get_lo_setting (char *name) |
| { |
| int index; |
| lo_expand_t *loe; |
| char *lo_name = get_basename (name); |
| Vec_loop (lo_expand_t*, lo_expands, index, loe) |
| { |
| if (strcmp (loe->libname, lo_name) == 0) |
| return loe->expand; |
| } |
| return lo_expand_default; |
| } |