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 / status.C < prev    next >
C/C++ Source or Header  |  1998-12-06  |  16KB  |  629 lines

  1. // $Id: status.C,v 1.50.4.1 1998/12/06 13:53:41 zeller Exp $ -*- C++ -*-
  2. // Show messages in status line
  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 status_rcsid[] = 
  30.     "$Id: status.C,v 1.50.4.1 1998/12/06 13:53:41 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "status.h"
  37.  
  38. #include "Command.h"
  39. #include "Delay.h"
  40. #include "DestroyCB.h"
  41. #include "GDBAgent.h"
  42. #include "HelpCB.h"
  43. #include "MakeMenu.h"
  44. #include "charsets.h"
  45. #include "ddd.h"
  46. #include "findParent.h"
  47. #include "mydialogs.h"
  48. #include "post.h"
  49. #include "string-fun.h"
  50. #include "verify.h"
  51.  
  52. #include <ctype.h>
  53. #include <Xm/Xm.h>
  54. #include <Xm/Text.h>
  55. #include <Xm/SelectioB.h>
  56. #include <Xm/RowColumn.h>
  57. #include <Xm/Label.h>
  58. #include <Xm/MenuShell.h>
  59.  
  60. #include <X11/IntrinsicP.h>    // LessTif hacks
  61. #include "LessTifH.h"
  62.  
  63. //-----------------------------------------------------------------------------
  64. // Data
  65. //-----------------------------------------------------------------------------
  66.  
  67. // True if last cmd came from GDB window
  68. bool gdb_keyboard_command = false;
  69.  
  70. // True if the next line is to be displayed in the status line
  71. bool show_next_line_in_status = false;
  72.  
  73. // True if GDB is asking `yes or no' right now
  74. bool gdb_asks_yn;
  75.  
  76. // Current contents of status window
  77. static MString current_status_text;
  78.  
  79. // Non-zero if status is locked (i.e. unchangeable)
  80. static int status_locked = 0;
  81.  
  82. // True iff status is to be logged
  83. static bool log_status = true;
  84.  
  85.  
  86. //-----------------------------------------------------------------------------
  87. // Status lock
  88. //-----------------------------------------------------------------------------
  89.  
  90. void lock_status()       { status_locked++;   }
  91. void unlock_status()     { if (status_locked > 0) status_locked--; }
  92. void reset_status_lock() { status_locked = 0; }
  93.  
  94.  
  95. //-----------------------------------------------------------------------------
  96. // Prompt recognition
  97. //-----------------------------------------------------------------------------
  98.  
  99. void set_buttons_from_gdb(Widget buttons, string& text)
  100. {
  101.     bool yn = text.contains("(y or n) ", -1) 
  102.     || text.contains("(yes or no) ", -1)
  103.     || ((gdb->type() == XDB || gdb->type() == JDB) 
  104.         && text.contains("? ", -1));
  105.  
  106.     if (yn)
  107.     {
  108.     gdb_asks_yn = true;
  109.     }
  110.     else if (gdb->isReadyWithPrompt())
  111.     {
  112.     gdb_asks_yn = false;
  113.     unpost_gdb_yn();
  114.     }
  115.  
  116.     if (yn && !gdb_keyboard_command)
  117.     {
  118.     // Fetch previous output lines, in case this is a multi-line message.
  119.     String s = XmTextGetString(gdb_w);
  120.     string prompt(s);
  121.     XtFree(s);
  122.  
  123.     // FIXME: Handle JDB
  124.     char prompt_start = (gdb->type() == XDB ? '>' : '(');
  125.  
  126.     int pos = prompt.index(prompt_start, -1);
  127.     if (pos >= 0)
  128.         pos = prompt.index('\n', pos) + 1;
  129.     if (pos == 0)
  130.         pos = messagePosition;
  131.  
  132.     XmTextReplace(gdb_w, pos, XmTextGetLastPosition(gdb_w), "");
  133.  
  134.     prompt = prompt.from(pos);
  135.     if (text.contains('('))
  136.         prompt += text.before('(', -1); // Don't repeat `(y or n)'
  137.     else
  138.         prompt += text;
  139.  
  140.     post_gdb_yn(prompt);
  141.     text = "";
  142.     return;
  143.     }
  144.  
  145.     if (buttons == 0)
  146.     return;
  147.  
  148.     static bool last_yn = false;
  149.     if (yn == last_yn)
  150.     return;
  151.  
  152.     last_yn = yn;
  153.  
  154.     if (XtIsComposite(buttons))
  155.     {
  156.     set_sensitive(buttons, false);
  157.  
  158.     WidgetList children   = 0;
  159.     Cardinal num_children = 0;
  160.  
  161.     XtVaGetValues(buttons,
  162.               XmNchildren, &children,
  163.               XmNnumChildren, &num_children,
  164.               NULL);
  165.  
  166.     int i;
  167.     for (i = 0; i < int(num_children); i++)
  168.         XtManageChild(children[i]);
  169.     for (i = 0; i < int(num_children); i++)
  170.     {
  171.     
  172.         Widget w = children[i];
  173.         string name = XtName(w);
  174.  
  175.         if (yn == (name == "Yes" || name == "No"))
  176.         XtManageChild(w);
  177.         else
  178.         XtUnmanageChild(w);
  179.     }
  180.  
  181.     set_sensitive(buttons, true);
  182.     }
  183. }
  184.  
  185.  
  186. //-----------------------------------------------------------------------------
  187. // Status history
  188. //-----------------------------------------------------------------------------
  189.  
  190. int status_history_size = 20;
  191. static MString *history = 0;
  192. static int current_history = 0;
  193.  
  194. static Widget history_label = 0;
  195. static Widget history_row   = 0;
  196.  
  197. static Widget create_status_history(Widget parent)
  198. {
  199.     static Widget history_shell = 0;
  200.  
  201.     if (history_shell != 0)
  202.     return history_shell;
  203.  
  204.     Arg args[10];
  205.     int arg;
  206.  
  207.     arg = 0;
  208.     XtSetArg(args[arg], XmNallowShellResize, True); arg++;
  209.     XtSetArg(args[arg], XmNwidth,            10);   arg++;
  210.     XtSetArg(args[arg], XmNheight,           10);   arg++;
  211.     history_shell = verify(XmCreateMenuShell(parent, "status_history", 
  212.                          args, arg));
  213.  
  214.     arg = 0;
  215.     XtSetArg(args[arg], XmNmarginWidth, 0);     arg++;
  216.     XtSetArg(args[arg], XmNmarginHeight, 0);    arg++;
  217.     XtSetArg(args[arg], XmNresizeWidth, True);  arg++;
  218.     XtSetArg(args[arg], XmNresizeHeight, True); arg++;
  219.     XtSetArg(args[arg], XmNborderWidth, 0);     arg++;
  220.     XtSetArg(args[arg], XmNshadowThickness, 0); arg++;
  221.     history_row = verify(XmCreateRowColumn(history_shell, "row", args, arg));
  222.     XtManageChild(history_row);
  223.  
  224.     arg = 0;
  225.     XtSetArg(args[arg], XmNresizable, True); arg++;
  226.     XtSetArg(args[arg], XmNalignment, XmALIGNMENT_BEGINNING); arg++;
  227.     history_label = verify(XmCreateLabel(history_row, "label", args, arg));
  228.     XtManageChild(history_label);
  229.                        
  230.     return history_shell;
  231. }
  232.  
  233. Widget status_history(Widget parent)
  234. {
  235.     Widget history_shell = create_status_history(parent);
  236.  
  237.     MString history_msg;
  238.  
  239.     if (history == 0 || status_history_size == 0)
  240.     {
  241.     history_msg = rm("No history.");
  242.     }
  243.     else
  244.     {
  245.     history_msg = bf("Recent messages");
  246.     history_msg += rm(" (oldest first)");
  247.     history_msg += cr();
  248.  
  249.     int i = current_history;
  250.     do {
  251.         if (!history[i].isEmpty())
  252.         {
  253.         if (!history_msg.isEmpty())
  254.             history_msg += cr();
  255.         history_msg += history[i];
  256.         }
  257.         i = (i + 1) % status_history_size;
  258.     } while (i != current_history);
  259.     }
  260.  
  261.     if (lesstif_version < 1000)
  262.     {
  263.     // LessTif fails to resize the shell properly - the border
  264.     // width is zero.  Use this hack instead.
  265.     XmFontList font_list;
  266.     XtVaGetValues(history_label, XmNfontList, &font_list, NULL);
  267.     
  268.     Dimension history_width  = history_msg.width(font_list)  + 6;
  269.     Dimension history_height = history_msg.height(font_list) + 6;
  270.  
  271.     XtResizeWidget(history_label, history_width, history_height, 0);
  272.     XtResizeWidget(history_row,   history_width, history_height, 0);
  273.  
  274.     XtResizeWidget(history_shell, history_width, history_height, 1);
  275.     }
  276.  
  277.     XtVaSetValues(history_label, XmNlabelString, history_msg.xmstring(), 
  278.           XtPointer(0));
  279.  
  280.     return history_shell;
  281. }
  282.  
  283. // Return true iff S1 is a prefix of S2
  284. static bool is_prefix(const MString& m1, const MString& m2)
  285. {
  286.     XmString s1 = m1.xmstring();
  287.     XmString s2 = m2.xmstring();
  288.  
  289.     XmStringContext c1;
  290.     XmStringContext c2;
  291.  
  292.     XmStringInitContext(&c1, s1);
  293.     XmStringInitContext(&c2, s2);
  294.  
  295.     XmStringComponentType t1 = XmSTRING_COMPONENT_UNKNOWN;
  296.     XmStringComponentType t2 = XmSTRING_COMPONENT_UNKNOWN;
  297.  
  298.     while (t1 != XmSTRING_COMPONENT_END && t2 != XmSTRING_COMPONENT_END)
  299.     {
  300.     char *s_text1            = 0;
  301.     XmStringCharSet s_cs1    = 0;
  302.     XmStringDirection d1     = XmSTRING_DIRECTION_DEFAULT;
  303.     XmStringComponentType u1 = XmSTRING_COMPONENT_UNKNOWN;
  304.     unsigned short ul1       = 0;
  305.     unsigned char *s_uv1     = 0;
  306.     
  307.     t1 = XmStringGetNextComponent(c1, &s_text1, &s_cs1, &d1, 
  308.                       &u1, &ul1, &s_uv1);
  309.  
  310.     char *s_text2            = 0;
  311.     XmStringCharSet s_cs2    = 0;
  312.     XmStringDirection d2     = XmSTRING_DIRECTION_DEFAULT;
  313.     XmStringComponentType u2 = XmSTRING_COMPONENT_UNKNOWN;
  314.     unsigned short ul2       = 0;
  315.     unsigned char *s_uv2     = 0;
  316.  
  317.     t2 = XmStringGetNextComponent(c2, &s_text2, &s_cs2, &d2,
  318.                       &u2, &ul2, &s_uv2);
  319.  
  320.     // Upon EOF in LessTif 0.82, XmStringGetNextComponent()
  321.     // returns XmSTRING_COMPONENT_UNKNOWN instead of
  322.     // XmSTRING_COMPONENT_END.  Work around this.
  323.     if (t1 == XmSTRING_COMPONENT_UNKNOWN && s_uv1 == 0)
  324.         t1 = XmSTRING_COMPONENT_END;
  325.     if (t2 == XmSTRING_COMPONENT_UNKNOWN && s_uv2 == 0)
  326.         t2 = XmSTRING_COMPONENT_END;
  327.  
  328.     // Place string values in strings
  329.     string text1(s_text1 == 0 ? "" : s_text1);
  330.     string text2(s_text2 == 0 ? "" : s_text2);
  331.     string cs1(s_cs1 == 0 ? "" : s_cs1);
  332.     string cs2(s_cs2 == 0 ? "" : s_cs2);
  333.     string uv1;
  334.     string uv2;
  335.     if (s_uv1 != 0)
  336.         uv1 = string((char *)s_uv1, ul1);
  337.     if (s_uv2 != 0)
  338.         uv2 = string((char *)s_uv2, ul2);
  339.  
  340.     // Free unused memory
  341.     XtFree(s_text1);
  342.     XtFree(s_text2);
  343.     XtFree(s_cs1);
  344.     XtFree(s_cs2);
  345.     XtFree((char *)s_uv1);
  346.     XtFree((char *)s_uv2);
  347.  
  348.     if (t1 != t2)
  349.     {
  350.         goto done;        // Differing tags
  351.     }
  352.  
  353.     switch (t1)
  354.     {
  355.     case XmSTRING_COMPONENT_CHARSET:
  356.     {
  357.         if (cs1 == "")    // In LessTif 0.82, XmStringGetNextComponent()
  358.         cs1 = text1;    // swaps CS and TEXT.  Work around this.
  359.         if (cs2 == "")
  360.         cs2 = text2;
  361.  
  362.         if (cs1 != cs2)
  363.         goto done;    // Differing character sets
  364.         break;
  365.     }
  366.  
  367.     case XmSTRING_COMPONENT_TEXT:
  368. #if XmVersion >= 1002
  369.     case XmSTRING_COMPONENT_LOCALE_TEXT:
  370. #endif
  371. #if XmVersion >= 2000
  372.     case XmSTRING_COMPONENT_WIDECHAR_TEXT:
  373. #endif
  374.     {
  375.         if (text1 == "")    // In LessTif 0.82, XmStringGetNextComponent()
  376.         text1 = cs1;    // swaps CS and TEXT.  Work around this.
  377.         if (text2 == "")
  378.         text2 = cs2;
  379.  
  380.         if (!text2.contains(text1, 0))
  381.         goto done;
  382.         XmStringComponentType next2 = XmStringPeekNextComponent(c2);
  383.  
  384.         // In LessTif 0.82, XmStringPeekNextComponent() returns
  385.         // XmSTRING_COMPONENT_UNKNOWN instead of
  386.         // XmSTRING_COMPONENT_END.  Work around this.
  387.         if (next2 != XmSTRING_COMPONENT_END && 
  388.         next2 != XmSTRING_COMPONENT_UNKNOWN)
  389.         goto done;
  390.         break;
  391.     }
  392.  
  393.     case XmSTRING_COMPONENT_DIRECTION:
  394.     {
  395.         if (d1 != d2)
  396.         goto done;
  397.         break;
  398.     }
  399.  
  400.     case XmSTRING_COMPONENT_SEPARATOR:
  401.     case XmSTRING_COMPONENT_END:
  402.     {
  403.         // These are the same by definition
  404.         break;
  405.     }
  406.  
  407.     case XmSTRING_COMPONENT_UNKNOWN:
  408.     {
  409.         if (uv1 != uv2)
  410.         goto done;    // Differing unknown tags
  411.         break;
  412.     }
  413.  
  414.     default:
  415.     {
  416.         break;        // Skip everything else
  417.     }
  418.     }
  419.     }
  420.  done:
  421.  
  422.     XmStringFreeContext(c2);
  423.     XmStringFreeContext(c1);
  424.  
  425.     return t1 == XmSTRING_COMPONENT_END;
  426. }
  427.  
  428.  
  429. // Return all characters in M
  430. static string str(const MString& _m)
  431. {
  432.     string s = "";
  433.  
  434.     XmString m = _m.xmstring();
  435.     XmStringContext c;
  436.     XmStringInitContext(&c, m);
  437.     XmStringComponentType t = XmSTRING_COMPONENT_UNKNOWN;
  438.  
  439.     while (t != XmSTRING_COMPONENT_END)
  440.     {
  441.     char *s_text            = 0;
  442.     XmStringCharSet s_cs    = 0;
  443.     XmStringDirection d     = XmSTRING_DIRECTION_DEFAULT;
  444.     XmStringComponentType u = XmSTRING_COMPONENT_UNKNOWN;
  445.     unsigned short ul       = 0;
  446.     unsigned char *s_uv     = 0;
  447.     
  448.     t = XmStringGetNextComponent(c, &s_text, &s_cs, &d, &u, &ul, &s_uv);
  449.  
  450.     // Upon EOF in LessTif 0.82, XmStringGetNextComponent()
  451.     // returns XmSTRING_COMPONENT_UNKNOWN instead of
  452.     // XmSTRING_COMPONENT_END.  Work around this.
  453.     if (t == XmSTRING_COMPONENT_UNKNOWN && s_uv == 0)
  454.         t = XmSTRING_COMPONENT_END;
  455.  
  456.     // Place string values in strings
  457.     string text(s_text == 0 ? "" : s_text);
  458.     string cs(s_cs == 0 ? "" : s_cs);
  459.     string uv;
  460.     if (s_uv != 0)
  461.         uv = string((char *)s_uv, ul);
  462.  
  463.     // Free unused memory
  464.     XtFree(s_text);
  465.     XtFree(s_cs);
  466.     XtFree((char *)s_uv);
  467.  
  468.     switch (t)
  469.     {
  470.     case XmSTRING_COMPONENT_TEXT:
  471. #if XmVersion >= 1002
  472.     case XmSTRING_COMPONENT_LOCALE_TEXT:
  473. #endif
  474. #if XmVersion >= 2000
  475.     case XmSTRING_COMPONENT_WIDECHAR_TEXT:
  476. #endif
  477.         s += text;
  478.         break;
  479.  
  480.     case XmSTRING_COMPONENT_SEPARATOR:
  481.         s += "\n";
  482.         break;
  483.  
  484.     default:
  485.         break;
  486.     }
  487.     }
  488.  
  489.     XmStringFreeContext(c);
  490.  
  491.     return s;
  492. }
  493.  
  494. static void add_to_status_history(const MString& message)
  495. {
  496.     static MString empty = rm(" ");
  497.  
  498.     if (history == 0)
  499.     history = new MString[status_history_size];
  500.  
  501.     int last_history = 
  502.     (status_history_size + current_history - 1) % status_history_size;
  503.  
  504.     if (message.isNull() || message.isEmpty() || message == empty)
  505.     return;
  506.  
  507.     if (is_prefix(history[last_history], message))
  508.     {
  509.     history[last_history] = message;
  510.     return;
  511.     }
  512.  
  513.     history[current_history] = message;
  514.     current_history = (current_history + 1) % status_history_size;
  515. }
  516.  
  517. //-----------------------------------------------------------------------------
  518. // Status recognition
  519. //-----------------------------------------------------------------------------
  520.  
  521. void set_status_from_gdb(const string& text)
  522. {
  523.     if (private_gdb_input)
  524.     return;
  525.  
  526.     if (!show_next_line_in_status && !text.contains(gdb->prompt(), -1))
  527.     return;
  528.  
  529.     // Fetch line before prompt in GDB window
  530.     String s = XmTextGetString(gdb_w);
  531.     string message = s + messagePosition;
  532.     XtFree(s);
  533.  
  534.     if (message == "" && text.contains('\n'))
  535.     message = text;
  536.  
  537.     if (show_next_line_in_status && 
  538.     (message == "" || message[message.length() - 1] != '\n'))
  539.     return;
  540.  
  541.     // Skip prompt and uncomplete lines
  542.     int idx = message.index('\n', -1);
  543.     if (idx >= 0)
  544.     message = message.before(idx);
  545.  
  546.     strip_trailing_newlines(message);
  547.     if (message == "" && text.contains('\n'))
  548.     message = text;
  549.  
  550.     if (show_next_line_in_status)
  551.     {
  552.     messagePosition = XmTextGetLastPosition(gdb_w) + text.length();
  553.     show_next_line_in_status = false;
  554.     message.gsub('\n', ' ');
  555.     }
  556.     else
  557.     {
  558.     // Show first line only
  559.     while (message != "" && message[0] == '\n')
  560.         message = message.after('\n');
  561.     if (message.contains('\n'))
  562.         message = message.before('\n');
  563.     }
  564.  
  565.     strip_trailing_newlines(message);
  566.     message.gsub('\t', ' ');
  567.     if (message == "")
  568.     return;
  569.  
  570.     // Don't log this stuff - it's already logged
  571.     bool old_log_status = log_status;
  572.     log_status = false;
  573.     set_status(message);
  574.     log_status = old_log_status;
  575. }
  576.  
  577. // Show MESSAGE in status window.
  578. // If TEMPORARY is set, override locks and do not add to status history.
  579. void set_status(string message, bool temporary)
  580. {
  581.     if (status_w == 0)
  582.     return;
  583.  
  584.     if (message.length() > 0
  585.     && !message.contains("=") 
  586.     && isascii(message[0])
  587.     && islower(message[0]))
  588.     message[0] = toupper(message[0]);
  589.  
  590.     set_status_mstring(rm(message), temporary);
  591. }
  592.  
  593. // Same, but use an MString.
  594. void set_status_mstring(MString message, bool temporary)
  595. {
  596.     if (status_w == 0)
  597.     return;
  598.  
  599.     if (!temporary)
  600.     add_to_status_history(message);
  601.  
  602.     if (!status_locked)
  603.     {
  604.     current_status_text = message;
  605.  
  606.     XtVaSetValues(status_w,
  607.               XmNlabelString, message.xmstring(),
  608.               NULL);
  609.     XFlush(XtDisplay(status_w));
  610.     XmUpdateDisplay(status_w);
  611.     }
  612.  
  613.     if (log_status && !temporary)
  614.     {
  615.     // Log status message
  616.     string s = str(message);
  617.     if (s != "" && s != " ")
  618.     {
  619.         dddlog << "#  " << s << "\n";
  620.         dddlog.flush();
  621.     }
  622.     }
  623. }
  624.  
  625. const MString& current_status()
  626. {
  627.     return current_status_text;
  628. }
  629.