home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / options.C < prev    next >
C/C++ Source or Header  |  1998-11-29  |  73KB  |  2,843 lines

  1. // $Id: options.C,v 1.154 1998/11/29 09:54:07 zeller Exp $ -*- C++ -*-
  2. // Save and edit DDD options
  3.  
  4. // Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char options_rcsid[] = 
  30.     "$Id: options.C,v 1.154 1998/11/29 09:54:07 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "options.h"
  37.  
  38. #include "config.h"
  39.  
  40. #include "AppData.h"
  41. #include "DataDisp.h"
  42. #include "DestroyCB.h"
  43. #include "GDBAgent.h"
  44. #include "GraphEdit.h"
  45. #include "SourceView.h"
  46. #include "TimeOut.h"
  47. #include "UndoBuffer.h"
  48. #include "cook.h"
  49. #include "Command.h"
  50. #include "comm-manag.h"
  51. #include "ddd.h"
  52. #include "file.h"
  53. #include "filetype.h"
  54. #include "frame.h"
  55. #include "gdbinit.h"
  56. #include "plotter.h"
  57. #include "post.h"
  58. #include "resources.h"
  59. #include "session.h"
  60. #include "settings.h"
  61. #include "shell.h"
  62. #include "status.h"
  63. #include "string-fun.h"
  64. #include "verify.h"
  65. #include "windows.h"
  66. #include "wm.h"
  67.  
  68. #include <Xm/Xm.h>
  69. #include <Xm/Text.h>
  70. #include <Xm/TextF.h>
  71. #include <Xm/ToggleB.h>
  72. #include <Xm/Scale.h>
  73. #include <Xm/DialogS.h>
  74. #include <Xm/BulletinB.h>
  75. #include <Xm/MessageB.h>
  76. #include <Xm/PanedW.h>
  77.  
  78. #include <stdio.h>
  79. #include <fstream.h>
  80. #include <unistd.h>
  81. #include <errno.h>
  82. #include <string.h>        // strerror
  83. #include <time.h>        // ctime
  84.  
  85. #include <limits.h>
  86. #ifndef ARG_MAX
  87. #define ARG_MAX 4096
  88. #endif
  89.  
  90. #include <signal.h>
  91.  
  92. #if HAVE_PTRACE
  93. extern "C" {
  94. #if HAVE_SYS_PTRACE_H
  95. #include <sys/ptrace.h>
  96. #endif
  97. #if !HAVE_PTRACE_DECL
  98. extern int ptrace(int request, int pid, int addr, int data);
  99. #endif
  100. #if HAVE_SYS_WAIT_H
  101. #include <sys/wait.h>
  102. #endif
  103. }
  104. #endif
  105.  
  106. #if HAVE_LINK && !HAVE_LINK_DECL
  107. extern "C" int link (const char *oldname, const char *newname);
  108. #endif
  109.  
  110. #if HAVE_SYMLINK && !HAVE_SYMLINK_DECL
  111. extern "C" int symlink (const char *oldname, const char *newname);
  112. #endif
  113.  
  114. #if !HAVE_POPEN_DECL
  115. extern "C" FILE *popen(const char *command, const char *mode);
  116. #endif
  117. #if !HAVE_PCLOSE_DECL
  118. extern "C" int pclose(FILE *stream);
  119. #endif
  120.  
  121.  
  122. //-----------------------------------------------------------------------------
  123. // Helper Decls
  124. //-----------------------------------------------------------------------------
  125.  
  126. // If the current state file has changed, return true.
  127. // If MODE is ACKNOWLEDGE, refer to last acknowledgement time.  
  128. // If MODE is ACCESS, refer to last access time (read or write).
  129. // If RESET is given, reset modification time.
  130. enum ChangeMode { ACKNOWLEDGE, ACCESS };
  131. static bool options_file_has_changed(ChangeMode mode, bool reset = false);
  132.  
  133.  
  134. //-----------------------------------------------------------------------------
  135. // Source Options
  136. //-----------------------------------------------------------------------------
  137.  
  138. void sourceToggleFindWordsOnlyCB (Widget, XtPointer, XtPointer call_data)
  139. {
  140.     XmToggleButtonCallbackStruct *info = 
  141.     (XmToggleButtonCallbackStruct *)call_data;
  142.  
  143.     app_data.find_words_only = info->set;
  144.  
  145.     if (info->set)
  146.     set_status("Finding only complete words.");
  147.     else
  148.     set_status("Finding arbitrary occurrences.");
  149.  
  150.     update_options();
  151. }
  152.  
  153. void sourceToggleFindCaseSensitiveCB (Widget, XtPointer, XtPointer call_data)
  154. {
  155.     XmToggleButtonCallbackStruct *info = 
  156.     (XmToggleButtonCallbackStruct *)call_data;
  157.  
  158.     app_data.find_case_sensitive = info->set;
  159.  
  160.     if (info->set)
  161.     set_status("Case-sensitive search enabled.");
  162.     else
  163.     set_status("Case-sensitive search disabled.");
  164.  
  165.     update_options();
  166. }
  167.  
  168. void sourceToggleCacheSourceFilesCB (Widget, XtPointer, XtPointer call_data)
  169. {
  170.     XmToggleButtonCallbackStruct *info = 
  171.     (XmToggleButtonCallbackStruct *)call_data;
  172.  
  173.     app_data.cache_source_files = info->set;
  174.  
  175.     if (info->set)
  176.     set_status("Caching source texts.");
  177.     else
  178.     set_status("Not caching source texts.  "
  179.            "Source text cache has been cleared.");
  180.  
  181.     update_options();
  182. }
  183.  
  184. void sourceToggleCacheMachineCodeCB (Widget, XtPointer, XtPointer call_data)
  185. {
  186.     XmToggleButtonCallbackStruct *info = 
  187.     (XmToggleButtonCallbackStruct *)call_data;
  188.  
  189.     app_data.cache_machine_code = info->set;
  190.  
  191.     update_options();
  192.  
  193.     if (info->set)
  194.     set_status("Caching machine code.");
  195.     else
  196.     set_status("Not caching machine code.  "
  197.            "Machine code cache has been cleared.");
  198. }
  199.  
  200. void sourceToggleDisplayLineNumbersCB (Widget, XtPointer, XtPointer call_data)
  201. {
  202.     XmToggleButtonCallbackStruct *info = 
  203.     (XmToggleButtonCallbackStruct *)call_data;
  204.  
  205.     app_data.display_line_numbers = info->set;
  206.     update_options();
  207.  
  208. #if 0
  209.     if (info->set)
  210.     set_status("Displaying line numbers.");
  211.     else
  212.     set_status("Not displaying line numbers.");
  213. #endif
  214. }
  215.  
  216. void sourceSetUseSourcePathCB (Widget, XtPointer client_data, XtPointer)
  217. {
  218.     Boolean state = (int)(long)client_data;
  219.  
  220.     app_data.use_source_path = state;
  221.     string referring_to_sources_using =
  222.     "Referring to sources using ";
  223.  
  224.     if (state)
  225.     set_status(referring_to_sources_using + "full source file paths.");
  226.     else
  227.     set_status(referring_to_sources_using + "source file base names.");
  228.  
  229.     source_arg->set_string(source_view->line_of_cursor());
  230.     update_options();
  231. }
  232.  
  233. void sourceSetDisplayGlyphsCB (Widget, XtPointer client_data, XtPointer)
  234. {
  235.     Boolean state = (int)(long)client_data;
  236.  
  237.     app_data.display_glyphs = state;
  238.  
  239.     update_options();
  240.  
  241.     string displaying =    "Displaying breakpoints and positions ";
  242.     if (state)
  243.     set_status(displaying + "as glyphs.");
  244.     else
  245.     set_status(displaying + "as text characters.");
  246. }
  247.  
  248. void sourceToggleAllRegistersCB (Widget, XtPointer, XtPointer call_data)
  249. {
  250.     XmToggleButtonCallbackStruct *info = 
  251.     (XmToggleButtonCallbackStruct *)call_data;
  252.  
  253.     app_data.all_registers = info->set;
  254.  
  255.     if (info->set)
  256.     set_status("Showing all registers.");
  257.     else
  258.     set_status("Showing integer registers only.");
  259.  
  260.     update_options();
  261. }
  262.  
  263. void sourceSetTabWidthCB (Widget, XtPointer, XtPointer call_data)
  264. {
  265.     XmScaleCallbackStruct *info = (XmScaleCallbackStruct *)call_data;
  266.  
  267.     app_data.tab_width = info->value;
  268.     update_options();
  269.  
  270.     set_status("Tab width set to " + itostring(app_data.tab_width) + ".");
  271. }
  272.  
  273. void sourceSetSourceIndentCB (Widget, XtPointer, XtPointer call_data)
  274. {
  275.     XmScaleCallbackStruct *info = (XmScaleCallbackStruct *)call_data;
  276.  
  277.     app_data.indent_source = info->value;
  278.     update_options();
  279.  
  280.     set_status("Source indentation set to " + 
  281.            itostring(app_data.indent_source) + ".");
  282. }
  283.  
  284. void sourceSetCodeIndentCB (Widget, XtPointer, XtPointer call_data)
  285. {
  286.     XmScaleCallbackStruct *info = (XmScaleCallbackStruct *)call_data;
  287.  
  288.     app_data.indent_code = info->value;
  289.     update_options();
  290.  
  291.     set_status("Code indentation set to " + 
  292.            itostring(app_data.indent_code) + ".");
  293. }
  294.  
  295. //-----------------------------------------------------------------------------
  296. // Graph Options
  297. //-----------------------------------------------------------------------------
  298.  
  299. void graphToggleDetectAliasesCB(Widget, XtPointer, XtPointer call_data)
  300. {
  301.     XmToggleButtonCallbackStruct *info = 
  302.     (XmToggleButtonCallbackStruct *)call_data;
  303.  
  304.     app_data.detect_aliases = info->set;
  305.     string alias_detection = "Alias detection ";
  306.  
  307.     if (info->set)
  308.     set_status(alias_detection + "enabled.");
  309.     else
  310.     set_status(alias_detection + "disabled.");
  311.  
  312.     update_options();
  313. }
  314.  
  315. void graphToggleAlign2dArraysCB(Widget, XtPointer, XtPointer call_data)
  316. {
  317.     XmToggleButtonCallbackStruct *info = 
  318.     (XmToggleButtonCallbackStruct *)call_data;
  319.  
  320.     app_data.align_2d_arrays = info->set;
  321.     string displaying_arrays_as = 
  322.     "Two-dimensional arrays will be displayed as ";
  323.  
  324.     if (info->set)
  325.     set_status(displaying_arrays_as + "tables.");
  326.     else
  327.     set_status(displaying_arrays_as + "nested one-dimensional arrays.");
  328.  
  329.     update_options();
  330. }
  331.  
  332. void graphToggleShowHintsCB(Widget, XtPointer, XtPointer call_data)
  333. {
  334.     XmToggleButtonCallbackStruct *info = 
  335.     (XmToggleButtonCallbackStruct *)call_data;
  336.  
  337.     Arg args[10];
  338.     Cardinal arg = 0;
  339.     XtSetArg(args[arg], XtNshowHints, info->set); arg++;
  340.     XtSetValues(data_disp->graph_edit, args, arg);
  341.  
  342.     if (info->set)
  343.     set_status("Hints on.");
  344.     else
  345.     set_status("Hints off.");
  346.  
  347.     update_options();
  348. }
  349.  
  350. void graphToggleShowAnnotationsCB(Widget, XtPointer, XtPointer call_data)
  351. {
  352.     XmToggleButtonCallbackStruct *info = 
  353.     (XmToggleButtonCallbackStruct *)call_data;
  354.  
  355.     Arg args[10];
  356.     Cardinal arg = 0;
  357.     XtSetArg(args[arg], XtNshowAnnotations, info->set); arg++;
  358.     XtSetValues(data_disp->graph_edit, args, arg);
  359.  
  360.     if (info->set)
  361.     set_status("Annotations on.");
  362.     else
  363.     set_status("Annotations off.");
  364.  
  365.     data_disp->refresh_titles();
  366.  
  367.     update_options();
  368. }
  369.  
  370. void graphToggleShowDependentTitlesCB(Widget, XtPointer, XtPointer call_data)
  371. {
  372.     XmToggleButtonCallbackStruct *info = 
  373.     (XmToggleButtonCallbackStruct *)call_data;
  374.  
  375.     app_data.show_dependent_display_titles = info->set;
  376.     if (info->set)
  377.     set_status("Dependent titles on.");
  378.     else
  379.     set_status("Dependent titles off.");
  380.  
  381.     data_disp->refresh_titles();
  382.  
  383.     update_options();
  384. }
  385.  
  386. void graphToggleClusterDisplaysCB(Widget, XtPointer, XtPointer call_data)
  387. {
  388.     XmToggleButtonCallbackStruct *info = 
  389.     (XmToggleButtonCallbackStruct *)call_data;
  390.  
  391.     app_data.cluster_displays = info->set;
  392.  
  393.     if (info->set)
  394.     set_status("Display clustering enabled.");
  395.     else
  396.     set_status("Display clustering disabled.");
  397.  
  398.     update_options();
  399. }
  400.  
  401. void graphToggleSnapToGridCB(Widget, XtPointer, XtPointer call_data)
  402. {
  403.     XmToggleButtonCallbackStruct *info = 
  404.     (XmToggleButtonCallbackStruct *)call_data;
  405.  
  406.     Arg args[10];
  407.     Cardinal arg = 0;
  408.     XtSetArg(args[arg], XtNsnapToGrid, info->set); arg++;
  409.     XtSetValues(data_disp->graph_edit, args, arg);
  410.  
  411.     if (info->set)
  412.     set_status("Snap to grid on.");
  413.     else
  414.     set_status("Snap to grid off.");
  415.  
  416.     update_options();
  417. }
  418.  
  419.  
  420. void graphToggleCompactLayoutCB(Widget, XtPointer, XtPointer call_data)
  421. {
  422.     XmToggleButtonCallbackStruct *info = 
  423.     (XmToggleButtonCallbackStruct *)call_data;
  424.  
  425.     LayoutMode mode = RegularLayoutMode;
  426.     if (info->set)
  427.     mode = CompactLayoutMode;
  428.  
  429.     Arg args[10];
  430.     Cardinal arg = 0;
  431.     XtSetArg(args[arg], XtNlayoutMode, mode); arg++;
  432.     XtSetValues(data_disp->graph_edit, args, arg);
  433.  
  434.     if (info->set)
  435.     set_status("Compact layout enabled.");
  436.     else
  437.     set_status("Regular layout enabled.");
  438.  
  439.     update_options();
  440. }
  441.  
  442. void graphToggleAutoLayoutCB(Widget, XtPointer, XtPointer call_data)
  443. {
  444.     XmToggleButtonCallbackStruct *info = 
  445.     (XmToggleButtonCallbackStruct *)call_data;
  446.  
  447.     Arg args[10];
  448.     Cardinal arg = 0;
  449.     XtSetArg(args[arg], XtNautoLayout, info->set); arg++;
  450.     XtSetValues(data_disp->graph_edit, args, arg);
  451.  
  452.     if (info->set)
  453.     set_status("Automatic layout on.");
  454.     else
  455.     set_status("Automatic layout off.");
  456.  
  457.     update_options();
  458. }
  459.  
  460. void graphToggleAutoCloseCB(Widget, XtPointer, XtPointer call_data)
  461. {
  462.     XmToggleButtonCallbackStruct *info = 
  463.     (XmToggleButtonCallbackStruct *)call_data;
  464.  
  465.     app_data.auto_close_data_window = info->set;
  466.  
  467.     if (info->set)
  468.     set_status("Automatic closing on.");
  469.     else
  470.     set_status("Automatic closing off.");
  471.  
  472.     update_options();
  473. }
  474.  
  475. void graphSetGridSizeCB (Widget, XtPointer, XtPointer call_data)
  476. {
  477.     XmScaleCallbackStruct *info = (XmScaleCallbackStruct *)call_data;
  478.  
  479.     Arg args[10];
  480.     Cardinal arg = 0;
  481.  
  482.     if (info->value >= 2)
  483.     {
  484.     XtSetArg(args[arg], XtNgridWidth,  info->value); arg++;
  485.     XtSetArg(args[arg], XtNgridHeight, info->value); arg++;
  486.     XtSetArg(args[arg], XtNshowGrid,   True); arg++;
  487.     XtSetValues(data_disp->graph_edit, args, arg);
  488.     set_status("Grid size set to " + itostring(info->value) + ".");
  489.     }
  490.     else
  491.     {
  492.     XtSetArg(args[arg], XtNshowGrid, False); arg++;
  493.     XtSetValues(data_disp->graph_edit, args, arg);
  494.     set_status("Grid off.");
  495.     }
  496.  
  497.     update_options();
  498. }
  499.  
  500. //-----------------------------------------------------------------------------
  501. // General Options
  502. //-----------------------------------------------------------------------------
  503.  
  504. void dddToggleGroupIconifyCB (Widget, XtPointer, XtPointer call_data)
  505. {
  506.     XmToggleButtonCallbackStruct *info = 
  507.     (XmToggleButtonCallbackStruct *)call_data;
  508.  
  509.     app_data.group_iconify = info->set;
  510.     string ddd_windows_are_iconified = 
  511.     DDD_NAME " windows are iconified ";
  512.  
  513.     if (info->set)
  514.     set_status(ddd_windows_are_iconified + "as a group.");
  515.     else
  516.     set_status(ddd_windows_are_iconified + "separately.");
  517.  
  518.     update_options();
  519. }
  520.  
  521. void dddToggleUniconifyWhenReadyCB (Widget, XtPointer, XtPointer call_data)
  522. {
  523.     XmToggleButtonCallbackStruct *info = 
  524.     (XmToggleButtonCallbackStruct *)call_data;
  525.  
  526.     app_data.uniconify_when_ready = info->set;
  527.  
  528.     if (info->set)
  529.     set_status(DDD_NAME " windows will be uniconified automatically "
  530.            "whenever " DDD_NAME " becomes ready.");
  531.     else
  532.     set_status(DDD_NAME " windows always remain iconified.");
  533.  
  534.     update_options();
  535. }
  536.  
  537. void dddSetGlobalTabCompletionCB(Widget, XtPointer client_data, XtPointer)
  538. {
  539.     Boolean state = (int)(long)client_data;
  540.  
  541.     app_data.global_tab_completion = state;
  542.  
  543.     if (state)
  544.     set_status("TAB key completes in all " DDD_NAME " windows.");
  545.     else
  546.     set_status("TAB key completes in " DDD_NAME " debugger console only.");
  547.  
  548.     update_options();
  549. }
  550.  
  551. void dddToggleSeparateExecWindowCB (Widget, XtPointer, XtPointer call_data)
  552. {
  553.     XmToggleButtonCallbackStruct *info = 
  554.     (XmToggleButtonCallbackStruct *)call_data;
  555.  
  556.     app_data.separate_exec_window = info->set;
  557.     string debugged_program_will_be_executed_in =
  558.     "Debugged program will be executed in ";
  559.  
  560.     if (info->set)
  561.     set_status(debugged_program_will_be_executed_in 
  562.            + "a separate execution window.");
  563.     else
  564.     set_status(debugged_program_will_be_executed_in 
  565.            + "the " DDD_NAME " debugger console.");
  566.  
  567.     update_options();
  568. }
  569.  
  570. void dddToggleCheckGrabsCB (Widget, XtPointer, XtPointer call_data)
  571. {
  572.     XmToggleButtonCallbackStruct *info = 
  573.     (XmToggleButtonCallbackStruct *)call_data;
  574.  
  575.     app_data.check_grabs = info->set;
  576.  
  577.     if (info->set)
  578.     set_status("Checking for grabs.");
  579.     else
  580.     set_status("Not checking for grabs.");
  581.  
  582.     update_options();
  583. }
  584.  
  585. void dddToggleSaveHistoryOnExitCB (Widget, XtPointer, XtPointer call_data)
  586. {
  587.     XmToggleButtonCallbackStruct *info = 
  588.     (XmToggleButtonCallbackStruct *)call_data;
  589.  
  590.     app_data.save_history_on_exit = info->set;
  591.  
  592.     if (info->set)
  593.     set_status("History will be saved when " DDD_NAME " exits.");
  594.     else
  595.     set_status("History will not be saved.");
  596.  
  597.     update_options();
  598. }
  599.  
  600. void dddToggleSuppressWarningsCB (Widget, XtPointer, XtPointer call_data)
  601. {
  602.     XmToggleButtonCallbackStruct *info = 
  603.     (XmToggleButtonCallbackStruct *)call_data;
  604.  
  605.     app_data.suppress_warnings = info->set;
  606.  
  607.     if (info->set)
  608.     set_status("X Warnings are suppressed.");
  609.     else
  610.     set_status("X Warnings are not suppressed.");
  611.  
  612.     update_options();
  613. }
  614.  
  615. void dddToggleWarnIfLockedCB (Widget, XtPointer, XtPointer call_data)
  616. {
  617.     XmToggleButtonCallbackStruct *info = 
  618.     (XmToggleButtonCallbackStruct *)call_data;
  619.  
  620.     app_data.warn_if_locked = info->set;
  621.  
  622.     if (info->set)
  623.     set_status(DDD_NAME " will warn you "
  624.            "when multiple " DDD_NAME " instances are running.");
  625.     else
  626.     set_status(DDD_NAME " will not warn you "
  627.            "when multiple " DDD_NAME " instances are running.");
  628.  
  629.     update_options();
  630. }
  631.  
  632. void dddSetBuiltinPlotWindowCB (Widget, XtPointer client_data, XtPointer)
  633. {
  634.     if ((int)(long)client_data)
  635.     app_data.plot_term_type = "xlib";
  636.     else
  637.     app_data.plot_term_type = "x11";
  638.  
  639.     string plot_term_type = downcase(app_data.plot_term_type);
  640.  
  641.     if (plot_term_type.contains("xlib", 0))
  642.     {
  643.     set_status("Next plot will be done in builtin " DDD_NAME " window.");
  644.     }
  645.     else if (plot_term_type.contains("x11", 0))
  646.     {
  647.     set_status("Next plot will be done in external " + 
  648.            cook(app_data.plot_window_class) + " window.");
  649.     }
  650.     else
  651.     {
  652.     set_status("Next plot will be done in an unknown place.");
  653.     }
  654.  
  655.     clear_plot_window_cache();
  656.     update_options();
  657. }
  658.  
  659. void dddToggleButtonTipsCB (Widget, XtPointer, XtPointer call_data)
  660. {
  661.     XmToggleButtonCallbackStruct *info = 
  662.     (XmToggleButtonCallbackStruct *)call_data;
  663.  
  664.     app_data.button_tips = info->set;
  665.  
  666.     if (info->set)
  667.     set_status("Button tips enabled.");
  668.     else
  669.     set_status("Button tips disabled.");
  670.  
  671.     update_options();
  672. }
  673.  
  674. void dddToggleValueTipsCB (Widget, XtPointer, XtPointer call_data)
  675. {
  676.     XmToggleButtonCallbackStruct *info = 
  677.     (XmToggleButtonCallbackStruct *)call_data;
  678.  
  679.     app_data.value_tips = info->set;
  680.  
  681.     if (info->set)
  682.     set_status("Value tips enabled.");
  683.     else
  684.     set_status("Value tips disabled.");
  685.  
  686.     update_options();
  687. }
  688.  
  689. void dddToggleButtonDocsCB (Widget, XtPointer, XtPointer call_data)
  690. {
  691.     XmToggleButtonCallbackStruct *info = 
  692.     (XmToggleButtonCallbackStruct *)call_data;
  693.  
  694.     app_data.button_docs = info->set;
  695.  
  696.     if (info->set)
  697.     set_status("Button docs enabled.");
  698.     else
  699.     set_status("Button docs disabled.");
  700.  
  701.     update_options();
  702. }
  703.  
  704. void dddToggleValueDocsCB (Widget, XtPointer, XtPointer call_data)
  705. {
  706.     XmToggleButtonCallbackStruct *info = 
  707.     (XmToggleButtonCallbackStruct *)call_data;
  708.  
  709.     app_data.value_docs = info->set;
  710.  
  711.     if (info->set)
  712.     set_status("Value docs enabled.");
  713.     else
  714.     set_status("Value docs disabled.");
  715.  
  716.     update_options();
  717. }
  718.  
  719.  
  720. //-----------------------------------------------------------------------------
  721. // Maintenance
  722. //-----------------------------------------------------------------------------
  723.  
  724. void dddSetCrashCB(Widget, XtPointer client_data, XtPointer)
  725. {
  726.     int state = (int)(long)client_data;
  727.     string msg = "When " DDD_NAME " crashes, ";
  728.  
  729.     switch (state)
  730.     {
  731.     case 0:
  732.     app_data.dump_core        = False;
  733.     app_data.debug_core_dumps = False;
  734.     msg += "do nothing.";
  735.     break;
  736.  
  737.     case 1:
  738.     app_data.dump_core        = True;
  739.     app_data.debug_core_dumps = False;
  740.     msg += "dump core.";
  741.     break;
  742.  
  743.     case 2:
  744.     app_data.dump_core        = True;
  745.     app_data.debug_core_dumps = True;
  746.     msg += "dump core and invoke a debugger.";
  747.     break;
  748.     }
  749.  
  750.     set_status(msg);
  751.     update_options();
  752. }
  753.  
  754. void dddClearMaintenanceCB(Widget, XtPointer, XtPointer)
  755. {
  756.     app_data.maintenance = False;
  757.     update_options();
  758. }
  759.  
  760.  
  761. //-----------------------------------------------------------------------------
  762. // Startup Options
  763. //-----------------------------------------------------------------------------
  764.  
  765. static void post_startup_warning(Widget w)
  766. {
  767. #if 0
  768.     static bool posted = false;
  769.  
  770.     if (!posted)
  771.     post_warning("This change will only be effective\n"
  772.              "after saving options and restarting " DDD_NAME ".",
  773.              "startup_warning", w);
  774.  
  775.     posted = true;
  776. #endif
  777.     (void) w;            // Use it
  778. }
  779.  
  780. static string next_ddd_will_start_with = 
  781.     "Next " DDD_NAME " invocation will start-up with ";
  782.  
  783. void dddSetSeparateWindowsCB (Widget w, XtPointer client_data, XtPointer)
  784. {
  785.     int state = (int)(long)client_data;
  786.     switch (state)
  787.     {
  788.     case 0:
  789.     app_data.separate_data_window   = True;
  790.     app_data.separate_source_window = True;
  791.     app_data.common_toolbar         = False;
  792.     break;
  793.  
  794.     case 1:
  795.     app_data.separate_data_window   = False;
  796.     app_data.separate_source_window = False;
  797.     app_data.common_toolbar         = True;
  798.     break;
  799.  
  800.     case 2:
  801.     app_data.separate_data_window   = False;
  802.     app_data.separate_source_window = False;
  803.     app_data.common_toolbar         = False;
  804.     break;
  805.     }
  806.  
  807.     if (app_data.separate_data_window || app_data.separate_source_window)
  808.     set_status(next_ddd_will_start_with + "separate windows.");
  809.     else if (app_data.common_toolbar)
  810.     set_status(next_ddd_will_start_with + "one window, one toolbar.");
  811.     else
  812.     set_status(next_ddd_will_start_with + "one window, two toolbars.");
  813.  
  814.     update_options();
  815.     post_startup_warning(w);
  816. }
  817.  
  818. void dddSetStatusAtBottomCB (Widget w, XtPointer client_data, XtPointer)
  819. {
  820.     Boolean state = (int)(long)client_data;
  821.  
  822.     app_data.status_at_bottom = state;
  823.  
  824.     if (state)
  825.     set_status(next_ddd_will_start_with + "status line at bottom.");
  826.     else
  827.     set_status(next_ddd_will_start_with + "status line at top.");
  828.  
  829.     update_options();
  830.     post_startup_warning(w);
  831. }
  832.  
  833. void dddSetToolBarCB (Widget w, XtPointer client_data, XtPointer)
  834. {
  835.     Boolean state = (int)(long)client_data;
  836.  
  837.     app_data.command_toolbar = state;
  838.     string tool_buttons_are_located_in = "Tool buttons are located in ";
  839.  
  840.     if (state)
  841.     set_status(tool_buttons_are_located_in + "command toolbar.");
  842.     else
  843.     set_status(tool_buttons_are_located_in + "command tool.");
  844.  
  845.     update_options();
  846.     post_startup_warning(w);
  847. }
  848.  
  849. void dddSetKeyboardFocusPolicyCB (Widget w, XtPointer client_data, XtPointer)
  850. {
  851.     unsigned char policy = (unsigned char)(int)(long)client_data;
  852.  
  853.     if (policy != XmEXPLICIT && policy != XmPOINTER)
  854.     return;
  855.  
  856.     StatusDelay delay(policy == XmEXPLICIT ?
  857.               "Setting click-to-type keyboard focus policy" :
  858.               "Setting pointer-driven keyboard focus policy");
  859.  
  860.     if (policy == XmPOINTER)
  861.     {
  862.     // Leave old focus on the default button
  863.     Widget default_button = 0;
  864.  
  865.     Widget bulletin_board = w;
  866.     while (bulletin_board != 0 && 
  867.            !XtIsSubclass(bulletin_board, xmBulletinBoardWidgetClass))
  868.         bulletin_board = XtParent(bulletin_board);
  869.  
  870.     if (bulletin_board != 0)
  871.     {
  872.         XtVaGetValues(bulletin_board, 
  873.               XmNdefaultButton, &default_button, NULL);
  874.     }
  875.  
  876.     if (default_button == 0)
  877.         default_button = w;
  878.  
  879.     XmProcessTraversal(default_button, XmTRAVERSE_CURRENT);
  880.     }
  881.  
  882.     // Apply to existing shells
  883.     const WidgetArray& shells = Delay::shells();
  884.     for (int i = 0; i < shells.size(); i++)
  885.     {
  886.     Widget shell = shells[i];
  887.     while (shell != 0 && !XtIsSubclass(shell, vendorShellWidgetClass))
  888.         shell = XtParent(shell);
  889.     if (shell != 0)
  890.         XtVaSetValues(shell, XmNkeyboardFocusPolicy, policy, NULL);
  891.     }
  892.  
  893.     // Apply to future shells
  894.     string keyboardFocusPolicy = "*" + string(XmNkeyboardFocusPolicy);
  895.     XrmDatabase target = XtDatabase(XtDisplay(w));
  896.     switch (policy)
  897.     {
  898.     case XmEXPLICIT:
  899.     XrmPutStringResource(&target, keyboardFocusPolicy, "EXPLICIT");
  900.     break;
  901.  
  902.     case XmPOINTER:
  903.     XrmPutStringResource(&target, keyboardFocusPolicy, "POINTER");
  904.     break;
  905.     }
  906.  
  907.     if (policy == XmEXPLICIT)
  908.     {
  909.     // Place new focus on this button
  910.     XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  911.     }
  912.  
  913.     update_options();
  914. }
  915.  
  916. void dddSetPannerCB (Widget w, XtPointer client_data, XtPointer)
  917. {
  918.     Boolean state = (int)(long)client_data;
  919.     app_data.panned_graph_editor = state;
  920.  
  921.     if (state)
  922.     set_status(next_ddd_will_start_with + "a panned graph editor.");
  923.     else
  924.     set_status(next_ddd_will_start_with + "a scrolled graph editor.");
  925.  
  926.     update_options();
  927.     post_startup_warning(w);
  928. }
  929.  
  930. static void report_debugger_type()
  931. {
  932.     DebuggerType type;
  933.     bool type_ok = get_debugger_type(app_data.debugger, type);
  934.  
  935.     if (!type_ok || app_data.auto_debugger)
  936.     {
  937.     set_status("Next " DDD_NAME 
  938.            " invocation will determine the debugger automatically.");
  939.     }
  940.     else
  941.     {
  942.     string title;
  943.     if (type == PERL)
  944.         title = "Perl";
  945.     else
  946.         title = upcase(app_data.debugger);
  947.     set_status(next_ddd_will_start_with + "a " + title + " debugger.");
  948.     }
  949. }
  950.  
  951. void dddSetDebuggerCB (Widget w, XtPointer client_data, XtPointer call_data)
  952. {
  953.     XmToggleButtonCallbackStruct *info = 
  954.     (XmToggleButtonCallbackStruct *)call_data;
  955.  
  956.     if (!info->set)
  957.     return;
  958.  
  959.     DebuggerType type = DebuggerType((int)(long)client_data);
  960.     app_data.debugger = default_debugger(type);
  961.     app_data.auto_debugger = false;
  962.  
  963.     report_debugger_type();
  964.  
  965.     update_options();
  966.     post_startup_warning(w);
  967. }
  968.  
  969. void dddToggleAutoDebuggerCB(Widget w, XtPointer, XtPointer call_data)
  970. {
  971.     XmToggleButtonCallbackStruct *info = 
  972.     (XmToggleButtonCallbackStruct *)call_data;
  973.  
  974.     app_data.auto_debugger = info->set;
  975.  
  976.     report_debugger_type();
  977.  
  978.     update_options();
  979.     post_startup_warning(w);
  980. }
  981.  
  982. void dddSetCutCopyPasteBindingsCB (Widget, XtPointer client_data, 
  983.                    XtPointer call_data)
  984. {
  985.     XmToggleButtonCallbackStruct *info = 
  986.     (XmToggleButtonCallbackStruct *)call_data;
  987.  
  988.     if (!info->set)
  989.     return;
  990.  
  991.     BindingStyle style = BindingStyle((int)(long)client_data);
  992.     app_data.cut_copy_paste_bindings = style;
  993.  
  994.     switch (style)
  995.     {
  996.     case KDEBindings:
  997.     set_status(next_ddd_will_start_with + 
  998.            "KDE-style Cut/Copy/Paste bindings.");
  999.     break;
  1000.     case MotifBindings:
  1001.     set_status(next_ddd_will_start_with + 
  1002.            "Motif-style Cut/Copy/Paste bindings.");
  1003.     break;
  1004.     }
  1005.  
  1006.     update_options();
  1007. }
  1008.  
  1009. void dddSetSelectAllBindingsCB (Widget, XtPointer client_data, 
  1010.                 XtPointer call_data)
  1011. {
  1012.     XmToggleButtonCallbackStruct *info = 
  1013.     (XmToggleButtonCallbackStruct *)call_data;
  1014.  
  1015.     if (!info->set)
  1016.     return;
  1017.  
  1018.     BindingStyle style = BindingStyle((int)(long)client_data);
  1019.     app_data.select_all_bindings = style;
  1020.  
  1021.     switch (style)
  1022.     {
  1023.     case KDEBindings:
  1024.     set_status(next_ddd_will_start_with + 
  1025.            "KDE-style Select All bindings.");
  1026.     break;
  1027.     case MotifBindings:
  1028.     set_status(next_ddd_will_start_with + 
  1029.            "Motif-style Select All bindings.");
  1030.     break;
  1031.     }
  1032.  
  1033.     update_options();
  1034. }
  1035.  
  1036. void dddSetUndoBufferSizeCB(Widget w, XtPointer, XtPointer)
  1037. {
  1038.     String s = XmTextFieldGetString(w);
  1039.     string value = s;
  1040.     XtFree(s);
  1041.  
  1042.     s = value;
  1043.     long val = strtol(value.chars(), &s, 0);
  1044.     if (s != value)
  1045.     {
  1046.     app_data.max_undo_size = int(val * 1000);
  1047.     undo_buffer.max_history_size = app_data.max_undo_size;
  1048.     }
  1049.  
  1050.     update_reset_preferences();
  1051. }
  1052.  
  1053. void dddClearUndoBufferCB(Widget, XtPointer, XtPointer)
  1054. {
  1055.     StatusDelay delay("Clearing undo buffer");
  1056.     undo_buffer.clear();
  1057. }
  1058.  
  1059. static void toggle_button_appearance(Widget w, Boolean& data, 
  1060.                      XtPointer call_data)
  1061. {
  1062.     XmToggleButtonCallbackStruct *info = 
  1063.     (XmToggleButtonCallbackStruct *)call_data;
  1064.  
  1065.     data = info->set;
  1066.     
  1067.     string msg = next_ddd_will_start_with;
  1068.     if (app_data.button_images && app_data.button_captions)
  1069.     {
  1070.     msg += " captioned images";
  1071.     }
  1072.     else if (app_data.button_images && !app_data.button_captions)
  1073.     {
  1074.     msg += " images only";
  1075.     }
  1076.     else if (!app_data.button_images && app_data.button_captions)
  1077.     {
  1078.     msg += " captions only";
  1079.     }
  1080.     else if (!app_data.button_images && !app_data.button_captions)
  1081.     {
  1082.     msg += " ordinary labels";
  1083.     }
  1084.  
  1085.     update_options();
  1086.     post_startup_warning(w);
  1087. }
  1088.  
  1089. void dddToggleButtonCaptionsCB(Widget w, XtPointer, XtPointer call_data)
  1090. {
  1091.     toggle_button_appearance(w, app_data.button_captions, call_data);
  1092. }
  1093.  
  1094. void dddToggleButtonImagesCB(Widget w, XtPointer, XtPointer call_data)
  1095. {
  1096.     toggle_button_appearance(w, app_data.button_images, call_data);
  1097. }
  1098.  
  1099. void dddToggleFlatButtonsCB(Widget w, XtPointer, XtPointer call_data)
  1100. {
  1101.     XmToggleButtonCallbackStruct *info = 
  1102.     (XmToggleButtonCallbackStruct *)call_data;
  1103.  
  1104.     app_data.flat_toolbar_buttons = info->set;
  1105.     app_data.flat_dialog_buttons  = info->set;
  1106.  
  1107.     if (info->set)
  1108.     set_status(next_ddd_will_start_with + "flat buttons.");
  1109.     else
  1110.     set_status(next_ddd_will_start_with + "raised buttons.");
  1111.  
  1112.     update_options();
  1113.     post_startup_warning(w);
  1114. }
  1115.  
  1116. void dddToggleColorButtonsCB(Widget w, XtPointer, XtPointer call_data)
  1117. {
  1118.     XmToggleButtonCallbackStruct *info = 
  1119.     (XmToggleButtonCallbackStruct *)call_data;
  1120.  
  1121. #if XmVersion >= 2000
  1122.     switch (info->set)
  1123.     {
  1124.     case XmSET:
  1125.     app_data.button_color_key        = "c";
  1126.     app_data.active_button_color_key = "c";
  1127.     break;
  1128.  
  1129.     case XmUNSET:
  1130.     app_data.button_color_key        = "g";
  1131.     app_data.active_button_color_key = "g";
  1132.     break;
  1133.  
  1134.     case XmINDETERMINATE:
  1135.     app_data.button_color_key        = "g";
  1136.     app_data.active_button_color_key = "c";
  1137.     break;
  1138.     }
  1139. #else
  1140.     if (info->set)
  1141.     app_data.button_color_key = "c";
  1142.     else
  1143.     app_data.button_color_key = "g";
  1144. #endif
  1145.  
  1146.     string button_color_key        = app_data.button_color_key;
  1147.     string active_button_color_key = app_data.active_button_color_key;
  1148.  
  1149.     if (button_color_key == 'c' && active_button_color_key == 'c')
  1150.     set_status(next_ddd_will_start_with + "color buttons.");
  1151.     else if (button_color_key == active_button_color_key)
  1152.     set_status(next_ddd_will_start_with + "grey buttons.");
  1153.     else            // indeterminate
  1154.     set_status(next_ddd_will_start_with + "grey/color buttons.");
  1155.  
  1156.     update_options();
  1157.     post_startup_warning(w);
  1158. }
  1159.  
  1160. void dddToggleToolbarsAtBottomCB(Widget w, XtPointer, XtPointer call_data)
  1161. {
  1162.     XmToggleButtonCallbackStruct *info = 
  1163.     (XmToggleButtonCallbackStruct *)call_data;
  1164.  
  1165.     app_data.toolbars_at_bottom = info->set;
  1166.  
  1167.     if (info->set)
  1168.     set_status(next_ddd_will_start_with + "toolbars at bottom.");
  1169.     else
  1170.     set_status(next_ddd_will_start_with + "toolbars at top.");
  1171.  
  1172.     update_options();
  1173.     post_startup_warning(w);
  1174. }
  1175.  
  1176.  
  1177. // ---------------------------------------------------------------------------
  1178. // Helpers
  1179. // ---------------------------------------------------------------------------
  1180.  
  1181. void dddSetEditCommandCB(Widget w, XtPointer, XtPointer)
  1182. {
  1183.     String s = XmTextFieldGetString(w);
  1184.     static string command;
  1185.     command = s;
  1186.     XtFree(s);
  1187.  
  1188.     app_data.edit_command = command;
  1189.     // set_status("Edit Sources command is " + quote(command));
  1190.     update_reset_preferences();
  1191. }
  1192.  
  1193. void dddSetPlotCommandCB(Widget w, XtPointer, XtPointer)
  1194. {
  1195.     String s = XmTextFieldGetString(w);
  1196.     static string command;
  1197.     command = s;
  1198.     XtFree(s);
  1199.  
  1200.     app_data.plot_command = command;
  1201.     // set_status("Edit Sources command is " + quote(command));
  1202.     update_reset_preferences();
  1203. }
  1204.  
  1205.  
  1206. void dddSetGetCoreCommandCB(Widget w, XtPointer, XtPointer)
  1207. {
  1208.     String s = XmTextFieldGetString(w);
  1209.     static string command;
  1210.     command = s;
  1211.     XtFree(s);
  1212.  
  1213.     app_data.get_core_command = command;
  1214.     // set_status("Get Core command is " + quote(command));
  1215.     update_reset_preferences();
  1216. }
  1217.  
  1218.  
  1219. void dddSetPSCommandCB(Widget w, XtPointer, XtPointer)
  1220. {
  1221.     String s = XmTextFieldGetString(w);
  1222.     static string command;
  1223.     command = s;
  1224.     XtFree(s);
  1225.  
  1226.     app_data.ps_command = command;
  1227.     // set_status("List Processes command is " + quote(command));
  1228.     update_reset_preferences();
  1229. }
  1230.  
  1231.  
  1232. void dddSetTermCommandCB(Widget w, XtPointer, XtPointer)
  1233. {
  1234.     String s = XmTextFieldGetString(w);
  1235.     static string command;
  1236.     command = s;
  1237.     XtFree(s);
  1238.  
  1239.     app_data.term_command = command;
  1240.     // set_status("Execution Window command is " + quote(command));
  1241.     update_reset_preferences();
  1242. }
  1243.  
  1244.  
  1245. void dddSetUncompressCommandCB(Widget w, XtPointer, XtPointer)
  1246. {
  1247.     String s = XmTextFieldGetString(w);
  1248.     static string command;
  1249.     command = s;
  1250.     XtFree(s);
  1251.  
  1252.     app_data.uncompress_command = command;
  1253.     // set_status("Uncompress command is " + quote(command));
  1254.     update_reset_preferences();
  1255. }
  1256.  
  1257.  
  1258. void dddSetWWWCommandCB(Widget w, XtPointer, XtPointer)
  1259. {
  1260.     String s = XmTextFieldGetString(w);
  1261.     static string command;
  1262.     command = s;
  1263.     XtFree(s);
  1264.  
  1265.     app_data.www_command = command;
  1266.     // set_status("Web Browser is " + quote(command));
  1267.     update_reset_preferences();
  1268. }
  1269.  
  1270.  
  1271.  
  1272.  
  1273.  
  1274. // ---------------------------------------------------------------------------
  1275. // Get core
  1276. // ---------------------------------------------------------------------------
  1277.  
  1278. static bool copy(const string& src, const string& dest)
  1279. {
  1280.     FILE *from = fopen(src, "r");
  1281.     if (from == NULL)
  1282.     return false;
  1283.  
  1284.     FILE *to = fopen(dest, "w");
  1285.     if (to == NULL)
  1286.     return false;
  1287.  
  1288.     int c;
  1289.     while ((c = getc(from)) != EOF)
  1290.     putc(c, to);
  1291.  
  1292.     fclose(from);
  1293.     if (fclose(to) == EOF)
  1294.     {
  1295.     unlink(dest);
  1296.     return false;
  1297.     }
  1298.  
  1299.     return true;
  1300. }
  1301.  
  1302. static bool move(const string& from, const string& to)
  1303. {
  1304.     if (rename(from, to) == 0)
  1305.     return true;
  1306.  
  1307.     if (copy(from, to) && unlink(from) == 0)
  1308.     return true;
  1309.  
  1310.     return false;
  1311. }
  1312.  
  1313. // Some GDB implementations want a confirmation when detaching:
  1314. // `Was stopped when attached, make it runnable again? (y or n) '
  1315. // Handle this by turning confirmations off.
  1316. static void get_confirm(const string& complete_answer, void *qu_data)
  1317. {
  1318.     bool *flag = (bool *)qu_data;
  1319.     *flag = complete_answer.contains("is on");
  1320. }
  1321.  
  1322. static void detach()
  1323. {
  1324.     bool confirm = true;
  1325.     gdb_command("show confirm", 0, get_confirm, &confirm);
  1326.     syncCommandQueue();
  1327.  
  1328.     if (confirm)
  1329.     gdb_question("set confirm off");
  1330.  
  1331.     gdb_question("detach");
  1332.  
  1333.     if (confirm)
  1334.     gdb_question("set confirm on");
  1335. }
  1336.  
  1337. // Get core from running program
  1338. static bool _get_core(const string& session, unsigned long flags, 
  1339.               string& target)
  1340. {
  1341.     const bool may_kill         = (flags & MAY_KILL);
  1342.     const bool may_ptrace       = (flags & MAY_PTRACE);
  1343.     const bool may_gcore        = (flags & MAY_GCORE);
  1344.     const bool dont_save        = (flags & DONT_SAVE);
  1345.     const bool dont_reload_core = (flags & DONT_RELOAD_CORE);
  1346.  
  1347.     if (!gdb->has_core_files())
  1348.     return true;        // No need to get core files
  1349.  
  1350.     create_session_dir(session);
  1351.     target = session_core_file(session);
  1352.  
  1353.     ProgramInfo info;
  1354.     if (!info.running)
  1355.     {
  1356.     // The program is not running.
  1357.     if (info.core != "" && info.core != NO_GDB_ANSWER)
  1358.     {
  1359.         // We already have some core file.
  1360.         if (dont_save)
  1361.         return true;    // Fine
  1362.  
  1363.         StatusDelay delay("Getting core dump from " + quote(info.core));
  1364.         if (info.core == target)
  1365.         {
  1366.         // It is our target.
  1367.         return true;
  1368.         }
  1369.  
  1370.         if (flags & DONT_COPY_CORE)
  1371.         {
  1372.         target = info.core;
  1373.         return true;    // Don't copy existing core file
  1374.         }
  1375.  
  1376.         // Remove old target, if any
  1377.         unlink(target);
  1378.  
  1379. #if HAVE_LINK
  1380.         // Try a hard link from current core file to target
  1381.         if (link(info.core, target) == 0)
  1382.         return true;
  1383. #endif
  1384.  
  1385. #if HAVE_SYMLINK
  1386.         // Try a symlink link from target to current core file
  1387.         if (symlink(info.core, target) == 0)
  1388.         return true;
  1389. #endif
  1390.  
  1391.         // Looks as if we have to copy some large core file.  Blechhh.
  1392.         return copy(info.core, target);
  1393.     }
  1394.  
  1395.     // Program is not running, and we have no core.  Quit.
  1396.     return false;
  1397.     }
  1398.  
  1399.     if (may_ptrace)
  1400.     {
  1401. #if HAVE_PTRACE_DUMPCORE
  1402.     if (gdb->type() == GDB && info.pid > 0)
  1403.     {
  1404.         // Try getting core via ptrace(2) call
  1405.         if (dont_save)
  1406.         return true;        // Will probably work
  1407.  
  1408.         // Get new core file from running process
  1409.         StatusDelay delay("Getting core dump via ptrace()");
  1410.         
  1411.         // 1. Stop the program being debugged, using a STOP signal.
  1412.         kill(info.pid, SIGSTOP);
  1413.  
  1414.         // 2. Detach GDB from the debuggee.  The debuggee is still stopped.
  1415.         detach();
  1416.  
  1417.         // 3. Attach to the process, using the ptrace() call.
  1418.         string gcore_target = target + "." + itostring(info.pid);
  1419.         int ok = ptrace(PTRACE_ATTACH, info.pid, 0, 0);
  1420.         if (ok < 0)
  1421.         {
  1422.         cerr << ddd_NAME ": PTRACE_ATTACH: "
  1423.              << strerror(errno) << '\n';
  1424.         }
  1425.         else
  1426.         {
  1427.         // 4. Get a core file from the running process
  1428.         ok = ptrace(PTRACE_DUMPCORE, info.pid, 
  1429.                 int(gcore_target.chars()), 0);
  1430.  
  1431.         if (ok < 0)
  1432.         {
  1433.             cerr << ddd_NAME ": PTRACE_DUMPCORE: "
  1434.              << strerror(errno) << '\n';
  1435.         }
  1436.         
  1437.         // 5. Detach from the debuggee, leaving it stopped
  1438.         kill(info.pid, SIGSTOP);
  1439.         ok = ptrace(PTRACE_DETACH, info.pid, 0x1, SIGSTOP);
  1440.  
  1441.         if (ok < 0)
  1442.         {
  1443.             cerr << ddd_NAME ": PTRACE_DETACH: "
  1444.              << strerror(errno) << '\n';
  1445.         }
  1446.         }
  1447.  
  1448.         // 6. Attach GDB to the debuggee again.
  1449.         sleep(1);
  1450.         gdb_command("attach " + itostring(info.pid));
  1451.  
  1452.         if (is_core_file(gcore_target) && move(gcore_target, target))
  1453.         return true;
  1454.  
  1455.         delay.outcome = "failed";
  1456.     }
  1457.     else
  1458. #endif
  1459.         if (dont_save)
  1460.         return false;    // unsupported
  1461.     }
  1462.     
  1463.  
  1464.     if (may_gcore)
  1465.     {
  1466.     // Try `gcore' command
  1467.     string gcore = app_data.get_core_command;
  1468.     if (gcore != "" && gdb->type() == GDB && info.pid > 0)
  1469.     {
  1470.         if (dont_save)
  1471.         return true;    // Will probably work
  1472.  
  1473.         // Get new core file from running process
  1474.         StatusDelay delay("Getting core dump via `gcore'");
  1475.  
  1476.         // 1. Stop the program being debugged, using a STOP signal.
  1477.         // (Other signals may be blocked, caught or ignored)
  1478.         kill(info.pid, SIGSTOP);
  1479.  
  1480.         // 2. Detach GDB from the debuggee.  The debuggee is still stopped.
  1481.         detach();
  1482.  
  1483.         // 3. Invoke `gcore' command.
  1484.         string gcore_target = target + "." + itostring(info.pid);
  1485.         gcore.gsub("@FILE@", target);
  1486.         gcore.gsub("@PID@",  itostring(info.pid));
  1487.         string cmd = sh_command(gcore, true) + " 2>&1";
  1488.         ostrstream errs;
  1489.         FILE *fp = popen(cmd, "r");
  1490.         if (fp != 0)
  1491.         {
  1492.         kill(info.pid, SIGSTOP);
  1493.         int c;
  1494.         while ((c = getc(fp)) != EOF)
  1495.         {
  1496.             kill(info.pid, SIGSTOP);
  1497.             errs << c;
  1498.         }
  1499.         }
  1500.         int gcore_status = pclose(fp);
  1501.  
  1502.         // 4. Since `gcore' restarts the debuggee, stop it again.
  1503.         kill(info.pid, SIGSTOP);
  1504.         if (gcore_status != 0)
  1505.         cerr << string(errs);
  1506.  
  1507.         // 5. Attach GDB again.
  1508.         sleep(1);
  1509.         gdb_command("attach " + itostring(info.pid));
  1510.  
  1511.         if (is_core_file(gcore_target) && move(gcore_target, target))
  1512.         return true;
  1513.  
  1514.         delay.outcome = "failed";
  1515.     }
  1516.     else
  1517.     {
  1518.         if (dont_save)
  1519.         {
  1520.         // No `gcore' support
  1521.         return false;
  1522.         }
  1523.     }
  1524.     }
  1525.  
  1526.  
  1527.     // Try direct kill.
  1528.     if (may_kill)
  1529.     {
  1530.     if (dont_save)
  1531.         return true;    // Will probably work
  1532.  
  1533.     // Get new core file from running process
  1534.     StatusDelay delay("Getting core dump via killing debuggee");
  1535.  
  1536.     string core = SourceView::full_path("core");
  1537.     string core_backup = core + "~";
  1538.  
  1539.     bool had_a_core_file = false;
  1540.     if (is_regular_file(core) || is_directory(core))
  1541.     {
  1542.         // There is already a file named `core'.  Preserve it.
  1543.         had_a_core_file = true;
  1544.  
  1545.         // Try `core~', `core1', `core2', etc., until we find a
  1546.         // file name that is not being used yet.
  1547.         int suffix = 0;
  1548.         for (;;)
  1549.         {
  1550.         if (!is_regular_file(core_backup)
  1551.             && !is_directory(core_backup))
  1552.         {
  1553.             move(core, core_backup);
  1554.             break;
  1555.         }
  1556.  
  1557.         core_backup = "core" + itostring(++suffix);
  1558.         }
  1559.     }
  1560.  
  1561.     if (gdb->has_system_calls())
  1562.     {
  1563.         // Kill the process, hopefully leaving a core file.
  1564.  
  1565.         // Since g77 catches SIGABRT, we disable its handler first.
  1566.         ostrstream os;
  1567.         os << "signal(" << SIGABRT << ", " 
  1568.            << (unsigned long)SIG_DFL << ")";
  1569.         gdb_question(gdb->print_command(string(os)));
  1570.  
  1571.         // Send signal
  1572.         gdb_question(gdb->signal_command(SIGABRT));
  1573.     }
  1574.  
  1575.     if (is_core_file(core))
  1576.     {
  1577.         // It worked.  Fine!  Move generated core file to target.
  1578.         bool ok = move(core, target);
  1579.         
  1580.         if (!ok)
  1581.         {
  1582.         // Move failed.  Sorry.
  1583.         unlink(core);
  1584.         }
  1585.  
  1586.         // Restore the old core file, if any.
  1587.         if (had_a_core_file)
  1588.         move(core_backup, core);
  1589.  
  1590.         if (ok && gdb->type() == GDB && !dont_reload_core)
  1591.         {
  1592.         // Load the core file just saved, such that we can
  1593.         // keep on examining data in this session.
  1594.         Command c("core " + target);
  1595.         c.verbose  = false;
  1596.         c.prompt   = false;
  1597.         c.check    = true;
  1598.         c.priority = COMMAND_PRIORITY_AGAIN;
  1599.         gdb_command(c);
  1600.         c.command  = "graph refresh";
  1601.         gdb_command(c);
  1602.         c.command  = "# reset";
  1603.         gdb_command(c);
  1604.         syncCommandQueue();
  1605.         }
  1606.  
  1607.         return ok;
  1608.     }
  1609.  
  1610.     // No core file.  Sorry.
  1611.     delay.outcome = "failed";
  1612.  
  1613.     // Restore the old core file, if any.
  1614.     if (had_a_core_file)
  1615.         move(core_backup, core);
  1616.     }
  1617.  
  1618.     return false;
  1619. }
  1620.  
  1621. static bool get_core(const string& session, unsigned long flags, 
  1622.              string& target)
  1623. {
  1624.     const bool interact      = (flags & MAY_INTERACT);
  1625.  
  1626.     bool ok = _get_core(session, flags, target);
  1627.     if (!ok && interact)
  1628.     post_warning("Could not save core file.", "core_missing_warning");
  1629.  
  1630.     return ok;
  1631. }
  1632.  
  1633. static bool must_kill_to_get_core()
  1634. {
  1635.     string dummy_target;
  1636.     return !_get_core(app_data.session, DONT_SAVE, dummy_target);
  1637. }
  1638.  
  1639.  
  1640. //-----------------------------------------------------------------------------
  1641. // Reload state
  1642. //-----------------------------------------------------------------------------
  1643.  
  1644. static bool options_file_has_changed(ChangeMode mode, bool reset)
  1645. {
  1646.     static string last_options_file = "";
  1647.     static time_t last_access      = 0;
  1648.     static time_t last_acknowledge = 0;
  1649.  
  1650.     string options_file = session_state_file(app_data.session);
  1651.  
  1652.     if (options_file != last_options_file)
  1653.     {
  1654.     // Name of state file has changed
  1655.     last_options_file = options_file;
  1656.     mode  = ACCESS;
  1657.     reset = true;
  1658.     }
  1659.  
  1660.     time_t modification_time = last_modification_time(options_file);
  1661.  
  1662. #if 0
  1663.     clog << quote(options_file) << " last modified " 
  1664.      << ctime(&modification_time);
  1665. #endif
  1666.  
  1667.     if (reset || last_acknowledge == 0)
  1668.     last_acknowledge = modification_time;
  1669.     if ((reset && mode == ACCESS) || last_access == 0)
  1670.     last_access = modification_time;
  1671.  
  1672.     time_t& last_time = (mode == ACKNOWLEDGE ? last_acknowledge : last_access);
  1673.     if (modification_time > last_time)
  1674.     {
  1675.     // File has been written since last check
  1676.     return true;
  1677.     }
  1678.  
  1679.     // File is unchanged
  1680.     return false;
  1681. }
  1682.  
  1683. inline String str(String s)
  1684. {
  1685.     return s != 0 ? s : "";
  1686. }
  1687.  
  1688. static Boolean done_if_idle(XtPointer data)
  1689. {
  1690.     if (emptyCommandQueue() && gdb->isReadyWithPrompt())
  1691.     {
  1692.     update_settings();    // Refresh settings and signals
  1693.     update_signals();
  1694.  
  1695.     delete (Delay *)data;
  1696.     return True;        // Remove from the list of work procs
  1697.     }
  1698.  
  1699.     return False;        // Get called again
  1700. }
  1701.  
  1702. static void done(const string&, void *data)
  1703. {
  1704.     XtAppAddWorkProc(XtWidgetToApplicationContext(command_shell),
  1705.              done_if_idle, data);
  1706. }
  1707.  
  1708. static void reload_options()
  1709. {
  1710.     static string session;
  1711.     session = app_data.session;
  1712.  
  1713.     string file = session_state_file(session);
  1714.  
  1715.     StatusDelay *delay_ptr = 
  1716.     new StatusDelay("Loading options from " + quote(file));
  1717.  
  1718.     XrmDatabase session_db = XrmGetFileDatabase(file);
  1719.  
  1720.     Widget toplevel = find_shell();
  1721.     while (XtParent(toplevel) != 0)
  1722.     toplevel = XtParent(toplevel);
  1723.  
  1724.     if (session_db == 0)
  1725.     {
  1726.     delay_ptr->outcome = "failed";
  1727.     delete delay_ptr;
  1728.     return;
  1729.     }
  1730.  
  1731.     XrmDatabase target = XtDatabase(XtDisplay(toplevel));
  1732.  
  1733. #if 0                // This causes core dumps. - AZ
  1734.     XrmDatabase default_db = app_defaults(XtDisplay(toplevel));
  1735.     if (default_db != 0)
  1736.     XrmMergeDatabases(default_db, &target);
  1737. #endif
  1738.  
  1739.     XrmMergeDatabases(session_db, &target);
  1740.  
  1741.     XtVaGetApplicationResources(toplevel, (XtPointer)&app_data,
  1742.                 ddd_resources, ddd_resources_size, NULL);
  1743.  
  1744.     // Keep session ID across reloads
  1745.     app_data.session = session;
  1746.  
  1747.     save_option_state();
  1748.     options_file_has_changed(ACCESS, true);
  1749.  
  1750.     // Set options and buttons
  1751.     update_options();
  1752.     update_user_buttons();
  1753.  
  1754.     // Pop down settings and signals panel (such that GDB settings
  1755.     // and signals will be updated from scratch)
  1756.     reset_settings();
  1757.     reset_signals();
  1758.  
  1759.     // Load GDB settings.  Don't care about init or restart commands here.
  1760.     string restart = "";
  1761.     string settings;
  1762.     switch (gdb->type())
  1763.     {
  1764.     case GDB:
  1765.     settings = str(app_data.gdb_settings);
  1766.     break;
  1767.  
  1768.     case DBX:
  1769.     settings = str(app_data.dbx_settings);
  1770.     break;
  1771.  
  1772.     case XDB:
  1773.     settings = str(app_data.xdb_settings);
  1774.     break;
  1775.  
  1776.     case JDB:
  1777.     settings = str(app_data.jdb_settings);
  1778.     break;
  1779.  
  1780.     case PYDB:
  1781.     settings = str(app_data.pydb_settings);
  1782.     break;
  1783.  
  1784.     case PERL:
  1785.     settings = str(app_data.perl_settings);
  1786.     break;
  1787.     }
  1788.  
  1789.     init_session(restart, settings, app_data.source_init_commands);
  1790.  
  1791.     // One last command to reload the new settings
  1792.     Command c("# reset");
  1793.     c.callback = done;
  1794.     c.data     = (void *)(Delay *)delay_ptr;
  1795.     c.priority = COMMAND_PRIORITY_BATCH;
  1796.     c.verbose  = false;
  1797.     c.prompt   = false;
  1798.     c.check    = true;
  1799.     gdb_command(c);
  1800. }
  1801.  
  1802. static void ReloadOptionsCB(Widget, XtPointer, XtPointer)
  1803. {
  1804.     reload_options();
  1805. }
  1806.  
  1807. static void DontReloadOptionsCB(Widget, XtPointer, XtPointer)
  1808. {
  1809.     // Acknowledge change
  1810.     options_file_has_changed(ACKNOWLEDGE, true);
  1811. }
  1812.  
  1813. // Pending timer
  1814. static XtIntervalId check_options_timer = 0;
  1815.  
  1816. static void CheckOptionsFileCB(XtPointer client_data, XtIntervalId *id)
  1817. {
  1818.     (void) id;            // Use it
  1819.  
  1820.     assert(*id == check_options_timer);
  1821.     check_options_timer = 0;
  1822.  
  1823.     if (options_file_has_changed(ACKNOWLEDGE))
  1824.     {
  1825.     // Options file has changed since last acknowledgement -- offer reload
  1826.     static Widget dialog = 0;
  1827.  
  1828.     if (dialog == 0)
  1829.     {
  1830.         dialog = verify(XmCreateQuestionDialog(find_shell(),
  1831.                            "reload_options_dialog",
  1832.                            0, 0));
  1833.         Delay::register_shell(dialog);
  1834.         XtAddCallback(dialog, XmNokCallback,     ReloadOptionsCB, 0);
  1835.         XtAddCallback(dialog, XmNcancelCallback, DontReloadOptionsCB, 0);
  1836.         XtAddCallback(dialog, XmNhelpCallback,   ImmediateHelpCB, 0);
  1837.     }
  1838.  
  1839.     if (!XtIsManaged(dialog))
  1840.         manage_and_raise(dialog);
  1841.     }
  1842.     
  1843.     if (app_data.check_options > 0)
  1844.     {
  1845.     // Try again later
  1846.     check_options_timer = 
  1847.         XtAppAddTimeOut(XtWidgetToApplicationContext(find_shell()),
  1848.                 app_data.check_options * 1000,
  1849.                 CheckOptionsFileCB, client_data);
  1850.     }
  1851. }
  1852.  
  1853. void check_options_file()
  1854. {
  1855.     if (check_options_timer != 0)
  1856.     XtRemoveTimeOut(check_options_timer);
  1857.  
  1858.     check_options_timer = 
  1859.     XtAppAddTimeOut(XtWidgetToApplicationContext(find_shell()), 0,
  1860.             CheckOptionsFileCB, XtPointer(0));
  1861. }
  1862.  
  1863.  
  1864. //-----------------------------------------------------------------------------
  1865. // Write state
  1866. //-----------------------------------------------------------------------------
  1867.  
  1868. static bool is_fallback_value(string resource, string val)
  1869. {
  1870.     XrmDatabase default_db = app_defaults(XtDisplay(find_shell()));
  1871.  
  1872.     static String app_name  = 0;
  1873.     static String app_class = 0;
  1874.  
  1875.     if (app_name == 0)
  1876.     XtGetApplicationNameAndClass(XtDisplay(find_shell()), 
  1877.                      &app_name, &app_class);
  1878.  
  1879.     string str_name  = string(app_name)  + "*" + resource;
  1880.     string str_class = string(app_class) + "*" + resource;
  1881.  
  1882.     char *type;
  1883.     XrmValue xrmvalue;
  1884.     Bool success = XrmGetResource(default_db, str_name, str_class, 
  1885.                   &type, &xrmvalue);
  1886.     string default_val = NO_GDB_ANSWER;
  1887.  
  1888.     if (success)
  1889.     {
  1890.     char *str = (char *)xrmvalue.addr;
  1891.     int len   = xrmvalue.size - 1; // includes the final `\0'
  1892.     default_val = string(str, len);
  1893.     }
  1894.  
  1895.     val = uncook(val);
  1896.  
  1897. #if 0
  1898.     if (val != default_val)
  1899.     {
  1900.     clog << resource
  1901.          << ": val " << quote(val)
  1902.          << " != default " << quote(default_val)
  1903.          << '\n';
  1904.     }
  1905. #endif
  1906.  
  1907.     return val == default_val;
  1908. }
  1909.  
  1910. static string app_value(string resource, const string& value, 
  1911.             bool check_default)
  1912. {
  1913.     static String app_name  = 0;
  1914.     static String app_class = 0;
  1915.  
  1916.     if (app_name == 0)
  1917.     XtGetApplicationNameAndClass(XtDisplay(find_shell()), 
  1918.                      &app_name, &app_class);
  1919.  
  1920.     string prefix = "";
  1921.     if (check_default && is_fallback_value(resource, value))
  1922.     prefix = "! ";
  1923.  
  1924.     string s = prefix + app_class;
  1925.  
  1926.     if (resource.contains(string(app_name) + ".", 0))
  1927.     s += resource.from(".") + ": " + value;
  1928.     else
  1929.     s += "*" + resource + ": " + value;
  1930.  
  1931.     if (prefix != "")
  1932.     s.gsub('\n', "\n" + prefix);
  1933.  
  1934.     return s;
  1935. }
  1936.  
  1937. inline String bool_value(bool value)
  1938. {
  1939.     // Since GDB uses `on' and `off' for its settings, we do so, too. 
  1940.     return value ? "on" : "off";
  1941. }
  1942.  
  1943. inline String binding_value(BindingStyle value)
  1944. {
  1945.     switch (value)
  1946.     {
  1947.     case KDEBindings:
  1948.     return "KDE";
  1949.  
  1950.     case MotifBindings:
  1951.     return "Motif";
  1952.     }
  1953.  
  1954.     return "";            // Never reached
  1955. }
  1956.  
  1957. static string bool_app_value(const string& name, bool value, 
  1958.                  bool check_default = false)
  1959. {
  1960.     return app_value(name, bool_value(value), check_default);
  1961. }
  1962.  
  1963. static string int_app_value(const string& name, int value,
  1964.                 bool check_default = false)
  1965. {
  1966.     return app_value(name, itostring(value), check_default);
  1967. }
  1968.  
  1969. static string binding_app_value(const string& name, BindingStyle value,
  1970.                 bool check_default = false)
  1971. {
  1972.     return app_value(name, binding_value(value), check_default);
  1973. }
  1974.  
  1975.  
  1976. static string string_app_value(const string& name, String v,
  1977.                    bool check_default = false)
  1978. {
  1979.     if (v == 0)
  1980.     return "";
  1981.  
  1982.     string value = cook(v);
  1983.  
  1984.     // Xt cannot read `\t', so leave it unchanged.
  1985.     value.gsub("\\t", '\t');
  1986.  
  1987.     if (value.contains("\\n"))
  1988.     {
  1989.     value.gsub("\\n", "\\n\\\n");
  1990.     value.gsub("\\\\n\\\n\\n", "\\\\n\\n");
  1991.  
  1992.     if (value.contains("\\\n", -1))
  1993.         value = value.before(int(value.length()) - 2);
  1994.     value = "\\\n" + value;
  1995.     }
  1996.  
  1997.     return app_value(name, value, check_default);
  1998. }
  1999.  
  2000. static string widget_value(Widget w, String name, bool check_default = false)
  2001. {
  2002.     String value = 0;
  2003.     XtVaGetValues(w, 
  2004.           XtVaTypedArg, name, XtRString, &value, sizeof(value),
  2005.           NULL);
  2006.  
  2007.     return string_app_value(string(XtName(w)) + "." + name, value, 
  2008.                 check_default);
  2009. }
  2010.  
  2011. static string paned_widget_size(Widget w, bool height_only = false)
  2012. {
  2013.     string s;
  2014.     const bool check_default = false;
  2015.  
  2016.     if (XmIsText(w) || XmIsTextField(w))
  2017.     {
  2018.     // Store rows and columns
  2019.     short columns = 0;
  2020.     XtVaGetValues(w, XmNcolumns, &columns, NULL);
  2021.     if (!height_only && columns > 0)
  2022.     {
  2023.         if (s != "")
  2024.         s += '\n';
  2025.         s += int_app_value(string(XtName(w)) + "." + XmNcolumns, columns,
  2026.                    check_default);
  2027.     }
  2028.  
  2029.     if (XmIsText(w))
  2030.     {
  2031.         short rows = 0;
  2032.         XtVaGetValues(w, XmNrows, &rows, NULL);
  2033.         if (rows > 0)
  2034.         {
  2035.         if (s != "")
  2036.             s += '\n';
  2037.         s += int_app_value(string(XtName(w)) + "." + XmNrows, rows,
  2038.                    check_default);
  2039.         }
  2040.     }
  2041.     }
  2042.     else
  2043.     {
  2044.     // We store the size of the paned child, in order to account
  2045.     // for scrolled windows etc.
  2046.     Widget ref = w;
  2047.     while (XtParent(ref) != 0 && !XmIsPanedWindow(XtParent(ref)))
  2048.         ref = XtParent(ref);
  2049.     if (XtParent(ref) == 0)
  2050.         ref = w;
  2051.  
  2052.     // Store absolute sizes
  2053.     Dimension width  = 0;
  2054.     Dimension height = 0;
  2055.     XtVaGetValues(ref, XmNwidth, &width, XmNheight, &height, NULL);
  2056.  
  2057.     if (!height_only)
  2058.         s += int_app_value(string(XtName(w)) + "." + XmNwidth, width,
  2059.                    check_default);
  2060.  
  2061.     if (s != "")
  2062.         s += '\n';
  2063.     s += int_app_value(string(XtName(w)) + "." + XmNheight, height,
  2064.                check_default);
  2065.     }
  2066.  
  2067.     return s;
  2068. }
  2069.  
  2070. inline string paned_widget_height(Widget w)
  2071. {
  2072.     return paned_widget_size(w, true);
  2073. }
  2074.  
  2075. static string widget_geometry(Widget w, bool include_size = false)
  2076. {
  2077.     const bool check_default = false;
  2078.  
  2079.     Dimension width, height;
  2080.     XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
  2081.  
  2082.     XWindowAttributes attr;
  2083.     XGetWindowAttributes(XtDisplay(w), frame(w), &attr);
  2084.  
  2085.     ostrstream geometry;
  2086.     if (include_size)
  2087.     geometry << width << "x" << height;
  2088.     geometry << "+" << attr.x << "+" << attr.y;
  2089.     string geo(geometry);
  2090.  
  2091.     return string_app_value(string(XtName(w)) + ".geometry", geo, 
  2092.                 check_default);
  2093. }
  2094.  
  2095. bool saving_options_kills_program(unsigned long flags)
  2096. {
  2097.     ProgramInfo info;
  2098.  
  2099.     const bool save_session  = (flags & SAVE_SESSION);
  2100.     const bool may_kill      = (flags & MAY_KILL);
  2101.     const bool may_gcore     = (flags & MAY_GCORE);
  2102.     const bool may_ptrace    = (flags & MAY_PTRACE);
  2103.     const bool save_core     = (flags & SAVE_CORE);
  2104.  
  2105.     return info.running
  2106.     && save_session
  2107.     && save_core
  2108.     && must_kill_to_get_core()
  2109.     && !may_kill
  2110.     && !may_gcore
  2111.     && !may_ptrace;
  2112. }
  2113.  
  2114. bool saving_options_excludes_data(unsigned long flags)
  2115. {
  2116.     const bool save_session  = (flags & SAVE_SESSION);
  2117.     const bool save_core     = (flags & SAVE_CORE);
  2118.  
  2119.     return save_session
  2120.     && !save_core
  2121.     && data_disp->need_core_to_restore();
  2122. }
  2123.  
  2124. bool get_restart_commands(string& restart, unsigned long flags)
  2125. {
  2126.     bool ok = true;
  2127.     const bool interact     = (flags & MAY_INTERACT);
  2128.     const bool save_core    = (flags & SAVE_CORE);
  2129.     const bool save_session = (flags & SAVE_SESSION);
  2130.  
  2131.     string session = 
  2132.     (save_session ? app_data.session : (char *)DEFAULT_SESSION);
  2133.  
  2134.     ProgramInfo info;
  2135.     if (info.file == NO_GDB_ANSWER)
  2136.     {
  2137.     if (interact)
  2138.         post_warning("Could not save program name.",
  2139.              "program_name_missing_warning");
  2140.     ok = false;
  2141.     }
  2142.  
  2143.     // Stream to hold data and breakpoints
  2144.     ostrstream rs;
  2145.  
  2146.     // Get breakpoints and cursor position
  2147.     bool breakpoints_ok = source_view->get_state(rs);
  2148.     if (!breakpoints_ok)
  2149.     {
  2150.     if (interact)
  2151.         post_warning("Could not save all breakpoints", 
  2152.              "breakpoint_missing_warning");
  2153.     ok = false;
  2154.     }
  2155.  
  2156.     bool core_ok = false;
  2157.     string core;
  2158.     bool have_data = 
  2159.     info.running || (info.core != "" && info.core != NO_GDB_ANSWER);
  2160.  
  2161.     bool have_data_displays = (data_disp->count_data_displays() > 0);
  2162.  
  2163.     IntArray display_numbers;
  2164.     data_disp->get_all_display_numbers(display_numbers);
  2165.     bool have_displays = display_numbers.size() > 0;
  2166.  
  2167.     if (have_data || have_displays)
  2168.     {
  2169.     // Get displays
  2170.     StringArray scopes;
  2171.     bool displays_ok = true;
  2172.  
  2173.     if (have_data && have_data_displays && displays_ok)
  2174.         displays_ok = data_disp->get_scopes(scopes);
  2175.  
  2176.     if (have_data && save_core)
  2177.         core_ok = get_core(session, flags, core);
  2178.  
  2179.     if (displays_ok)
  2180.     {
  2181.         int target_frame = source_view->get_frame();
  2182.         if (target_frame < 0)
  2183.         target_frame = 0;
  2184.         displays_ok = data_disp->get_state(rs, scopes, target_frame);
  2185.     }
  2186.  
  2187.     if (!displays_ok)
  2188.     {
  2189.         if (interact)
  2190.         post_warning("Could not save all data displays.",
  2191.                  "displays_missing_warning");
  2192.         ok = false;
  2193.     }
  2194.     }
  2195.  
  2196.     // Stream to hold exec and core file specs
  2197.     ostrstream es;
  2198.  
  2199.     // Get exec and core file
  2200.     switch (gdb->type())
  2201.     {
  2202.     case GDB:
  2203.     es << "set confirm off\n";
  2204.     if (info.file != "" && info.file != NO_GDB_ANSWER)
  2205.         es << "file " << info.file << '\n';
  2206.     if (core_ok)
  2207.         es << "core " << core << '\n';
  2208.     break;
  2209.  
  2210.     case DBX:
  2211.     if (info.file != "" && info.file != NO_GDB_ANSWER)
  2212.     {
  2213.         string cmd = gdb->debug_command(info.file);
  2214.         if (cmd != "")
  2215.         {
  2216.         es << cmd;
  2217.         if (core_ok)
  2218.             es << " " << core;
  2219.         es << '\n';
  2220.         }
  2221.     }
  2222.     break;
  2223.  
  2224.     case PERL:
  2225.     if (info.file != "" && info.file != NO_GDB_ANSWER)
  2226.     {
  2227.         string cmd = gdb->debug_command(info.file);
  2228.         if (cmd != "")
  2229.         es << cmd << '\n';
  2230.     }
  2231.     break;
  2232.  
  2233.     case XDB:
  2234.     case JDB:
  2235.     case PYDB:
  2236.     // FIXME
  2237.     break;
  2238.     }
  2239.  
  2240.     restart = string(es) + string(rs) + get_signals(gdb->type());
  2241.     restart.gsub(app_data.auto_command_prefix, "@AUTO@");
  2242.  
  2243.     return ok;
  2244. }
  2245.  
  2246. bool save_options(unsigned long flags)
  2247. {
  2248.     const bool create        = (flags & CREATE_OPTIONS);
  2249.     const bool save_session  = (flags & SAVE_SESSION);
  2250.     const bool save_geometry = (flags & SAVE_GEOMETRY);
  2251.     const bool interact      = (flags & MAY_INTERACT);
  2252.  
  2253.     string session = 
  2254.     (save_session ? app_data.session : (char *)DEFAULT_SESSION);
  2255.  
  2256.     create_session_dir(session);
  2257.     const string file = session_state_file(session);
  2258.  
  2259.     string options = (save_session ? "session" : "options");
  2260.     string status = (create ? "Creating " : "Saving ") + options + " in ";
  2261.  
  2262.     StatusDelay delay(status + quote(file));
  2263.  
  2264.     const char delimiter[] = "! DO NOT ADD ANYTHING BELOW THIS LINE";
  2265.  
  2266.     // Read the file contents into memory ...
  2267.     string dddinit;
  2268.     ifstream is(file);
  2269.     if (is.bad())
  2270.     {
  2271.     // File not found: create a new one
  2272.     dddinit = 
  2273.         "! " DDD_NAME " initialization file\n"
  2274.         "! Enter your personal " DDD_NAME " resources here.\n"
  2275.         "\n";
  2276.     }
  2277.     else
  2278.     {
  2279.     char line[ARG_MAX + BUFSIZ];
  2280.     while (is)
  2281.     {
  2282.         line[0] = '\0';
  2283.         is.getline(line, sizeof(line));
  2284.         if (string(line).contains(delimiter, 0))
  2285.         break;
  2286.         dddinit += line;
  2287.         dddinit += '\n';
  2288.     }
  2289.     }
  2290.  
  2291.     // ... and write them back again
  2292.     bool ok = true;
  2293.     string workfile = file + "#";
  2294.     ofstream os(workfile);
  2295.     if (os.bad())
  2296.     {
  2297.     workfile = file;
  2298.     os.open(workfile);
  2299.     }
  2300.     if (os.bad())
  2301.     {
  2302.     if (interact)
  2303.         post_error("Cannot save " + options + " in " + quote(workfile),
  2304.                "options_save_error");
  2305.     delay.outcome = "failed";
  2306.     return false;
  2307.     }
  2308.  
  2309.     os << dddinit << delimiter << " -- " DDD_NAME " WILL OVERWRITE IT\n";
  2310.     os << string_app_value(XtNdddinitVersion, DDD_VERSION) << '\n';
  2311.  
  2312.     if (create)
  2313.     {
  2314.     app_data.dddinit_version = DDD_VERSION;
  2315.     os.close();
  2316.  
  2317.     if (workfile != file && rename(workfile, file) != 0)
  2318.     {
  2319.         if (interact)
  2320.         post_error("Cannot rename " + quote(workfile)
  2321.                + " to " + quote(file) + ": " + strerror(errno),
  2322.                "options_save_error");
  2323.         ok = false;
  2324.         unlink(workfile);
  2325.     }
  2326.  
  2327.     return ok;
  2328.     }
  2329.  
  2330.     if (app_data.initial_session != 0)
  2331.     {
  2332.     os << "\n! Session.\n";
  2333.     os << string_app_value(XtNinitialSession, app_data.initial_session) 
  2334.        << '\n';
  2335.     }
  2336.  
  2337.     os << "\n! Debugger settings.\n";
  2338.     os << bool_app_value(XtNautoDebugger, app_data.auto_debugger) << '\n';
  2339.     os << string_app_value(XtNdebugger, app_data.debugger) << '\n';
  2340.     os << bool_app_value(XtNuseSourcePath, app_data.use_source_path) << '\n';
  2341.  
  2342.     string gdb_settings  = app_data.gdb_settings;
  2343.     string dbx_settings  = app_data.dbx_settings;
  2344.     string xdb_settings  = app_data.xdb_settings;
  2345.     string jdb_settings  = app_data.jdb_settings;
  2346.     string pydb_settings = app_data.pydb_settings;
  2347.     string perl_settings = app_data.perl_settings;
  2348.  
  2349.     if (need_settings() || need_save_defines())
  2350.     {
  2351.     string settings;
  2352.     settings += get_settings(gdb->type());
  2353.     settings += get_defines(gdb->type());
  2354.  
  2355.     settings.gsub(app_data.auto_command_prefix, "@AUTO@");
  2356.  
  2357.     switch (gdb->type())
  2358.     {
  2359.     case GDB:
  2360.         gdb_settings = settings;
  2361.         break;
  2362.  
  2363.     case DBX:
  2364.         dbx_settings = settings;
  2365.         break;
  2366.  
  2367.     case XDB:
  2368.         xdb_settings = settings;
  2369.         break;
  2370.  
  2371.     case JDB:
  2372.         jdb_settings = settings;
  2373.         break;
  2374.  
  2375.     case PYDB:
  2376.         pydb_settings = settings;
  2377.         break;
  2378.  
  2379.     case PERL:
  2380.         perl_settings = settings;
  2381.         break;
  2382.     }
  2383.     }
  2384.  
  2385.     os << string_app_value(XtNgdbSettings,  gdb_settings, true)  << '\n';
  2386.     os << string_app_value(XtNdbxSettings,  dbx_settings, true)  << '\n';
  2387.     os << string_app_value(XtNxdbSettings,  xdb_settings, true)  << '\n';
  2388.     os << string_app_value(XtNjdbSettings,  jdb_settings, true)  << '\n';
  2389.     os << string_app_value(XtNpydbSettings, pydb_settings, true) << '\n';
  2390.     os << string_app_value(XtNperlSettings, perl_settings, true) << '\n';
  2391.  
  2392.     os << "\n! Source.\n";
  2393.     os << bool_app_value(XtNfindWordsOnly,
  2394.              app_data.find_words_only) << '\n';
  2395.     os << bool_app_value(XtNfindCaseSensitive,
  2396.              app_data.find_case_sensitive) << '\n';
  2397.     os << int_app_value(XtNtabWidth,
  2398.              app_data.tab_width, true) << '\n';
  2399.     os << int_app_value(XtNindentSource,
  2400.              app_data.indent_source, true) << '\n';
  2401.     os << int_app_value(XtNindentCode,
  2402.              app_data.indent_code, true) << '\n';
  2403.     os << bool_app_value(XtNcacheSourceFiles,
  2404.              app_data.cache_source_files) << '\n';
  2405.     os << bool_app_value(XtNcacheMachineCode,
  2406.              app_data.cache_machine_code) << '\n';
  2407.     os << bool_app_value(XtNdisplayGlyphs,
  2408.              app_data.display_glyphs) << '\n';
  2409.     os << bool_app_value(XtNdisplayLineNumbers,
  2410.              app_data.display_line_numbers) << '\n';
  2411.     os << bool_app_value(XtNdisassemble,
  2412.              app_data.disassemble) << '\n';
  2413.     os << bool_app_value(XtNallRegisters,
  2414.              app_data.all_registers) << '\n';
  2415.  
  2416.     os << "\n! Undo Buffer.\n";
  2417.     os << int_app_value(XtNmaxUndoDepth,
  2418.              app_data.max_undo_depth, true) << '\n';
  2419.     os << int_app_value(XtNmaxUndoSize,
  2420.              app_data.max_undo_size, true) << '\n';
  2421.  
  2422.     // Misc stuff
  2423.     os << "\n! Misc preferences.\n";
  2424.     unsigned char policy = '\0';
  2425.     XtVaGetValues(command_shell, XmNkeyboardFocusPolicy, &policy, NULL);
  2426.     switch (policy)
  2427.     {
  2428.     case XmPOINTER:
  2429.     os << string_app_value(string(XmNkeyboardFocusPolicy), "POINTER") 
  2430.        << '\n';
  2431.     break;
  2432.     case XmEXPLICIT:
  2433.     os << string_app_value(string(XmNkeyboardFocusPolicy), "EXPLICIT")
  2434.        << '\n';
  2435.     break;
  2436.     }
  2437.  
  2438.     os << bool_app_value(XtNstatusAtBottom,
  2439.              app_data.status_at_bottom) << '\n';
  2440.     os << bool_app_value(XtNsuppressWarnings,
  2441.              app_data.suppress_warnings) << '\n';
  2442.     os << bool_app_value(XtNwarnIfLocked,
  2443.              app_data.warn_if_locked) << '\n';
  2444.     os << bool_app_value(XtNcheckGrabs,
  2445.              app_data.check_grabs) << '\n';
  2446.     os << bool_app_value(XtNsaveHistoryOnExit,
  2447.              app_data.save_history_on_exit) << '\n';
  2448.     os << string_app_value(XtNpaperSize,
  2449.                app_data.paper_size) << '\n';
  2450.     os << bool_app_value(XtNblinkWhileBusy,
  2451.              app_data.blink_while_busy) << '\n';
  2452.     os << bool_app_value(XtNsplashScreen,
  2453.              app_data.splash_screen) << '\n';
  2454.     os << bool_app_value(XtNstartupTips, 
  2455.              app_data.startup_tips) << '\n';
  2456.  
  2457.     // Keys
  2458.     os << "\n! Keys.\n";
  2459.     os << bool_app_value(XtNglobalTabCompletion, 
  2460.              app_data.global_tab_completion) << '\n';
  2461.     os << binding_app_value(XtNcutCopyPasteBindings,
  2462.                 app_data.cut_copy_paste_bindings) << '\n';
  2463.     os << binding_app_value(XtNselectAllBindings,
  2464.                 app_data.select_all_bindings) << '\n';
  2465.  
  2466.     // Graph editor
  2467.     os << "\n! Data.\n";
  2468.     os << bool_app_value(XtNpannedGraphEditor, 
  2469.              app_data.panned_graph_editor) << '\n';
  2470.     os << widget_value(data_disp->graph_edit, XtNshowGrid)   << '\n';
  2471.     os << widget_value(data_disp->graph_edit, XtNsnapToGrid) << '\n';
  2472.     os << widget_value(data_disp->graph_edit, XtNshowHints)  << '\n';
  2473.     os << widget_value(data_disp->graph_edit, XtNshowAnnotations) << '\n';
  2474.     os << widget_value(data_disp->graph_edit, XtNlayoutMode) << '\n';
  2475.     os << widget_value(data_disp->graph_edit, XtNautoLayout) << '\n';
  2476.     os << bool_app_value(XtNshowBaseDisplayTitles, 
  2477.              app_data.show_base_display_titles) << '\n';
  2478.     os << bool_app_value(XtNshowDependentDisplayTitles,
  2479.              app_data.show_dependent_display_titles) << '\n';
  2480.     os << bool_app_value(XtNautoCloseDataWindow,
  2481.              app_data.auto_close_data_window) << '\n';
  2482.  
  2483.     Dimension grid_width, grid_height;
  2484.     XtVaGetValues(data_disp->graph_edit,
  2485.           XtNgridWidth, &grid_width,
  2486.           XtNgridHeight, &grid_height,
  2487.           NULL);
  2488.     if (grid_width == grid_height)
  2489.     {
  2490.     os << int_app_value(string(XtName(data_disp->graph_edit)) + "." 
  2491.                 + XtCGridSize, grid_width, true) << '\n';
  2492.     }
  2493.     else
  2494.     {
  2495.     os << int_app_value(string(XtName(data_disp->graph_edit)) + "." 
  2496.                 + XtNgridWidth,  grid_width, true) << '\n';
  2497.     os << int_app_value(string(XtName(data_disp->graph_edit)) + "." 
  2498.                 + XtNgridHeight, grid_height, true) << '\n';
  2499.     }
  2500.     os << bool_app_value(XtNdetectAliases,  app_data.detect_aliases)   << '\n';
  2501.     os << bool_app_value(XtNclusterDisplays,app_data.cluster_displays) << '\n';
  2502.     os << bool_app_value(XtNalign2dArrays,  app_data.align_2d_arrays)  << '\n';
  2503.  
  2504.     // Tips
  2505.     os << "\n! Tips.\n";
  2506.     os << bool_app_value(XtNbuttonTips,
  2507.              app_data.button_tips) << '\n';
  2508.     os << bool_app_value(XtNvalueTips,
  2509.              app_data.value_tips) << '\n';
  2510.     os << bool_app_value(XtNbuttonDocs,
  2511.              app_data.button_docs) << '\n';
  2512.     os << bool_app_value(XtNvalueDocs,
  2513.              app_data.value_docs) << '\n';
  2514.  
  2515.     // Helpers
  2516.     os << "\n! Helpers.\n";
  2517.     os << string_app_value(XtNeditCommand,    app_data.edit_command, true)
  2518.        << '\n';
  2519.     os << string_app_value(XtNgetCoreCommand, app_data.get_core_command, true)
  2520.        << '\n';
  2521.     os << string_app_value(XtNpsCommand,      app_data.ps_command, true)
  2522.        << '\n';
  2523.     os << string_app_value(XtNtermCommand,    app_data.term_command, true)
  2524.        << '\n';
  2525.     os << string_app_value(XtNuncompressCommand, app_data.uncompress_command,
  2526.                true) << '\n';
  2527.     os << string_app_value(XtNwwwCommand,     app_data.www_command, true) 
  2528.        << '\n';
  2529.     os << string_app_value(XtNplotCommand,    app_data.plot_command, true)
  2530.        << '\n';
  2531.     os << string_app_value(XtNplotTermType,   app_data.plot_term_type)
  2532.        << '\n';
  2533.     os << string_app_value(XtNprintCommand,   app_data.print_command, true) 
  2534.        << '\n';
  2535.  
  2536.     // Toolbar
  2537.     os << "\n! Tool Bars.\n";
  2538.  
  2539. #if 0  // We cannot change this interactively.  Don't save.
  2540.     os << bool_app_value(XtNcommonToolBar,
  2541.              app_data.common_toolbar)  << '\n';
  2542. #endif
  2543.  
  2544.     os << bool_app_value(XtNtoolbarsAtBottom, 
  2545.              app_data.toolbars_at_bottom) << '\n';
  2546.     os << bool_app_value(XtNbuttonImages,
  2547.              app_data.button_images)   << '\n';
  2548.     os << bool_app_value(XtNbuttonCaptions,
  2549.              app_data.button_captions) << '\n';
  2550.  
  2551.     if (app_data.flat_toolbar_buttons == app_data.flat_dialog_buttons)
  2552.     {
  2553.     os << bool_app_value(XtCFlatButtons,
  2554.                  app_data.flat_toolbar_buttons) << '\n';
  2555.     }
  2556.     else
  2557.     {
  2558.     os << bool_app_value(XtNflatToolbarButtons,
  2559.                  app_data.flat_toolbar_buttons) << '\n';
  2560.     os << bool_app_value(XtNflatDialogButtons,
  2561.                  app_data.flat_dialog_buttons) << '\n';
  2562.     }
  2563.     os << string_app_value(XtNbuttonColorKey,
  2564.                app_data.button_color_key) << '\n';
  2565.     os << string_app_value(XtNactiveButtonColorKey,
  2566.                app_data.active_button_color_key) << '\n';
  2567.  
  2568.     // Command tool
  2569.     os << "\n! Command Tool.\n";
  2570.     get_tool_offset();
  2571.     os << bool_app_value(XtNcommandToolBar,
  2572.              app_data.command_toolbar) << '\n';
  2573.     os << int_app_value(XtNtoolRightOffset,
  2574.             app_data.tool_right_offset, true) << '\n';
  2575.     os << int_app_value(XtNtoolTopOffset,
  2576.             app_data.tool_top_offset, true) << '\n';
  2577.  
  2578.     // Buttons
  2579.     os << "\n! Buttons.\n";
  2580.     os << string_app_value(XtNconsoleButtons, app_data.console_buttons)
  2581.        << '\n';
  2582.     os << string_app_value(XtNsourceButtons,  app_data.source_buttons)
  2583.        << '\n';
  2584.     os << string_app_value(XtNdataButtons,    app_data.data_buttons)
  2585.        << '\n';
  2586.     os << bool_app_value(XtNverifyButtons,    app_data.verify_buttons)
  2587.        << '\n';
  2588.  
  2589.     // Shortcut expressions
  2590.     os << "\n! Display shortcuts.\n";
  2591.     {
  2592.     StringArray exprs;
  2593.     StringArray labels;
  2594.     data_disp->get_shortcut_menu(exprs, labels);
  2595.     string expr = "";
  2596.  
  2597.     for (int i = 0; i < exprs.size(); i++)
  2598.     {
  2599.         if (i > 0)
  2600.         expr += '\n';
  2601.  
  2602.         expr += exprs[i];
  2603.  
  2604.         if (labels[i] != "")
  2605.         {
  2606.         expr += string('\t') + app_data.label_delimiter + ' ' + 
  2607.             labels[i];
  2608.         }
  2609.     }
  2610.  
  2611.     string gdb_display_shortcuts  = app_data.gdb_display_shortcuts;
  2612.     string dbx_display_shortcuts  = app_data.dbx_display_shortcuts;
  2613.     string xdb_display_shortcuts  = app_data.xdb_display_shortcuts;
  2614.     string jdb_display_shortcuts  = app_data.jdb_display_shortcuts;
  2615.     string pydb_display_shortcuts = app_data.pydb_display_shortcuts;
  2616.     string perl_display_shortcuts = app_data.perl_display_shortcuts;
  2617.  
  2618.     switch (gdb->type())
  2619.     {
  2620.     case GDB:  gdb_display_shortcuts  = expr; break;
  2621.     case DBX:  dbx_display_shortcuts  = expr; break;
  2622.     case XDB:  xdb_display_shortcuts  = expr; break;
  2623.     case JDB:  jdb_display_shortcuts  = expr; break;
  2624.     case PYDB: pydb_display_shortcuts = expr; break;
  2625.     case PERL: perl_display_shortcuts = expr; break;
  2626.     }
  2627.  
  2628.     os << string_app_value(XtNgdbDisplayShortcuts, 
  2629.                    gdb_display_shortcuts, true) << '\n';
  2630.     os << string_app_value(XtNdbxDisplayShortcuts,
  2631.                    dbx_display_shortcuts, true) << '\n';
  2632.     os << string_app_value(XtNxdbDisplayShortcuts,
  2633.                    xdb_display_shortcuts, true) << '\n';
  2634.     os << string_app_value(XtNjdbDisplayShortcuts,
  2635.                    jdb_display_shortcuts, true) << '\n';
  2636.     os << string_app_value(XtNpydbDisplayShortcuts,
  2637.                    pydb_display_shortcuts, true) << '\n';
  2638.     os << string_app_value(XtNperlDisplayShortcuts,
  2639.                    perl_display_shortcuts, true) << '\n';
  2640.     }
  2641.  
  2642.     // Fonts
  2643.     os << "\n! Fonts.\n";
  2644.     os << string_app_value(XtNdefaultFont,
  2645.                app_data.default_font, true) << '\n';
  2646.     os << string_app_value(XtNvariableWidthFont, 
  2647.                app_data.variable_width_font, true) << '\n';
  2648.     os << string_app_value(XtNfixedWidthFont,
  2649.                app_data.fixed_width_font, true) << '\n';
  2650.     if (app_data.default_font_size == app_data.variable_width_font_size &&
  2651.     app_data.default_font_size == app_data.fixed_width_font_size)
  2652.     {
  2653.     os << int_app_value(XtCFontSize, app_data.default_font_size)
  2654.        << '\n';
  2655.     }
  2656.     else
  2657.     {
  2658.     os << int_app_value(XtNdefaultFontSize,
  2659.                 app_data.default_font_size) << '\n';
  2660.     os << int_app_value(XtNvariableWidthFontSize, 
  2661.                 app_data.variable_width_font_size) << '\n';
  2662.     os << int_app_value(XtNfixedWidthFontSize, 
  2663.                 app_data.fixed_width_font_size) << '\n';
  2664.     }
  2665.  
  2666.     // Windows.
  2667.     os << "\n! Windows.\n";
  2668.     os << bool_app_value(XtNopenDataWindow,      
  2669.              app_data.data_window)      << '\n';
  2670.     os << bool_app_value(XtNopenSourceWindow,    
  2671.              app_data.source_window)    << '\n';
  2672.     os << bool_app_value(XtNopenDebuggerConsole, 
  2673.              app_data.debugger_console) << '\n';
  2674.  
  2675.     if (!app_data.separate_source_window && !app_data.separate_data_window)
  2676.     {
  2677.     os << bool_app_value(XtCSeparate, false) << '\n';
  2678.     }
  2679.     else if (app_data.separate_source_window && app_data.separate_data_window)
  2680.     {
  2681.     os << bool_app_value(XtCSeparate, true) << '\n';
  2682.     }
  2683.     else
  2684.     {
  2685.     os << bool_app_value(XtNseparateSourceWindow, 
  2686.                  app_data.separate_source_window) << '\n';
  2687.     os << bool_app_value(XtNseparateDataWindow, 
  2688.                  app_data.separate_data_window) << '\n';
  2689.     }
  2690.     os << bool_app_value(XtNseparateExecWindow,
  2691.              app_data.separate_exec_window) << '\n';
  2692.     os << bool_app_value(XtNgroupIconify,
  2693.              app_data.group_iconify) << '\n';
  2694.     os << bool_app_value(XtNuniconifyWhenReady,
  2695.              app_data.uniconify_when_ready) << '\n';
  2696.  
  2697.     // Maintenance
  2698.     os << "\n! Maintenance.\n";
  2699.     os << bool_app_value(XtNdumpCore,       app_data.dump_core) << '\n';
  2700.     os << bool_app_value(XtNdebugCoreDumps, app_data.debug_core_dumps) << '\n';
  2701.  
  2702.     // Window sizes.
  2703.     os << "\n! Window sizes.\n";
  2704.  
  2705.     os << paned_widget_height(data_disp->graph_edit) << '\n';
  2706.     os << paned_widget_size(source_view->source())   << '\n';
  2707.     os << paned_widget_size(source_view->code())     << '\n';
  2708.     os << paned_widget_size(gdb_w)                   << '\n';
  2709.  
  2710.     if (save_geometry)
  2711.     {
  2712.     // Widget geometry
  2713.     os << "\n! Last " DDD_NAME " geometry.\n";
  2714.  
  2715.     if (command_shell)
  2716.         os << widget_geometry(command_shell)     << '\n';
  2717.     if (source_view_shell)
  2718.         os << widget_geometry(source_view_shell) << '\n';
  2719.     if (data_disp_shell)
  2720.         os << widget_geometry(data_disp_shell)   << '\n';
  2721.     }
  2722.  
  2723.     if (save_session)
  2724.     {
  2725.     // Restart commands
  2726.     os << "\n! Last " DDD_NAME " session.\n";
  2727.  
  2728.     string restart;
  2729.     bool restart_ok = get_restart_commands(restart, flags);
  2730.     if (!restart_ok)
  2731.         ok = false;
  2732.  
  2733.     os << string_app_value(XtNrestartCommands, restart) << '\n';
  2734.     }
  2735.  
  2736.     bool saved = true;
  2737.  
  2738.     os.close();
  2739.     if (os.bad())
  2740.     {
  2741.     if (interact)
  2742.         post_error("Cannot save " + options + " in " + quote(workfile),
  2743.                "options_save_error");
  2744.     ok = saved = false;
  2745.     unlink(workfile);
  2746.     }
  2747.  
  2748.     if (workfile != file && rename(workfile, file) != 0)
  2749.     {
  2750.     if (interact)
  2751.         post_error("Cannot rename " + quote(workfile)
  2752.                + " to " + quote(file) + ": " + strerror(errno),
  2753.                "options_save_error");
  2754.     ok = saved = false;
  2755.     unlink(workfile);
  2756.     }
  2757.  
  2758.     if (saved)
  2759.     {
  2760.     save_option_state();
  2761.     save_settings_state();
  2762.     options_file_has_changed(ACCESS, true);
  2763.     }
  2764.  
  2765.     return ok;
  2766. }
  2767.  
  2768. // ---------------------------------------------------------------------------
  2769. // Callbacks
  2770. // ---------------------------------------------------------------------------
  2771.  
  2772. static void DoSaveOptionsCB(Widget, XtPointer client_data, XtPointer)
  2773. {
  2774.     unsigned long flags = (unsigned long)client_data;
  2775.     save_options(flags);
  2776. }
  2777.  
  2778. // Save options
  2779. void DDDSaveOptionsCB(Widget w, XtPointer client_data, XtPointer call_data)
  2780. {
  2781.     unsigned long flags = (unsigned long)client_data;
  2782.     if ((flags & SAVE_SESSION) && app_data.session == DEFAULT_SESSION)
  2783.     {
  2784.     // No current session; cannot save
  2785.     return;
  2786.     }
  2787.     else if (options_file_has_changed(ACCESS))
  2788.     {
  2789.     // Options file has changed since last access; request confirmation
  2790.     static Widget dialog = 0;
  2791.     if (dialog)
  2792.         DestroyWhenIdle(dialog);
  2793.  
  2794.     dialog = verify(XmCreateQuestionDialog(find_shell(w), 
  2795.                            "overwrite_options_dialog",
  2796.                            0, 0));
  2797.     Delay::register_shell(dialog);
  2798.     XtAddCallback(dialog, XmNokCallback, DoSaveOptionsCB, 
  2799.               XtPointer(flags));
  2800.     XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, 0);
  2801.  
  2802.     manage_and_raise(dialog);
  2803.     }
  2804.     else if (saving_options_kills_program(flags))
  2805.     {
  2806.     // Saving session would kill program; request confirmation
  2807.     static Widget dialog = 0;
  2808.     if (dialog)
  2809.         DestroyWhenIdle(dialog);
  2810.  
  2811.     dialog = verify(XmCreateQuestionDialog(find_shell(w), 
  2812.                            "kill_to_save_dialog",
  2813.                            0, 0));
  2814.     Delay::register_shell(dialog);
  2815.     XtAddCallback(dialog, XmNokCallback, DoSaveOptionsCB, 
  2816.               XtPointer(flags | MAY_KILL));
  2817.     XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, 0);
  2818.  
  2819.     manage_and_raise(dialog);
  2820.     }
  2821.     else if (saving_options_excludes_data(flags))
  2822.     {
  2823.     // Saving session results in data loss; request confirmation
  2824.     static Widget dialog = 0;
  2825.     if (dialog)
  2826.         DestroyWhenIdle(dialog);
  2827.  
  2828.     dialog = verify(XmCreateQuestionDialog(find_shell(w), 
  2829.                            "data_not_saved_dialog",
  2830.                            0, 0));
  2831.     Delay::register_shell(dialog);
  2832.     XtAddCallback(dialog, XmNokCallback, DoSaveOptionsCB, 
  2833.               XtPointer(flags));
  2834.     XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, 0);
  2835.  
  2836.     manage_and_raise(dialog);
  2837.     }
  2838.     else
  2839.     {
  2840.     DoSaveOptionsCB(w, client_data, call_data);
  2841.     }
  2842. }
  2843.