home *** CD-ROM | disk | FTP | other *** search
- // $Id: file.C,v 1.69 1998/11/26 13:28:43 zeller Exp $ -*- C++ -*-
- // DDD file functions
-
- // Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
- // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
- //
- // This file is part of DDD.
- //
- // DDD 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 2 of the License, or (at your option) any later version.
- //
- // DDD 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 DDD -- see the file COPYING.
- // If not, write to the Free Software Foundation, Inc.,
- // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- // DDD is the data display debugger.
- // For details, see the DDD World-Wide-Web page,
- // `http://www.cs.tu-bs.de/softech/ddd/',
- // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
-
- char file_rcsid[] =
- "$Id: file.C,v 1.69 1998/11/26 13:28:43 zeller Exp $";
-
- #ifdef __GNUG__
- #pragma implementation
- #pragma implementation "DynArray"
- #pragma implementation "VarArray"
- #endif
-
- #include "file.h"
-
- #include "AppData.h"
- #include "GDBAgent.h"
- #include "MString.h"
- #include "Delay.h"
- #include "DestroyCB.h"
- #include "ExitCB.h"
- #include "HelpCB.h"
- #include "SmartC.h"
- #include "SourceView.h"
- #include "VarArray.h"
- #include "Command.h"
- #include "cook.h"
- #include "ddd.h"
- #include "filetype.h"
- #include "glob.h"
- #include "history.h"
- #include "java.h"
- #include "mydialogs.h"
- #include "post.h"
- #include "question.h"
- #include "regexps.h"
- #include "shell.h"
- #include "strclass.h"
- #include "status.h"
- #include "string-fun.h"
- #include "uniquify.h"
- #include "verify.h"
- #include "wm.h"
-
- #include <limits.h>
- #include <string.h> // strerror()
- #include <errno.h>
-
- #include <Xm/Xm.h>
- #include <Xm/FileSB.h>
- #include <Xm/List.h>
- #include <Xm/SelectioB.h>
- #include <Xm/MessageB.h>
- #include <Xm/Text.h>
- #include <Xm/RowColumn.h>
- #include <Xm/TextF.h>
- #include <Xm/Label.h>
- #include <Xm/PushB.h>
-
- // ANSI C++ doesn't like the XtIsRealized() macro
- #ifdef XtIsRealized
- #undef XtIsRealized
- #endif
-
- #if !HAVE_POPEN_DECL
- extern "C" FILE *popen(const char *command, const char *mode);
- #endif
- #if !HAVE_PCLOSE_DECL
- extern "C" int pclose(FILE *stream);
- #endif
-
-
- //-----------------------------------------------------------------------------
- // Helpers
- //-----------------------------------------------------------------------------
-
- // Don't rely on libiberty basename() because we don't want to depend
- // on libiberty include files
- static const char *file_basename(const char *name)
- {
- const char *base = name;
-
- while (*name)
- {
- if (*name++ == '/')
- base = name;
- }
-
- return base;
- }
-
- #define basename file_basename
-
-
- //-----------------------------------------------------------------------------
- // Opening files
- //-----------------------------------------------------------------------------
-
- typedef void (*FileSearchProc)(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs);
-
- static WidgetArray file_filters;
- static WidgetArray file_dialogs;
-
- static string current_file_filter = "";
-
- // Make sure that every change in one filter is reflected in all others
- static void SyncFiltersCB(Widget dialog, XtPointer, XtPointer)
- {
- static bool entered = false;
-
- if (entered)
- return;
-
- entered = true;
-
- // clog << "widget = " << longName(text) << "\n";
-
- while (dialog != 0 && !XmIsFileSelectionBox(dialog))
- dialog = XtParent(dialog);
-
- // clog << "dialog = " << longName(dialog) << "\n";
-
- Widget text = XmFileSelectionBoxGetChild(dialog, XmDIALOG_FILTER_TEXT);
- String _current_file_filter = XmTextGetString(text);
- current_file_filter = _current_file_filter;
- XtFree(_current_file_filter);
-
- for (int i = 0; i < file_filters.size(); i++)
- {
- if (file_dialogs[i] != dialog)
- {
- // clog << "other dialog = " << longName(file_dialogs[i]) << "\n";
- XmTextSetString(file_filters[i], current_file_filter);
- }
- }
-
- entered = false;
- }
-
- // Make sure that every new filter call is performed in all other
- // dialogs as well
- static void FilterAllCB(Widget dialog, XtPointer client_data,
- XtPointer call_data)
- {
- SyncFiltersCB(dialog, client_data, call_data);
-
- // clog << "widget = " << longName(dialog) << "\n";
-
- while (dialog != 0 && !XmIsFileSelectionBox(dialog))
- dialog = XtParent(dialog);
-
- // clog << "dialog = " << longName(dialog) << "\n";
-
- for (int i = 0; i < file_dialogs.size(); i++)
- {
- if (file_dialogs[i] != dialog)
- {
- // clog << "other dialog = " << longName(file_dialogs[i]) << "\n";
- XmFileSelectionDoSearch(file_dialogs[i], NULL);
- }
- }
- }
-
- static void ClearStatusCB(Widget, XtPointer, XtPointer)
- {
- set_status("");
- }
-
- // Create a file dialog NAME with DO_SEARCH_FILES and DO_SEARCH_DIRS
- // as search procedures for files and directories, respectively, and
- // OK_CALLBACK as the procedure called when a file is selected.
- static Widget file_dialog(Widget w, const string& name,
- FileSearchProc do_search_files = 0,
- FileSearchProc do_search_dirs = 0,
- XtCallbackProc ok_callback = 0)
- {
- Delay delay(w);
-
- Arg args[10];
- int arg = 0;
-
- string pwd;
-
- arg = 0;
- if (do_search_files)
- {
- XtSetArg(args[arg], XmNfileSearchProc, do_search_files); arg++;
- }
- if (do_search_dirs)
- {
- XtSetArg(args[arg], XmNdirSearchProc, do_search_dirs); arg++;
- }
-
- if (remote_gdb())
- {
- static MString xmpwd;
- xmpwd = source_view->pwd();
- XtSetArg(args[arg], XmNdirectory, xmpwd.xmstring()); arg++;
- }
-
- Widget dialog =
- verify(XmCreateFileSelectionDialog(w, name, args, arg));
- Delay::register_shell(dialog);
-
- if (ok_callback != 0)
- XtAddCallback(dialog, XmNokCallback, ok_callback, 0);
-
- XtAddCallback(dialog, XmNcancelCallback, UnmanageThisCB,
- XtPointer(dialog));
- XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, 0);
-
- Widget filter = XmFileSelectionBoxGetChild(dialog, XmDIALOG_FILTER_TEXT);
- file_filters += filter;
- if (current_file_filter != "")
- XmTextSetString(filter, current_file_filter);
- XtAddCallback(filter, XmNvalueChangedCallback, SyncFiltersCB, 0);
-
- Widget filter_button =
- XmFileSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON);
- XtAddCallback(filter_button, XmNactivateCallback, FilterAllCB, 0);
- XtAddCallback(dialog, XmNunmapCallback, ClearStatusCB, 0);
-
- file_dialogs += dialog;
-
- return dialog;
- }
-
- // Create various file dialogs
- static Widget create_file_dialog(Widget w, String name,
- FileSearchProc searchRemoteFiles = 0,
- FileSearchProc searchRemoteDirectories = 0,
- FileSearchProc searchLocalFiles = 0,
- FileSearchProc searchLocalDirectories = 0,
- XtCallbackProc openDone = 0)
- {
- if (remote_gdb())
- return file_dialog(find_shell(w), name,
- searchRemoteFiles, searchRemoteDirectories,
- openDone);
- else if (app_data.filter_files)
- return file_dialog(find_shell(w), name,
- searchLocalFiles, searchLocalDirectories,
- openDone);
- else
- return file_dialog(find_shell(w), name, 0, 0, openDone);
- }
-
-
- // Synchronize file dialogs with current directory
- void process_cd(string pwd)
- {
- current_file_filter = pwd + "/*";
-
- for (int i = 0; i < file_filters.size(); i++)
- {
- if (file_filters[i] != 0)
- {
- XmTextSetString(file_filters[i], current_file_filter);
- break;
- }
- }
- }
-
- static char delay_message[] = "Filtering files";
-
- // Search for remote files and directories, using the command CMD
- static void searchRemote(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs,
- String cmd,
- bool search_dirs)
- {
- StatusDelay delay(delay_message);
-
- int nitems = 0;
- int size = 256;
- XmStringTable items =
- XmStringTable(XtMalloc(size * sizeof(XmString)));
-
- String mask;
- if (!XmStringGetLtoR(cbs->mask, MSTRING_DEFAULT_CHARSET, &mask))
- {
- delay.outcome = "failed";
- return;
- }
- String dir;
- if (!XmStringGetLtoR(cbs->dir, MSTRING_DEFAULT_CHARSET, &dir))
- {
- delay.outcome = "failed";
- return;
- }
-
- if (search_dirs)
- {
- string extra_dir = string(dir) + ".";
- items[nitems++] =
- XmStringCreateLtoR(extra_dir, MSTRING_DEFAULT_CHARSET);
- extra_dir = string(dir) + "..";
- items[nitems++] =
- XmStringCreateLtoR(extra_dir, MSTRING_DEFAULT_CHARSET);
- }
-
- string command = cmd;
- command.gsub("@MASK@", mask);
- command = sh_command(command);
-
- Agent search(command);
- search.start();
-
- FILE *fp = search.inputfp();
- if (fp == 0)
- {
- delay.outcome = strerror(errno);
- return;
- }
-
- char buf[BUFSIZ];
- while (fgets(buf, sizeof(buf), fp))
- {
- if (buf[0] && buf[strlen(buf) - 1] == '\n')
- buf[strlen(buf) - 1] = '\0';
-
- if (nitems >= size)
- {
- size += 256;
- items = XmStringTable(XtRealloc((char *)items,
- size * sizeof(XmString)));
- }
-
- items[nitems++] = XmStringCreateLtoR(buf, MSTRING_DEFAULT_CHARSET);
-
- if (nitems == 1 || nitems % 10 == 0)
- {
- ostrstream status;
- status << delay_message << "... ("
- << nitems << " processed)";
- string s(status);
- set_status(s, true);
- }
- }
-
- if (search_dirs)
- {
- XtVaSetValues(fs,
- XmNdirListItems, items,
- XmNdirListItemCount, nitems,
- XmNdirectoryValid, True,
- XmNlistUpdated, True,
- NULL);
- }
- else
- {
- if (nitems > 0)
- {
- XtVaSetValues(fs,
- XmNfileListItems, items,
- XmNfileListItemCount, nitems,
- XmNdirSpec, items[0],
- XmNlistUpdated, True,
- NULL);
- }
- else
- {
- XtVaSetValues(fs,
- XmNfileListItems, 0,
- XmNfileListItemCount, 0,
- XmNlistUpdated, True,
- NULL);
- }
- }
- }
-
-
- static void searchRemoteExecFiles(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs)
- {
- searchRemote(fs, cbs, app_data.list_exec_command, false);
- }
-
- static void searchRemoteCoreFiles(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs)
- {
- searchRemote(fs, cbs, app_data.list_core_command, false);
- }
-
- static void searchRemoteSourceFiles(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs)
- {
- searchRemote(fs, cbs, app_data.list_source_command, false);
- }
-
- static void searchRemoteDirectories(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs)
- {
- searchRemote(fs, cbs, app_data.list_dir_command, true);
- }
-
- // Search for local files and directories, using the predicate IS_OKAY
- static void searchLocal(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs,
- bool is_okay(const string& file_name))
- {
- String mask;
- if (!XmStringGetLtoR(cbs->mask, MSTRING_DEFAULT_CHARSET, &mask))
- return;
-
- char **files = glob_filename(mask);
- if (files == (char **)0)
- {
- cerr << mask << ": glob failed\n";
- }
- else if (files == (char **)-1)
- {
- post_error(string(mask) + ": " + strerror(errno));
- }
- else
- {
- StatusDelay delay(delay_message);
-
- int count;
- for (count = 0; files[count] != 0; count++)
- ;
- smart_sort(files, count);
-
- XmStringTable items =
- XmStringTable(XtMalloc(count * sizeof(XmString)));
-
- int nitems = 0;
- for (int i = 0; files[i] != 0; i++)
- {
- if (is_okay(files[i]))
- items[nitems++] = XmStringCreateLtoR(files[i],
- MSTRING_DEFAULT_CHARSET);
- free(files[i]);
-
- int percent = (i * 100) / count;
- int old_percent = ((i - 1) * 100) / count;
- if (percent % 10 == 0 && old_percent % 10 != 0)
- {
- ostrstream status;
- status << delay_message << "... ("
- << percent << "% processed)";
- string s(status);
- set_status(s, true);
- }
- }
- free((char *)files);
-
- if (nitems > 0)
- {
- XtVaSetValues(fs,
- XmNfileListItems, items,
- XmNfileListItemCount, nitems,
- XmNdirSpec, items[0],
- XmNlistUpdated, True,
- NULL);
-
- XtFree((char *)items);
- return;
- }
- }
-
- // Error or nothing found
- XtVaSetValues(fs,
- XmNfileListItems, 0,
- XmNfileListItemCount, 0,
- XmNlistUpdated, True,
- NULL);
- }
-
- static void searchLocalExecFiles(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs)
- {
- switch (gdb->type())
- {
- case PYDB:
- searchLocal(fs, cbs, is_python_file);
- break;
-
- case PERL:
- searchLocal(fs, cbs, is_perl_file);
- break;
-
- default:
- searchLocal(fs, cbs, is_exec_file);
- }
- }
-
- static void searchLocalCoreFiles(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs)
- {
- searchLocal(fs, cbs, is_core_file);
- }
-
- static void searchLocalSourceFiles(Widget fs,
- XmFileSelectionBoxCallbackStruct *cbs)
- {
- switch (gdb->type())
- {
- case PYDB:
- searchLocal(fs, cbs, is_python_file);
- break;
-
- case PERL:
- searchLocal(fs, cbs, is_perl_file);
- break;
-
- default:
- searchLocal(fs, cbs, is_source_file);
- }
- }
-
- // Get the file name from the file selection box W
- string get_file(Widget w, XtPointer, XtPointer call_data)
- {
- XmFileSelectionBoxCallbackStruct *cbs =
- (XmFileSelectionBoxCallbackStruct *)call_data;
-
- String s;
- if (!XmStringGetLtoR(cbs->value, MSTRING_DEFAULT_CHARSET, &s))
- return NO_GDB_ANSWER;
-
- string filename = s;
- XtFree(s);
-
- if (filename == "" || filename[0] != '/')
- {
- String dir;
- if (!XmStringGetLtoR(cbs->dir, MSTRING_DEFAULT_CHARSET, &dir))
- return NO_GDB_ANSWER;
-
- filename = string(dir) + "/" + filename;
- XtFree(dir);
- }
-
- if (is_directory(filename))
- {
- MString filter(filename);
- XmFileSelectionDoSearch(w, filter.xmstring());
- return "";
- }
-
- return filename;
- }
-
-
-
- //-----------------------------------------------------------------------------
- // OK pressed
- //-----------------------------------------------------------------------------
-
- static void open_file(const string& filename)
- {
- if (gdb->type() == GDB)
- {
- // GDB does not always detach processes upon opening new
- // files, so we do it explicitly
- ProgramInfo info;
- if (info.attached)
- gdb_command("detach");
- }
-
- string cmd = gdb->debug_command(filename);
-
- if (gdb->type() == PERL)
- cmd.gsub("perl", string(app_data.debugger_command));
-
- gdb_command(cmd);
- }
-
- // OK pressed in `Open File'
- static void openFileDone(Widget w, XtPointer client_data, XtPointer call_data)
- {
- string filename = get_file(w, client_data, call_data);
- if (filename == "")
- return;
-
- XtUnmanageChild(w);
-
- if (filename == NO_GDB_ANSWER)
- return;
-
- open_file(filename);
- }
-
-
- // OK pressed in `Open Core'
- static void openCoreDone(Widget w, XtPointer client_data, XtPointer call_data)
- {
- string corefile = get_file(w, client_data, call_data);
- if (corefile == "")
- return;
-
- ProgramInfo info;
-
- XtUnmanageChild(w);
-
- if (corefile != NO_GDB_ANSWER)
- {
- switch(gdb->type())
- {
- case GDB:
- gdb_command("core-file " + corefile);
- break;
-
- case DBX:
- if (info.file != NO_GDB_ANSWER && info.file != "")
- gdb_command(gdb->debug_command(info.file) + " " + info.core);
- else
- post_error("No program.", "no_program", w);
- break;
-
- case XDB:
- case JDB:
- case PYDB:
- case PERL:
- break; // FIXME
- }
- }
- }
-
- // OK pressed in `Open Source'
- static void openSourceDone(Widget w, XtPointer client_data,
- XtPointer call_data)
- {
- string filename = get_file(w, client_data, call_data);
- if (filename == "")
- return;
-
- XtUnmanageChild(w);
- set_status("");
-
- // For PYDB, issue a 'file filename' command
- if (gdb->type() == PYDB)
- gdb_command(gdb->debug_command(filename));
-
- if (filename != NO_GDB_ANSWER)
- source_view->read_file(filename);
- }
-
-
- //-----------------------------------------------------------------------------
- // Program Info
- //-----------------------------------------------------------------------------
-
- // Get information on current debuggee
- ProgramInfo::ProgramInfo()
- : file(NO_GDB_ANSWER),
- core(NO_GDB_ANSWER),
- pid(0),
- attached(false),
- running(false),
- state()
- {
- if (source_view->have_exec_pos())
- {
- state = "has stopped";
- running = true;
- }
- else
- {
- state = "is not being run";
- running = false;
- }
-
- switch(gdb->type())
- {
- case GDB:
- case PYDB:
- {
- string ans = gdb_question("info files");
- if (ans == NO_GDB_ANSWER)
- break;
-
- file = "";
- if (ans.contains("Symbols from "))
- {
- file = ans.after("Symbols from ");
- file = file.before(".\n");
- file = unquote(file);
- }
-
- core = "";
- if (ans.contains("core dump"))
- {
- core = ans.after("core dump");
- core = core.after('`');
- core = core.before("',");
- }
-
- if (ans.contains("process "))
- {
- string p = ans.after("process ");
- pid = atoi(p.chars());
- }
-
- attached = ans.contains("attached process ");
-
- ans = gdb_question("info program");
- if (ans == NO_GDB_ANSWER)
- break;
-
- if (ans.contains("not being run"))
- running = false;
- else if (ans.contains("\nIt stopped "))
- {
- state = ans.from("\nIt stopped ");
- state = "has " + state.after("\nIt ");
- state = state.before('.');
- running = true;
- }
- break;
- }
-
- case DBX:
- {
- string ans = gdb_question(gdb->debug_command());
- if (ans != NO_GDB_ANSWER)
- {
- if (ans.contains("Debugging: ", 0))
- ans = ans.after(": ");
-
- strip_space(ans);
- if (!ans.contains(' ')) // Sanity check
- file = ans;
- }
- break;
- }
-
- case XDB:
- break; // FIXME
-
- case PERL:
- // Just use the current file.
- file = source_view->file_of_cursor();
- file = file.before(":");
- core = "";
- break;
-
- case JDB:
- // Just use the current class.
- file = source_view->line_of_cursor();
- file = file.before(":");
- core = "";
- break;
- }
-
- if (file == NO_GDB_ANSWER)
- {
- // As a fallback, get core file and executable from argument list.
- // Works only on local file system and is more a guess.
- char **argv = saved_argv();
- int argc = 0;
- while (argv[argc] != 0)
- argc++;
-
- for (int i = argc - 1; i > 0 && file == NO_GDB_ANSWER; i--)
- {
- // All debuggers supported by DDD have [EXEC [CORE]] as
- // their last arguments.
- string arg = argv[i];
- if (is_core_file(arg))
- core = arg;
- else if (is_exec_file(arg))
- file = arg;
- }
- }
-
- if (file != NO_GDB_ANSWER)
- add_to_recent(file);
- }
-
-
- //-----------------------------------------------------------------------------
- // Processes
- //-----------------------------------------------------------------------------
-
- // Process selection
- static int ps_pid_index = 0;
-
- // Retrieve PID from PS output
- static int ps_pid(const string& line)
- {
- const char *s = line.chars() + ps_pid_index;
- while (s > line.chars() && isdigit(s[-1]))
- --s;
-
- return atoi(s);
- }
-
- // Fill the pids in DISP_NRS
- static void getPIDs(Widget selectionList, IntArray& disp_nrs)
- {
- static IntArray empty;
- disp_nrs = empty;
-
- XmStringTable selected_items;
- int selected_items_count = 0;
-
- assert(XmIsList(selectionList));
-
- XtVaGetValues(selectionList,
- XmNselectedItemCount, &selected_items_count,
- XmNselectedItems, &selected_items,
- NULL);
-
- for (int i = 0; i < selected_items_count; i++)
- {
- String _item;
- XmStringGetLtoR(selected_items[i], LIST_CHARSET, &_item);
- string item(_item);
- XtFree(_item);
-
- int p = ps_pid(item);
- if (p > 0)
- disp_nrs += p;
- }
- }
-
- // Get the PID from the selection list in CLIENT_DATA
- static int get_pid(Widget, XtPointer client_data, XtPointer)
- {
- IntArray pids;
- Widget processes = Widget(client_data);
- if (processes != 0)
- getPIDs(processes, pids);
-
- if (pids.size() == 1)
- return pids[0];
- else
- return 0;
- }
-
- // Process selection
-
- static void sortProcesses(StringArray& a)
- {
- // Shell sort -- simple and fast
- int h = 1;
- do {
- h = h * 3 + 1;
- } while (h <= a.size());
- do {
- h /= 3;
- for (int i = h; i < a.size(); i++)
- {
- string v = a[i];
- int j;
- for (j = i; j >= h && ps_pid(a[j - h]) > ps_pid(v); j -= h)
- a[j] = a[j - h];
- if (i != j)
- a[j] = v;
- }
- } while (h != 1);
- }
-
-
- inline bool is_separator(char c)
- {
- return c == ' ' || c == '\'' || c == '\"';
- }
-
- // Check whether LINE is a valid PS line. Exclude occurrences of PS_COMMAND.
- static bool valid_ps_line(const string& line, const string& ps_command)
- {
- int pid = ps_pid(line);
- if (pid == 0)
- return false; // No PID
-
- // You don't want to debug DDD, don't you?
- if (!remote_gdb() && pid == getpid())
- return false;
-
- // Neither should you debug GDB by itself.
- if (pid == gdb->pid())
- return false;
-
- // Don't issue lines containing `ps' (or whatever the first word
- // in PS_COMMAND is).
- string ps = ps_command;
- if (ps.contains(' '))
- ps = ps.before(' ');
- ps = basename(ps);
- int index = line.index(ps);
- if (index > 0
- && (line[index - 1] == '/' || is_separator(line[index - 1]))
- && (line.length() == index + ps.length()
- || is_separator(line[index + ps.length()])))
- return false;
-
- // Okay, just leave it
- return true;
- }
-
-
- // Create list of processes
- static void update_processes(Widget processes, bool keep_selection)
- {
- StatusDelay delay("Getting list of processes");
-
- string cmd = sh_command(app_data.ps_command) + " 2>&1";
- FILE *fp = popen(cmd.chars(), "r");
- if (fp == 0)
- {
- delay.outcome = strerror(errno);
- return;
- }
-
- StringArray all_process_list;
- int c;
- string line = "";
- bool first_line = true;
-
- while ((c = getc(fp)) != EOF)
- {
- if (c == '\n')
- {
- if (first_line || valid_ps_line(line, app_data.ps_command))
- all_process_list += line;
- #if 0
- else
- clog << "Excluded: " << line << "\n";
- #endif
-
- if (first_line)
- {
- // Find first occurrence of `PID' title
- ps_pid_index = line.index(" PID ");
- if (ps_pid_index < 0)
- ps_pid_index = 0;
- }
-
- line = "";
- first_line = false;
- }
- else
- {
- line += c;
- }
- }
-
- pclose(fp);
- sortProcesses(all_process_list);
- DynIntArray pids(all_process_list.size());
-
- // If GDB cannot send a signal to the process, we cannot debug it.
- // Try a `kill -0' (via GDB, as it may be setuid) and filter out
- // all processes in the `kill' diagnostic -- that is, all
- // processes that `kill' could not send a signal.
- string kill = "kill -0";
- int i;
- for (i = 0; i < all_process_list.size(); i++)
- {
- pids[i] = ps_pid(all_process_list[i]);
- if (pids[i])
- kill += string(" ") + itostring(pids[i]);
- }
- string kill_result = gdb_question(gdb->shell_command(kill));
- i = 0;
- while (i >= 0)
- {
- i = kill_result.index(rxint, i);
- if (i >= 0)
- {
- int bad_pid = atoi((char *)kill_result + i);
- for (int k = 0; k < all_process_list.size(); k++)
- {
- if (pids[k] != 0 && pids[k] == bad_pid)
- {
- #if 0
- clog << "Excluded: " << all_process_list[k] << "\n";
- #endif
- all_process_list[k] = NO_GDB_ANSWER;
- }
- }
- i++;
- }
- }
-
- StringArray process_list;
- for (i = 0; i < all_process_list.size(); i++)
- if (all_process_list[i] != NO_GDB_ANSWER)
- process_list += all_process_list[i];
-
- // Now set the selection.
- bool *selected = new bool[process_list.size()];
- for (i = 0; i < process_list.size(); i++)
- selected[i] = false;
-
- int pos = -1;
- if (keep_selection)
- {
- // Preserve old selection: each PID selected before will also be
- // selected after.
- IntArray selection;
- getPIDs(processes, selection);
-
- for (i = 0; i < selection.size(); i++)
- {
- for (int j = 0; j < process_list.size(); j++)
- if (selection[i] == ps_pid(process_list[j]))
- {
- if (pos < 0)
- pos = j;
- selected[j] = true;
- }
- }
- }
-
- if (pos < 0)
- {
- // Create new selection from current file and current pid.
- ProgramInfo info;
-
- // Check for current pid; if found, highlight it.
- for (i = 0; pos < 0 && i < process_list.size(); i++)
- {
- if (info.pid != 0 && ps_pid(process_list[i]) == info.pid)
- pos = i;
- }
-
- if (pos < 0)
- {
- // Not found? Try leftmost occurrence of process base name.
- string current_base = basename(info.file.chars());
- int leftmost = INT_MAX;
- for (i = 0; i < process_list.size(); i++)
- {
- int occurrence = process_list[i].index(current_base);
- if (occurrence >= 0 && occurrence < leftmost
- && ps_pid(process_list[i]) > 0)
- {
- leftmost = occurrence;
- pos = i;
- }
- }
- }
- }
-
- if (pos >= 0)
- selected[pos] = true;
-
- setLabelList(processes, process_list.values(),
- selected, process_list.size(), true, false);
-
- if (pos >= 0)
- ListSetAndSelectPos(processes, pos + 1);
-
- delete[] selected;
- }
-
-
- static void gdbUpdateProcessesCB(Widget, XtPointer client_data, XtPointer)
- {
- Widget processes = Widget(client_data);
- update_processes(processes, true);
- }
-
- // Select a process
- static void SelectProcessCB(Widget w, XtPointer client_data,
- XtPointer call_data)
- {
- XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data;
- int pos = cbs->item_position;
- if (pos == 1)
- XmListDeselectAllItems(w); // Title selected
- else
- ListSetAndSelectPos(w, pos);
-
- int pid = get_pid(w, client_data, call_data);
- if (pid <= 0)
- set_status("");
- else
- set_status("Process " + itostring(pid));
- }
-
-
- // OK pressed in `Open Process'
- static void openProcessDone(Widget w, XtPointer client_data,
- XtPointer call_data)
- {
- int pid = get_pid(w, client_data, call_data);
- if (pid <= 0)
- {
- gdbUpdateProcessesCB(w, client_data, call_data);
- return;
- }
-
- XtUnmanageChild(w);
-
- ProgramInfo info;
-
- if (pid == info.pid)
- {
- set_status("Already attached to process " + itostring(pid) + ".");
- return;
- }
-
- switch(gdb->type())
- {
- case GDB:
- // GDB does not always detach processes upon opening new
- // files, so we do it explicitly
- if (info.attached)
- gdb_command("detach");
-
- // Attach to new process
- gdb_command("attach " + itostring(pid));
- break;
-
- case DBX:
- // Attach to new process
- if (info.file != NO_GDB_ANSWER && info.file != "")
- gdb_command("debug " + info.file + " " + itostring(pid));
- else
- post_error("No program.", "no_program", w);
- break;
-
- case XDB:
- case JDB:
- case PYDB:
- case PERL:
- break; // FIXME
- }
- }
-
- // When W is to be destroyed, remove all references in Widget(CLIENT_DATA)
- static void RemoveCallbacksCB(Widget w, XtPointer client_data, XtPointer)
- {
- Widget ref = Widget(client_data);
- XtRemoveCallback(ref, XmNokCallback, UnmanageThisCB, XtPointer(w));
- XtRemoveCallback(ref, XmNcancelCallback, UnmanageThisCB, XtPointer(w));
- XtRemoveCallback(ref, XmNdestroyCallback, RemoveCallbacksCB, XtPointer(w));
- }
-
- // If we don't have a current executable, issue a warning.
- static void warn_if_no_program(Widget popdown)
- {
- ProgramInfo info;
-
- if (info.file == "")
- {
- Widget warning = post_warning("Please open a program first.",
- "no_program", popdown);
-
- if (popdown != 0 && warning != 0)
- {
- // Tie the warning to the dialog - if one is popped down,
- // so is the other.
- XtAddCallback(warning, XmNokCallback,
- UnmanageThisCB, XtPointer(popdown));
- XtAddCallback(warning, XmNcancelCallback,
- UnmanageThisCB, XtPointer(popdown));
- XtAddCallback(popdown, XmNdestroyCallback,
- RemoveCallbacksCB, XtPointer(warning));
-
- XtAddCallback(popdown, XmNokCallback,
- UnmanageThisCB, XtPointer(warning));
- XtAddCallback(popdown, XmNcancelCallback,
- UnmanageThisCB, XtPointer(warning));
- XtAddCallback(warning, XmNdestroyCallback,
- RemoveCallbacksCB, XtPointer(popdown));
- }
- }
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Helpers for class and source selection
- //-----------------------------------------------------------------------------
-
- // Get the selected item ids
- static void get_items(Widget selectionList, StringArray& itemids)
- {
- static StringArray empty;
- itemids = empty;
-
- XmStringTable selected_items;
- int selected_items_count = 0;
-
- assert(XmIsList(selectionList));
-
- XtVaGetValues(selectionList,
- XmNselectedItemCount, &selected_items_count,
- XmNselectedItems, &selected_items,
- NULL);
-
- for (int i = 0; i < selected_items_count; i++)
- {
- String _item;
- XmStringGetLtoR(selected_items[i], LIST_CHARSET, &_item);
- string item(_item);
- XtFree(_item);
-
- itemids += item;
- }
- }
-
- // Get the item from the selection list in CLIENT_DATA
- static string get_item(Widget, XtPointer client_data, XtPointer)
- {
- StringArray itemids;
- Widget items = Widget(client_data);
- if (items != 0)
- get_items(items, itemids);
-
- if (itemids.size() == 1)
- return itemids[0];
-
- return "";
- }
-
-
- //-----------------------------------------------------------------------------
- // Classes (JDB only)
- //-----------------------------------------------------------------------------
-
- // Select a class
- static void SelectClassCB(Widget w, XtPointer client_data,
- XtPointer call_data)
- {
- XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data;
- int pos = cbs->item_position;
- ListSetAndSelectPos(w, pos);
-
- string cls = get_item(w, client_data, call_data);
- if (cls == "")
- set_status("");
- else
- set_status(source_view->full_path(java_class_file(cls)));
- }
-
- static void update_classes(Widget classes)
- {
- StatusDelay delay("Getting list of classes");
- StringArray classes_list;
- get_java_classes(classes_list);
-
- // Now set the selection.
- bool *selected = new bool[classes_list.size()];
- for (int i = 0; i < classes_list.size(); i++)
- selected[i] = false;
-
- setLabelList(classes, classes_list.values(),
- selected, classes_list.size(), false, false);
-
- delete[] selected;
- }
-
- static void gdbUpdateClassesCB(Widget, XtPointer client_data, XtPointer)
- {
- Widget classes = Widget(client_data);
- update_classes(classes);
- }
-
- // OK pressed in `Open Class'
- static void openClassDone(Widget w, XtPointer client_data,
- XtPointer call_data)
- {
- string cls = get_item(w, client_data, call_data);
- if (cls == "")
- {
- gdbUpdateClassesCB(w, client_data, call_data);
- return;
- }
-
- XtUnmanageChild(w);
-
- gdb_command(gdb->debug_command(cls));
- }
-
-
- //-----------------------------------------------------------------------------
- // Lookup sources and functions (GDB only)
- //-----------------------------------------------------------------------------
-
- static StringArray all_sources;
-
- // Select a source; show the full path name in the status line
- static void SelectSourceCB(Widget w, XtPointer, XtPointer call_data)
- {
- XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data;
- int pos = cbs->item_position;
- ListSetAndSelectPos(w, pos);
-
- pos--;
- if (pos < 0)
- pos = all_sources.size() - 1;
- set_status(all_sources[pos]);
- }
-
- // Get list of sources into SOURCES_LIST
- void get_gdb_sources(StringArray& sources_list)
- {
- static StringArray empty;
- sources_list = empty;
-
- // Load all shared libraries first. Otherwise, their sources
- // won't show up in `info sources'.
- gdb_question("sharedlibrary");
-
- string ans = gdb_question("info sources");
- if (ans != NO_GDB_ANSWER)
- {
- // Create a newline-separated list of sources
- string new_ans;
- while (ans != "")
- {
- string line = ans.before('\n');
- ans = ans.after('\n');
-
- if (line == "" || line.contains(':', -1))
- continue;
-
- line.gsub(", ", "\n");
- new_ans += line + '\n';
- }
-
- ans = new_ans;
- while (ans != "")
- {
- string line = ans.before('\n');
- ans = ans.after('\n');
-
- sources_list += line;
- }
-
- smart_sort(sources_list);
- uniq(sources_list);
- }
- }
-
- // Remove adjacent duplicates in A1
- static void uniq(StringArray& a1, StringArray& a2)
- {
- StringArray b1;
- StringArray b2;
-
- for (int i = 0; i < a1.size(); i++)
- {
- if (i == 0 || a1[i - 1] != a1[i])
- {
- b1 += a1[i];
- b2 += a2[i];
- }
- }
-
- a1 = b1;
- a2 = b2;
- }
-
- // Sort A1 and A2 according to the values in A1
- static void sort(StringArray& a1, StringArray& a2)
- {
- assert(a1.size() == a2.size());
-
- // Shell sort -- simple and fast
- int h = 1;
- do {
- h = h * 3 + 1;
- } while (h <= a1.size());
- do {
- h /= 3;
- for (int i = h; i < a1.size(); i++)
- {
- string v1 = a1[i];
- string v2 = a2[i];
- int j;
- for (j = i; j >= h && smart_compare(a1[j - h], v1) > 0; j -= h)
- {
- a1[j] = a1[j - h];
- a2[j] = a2[j - h];
- }
- if (i != j)
- {
- a1[j] = v1;
- a2[j] = v2;
- }
- }
- } while (h != 1);
- }
-
- static void filter_sources(StringArray& labels, StringArray& sources,
- const string& pattern)
- {
- assert(labels.size() == sources.size());
-
- StringArray new_labels;
- StringArray new_sources;
-
- for (int i = 0; i < labels.size(); i++)
- {
- if (glob_match(pattern, labels[i], 0) ||
- glob_match(pattern, sources[i], 0))
- {
- new_labels += labels[i];
- new_sources += sources[i];
- }
- }
-
- labels = new_labels;
- sources = new_sources;
- }
-
- static void update_sources(Widget sources, Widget filter)
- {
- StatusDelay delay("Getting sources");
- get_gdb_sources(all_sources);
-
- String pattern_s = XmTextFieldGetString(filter);
- string pattern = pattern_s;
- XtFree(pattern_s);
-
- strip_space(pattern);
- if (pattern == "")
- pattern = "*";
- XmTextFieldSetString(filter, (char *)pattern);
-
- StringArray labels;
- uniquify(all_sources, labels);
-
- // Sort and remove duplicates
- sort(labels, all_sources);
- uniq(labels, all_sources);
-
- // Filter pattern
- filter_sources(labels, all_sources, pattern);
-
- // Now set the selection.
- bool *selected = new bool[labels.size()];
- for (int i = 0; i < labels.size(); i++)
- selected[i] = false;
-
- setLabelList(sources, labels.values(),
- selected, labels.size(), false, false);
-
- delete[] selected;
- }
-
- // OK pressed in `Lookup Source'
- static void lookupSourceDone(Widget w,
- XtPointer client_data,
- XtPointer call_data)
- {
- Widget sources = Widget(client_data);
- XmSelectionBoxCallbackStruct *cbs =
- (XmSelectionBoxCallbackStruct *)call_data;
-
- set_status("");
-
- string source = get_item(w, client_data, call_data);
-
- if (source.contains('/'))
- {
- // Expand to full path name
- int *position_list = 0;
- int position_count = 0;
- if (XmListGetSelectedPos(sources, &position_list, &position_count))
- {
- if (position_count == 1)
- {
- int pos = position_list[0];
- pos--;
- if (pos < 0)
- pos = all_sources.size() - 1;
- source = all_sources[pos];
- }
-
- XtFree((char *)position_list);
- }
- }
-
- if (source != "")
- {
- source_view->lookup(source + ":1");
-
- if (cbs != 0 &&
- cbs->reason != XmCR_APPLY &&
- cbs->reason != XmCR_ACTIVATE)
- {
- Widget scroll = XtParent(sources);
- Widget dialog = XtParent(scroll);
- XtUnmanageChild(dialog);
- }
- }
- }
-
- static void open_source_msg()
- {
- set_status("Open Source is an idea whose time has finally come. "
- "See http://www.opensource.org/.");
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Entry Points
- //-----------------------------------------------------------------------------
-
- void gdbOpenFileCB(Widget w, XtPointer, XtPointer)
- {
- static Widget dialog =
- create_file_dialog(w, "exec_files",
- searchRemoteExecFiles,
- searchRemoteDirectories,
- searchLocalExecFiles, 0,
- openFileDone);
- manage_and_raise(dialog);
- }
-
- void gdbOpenRecentCB(Widget, XtPointer client_data, XtPointer)
- {
- int index = ((int)(long)client_data) - 1;
-
- StringArray recent_files;
- get_recent(recent_files);
-
- if (index >= 0 && index < recent_files.size())
- {
- string file = recent_files[index];
- open_file(file);
- // This is a kludge as I don't [yet] understand how to force the
- // reading of the source file automatically, as is done when an
- // compiled executable is opened.
- if (gdb->type() == PYDB)
- source_view->read_file(file);
- }
- }
-
- void gdbOpenCoreCB(Widget w, XtPointer, XtPointer)
- {
- static Widget dialog =
- create_file_dialog(w, "core_files",
- searchRemoteCoreFiles, searchRemoteDirectories,
- searchLocalCoreFiles, 0,
- openCoreDone);
- manage_and_raise(dialog);
- warn_if_no_program(dialog);
- }
-
- void gdbOpenSourceCB(Widget w, XtPointer, XtPointer)
- {
- static Widget dialog =
- create_file_dialog(w, "source_files",
- searchRemoteSourceFiles, searchRemoteDirectories,
- searchLocalSourceFiles, 0,
- openSourceDone);
- manage_and_raise(dialog);
-
- open_source_msg();
-
- if ((gdb->type() != JDB) && (gdb->type() != PYDB))
- {
- warn_if_no_program(dialog);
- }
- else
- {
- // JDB works well without executable
- // PYDB doesn't use an executable
- }
- }
-
- void gdbOpenProcessCB(Widget w, XtPointer, XtPointer)
- {
- static Widget dialog = 0;
- static Widget processes = 0;
-
- if (dialog == 0)
- {
- Arg args[10];
- int arg = 0;
-
- XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
- dialog = verify(XmCreateSelectionDialog(find_shell(w),
- "processes", args, arg));
-
- Delay::register_shell(dialog);
-
- XtUnmanageChild(XmSelectionBoxGetChild(dialog,
- XmDIALOG_SELECTION_LABEL));
- XtUnmanageChild(XmSelectionBoxGetChild(dialog,
- XmDIALOG_TEXT));
-
- processes = XmSelectionBoxGetChild(dialog, XmDIALOG_LIST);
-
- XtAddCallback(processes, XmNsingleSelectionCallback,
- SelectProcessCB, XtPointer(processes));
- XtAddCallback(processes, XmNmultipleSelectionCallback,
- SelectProcessCB, XtPointer(processes));
- XtAddCallback(processes, XmNextendedSelectionCallback,
- SelectProcessCB, XtPointer(processes));
- XtAddCallback(processes, XmNbrowseSelectionCallback,
- SelectProcessCB, XtPointer(processes));
-
- XtAddCallback(dialog, XmNokCallback,
- openProcessDone, XtPointer(processes));
- XtAddCallback(dialog, XmNapplyCallback,
- gdbUpdateProcessesCB, XtPointer(processes));
- XtAddCallback(dialog, XmNcancelCallback,
- UnmanageThisCB, XtPointer(dialog));
- XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, 0);
- }
-
- update_processes(processes, false);
- manage_and_raise(dialog);
- warn_if_no_program(dialog);
- }
-
- void gdbOpenClassCB(Widget w, XtPointer, XtPointer)
- {
- static Widget dialog = 0;
- static Widget classes = 0;
-
- if (dialog == 0)
- {
- Arg args[10];
- int arg = 0;
-
- XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
- dialog = verify(XmCreateSelectionDialog(find_shell(w),
- "classes", args, arg));
-
- Delay::register_shell(dialog);
-
- XtUnmanageChild(XmSelectionBoxGetChild(dialog,
- XmDIALOG_SELECTION_LABEL));
- XtUnmanageChild(XmSelectionBoxGetChild(dialog,
- XmDIALOG_TEXT));
-
- classes = XmSelectionBoxGetChild(dialog, XmDIALOG_LIST);
-
- XtAddCallback(classes, XmNsingleSelectionCallback,
- SelectClassCB, XtPointer(classes));
- XtAddCallback(classes, XmNmultipleSelectionCallback,
- SelectClassCB, XtPointer(classes));
- XtAddCallback(classes, XmNextendedSelectionCallback,
- SelectClassCB, XtPointer(classes));
- XtAddCallback(classes, XmNbrowseSelectionCallback,
- SelectClassCB, XtPointer(classes));
-
- XtAddCallback(dialog, XmNokCallback,
- openClassDone, XtPointer(classes));
- XtAddCallback(dialog, XmNapplyCallback,
- gdbUpdateClassesCB, XtPointer(classes));
- XtAddCallback(dialog, XmNcancelCallback,
- UnmanageThisCB, XtPointer(dialog));
- XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, 0);
- }
-
- update_classes(classes);
- manage_and_raise(dialog);
- }
-
- static Widget source_list = 0;
- static Widget source_filter = 0;
-
- void update_sources()
- {
- if (source_list != 0)
- update_sources(source_list, source_filter);
- }
-
- static void FilterSourcesCB(Widget, XtPointer, XtPointer)
- {
- update_sources();
- }
-
- void gdbLookupSourceCB(Widget w, XtPointer client_data, XtPointer call_data)
- {
- if (gdb->type() != GDB)
- {
- gdbOpenSourceCB(w, client_data, call_data);
- return;
- }
-
- static Widget dialog = 0;
-
- if (dialog == 0)
- {
- Arg args[10];
- int arg = 0;
-
- XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
- #if XmVersion >= 1002
- XtSetArg(args[arg], XmNchildPlacement, XmPLACE_TOP); arg++;
- #endif
- dialog = verify(XmCreateSelectionDialog(find_shell(w),
- "sources", args, arg));
-
- Delay::register_shell(dialog);
-
- XtUnmanageChild(XmSelectionBoxGetChild(dialog,
- XmDIALOG_SELECTION_LABEL));
- XtUnmanageChild(XmSelectionBoxGetChild(dialog,
- XmDIALOG_TEXT));
-
- arg = 0;
- XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
- XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
- XtSetArg(args[arg], XmNborderWidth, 0); arg++;
- XtSetArg(args[arg], XmNadjustMargin, False); arg++;
- XtSetArg(args[arg], XmNshadowThickness, 0); arg++;
- XtSetArg(args[arg], XmNspacing, 0); arg++;
- Widget box = XmCreateRowColumn(dialog, "box", args, arg);
- XtManageChild(box);
-
- arg = 0;
- Widget label = XmCreateLabel(box, "label", args, arg);
- XtManageChild(label);
-
- arg = 0;
- source_filter = XmCreateTextField(box, "filter", args, arg);
- XtManageChild(source_filter);
-
- #if XmVersion >= 1002
- arg = 0;
- Widget lookup = XmCreatePushButton(dialog, "lookup", args, arg);
- XtManageChild(lookup);
- #endif
-
- source_list = XmSelectionBoxGetChild(dialog, XmDIALOG_LIST);
-
- XtAddCallback(source_list, XmNsingleSelectionCallback,
- SelectSourceCB, XtPointer(source_list));
- XtAddCallback(source_list, XmNmultipleSelectionCallback,
- SelectSourceCB, XtPointer(source_list));
- XtAddCallback(source_list, XmNextendedSelectionCallback,
- SelectSourceCB, XtPointer(source_list));
- XtAddCallback(source_list, XmNbrowseSelectionCallback,
- SelectSourceCB, XtPointer(source_list));
-
- XtAddCallback(dialog, XmNokCallback,
- lookupSourceDone, XtPointer(source_list));
- XtAddCallback(dialog, XmNapplyCallback, FilterSourcesCB, 0);
- XtAddCallback(dialog, XmNcancelCallback,
- UnmanageThisCB, XtPointer(dialog));
- XtAddCallback(dialog, XmNunmapCallback, ClearStatusCB, 0);
- XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, 0);
-
- XtAddCallback(source_filter, XmNactivateCallback,
- FilterSourcesCB, 0);
-
- #if XmVersion >= 1002
- XtAddCallback(lookup, XmNactivateCallback,
- lookupSourceDone, XtPointer(source_list));
- #endif
- }
-
- update_sources(source_list, source_filter);
-
- open_source_msg();
- manage_and_raise(dialog);
- warn_if_no_program(dialog);
- }
-