home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / emxtutor.zip / emxsrcd1.zip / emx / src / pmgdb / display.cc < prev    next >
C/C++ Source or Header  |  1996-09-11  |  26KB  |  977 lines

  1. /* display.cc
  2.    Copyright (c) 1996 Eberhard Mattes
  3.  
  4. This file is part of pmgdb.
  5.  
  6. pmgdb is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. pmgdb is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with pmgdb; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21.  
  22. #define INCL_WIN
  23. #include <os2.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>              // sprintf()
  26. #include <stdarg.h>
  27. #include <string.h>
  28. #include <ctype.h>
  29. #include "string.h"
  30. #include "pmapp.h"
  31. #include "pmframe.h"
  32. #include "pmtxt.h"
  33. #include "pmtty.h"
  34. #include "pmgdb.h"
  35. #include "help.h"
  36. #include "breakpoi.h"
  37. #include "display.h"
  38. #include "annotati.h"
  39. #include "capture.h"
  40. #include "gdbio.h"
  41. #include "command.h"
  42.  
  43.  
  44. class dispfmt
  45. {
  46. public:
  47.   dispfmt () { count = 1; format = 0; size = 0; }
  48.   ~dispfmt () {}
  49.   void parse (const char *str);
  50.   void print (char *str) const;
  51.  
  52.   int count;
  53.   char format;
  54.   char size;
  55. };
  56.  
  57.  
  58. class display_window::display
  59. {
  60. public:
  61.   display () { enable = true; type = not_set; }
  62.   display (const display &src);
  63.   ~display () {}
  64.   bool is_line (int y) { return line <= y && y < line + line_count; }
  65.   void set_type (gdbio *gdb);
  66.   display &operator = (const display &src);
  67.  
  68.   // Dialog box
  69.   MRESULT display_msg (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  70.  
  71.   vstring expr;
  72.   vstring format;
  73.   vstring value;
  74.   display *next;
  75.   int number;
  76.   int line;
  77.   int line_count;
  78.   enum
  79.   {
  80.     not_set,
  81.     pointer,
  82.     other,
  83.   } type;
  84.   bool enable;
  85. };
  86.  
  87.  
  88. void dispfmt::parse (const char *s)
  89. {
  90.   count = 1; size = 0; format = 0;
  91.   s = strchr (s, '/');
  92.   s = s != NULL ? s + 1 : "";
  93.   if (*s >= '0' && *s <= '9')
  94.     {
  95.       count = atoi (s);
  96.       while (*s >= '0' && *s <= '9')
  97.         ++s;
  98.     }
  99.   while (*s != 0)
  100.     if (*s == 'b' || *s == 'h' || *s == 'w' || *s == 'g')
  101.       size = *s++;
  102.     else if (*s >= 'a' && *s <= 'z')
  103.       format = *s++;
  104.     else
  105.       break;
  106. }
  107.  
  108.  
  109. void dispfmt::print (char *str) const
  110. {
  111.   if (count != 1 || format != 0 || size != 0)
  112.     {
  113.       if (count != 1)
  114.         str += sprintf (str, "/%d", count);
  115.       else
  116.         *str++ = '/';
  117.       if (format != 0)
  118.         *str++ = format;
  119.       if (size != 0)
  120.         *str++ = size;
  121.     }
  122.   *str = 0;
  123. }
  124.  
  125.  
  126. display_window::display::display (const display &src)
  127. {
  128.   expr = src.expr;
  129.   format = src.format;
  130.   value = src.value;
  131.   next = NULL;
  132.   number = src.number;
  133.   line = src.line;
  134.   line_count = src.line_count;
  135.   enable = src.enable;
  136. }
  137.  
  138.  
  139. void display_window::display::set_type (gdbio *gdb)
  140. {
  141.   capture *capt;
  142.   capt = gdb->capture_cmd ("whatis %s", (const char *)expr);
  143.   if (capt == NULL)
  144.     return;
  145.   if (capt->error.is_set ())
  146.     type = other;
  147.   else
  148.     {
  149.       const char *s = gdb->get_output ();
  150.       int len = gdb->get_output ().length ();
  151.       while (len > 0 && s[len-1] == '\n')
  152.         --len;
  153.       if (len > 0 && s[len-1] == '*')
  154.         type = pointer;
  155.       else
  156.         type = other;
  157.     }
  158.   delete_capture (capt);
  159. }
  160.  
  161.  
  162. display_window::display
  163. &display_window::display::operator = (const display &src)
  164. {
  165.   expr = src.expr;
  166.   format = src.format;
  167.   value = src.value;
  168.   next = NULL;
  169.   number = src.number;
  170.   line = src.line;
  171.   line_count = src.line_count;
  172.   enable = src.enable;
  173.   type = src.type;
  174.   return *this;
  175. }
  176.  
  177.  
  178. static const struct
  179. {
  180.   const char *desc;
  181.   char chr;
  182. } formats[] =
  183.   {
  184.     {"Default",          0},
  185.     {"Signed decimal",   'd'},
  186.     {"Unsigned decimal", 'u'},
  187.     {"Hexadecimal",      'x'},
  188.     {"Octal",            'o'},
  189.     {"Binary",           't'},
  190.     {"Character",        'c'},
  191.     {"Address",          'a'},
  192.     {"Floating point",   'f'},
  193.     {"String",           's'},
  194.     {"Instruction",      'i'}
  195.   };
  196.  
  197. #define N_FORMATS       (sizeof (formats) / sizeof (formats[0]))
  198.  
  199. MRESULT display_window::display::display_msg (HWND hwnd, ULONG msg,
  200.                                               MPARAM mp1, MPARAM mp2)
  201. {
  202.   MRESULT mr;
  203.   HWND hwndTemp;
  204.   int i;
  205.   char fmtstr[40];
  206.  
  207.   switch (msg)
  208.     {
  209.     case WM_INITDLG:
  210.       {
  211.         dispfmt fmt;
  212.         dlg_sys_menu (hwnd);
  213.         WinSetWindowPtr (hwnd, QWL_USER, this);
  214.         WinSendDlgItemMsg (hwnd, IDC_ENABLE, BM_SETCHECK,
  215.                            MPFROMSHORT (enable), NULL);
  216.         WinSendDlgItemMsg (hwnd, IDC_EXPR, EM_SETTEXTLIMIT,
  217.                            MPFROMSHORT (128), 0);
  218.         if (!expr.is_null ())
  219.           WinSetDlgItemText (hwnd, IDC_EXPR, (PCSZ)expr);
  220.         if (!format.is_null ())
  221.           fmt.parse (format);
  222.         hwndTemp = WinWindowFromID (hwnd, IDC_FORMAT);
  223.         for (i = 0; i < (int)N_FORMATS; ++i)
  224.           {
  225.             WinSendMsg (hwndTemp, LM_INSERTITEM, MPFROMSHORT (i),
  226.                         MPFROMP (formats[i].desc));
  227.             if (formats[i].chr == fmt.format)
  228.               WinSendMsg (hwndTemp, LM_SELECTITEM,
  229.                           MPFROMSHORT (i), MPFROMSHORT (TRUE));
  230.           }
  231.         if (fmt.format == 0)
  232.           WinSendMsg (hwndTemp, LM_SELECTITEM,
  233.                       MPFROMSHORT (0), MPFROMSHORT (TRUE));
  234.         WinSendDlgItemMsg (hwnd, IDC_COUNT, SPBM_SETCURRENTVALUE,
  235.                            MPFROMLONG (fmt.count), 0);
  236.         WinSendDlgItemMsg (hwnd, IDC_COUNT, SPBM_SETLIMITS,
  237.                            MPFROMLONG (99), MPFROMLONG (1));
  238.         break;
  239.       }
  240.  
  241.     case WM_CONTROL:
  242.       switch (SHORT1FROMMP (mp1))
  243.         {
  244.         case IDC_FORMAT:
  245.           mr = WinSendDlgItemMsg (hwnd, IDC_FORMAT, LM_QUERYSELECTION,
  246.                                   MPFROMSHORT (LIT_FIRST), 0);
  247.           i = SHORT1FROMMR (mr);
  248.           bool enable_count = (i != LIT_NONE
  249.                                && (formats[i].chr == 's'
  250.                                    || formats[i].chr == 'i'));
  251.           WinEnableWindow (WinWindowFromID (hwnd, IDC_COUNT), enable_count);
  252.           break;
  253.         }
  254.       return 0;
  255.  
  256.     case WM_COMMAND:
  257.       switch (SHORT1FROMMP (mp1))
  258.         {
  259.         case DID_OK:
  260.           {
  261.             dispfmt fmt;
  262.             LONG n;
  263.             mr = WinSendDlgItemMsg (hwnd, IDC_ENABLE, BM_QUERYCHECK, 0, 0);
  264.             enable = (bool)SHORT1FROMMR (mr);
  265.             LONG len = WinQueryDlgItemTextLength (hwnd, IDC_EXPR);
  266.             expr.set (len);
  267.             WinQueryDlgItemText (hwnd, IDC_EXPR, len + 1, (PSZ)expr.modify ());
  268.  
  269.             mr = WinSendDlgItemMsg (hwnd, IDC_FORMAT, LM_QUERYSELECTION,
  270.                                     MPFROMSHORT (LIT_FIRST), 0);
  271.             i = SHORT1FROMMR (mr);
  272.             if (i != LIT_NONE && i != 0)
  273.               {
  274.                 fmt.format = formats[i].chr;
  275.                 if (fmt.format == 's' || fmt.format == 'i')
  276.                   {
  277.                     mr = WinSendDlgItemMsg (hwnd, IDC_COUNT, SPBM_QUERYVALUE,
  278.                                             MPFROMP (&n),
  279.                                             MPFROM2SHORT (0,
  280.                                                           SPBQ_ALWAYSUPDATE));
  281.                     if (SHORT1FROMMR (mr))
  282.                       fmt.count = n;
  283.                   }
  284.                 fmt.print (fmtstr);
  285.                 format.set (fmtstr);
  286.               }
  287.             else
  288.               format.set ("");
  289.             WinDismissDlg (hwnd, DID_OK);
  290.             return 0;
  291.           }
  292.         }
  293.       break;
  294.     }
  295.   return WinDefDlgProc (hwnd, msg, mp1, mp2);
  296. }
  297.  
  298.  
  299. MRESULT EXPENTRY dlg_display (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  300. {
  301.   display_window::display *p;
  302.  
  303.   if (msg == WM_INITDLG)
  304.     p = (display_window::display *)((struct pm_create *)PVOIDFROMMP (mp2))->ptr;
  305.   else
  306.     p = (display_window::display *)WinQueryWindowPtr (hwnd, QWL_USER);
  307.   return p->display_msg (hwnd, msg, mp1, mp2);
  308. }
  309.  
  310.  
  311. #define DSP_HEADER_LINES        1
  312.  
  313. display_window::display_window (command_window *in_cmd, gdbio *in_gdb,
  314.                                 unsigned in_id, const SWP *pswp,
  315.                                 const char *fontnamesize)
  316.   : pmtxt (in_cmd->get_app (), in_id,
  317.            pswp == NULL ? FCF_SHELLPOSITION : 0, pswp, fontnamesize)
  318. {
  319.   cmd = in_cmd; gdb = in_gdb;
  320.   head = NULL;
  321.   sel_line = -1;
  322.   exp_number = -1;
  323.  
  324.   sel_attr = get_default_attr ();
  325.   set_fg_color (sel_attr, CLR_BLACK);
  326.   set_bg_color (sel_attr, CLR_PALEGRAY);
  327.  
  328.   delete_all_displays (true);   // Update menu, insert header line
  329.   set_title ("pmgdb - Display");
  330.   set_keys_help_id (HELP_THR_KEYS);
  331. }
  332.  
  333.  
  334. display_window::~display_window ()
  335. {
  336.   delete_all_displays (false);
  337. }
  338.  
  339.  
  340. void display_window::delete_all_displays (bool init)
  341. {
  342.   display *p, *next;
  343.   for (p = head; p != NULL; p = next)
  344.     {
  345.       next = p->next;
  346.       delete p;
  347.     }
  348.   head = NULL;
  349.   sel_line = -1;
  350.  
  351.   if (init)
  352.     {
  353.       delete_all ();
  354.       int x = 0;
  355.       put (0, x, 4, " No ", false); x += 4;
  356.       put_tab (0, x++, false);
  357.       put_vrule (0, x++, false);
  358.       put (0, x, 5, " Ena ", false); x += 5;
  359.       put_tab (0, x++, false);
  360.       put_vrule (0, x++, false);
  361.       put (0, x, 5, " Fmt ", false); x += 5;
  362.       put_tab (0, x++, false);
  363.       put_vrule (0, x++, false);
  364.       put (0, x, 6, " Expr ", false); x += 6;
  365.       put_tab (0, x++, false);
  366.       put_vrule (0, x++, false);
  367.       put (0, x, 6, " Value", false); x += 6;
  368.       underline (0, true, false);
  369.       sync ();
  370.       menu_enable (IDM_ENABLE, false);
  371.       menu_enable (IDM_DISABLE, false);
  372.       menu_enable (IDM_MODIFY, false);
  373.       menu_enable (IDM_DELETE, false);
  374.       menu_enable (IDM_ENABLE_ALL, false);
  375.       menu_enable (IDM_DISABLE_ALL, false);
  376.       menu_enable (IDM_DELETE_ALL, false);
  377.       menu_enable (IDM_REPMENU, false);
  378.       menu_enable (IDM_DEREFERENCE, false);
  379.     }
  380. }
  381.  
  382.  
  383. bool display_window::add (HWND hwnd)
  384. {
  385.   bool result = false;
  386.   display temp;
  387.   pm_create create;
  388.   create.cb = sizeof (create);
  389.   create.ptr = (void *)&temp;
  390.   if (WinDlgBox (HWND_DESKTOP, hwnd, dlg_display, 0, IDD_DISPLAY,
  391.                  &create) == DID_OK
  392.       && temp.expr[0] != 0)
  393.     {
  394.       select_line (-1);
  395.       capture *capt;
  396.       capt = gdb->capture_cmd ("server display %s %s",
  397.                                (const char *)temp.format,
  398.                                (const char *)temp.expr);
  399.       if (capt != NULL && capt->disp_number.is_set ())
  400.         {
  401.           int number = capt->disp_number.get ();
  402.           if (!temp.enable)
  403.             gdb->send_cmd ("server disable display %d", number);
  404.           exp_number = number;
  405.           exp_line = -1;
  406.           exp_enable = temp.enable;
  407.           result = true;
  408.         }
  409.       delete_capture (capt);
  410.     }
  411.   return result;
  412. }
  413.  
  414.  
  415. MRESULT display_window::wm_close (HWND, ULONG, MPARAM, MPARAM)
  416. {
  417.   show (false);
  418.   return 0;
  419. }
  420.  
  421.  
  422. MRESULT display_window::wm_command (HWND hwnd, ULONG msg,
  423.                                     MPARAM mp1, MPARAM mp2)
  424. {
  425.   display *p;
  426.  
  427.   switch (SHORT1FROMMP (mp1))
  428.     {
  429.     case IDM_ENABLE:
  430.       p = find_by_line (sel_line);
  431.       if (p == NULL)
  432.         WinAlarm (HWND_DESKTOP, WA_ERROR);
  433.       else
  434.         gdb->send_cmd ("server enable display %d", p->number);
  435.       return 0;
  436.  
  437.     case IDM_DISABLE:
  438.       p = find_by_line (sel_line);
  439.       if (p == NULL)
  440.         WinAlarm (HWND_DESKTOP, WA_ERROR);
  441.       else
  442.         gdb->send_cmd ("server disable display %d", p->number);
  443.       return 0;
  444.  
  445.     case IDM_DELETE:
  446.       p = find_by_line (sel_line);
  447.       if (p == NULL)
  448.         WinAlarm (HWND_DESKTOP, WA_ERROR);
  449.       else
  450.         gdb->send_cmd ("server undisplay %d", p->number);
  451.       return 0;
  452.  
  453.     case IDM_ADD:
  454.       add (hwnd);
  455.       return 0;
  456.  
  457.     case IDM_MODIFY:
  458.       p = find_by_line (sel_line);
  459.       if (p == NULL)
  460.         WinAlarm (HWND_DESKTOP, WA_ERROR);
  461.       else
  462.         modify (p);
  463.       return 0;
  464.  
  465.     case IDM_ENABLE_ALL:
  466.       gdb->send_cmd ("server enable display");
  467.       return 0;
  468.  
  469.     case IDM_DISABLE_ALL:
  470.       gdb->send_cmd ("server disable display");
  471.       return 0;
  472.  
  473.     case IDM_DELETE_ALL:
  474.       gdb->send_cmd ("server undisplay");
  475.       delete_all_displays (true); // GDB doesn't send an annotation!
  476.       return 0;
  477.  
  478.     case IDM_REP_DEC_S:
  479.       change_representation ('d');
  480.       return 0;
  481.  
  482.     case IDM_REP_DEC_U:
  483.       change_representation ('u');
  484.       return 0;
  485.  
  486.     case IDM_REP_HEX:
  487.       change_representation ('x');
  488.       return 0;
  489.  
  490.     case IDM_REP_OCT:
  491.       change_representation ('o');
  492.       return 0;
  493.  
  494.     case IDM_REP_BIN:
  495.       change_representation ('t');
  496.       return 0;
  497.  
  498.     case IDM_REP_ADR:
  499.       change_representation ('a');
  500.       return 0;
  501.  
  502.     case IDM_REP_CHR:
  503.       change_representation ('c');
  504.       return 0;
  505.  
  506.     case IDM_REP_FLT:
  507.       change_representation ('f');
  508.       return 0;
  509.  
  510.     case IDM_REP_STR:
  511.       change_representation ('s');
  512.       return 0;
  513.  
  514.     case IDM_REP_INS:
  515.       change_representation ('i');
  516.       return 0;
  517.  
  518.     case IDM_DEREFERENCE:
  519.       p = find_by_line (sel_line);
  520.       if (p == NULL)
  521.         WinAlarm (HWND_DESKTOP, WA_ERROR);
  522.       else
  523.         dereference (p, false);
  524.       return 0;
  525.  
  526.     default:
  527.       return cmd->wm_command (hwnd, msg, mp1, mp2);
  528.     }
  529. }
  530.  
  531.  
  532. bool display_window::wm_user (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  533. {
  534.   if (parent::wm_user (hwnd, msg, mp1, mp2))
  535.     return true;
  536.   switch (msg)
  537.     {
  538.     case UWM_MENU:
  539.       // TODO: Cache
  540.       if (sel_line == -1)
  541.         {
  542.           menu_enable (IDM_ENABLE, false);
  543.           menu_enable (IDM_DISABLE, false);
  544.           menu_enable (IDM_MODIFY, false);
  545.           menu_enable (IDM_DELETE, false);
  546.           menu_enable (IDM_REPMENU, false);
  547.           menu_enable (IDM_DEREFERENCE, false);
  548.         }
  549.       else
  550.         {
  551.           const display *p = find_by_line (sel_line);
  552.           menu_enable (IDM_ENABLE, !p->enable);
  553.           menu_enable (IDM_DISABLE, p->enable);
  554.           menu_enable (IDM_MODIFY, true);
  555.           menu_enable (IDM_DELETE, true);
  556.           menu_enable (IDM_REPMENU, true);
  557.           // TODO: null pointer
  558.           menu_enable (IDM_DEREFERENCE, p->type == display::pointer);
  559.         }
  560.       menu_enable (IDM_ENABLE_ALL, head != NULL);
  561.       menu_enable (IDM_DISABLE_ALL, head != NULL);
  562.       menu_enable (IDM_DELETE_ALL, head != NULL);
  563.       return true;
  564.  
  565.     default:
  566.       return false;
  567.     }
  568. }
  569.  
  570.  
  571. MRESULT display_window::wm_activate (HWND hwnd, ULONG msg,
  572.                                      MPARAM mp1, MPARAM mp2)
  573. {
  574.   if (SHORT1FROMMP (mp1))
  575.     cmd->associate_help (get_hwndFrame ());
  576.   return WinDefWindowProc (hwnd, msg, mp1, mp2);
  577. }
  578.  
  579.  
  580. void display_window::button_event (int line, int column, int tab, int button,
  581.                                    int clicks)
  582. {
  583.   if (line >= 0 && column >= 0)
  584.     {
  585.       // TODO: Context menu
  586.       if (button == 1 && clicks == 2 && tab == 1)
  587.         {
  588.           const display *p = find_by_line (line);
  589.           if (p == NULL)
  590.             WinAlarm (HWND_DESKTOP, WA_ERROR);
  591.           else
  592.             gdb->send_cmd ("server %s display %d",
  593.                            p->enable ? "disable" : "enable", p->number);
  594.         }
  595.       else if (button == 1 && clicks == 2 && tab >= 2 && tab <= 3)
  596.         {
  597.           display *p = find_by_line (line);
  598.           if (p == NULL)
  599.             WinAlarm (HWND_DESKTOP, WA_ERROR);
  600.           else
  601.             {
  602.               select_line (line);
  603.               modify (p);
  604.             }
  605.         }
  606.       else if (button == 1 && clicks == 1)
  607.         select_line (line, true);
  608.       else if (button == 1 && clicks == 2)
  609.         select_line (line);
  610.     }
  611.   else
  612.     select_line (-1);
  613. }
  614.  
  615.  
  616. display_window::display *display_window::find_by_number (int number)
  617. {
  618.   for (display *p = head; p != NULL; p = p->next)
  619.     if (p->number == number)
  620.       return p;
  621.   return NULL;
  622. }
  623.  
  624.  
  625. display_window::display *display_window::find_by_line (int line)
  626. {
  627.   for (display *p = head; p != NULL; p = p->next)
  628.     if (p->is_line (line))
  629.       return p;
  630.   return NULL;
  631. }
  632.  
  633.  
  634. void display_window::enable (int number)
  635. {
  636.   display *p = find_by_number (number);
  637.   if (p != NULL && !p->enable)
  638.     {
  639.       p->enable = true;
  640.       if (p->line == sel_line)
  641.         WinPostMsg (get_hwndClient (), UWM_MENU, 0, 0);
  642.       update (p);
  643.     }
  644. }
  645.  
  646.  
  647. void display_window::disable (int number)
  648. {
  649.   display *p = find_by_number (number);
  650.   if (p != NULL && p->enable)
  651.     {
  652.       p->enable = false;
  653.       if (p->line == sel_line)
  654.         WinPostMsg (get_hwndClient (), UWM_MENU, 0, 0);
  655.       update (p);
  656.     }
  657. }
  658.  
  659.  
  660. void display_window::remove (int number)
  661. {
  662.   for (display **patch = &head; *patch != NULL; patch = &(*patch)->next)
  663.     if ((*patch)->number == number)
  664.       {
  665.         display *p = *patch;
  666.         for (display *q = (*patch)->next; q != NULL; q = q->next)
  667.           q->line -= p->line_count;
  668.         if (p->line == sel_line)
  669.           {
  670.             sel_line = -1;
  671.             WinPostMsg (get_hwndClient (), UWM_MENU, 0, 0);
  672.           }
  673.         delete_lines (p->line, p->line_count, true);
  674.         *patch = p->next;
  675.         delete p;
  676.         return;
  677.       }
  678. }
  679.  
  680.  
  681. void display_window::update (display *p)
  682. {
  683.   char buf[400];
  684.   int x = 0, len, line_count, diff;
  685.   pmtxt_attr attr;
  686.  
  687.   if (p->line == sel_line)
  688.     attr = sel_attr;
  689.   else
  690.     attr = get_default_attr ();
  691.  
  692.   line_count = 1;
  693.   if (p->enable)
  694.     for (const char *s = p->value; *s != 0; ++s)
  695.       if (*s == '\n')
  696.         ++line_count;
  697.  
  698.   diff = line_count - p->line_count;
  699.   if (diff < 0)
  700.     delete_lines (p->line + line_count, -diff, true);
  701.   if (diff > 0)
  702.     insert_lines (p->line + p->line_count, diff, true);
  703.   if (diff != 0)
  704.     {
  705.       for (display *q = p->next; q != NULL; q = q->next)
  706.         q->line += diff;
  707.       if (sel_line == p->line)
  708.         sel_count = line_count;
  709.       else if (sel_line > p->line)
  710.         sel_line += diff;
  711.       p->line_count = line_count;
  712.     }
  713.   clear_lines (p->line, line_count, true);
  714.  
  715.   len = snprintf (buf, sizeof (buf), " %d ", p->number);
  716.   put (p->line, x, len, buf, attr, true); x += len;
  717.   put_tab (p->line, x++, attr, true);
  718.   put_vrule (p->line, x++, attr, true);
  719.  
  720.   len = snprintf (buf, sizeof (buf), " %c ", p->enable ? 'y' : 'n');
  721.   put (p->line, x, len, buf, attr, true); x += len;
  722.   put_tab (p->line, x++, attr, true);
  723.   put_vrule (p->line, x++, attr, true);
  724.  
  725.   len = snprintf (buf, sizeof (buf), " %s ", (const char *)p->format);
  726.   put (p->line, x, len, buf, attr, true); x += len;
  727.   put_tab (p->line, x++, attr, true);
  728.   put_vrule (p->line, x++, attr, true);
  729.  
  730.   len = snprintf (buf, sizeof (buf), " %s ", (const char *)p->expr);
  731.   put (p->line, x, len, buf, attr, true); x += len;
  732.   put_tab (p->line, x++, attr, true);
  733.   put_vrule (p->line, x++, attr, true);
  734.  
  735.   if (p->line == sel_line)
  736.     set_eol_attr (p->line, sel_attr, true);
  737.  
  738.   if (p->enable)
  739.     {
  740.       int y = p->line;
  741.       const char *s = p->value;
  742.       while (*s != 0)
  743.         {
  744.           const char *nl = strchr (s, '\n');
  745.           len = nl != NULL ? nl - s : strlen (s);
  746.           if (y != p->line)
  747.             {
  748.               if (p->line == sel_line)
  749.                 set_eol_attr (y, sel_attr, true);
  750.               for (int i = 0; i < 4; ++i)
  751.                 {
  752.                   put_tab (y, x++, attr, true);
  753.                   put_vrule (y, x++, attr, true);
  754.                 }
  755.             }
  756.           put (y, x++, 1, " ", attr, true);
  757.           const char *tab;
  758.           while ((tab = (const char *)memchr (s, '\t', len)) != NULL)
  759.             {
  760.               if (tab != s)
  761.                 {
  762.                   put (y, x, tab - s, s, attr, true);
  763.                   x += tab - s; len -= tab - s; s = tab;
  764.                 }
  765.               ++s; --len;       // Skip TAB
  766.               put (y, x++, 1, " ", attr, true);
  767.               put_tab (y, x++, attr, true);
  768.             }
  769.           if (len != 0)
  770.             {
  771.               put (y, x, len, s, attr, true);
  772.               s += len;
  773.             }
  774.           if (*s != 0)
  775.             {
  776.               ++s;              // Skip linefeed
  777.               ++y; x = 0;       // New line
  778.             }
  779.         }
  780.     }
  781. }
  782.  
  783.  
  784. void display_window::update (int number, const char *expr, const char *format,
  785.                              const char *value, bool enable)
  786. {
  787.   int undisplay = -1;
  788.   display *p = find_by_number (number);
  789.   if (value == NULL) value = "";
  790.  
  791.   if (p == NULL)
  792.     {
  793.       if (exp_number == number && exp_line != -1
  794.           && (p = find_by_line (exp_line)) != NULL)
  795.         {
  796.           // Modifying a display
  797.           undisplay = p->number;
  798.           p->line = exp_line;
  799.         }
  800.       else
  801.         {
  802.           // New display
  803.           if (head == NULL)
  804.             {
  805.               menu_enable (IDM_ENABLE_ALL, true);
  806.               menu_enable (IDM_DISABLE_ALL, true);
  807.               menu_enable (IDM_DELETE_ALL, true);
  808.             }
  809.  
  810.           display **patch = &head;
  811.           int line = DSP_HEADER_LINES;
  812.           while (*patch != NULL)
  813.             {
  814.               line += (*patch)->line_count;
  815.               patch = &(*patch)->next;
  816.             }
  817.           p = new display;
  818.           *patch = p;
  819.           p->next = NULL;
  820.           p->line = line;
  821.           p->line_count = 1;
  822.           p->enable = true;
  823.         }
  824.       p->number = number;
  825.       p->expr.set (expr);
  826.       p->format.set (format);
  827.       p->value.set (value);
  828.       p->set_type (gdb);
  829.     }
  830.   else
  831.     {
  832.       if (number != exp_number && strcmp (value, p->value) == 0)
  833.         return;
  834.       // TODO: Redraw value only (if only the value changed)
  835.       p->value.set (value);
  836.     }
  837.  
  838.   // Set the state of a new display before GDB knows about and reports
  839.   // the new state
  840.   if (number == exp_number)
  841.     {
  842.       p->enable = exp_enable;
  843.       select_line (p->line);
  844.     }
  845.   if (!enable)
  846.     p->enable = false;
  847.   exp_number = -1;
  848.   if (undisplay != -1)
  849.     gdb->send_cmd ("server undisplay %d", undisplay);
  850.   update (p);
  851. }
  852.  
  853.  
  854. void display_window::select_line (int line, bool toggle)
  855. {
  856.   const display *p = line == -1 ? (display *)NULL : find_by_line (line);
  857.   line = p != NULL ? p->line : -1; // Normalize
  858.   if (toggle && line != -1 && line == sel_line)
  859.     line = -1;
  860.   if (line != sel_line)
  861.     {
  862.       if (sel_line != -1)
  863.         for (int i = 0; i < sel_count; ++i)
  864.           {
  865.             put (sel_line + i, 0, max_line_len, get_default_attr (), true);
  866.             set_eol_attr (sel_line + i, get_default_attr (), true);
  867.           }
  868.       if (line != -1)
  869.         {
  870.           sel_count = p->line_count;
  871.           for (int i = 0; i < sel_count; ++i)
  872.             {
  873.               put (line + i, 0, max_line_len, sel_attr, true);
  874.               set_eol_attr (line + i, sel_attr, true);
  875.             }
  876.         }
  877.       sel_line = line;
  878.     }
  879.   // TODO: Cache
  880.   if (line != -1)
  881.     {
  882.       menu_enable (IDM_ENABLE, !p->enable);
  883.       menu_enable (IDM_DISABLE, p->enable);
  884.       menu_enable (IDM_MODIFY, true);
  885.       menu_enable (IDM_DELETE, true);
  886.       menu_enable (IDM_REPMENU, true);
  887.       menu_enable (IDM_DEREFERENCE, p->type == display::pointer);
  888.       show_line (line, 1, 1);
  889.     }
  890.   else
  891.     {
  892.       menu_enable (IDM_ENABLE, false);
  893.       menu_enable (IDM_DISABLE, false);
  894.       menu_enable (IDM_MODIFY, false);
  895.       menu_enable (IDM_DELETE, false);
  896.       menu_enable (IDM_REPMENU, false);
  897.       menu_enable (IDM_DEREFERENCE, false);
  898.     }
  899. }
  900.  
  901.  
  902. void display_window::modify (const display *p, const char *new_format,
  903.                              const char *new_expr, bool new_enable, bool add)
  904. {
  905.   select_line (-1);
  906.   if (new_format == NULL)
  907.     new_format = p->format;
  908.   if (new_expr == NULL)
  909.     new_expr = p->expr;
  910.   capture *capt;
  911.   capt = gdb->capture_cmd ("server display %s %s", new_format, new_expr);
  912.   if (capt != NULL && capt->disp_number.is_set ())
  913.     {
  914.       int number = capt->disp_number.get ();
  915.       exp_number = number;
  916.       exp_enable = new_enable;
  917.       exp_line = add ? -1 : p->line;
  918.       if (!new_enable)
  919.         gdb->send_cmd ("server disable display %d", number);
  920.     }
  921.   delete_capture (capt);
  922. }
  923.  
  924.  
  925. void display_window::change_representation (char fmtchr)
  926. {
  927.   display *p = find_by_line (sel_line);
  928.   if (p == NULL)
  929.     {
  930.       WinAlarm (HWND_DESKTOP, WA_ERROR);
  931.       return;
  932.     }
  933.  
  934.   dispfmt fmt;
  935.   fmt.parse (p->format);
  936.  
  937.   if (fmtchr == fmt.format)
  938.     return;
  939.   fmt.format = fmtchr;
  940.   char new_format_buf[20];
  941.   fmt.print (new_format_buf);
  942.   modify (p, new_format_buf, NULL, p->enable, false);
  943. }
  944.  
  945.  
  946. void display_window::modify (display *p)
  947. {
  948.   display temp = *p;
  949.   pm_create create;
  950.   create.cb = sizeof (create);
  951.   create.ptr = (void *)&temp;
  952.   if (WinDlgBox (HWND_DESKTOP, get_hwndClient (), dlg_display, 0, IDD_DISPLAY,
  953.                  &create) == DID_OK
  954.       && temp.expr[0] != 0
  955.       && (temp.enable != p->enable
  956.           || strcmp (temp.expr, p->expr) != 0
  957.           || strcmp (temp.format, p->format) != 0))
  958.     {
  959.       if (strcmp (temp.expr, p->expr) == 0
  960.           && strcmp (temp.format, p->format) == 0)
  961.         gdb->send_cmd ("server %s display %d",
  962.                        temp.enable ? "enable" : "disable", p->number);
  963.       else
  964.         modify (p, temp.format, temp.expr, temp.enable, false);
  965.     }
  966. }
  967.  
  968.  
  969. void display_window::dereference (display *p, bool add)
  970. {
  971.   astring expr;
  972.   expr = "*(";
  973.   expr.append (p->expr);
  974.   expr.append (")");
  975.   modify (p, "", expr, true, add);
  976. }
  977.