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 / DispBox.C < prev    next >
C/C++ Source or Header  |  1998-12-04  |  14KB  |  633 lines

  1. // $Id: DispBox.C,v 1.69.4.2 1998/12/04 15:20:09 zeller Exp $
  2. // Display boxes
  3.  
  4. // Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>
  6. // and Andreas Zeller <zeller@ips.cs.tu-bs.de>
  7. // 
  8. // This file is part of DDD.
  9. // 
  10. // DDD is free software; you can redistribute it and/or
  11. // modify it under the terms of the GNU General Public
  12. // License as published by the Free Software Foundation; either
  13. // version 2 of the License, or (at your option) any later version.
  14. // 
  15. // DDD is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18. // See the GNU General Public License for more details.
  19. // 
  20. // You should have received a copy of the GNU General Public
  21. // License along with DDD -- see the file COPYING.
  22. // If not, write to the Free Software Foundation, Inc.,
  23. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  24. // 
  25. // DDD is the data display debugger.
  26. // For details, see the DDD World-Wide-Web page, 
  27. // `http://www.cs.tu-bs.de/softech/ddd/',
  28. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  29.  
  30. char DispBox_rcsid[] =
  31.     "$Id: DispBox.C,v 1.69.4.2 1998/12/04 15:20:09 zeller Exp $";
  32.  
  33. #ifdef __GNUG__
  34. #pragma implementation
  35. #endif
  36.  
  37. //-----------------------------------------------------------------------------
  38. // Create DispBoxes via VSL
  39. //-----------------------------------------------------------------------------
  40.  
  41. #include "assert.h"
  42. #include "DispBox.h"
  43. #include "StringBox.h"
  44. #include "ColorBox.h"
  45. #include "DispNode.h"
  46. #include "GDBAgent.h"
  47. #include "VSEFlags.h"
  48. #include "strclass.h"
  49. #include "bool.h"
  50. #include "cook.h"
  51. #include "ddd.h"
  52. #include "status.h"
  53. #include "shorten.h"
  54. #include "string-fun.h"
  55. #include "tabs.h"
  56. #include "version.h"
  57. #include "regexps.h"
  58.  
  59. #include <ctype.h>
  60.  
  61. #define assert_ok(x) assert(x)
  62.  
  63. #ifndef CACHE_BOXES
  64. #define CACHE_BOXES 1
  65. #endif
  66.  
  67.  
  68. //-----------------------------------------------------------------------------
  69.  
  70. VSLLib  DispBox::dummylib;
  71. VSLLib* DispBox::vsllib_ptr       = &DispBox::dummylib;
  72. string  DispBox::vsllib_name      = "builtin";
  73. string  DispBox::vsllib_path      = ".";
  74. string  DispBox::vsllib_defs      = "";
  75. string  DispBox::vsllib_base_defs = "";
  76. int     DispBox::max_display_title_length = 20;
  77. bool    DispBox::vsllib_initialized = false;
  78. bool    DispBox::align_2d_arrays = true;
  79.  
  80.  
  81. // ***************************************************************************
  82. //
  83. DispBox::DispBox (int disp_nr, const string& title, 
  84.           const DispValue *dv, const DispValue *parent)
  85.     : mybox(0), title_box(0)
  86. {
  87.     // Create display
  88.     set_title(disp_nr, title);
  89.     set_value(dv, parent);
  90. }
  91.  
  92.  
  93. // ***************************************************************************
  94. //
  95. void DispBox::init_vsllib(void (*background)())
  96. {
  97.     if (vsllib_initialized)
  98.     return;            // We already have a library
  99.  
  100.     static bool initializing = false;
  101.     if (initializing)
  102.     return;            // We are already initializing
  103.  
  104.     initializing = true;
  105.  
  106.     static const char builtin_def[] = 
  107. #include "ddd.vsl.h"
  108.     ;
  109.  
  110.     // Set include search path
  111.     VSEFlags::include_search_path = 
  112.     strcpy(new char[vsllib_path.length() + 1], vsllib_path);
  113.  
  114.     // Load library
  115.     void (*old_background)() = VSLLib::background;
  116.     VSLLib::background = background;
  117.  
  118.     if (string(vsllib_name) == "builtin")
  119.     {
  120.     string defs = string(builtin_def)
  121.         + "#line 1 \"" Ddd_NAME "*vslBaseDefs\"\n"
  122.         + vsllib_base_defs
  123.         + "#line 1 \"" Ddd_NAME "*vslDefs\"\n"
  124.         + vsllib_defs;
  125.     istrstream is(defs.chars());
  126.     vsllib_ptr = new VSLLib(is, VSEFlags::optimize_mode());
  127.     }
  128.     else
  129.     {
  130.     vsllib_ptr = new VSLLib(vsllib_name, VSEFlags::optimize_mode());
  131.     }
  132.  
  133.     VSLLib::background = old_background;
  134.     initializing = false;
  135.     vsllib_initialized = true;
  136. }
  137.  
  138.  
  139. // ***************************************************************************
  140. //
  141. DispBox::~DispBox ()
  142. {
  143.     assert_ok(mybox == 0 || mybox->OK());
  144.  
  145.     if (mybox != 0)
  146.     mybox->unlink();
  147.  
  148.     assert_ok(title_box == 0 || title_box->OK());
  149.  
  150.     if (title_box != 0)
  151.     title_box->unlink();
  152. }
  153.  
  154. // ***************************************************************************
  155. //
  156. void DispBox::set_value(const DispValue* dv, const DispValue *parent)
  157. {
  158.     if (mybox != 0)
  159.     {
  160.     mybox->unlink();
  161.     mybox = 0;
  162.     }
  163.  
  164.     VSLArgList args;
  165.     if (title_box != 0)
  166.     args += title_box->link();
  167.  
  168.     if (dv != 0)
  169.     ((DispValue *)dv)->validate_box_cache();
  170.  
  171.     args += create_value_box(dv, parent);
  172.     mybox = eval("display_box", args);
  173.  
  174.     assert_ok(mybox->OK());
  175. }
  176.  
  177. void DispBox::shorten_title(string& name)
  178. {
  179.     if (name == "")
  180.     return;
  181.  
  182.     if (!is_user_command(name))
  183.     {
  184.     // Strip DBX scope information from title
  185. #if RUNTIME_REGEX
  186.     static regex rxdbx_scope("[a-zA-Z_0-9]*`");
  187. #endif
  188.     int i = 0;
  189.     while (int(name.length()) > max_display_title_length 
  190.            && ((i = name.index(rxdbx_scope)) >= 0))
  191.     {
  192.         name = name.before(i) + name.after('`');
  193.     }
  194.     }
  195.  
  196.     // Shorten remainder
  197.     shorten(name, max_display_title_length);
  198. }
  199.  
  200. void DispBox::set_title(int disp_nr, string name)
  201. {
  202.     if (title_box != 0)
  203.     {
  204.     title_box->unlink();
  205.     title_box = 0;
  206.     }
  207.  
  208.     // Create title
  209.     if (name != "")
  210.     {
  211.     VSLArg args[3];
  212.     int arg = 0;
  213.  
  214.     if (is_user_command(name))
  215.     {
  216.         // User command: use NAME
  217.         string title = DispValue::make_title(name);
  218.         shorten_title(title);
  219.         args[arg++] = tag(title);
  220.     }
  221.     else
  222.     {
  223.         // Normal title: use NUMBER: NAME
  224.         args[arg++] = itostring(disp_nr);
  225.         shorten_title(name);
  226.         args[arg++] = tag(name);
  227.     }
  228.  
  229.     title_box = eval("title", args);
  230.  
  231.     assert_ok(title_box->OK());
  232.     }
  233. }
  234.  
  235. // Return true if DV is a (right-aligned) numeric value
  236. bool DispBox::is_numeric(const DispValue *dv, const DispValue *parent)
  237. {
  238.     if (parent != 0 && parent->type() != Array)
  239.     return false;
  240.  
  241.     if (dv->value() == "")
  242.     return false;
  243.     if (dv->value().contains(' '))
  244.     return false;
  245.  
  246.     char c = dv->value()[0];
  247.     return isdigit(c) || c == '+' || c == '-' || c == '.';
  248. }
  249.  
  250. // ***************************************************************************
  251. // Create a Box for the value DV
  252. Box *DispBox::_create_value_box(const DispValue *dv, const DispValue *parent)
  253. {
  254.     assert(dv != 0);
  255.  
  256.     Box *vbox = 0;
  257.  
  258. #if CACHE_BOXES
  259.     // Check cache first
  260.     vbox = dv->cached_box();
  261.  
  262.     if (vbox != 0)
  263.     {
  264.     vbox = vbox->link();
  265.     assert_ok(vbox->OK());
  266.     return vbox;
  267.     }
  268. #endif
  269.  
  270.     // Rebuild box
  271.     switch (dv->type())
  272.     {
  273.     case Simple:
  274.     {
  275.     if (dv->collapsed())
  276.         vbox = eval("collapsed_simple_value");
  277.     else
  278.     {
  279.         // Flush numeric values to the right, unless in a struct
  280.         if (is_numeric(dv, parent))
  281.         vbox = eval("numeric_value", dv->value());
  282.         else
  283.         vbox = eval("simple_value", dv->value());
  284.     }
  285.     break;
  286.     }
  287.  
  288.     case Text:
  289.     {
  290.     if (dv->collapsed())
  291.         vbox = eval("collapsed_text_value");
  292.     else
  293.     {
  294.         string v = dv->value();
  295.         strip_space(v);
  296.         untabify(v);
  297.  
  298.         int n = v.freq('\n');
  299.         string *lines = new string[n + 1];
  300.         split(v, lines, n + 1, '\n');
  301.  
  302.         VSLArgList args;
  303.         for (int i = 0; i < n + 1; i++)
  304.         {
  305.         if (lines[i] == "")
  306.             lines[i] = " ";
  307.         args += eval("text_line", lines[i]);
  308.         }
  309.         vbox = eval("text_value", args);
  310.  
  311.         delete[] lines;
  312.     }
  313.     break;
  314.     }
  315.  
  316.     case Pointer:
  317.     {
  318.     if (dv->collapsed())
  319.         vbox = eval("collapsed_pointer_value");
  320.     else if (dv->dereferenced())
  321.         vbox = eval("dereferenced_pointer_value", dv->value());
  322.     else
  323.         vbox = eval("pointer_value", dv->value());
  324.     break;
  325.     }
  326.  
  327.     case Array:
  328.     {
  329.     if (dv->collapsed())
  330.         vbox = eval("collapsed_array");
  331.     else
  332.     {
  333.         int count = dv->nchildren();
  334.         if (count == 0)
  335.         {
  336.         vbox = eval("empty_array");
  337.         }
  338.         else
  339.         {
  340.         bool have_2d_array = true;
  341.  
  342.         if (dv->repeats() > 1)
  343.             have_2d_array = false;
  344.  
  345.         int nchildren = 0;
  346.         for (int k = 0; have_2d_array && k < count; k++)
  347.         {
  348.             DispValue *child = dv->child(k);
  349.             if (child->type() != Array)
  350.             {
  351.             // Child is no array
  352.             have_2d_array = false;
  353.             break;
  354.             }
  355.  
  356.             if (child->repeats() > 1)
  357.             {
  358.             // Child is a repeated array
  359.             have_2d_array = false;
  360.             break;
  361.             }
  362.  
  363.             if (k == 0)
  364.             {
  365.             nchildren = child->nchildren();
  366.             }
  367.             else if (nchildren != child->nchildren())
  368.             {
  369.             // Children have differing sizes
  370.             have_2d_array = false;
  371.             break;
  372.             }
  373.         }
  374.  
  375.         if (have_2d_array && align_2d_arrays)
  376.         {
  377.             // Two-dimensional array
  378.             ListBox *table = new ListBox;
  379.  
  380.             if (dv->vertical_aligned())
  381.             {
  382.             // Sub-arrays are aligned vertically;
  383.             // each sub-array is laid out horizontally
  384.             for (int i = 0; i < count; i++)
  385.             {
  386.                 DispValue *c = dv->child(i);
  387.                 ListBox *row = new ListBox;
  388.                 for (int j = 0; j < c->nchildren(); j++)
  389.                 {
  390.                 DispValue *cc = c->child(j);
  391.                 Box *b = eval("twodim_array_elem", 
  392.                           create_value_box(cc, c));
  393.                 *row += b;
  394.                 b->unlink();
  395.                 }
  396.  
  397.                 *table += row;
  398.                 row->unlink();
  399.             }
  400.             }
  401.             else
  402.             {
  403.             // Sub-arrays are aligned horizontally;
  404.             // each sub-array is laid out vertically
  405.             int max_cc = 0;
  406.             for (int j = 0; j < count; j++)
  407.                 max_cc = max(max_cc, dv->child(j)->nchildren());
  408.             for (int i = 0; i < max_cc; i++)
  409.             {
  410.                 ListBox *row = new ListBox;
  411.                 for (int j = 0; j < count; j++)
  412.                 {
  413.                 DispValue *c = dv->child(j);
  414.                 Box *elem = 0;
  415.                 if (i < c->nchildren())
  416.                 {
  417.                     DispValue *cc = c->child(i);
  418.                     elem = create_value_box(cc, c);
  419.                 }
  420.                 else
  421.                 {
  422.                     elem = new ListBox;
  423.                 }
  424.  
  425.                 Box *b = eval("twodim_array_elem", elem);
  426.                 *row += b;
  427.                 b->unlink();
  428.                 }
  429.  
  430.                 *table += row;
  431.                 row->unlink();
  432.             }
  433.             }
  434.  
  435.             vbox = eval("twodim_array", table);
  436.         }
  437.         else
  438.         {
  439.             // One-dimensional array
  440.             VSLArgList args;
  441.             for (int i = 0; i < count; i++)
  442.             args += create_value_box(dv->child(i), dv);
  443.  
  444.             if (dv->vertical_aligned())
  445.             vbox = eval("vertical_array", args);
  446.             else
  447.             vbox = eval("horizontal_array", args);
  448.         }
  449.         }
  450.     }
  451.     break;
  452.     }
  453.  
  454.     case Sequence:
  455.     {
  456.     if (dv->collapsed())
  457.         vbox = eval("collapsed_sequence_value");
  458.     else
  459.     {
  460.         // Create children
  461.         VSLArgList args;
  462.         int count = dv->nchildren();
  463.         for (int i = 0; i < count; i++)
  464.         args += create_value_box(dv->child(i), dv);
  465.  
  466.         vbox = eval("sequence_value", args);
  467.     }
  468.     break;
  469.     }
  470.  
  471.     case List:
  472.     case Struct:
  473.     {
  474.     String collapsed_value = (dv->type() == List ? 
  475.                   "collapsed_list_value" :
  476.                   "collapsed_struct_value");
  477.     String empty_value     = (dv->type() == List ? 
  478.                   "empty_list_value" :
  479.                   "empty_struct_value");
  480.     String member_name     = (dv->type() == List ? 
  481.                   "list_member_name" :
  482.                   "struct_member_name");
  483.     String value           = (dv->type() == List ? 
  484.                   "list_value" :
  485.                   "struct_value");
  486.  
  487.     if (dv->collapsed())
  488.         vbox = eval(collapsed_value);
  489.     else
  490.     {
  491.         int count = dv->nchildren();
  492.         if (count == 0)
  493.         vbox = eval(empty_value);
  494.         else
  495.         {
  496.         // Determine maximum member name width
  497.         int max_member_name_width = 0;
  498.         int i;
  499.         for (i = 0; i < count; i++)
  500.         {
  501.             string child_member_name = dv->child(i)->name();
  502.             Box *box = eval(member_name, child_member_name);
  503.             max_member_name_width = 
  504.             max(max_member_name_width, box->size(X));
  505.             box->unlink();
  506.         }
  507.  
  508.         // Create children
  509.         VSLArgList args;
  510.         for (i = 0; i < count; i++)
  511.             args += create_value_box(dv->child(i), dv,
  512.                          max_member_name_width);
  513.  
  514.         vbox = eval(value, args);
  515.         }
  516.     }
  517.     break;
  518.     }
  519.  
  520.     case Reference:
  521.     {
  522.     if (dv->collapsed())
  523.         vbox = eval("collapsed_reference_value");
  524.     else
  525.     {
  526.         VSLArgList args;
  527.         for (int i = 0; i < 2; i++)
  528.         args += create_value_box(dv->child(i), dv);
  529.  
  530.         vbox = eval("reference_value", args);
  531.     }
  532.     break;
  533.     }
  534.  
  535.     case UnknownType:
  536.     assert(0);
  537.     abort();
  538.     }
  539.  
  540.     // Show repeats
  541.     if (dv->repeats() > 1 && !dv->collapsed())
  542.     {
  543.     vbox = eval("repeated_value", vbox, dv->repeats());
  544.     }
  545.  
  546.     // Highlight if value changed
  547.     if (dv->is_changed())
  548.     {
  549.     vbox = eval("changed_value", vbox);
  550.     }
  551.  
  552.     assert_ok(vbox->OK());
  553.  
  554. #if CACHE_BOXES
  555.     ((DispValue *)dv)->set_cached_box(vbox);
  556. #endif
  557.  
  558.     return vbox;
  559. }
  560.  
  561. Box *DispBox::create_value_box (const DispValue *dv,
  562.                 const DispValue *parent,
  563.                 int member_name_width)
  564. {
  565.     Box *vbox = 0;
  566.     if (dv == 0)
  567.     {
  568.     vbox = eval("none");
  569.     }
  570.     else if (!dv->enabled())
  571.     {
  572.     vbox = eval("disabled");
  573.     }
  574.     else
  575.     {
  576.     vbox = _create_value_box(dv, parent);
  577.     }
  578.  
  579.     // Add member name
  580.     if (dv != 0 && parent != 0 && 
  581.     dv->type() != Text &&
  582.     dv->name() != "" &&
  583.     !dv->name().matches(rxwhite))
  584.     {
  585.     switch (parent->type())
  586.     {
  587.     case List:
  588.         vbox = eval("list_member", dv->name(), " = ", 
  589.             vbox, member_name_width);
  590.         break;
  591.  
  592.     case Struct:
  593.         vbox = eval("struct_member", 
  594.             dv->name(), gdb->member_separator(), 
  595.             vbox, member_name_width);
  596.         break;
  597.  
  598.     case Sequence:
  599.     case Array:
  600.     case Reference:
  601.     case Simple:
  602.     case Text:
  603.     case Pointer:
  604.         break;
  605.  
  606.     case UnknownType:
  607.         assert(0);
  608.         abort();
  609.     }
  610.     }
  611.  
  612.     if (dv != 0)
  613.     {
  614.     Data *data = (Data *)dv;
  615.     vbox = vbox->tag(data);
  616.     }
  617.  
  618.     assert_ok(vbox->OK());
  619.  
  620.     return vbox;
  621. }
  622.  
  623. // Check evaluation result
  624. Box *DispBox::check(const string& func_name, const Box *box)
  625. {
  626.     if (box != 0)
  627.     return ((Box *)box);
  628.  
  629.     // Box not found
  630.     string bad_func_name = "<?" + func_name + ">";
  631.     return new ForegroundColorBox(new StringBox(bad_func_name), "red");
  632. }
  633.