| /* Copyright (C) 2021-2023 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; | |
| } |