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

  1. /* source.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_DOS
  23. #define INCL_WIN
  24. #include <os2.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <io.h>
  29. #include <fcntl.h>
  30. #include "string.h"
  31. #include "pmapp.h"
  32. #include "pmframe.h"
  33. #include "pmtxt.h"
  34. #include "pmtty.h"
  35. #include "pmgdb.h"
  36. #include "help.h"
  37. #include "breakpoi.h"
  38. #include "source.h"
  39. #include "display.h"
  40. #include "annotati.h"
  41. #include "capture.h"
  42. #include "gdbio.h"
  43. #include "command.h"
  44.  
  45. #define LINENO_WIDTH    6
  46. #define SOURCE_COLUMN   (LINENO_WIDTH + 4)
  47.  
  48. source_window::source_window (pmapp *in_app, unsigned in_id,
  49.                               const char *fontnamesize,
  50.                               const char *short_fname, const char *long_fname,
  51.                               command_window *in_cmd, gdbio *in_gdb)
  52.   : pmtxt (in_app, in_id, FCF_SHELLPOSITION, NULL, fontnamesize)
  53. {
  54.   cmd = in_cmd; gdb = in_gdb;
  55.   short_filename = short_fname;
  56.   long_filename = long_fname;
  57.  
  58.   astring title;
  59.   title = "pmgdb - ";
  60.   title.append (short_filename);
  61.   set_title (title);
  62.  
  63.   set_keys_help_id (HELP_SRC_KEYS);
  64.  
  65.   hilite_attr = get_default_attr ();
  66.   set_fg_color (hilite_attr, CLR_WHITE);
  67.   set_bg_color (hilite_attr, CLR_BLACK);
  68.  
  69.   sel_attr = get_default_attr ();
  70.   set_fg_color (sel_attr, CLR_BLACK);
  71.   set_bg_color (sel_attr, CLR_PALEGRAY);
  72.  
  73.   bpt_attr = get_default_attr ();
  74.   set_fg_color (bpt_attr, CLR_WHITE);
  75.   set_bg_color (bpt_attr, CLR_RED);
  76.  
  77.   sel_bpt_attr = get_default_attr ();
  78.   set_fg_color (sel_bpt_attr, CLR_WHITE);
  79.   set_bg_color (sel_bpt_attr, CLR_PINK);
  80.  
  81.   // Initialize menu
  82.   WinPostMsg (get_hwndClient (), UWM_STATE, MPFROMLONG (~0), 0);
  83.  
  84.   load ();
  85.   set_font (*cmd);
  86.   show (true);
  87. }
  88.  
  89.  
  90. source_window::~source_window ()
  91. {
  92. }
  93.  
  94.  
  95. void source_window::load ()
  96. {
  97.   char buf[max_line_len+2];     // Line read from source file
  98.   char pfx[10];                 // Line number
  99.   int c;
  100.  
  101.   delete_all ();
  102.   cur_lineno = -1; sel_lineno = -1;
  103.   exp_lineno = -1; find_string = "";
  104.   menu_enable (IDM_FINDNEXT, false);
  105.   menu_enable (IDM_FINDPREV, false);
  106.  
  107.   FILE *f = fopen (long_filename, "r");
  108.   if (f == NULL)
  109.     {
  110.       // TODO: Use GDB's value of `set directory'
  111.       // TODO: Dialog box, asking for file name
  112.       strcpy (buf, "Cannot open file");
  113.       put (0, 0, strlen (buf), buf, true);
  114.     }
  115.   else
  116.     {
  117.       int y = 0;
  118.       while (fgets (buf, sizeof (buf), f) != NULL)
  119.         {
  120.           size_t len = strlen (buf);
  121.           if (len > 0 && buf[len-1] == '\n')
  122.             --len;
  123.           else
  124.             {
  125.               // Line too long, skip rest
  126.               do
  127.                 {
  128.                   c = fgetc (f);
  129.                 } while (c != EOF && c != '\n');
  130.             }
  131.  
  132.           // Insert line number
  133.           int pfx_len = sprintf (pfx, "%*d    ", LINENO_WIDTH, y + 1);
  134.           put (y, 0, pfx_len, pfx, false);
  135.           put_tab (y, LINENO_WIDTH + 1, false);
  136.           put_vrule (y, LINENO_WIDTH + 2, false);
  137.  
  138.           // Insert source line
  139.           char *tab = (char *)memchr (buf, '\t', len);
  140.           if (tab == NULL)
  141.             put (y, SOURCE_COLUMN, len, buf, false);
  142.           else
  143.             {
  144.               // Expand TABs
  145.               int x = 0;
  146.               size_t i = 0;
  147.               while (tab != NULL)
  148.                 {
  149.                   size_t copy = tab - (buf + i);
  150.                   if (copy != 0)
  151.                     {
  152.                       put (y, SOURCE_COLUMN + x, copy, buf + i, false);
  153.                       i += copy; x += copy;
  154.                     }
  155.                   int tab_width = (x | 7) + 1 - x;
  156.                   put (y, SOURCE_COLUMN + x, tab_width, "        ", false);
  157.                   ++i; x += tab_width;
  158.                   tab = (char *)memchr (buf + i, '\t', len - i);
  159.                 }
  160.               if (i < len)
  161.                 put (y, SOURCE_COLUMN + x, len - i, buf + i, false);
  162.             }
  163.           ++y;
  164.         }
  165.       // TODO: ferror()
  166.       fclose (f);
  167.     }
  168.   cmd->get_breakpoints (this, false);
  169. }
  170.  
  171.  
  172. void source_window::show_line (int lineno)
  173. {
  174.   if (lineno != cur_lineno)
  175.     {
  176.       if (cur_lineno != -1)
  177.         {
  178.           put (cur_lineno - 1, SOURCE_COLUMN - 1, max_line_len,
  179.                get_default_attr (), true);
  180.           set_eol_attr (cur_lineno - 1, get_default_attr (), true);
  181.         }
  182.       if (lineno != -1)
  183.         {
  184.           put (lineno - 1, SOURCE_COLUMN - 1, max_line_len, hilite_attr, true);
  185.           set_eol_attr (lineno - 1, hilite_attr, true);
  186.         }
  187.       cur_lineno = lineno;
  188.       if (lineno == exp_lineno)
  189.         exp_lineno = -1;
  190.     }
  191.   if (lineno != -1)
  192.     parent::show_line (lineno - 1, 1, get_window_lines () * 2 / 3);
  193. }
  194.  
  195.  
  196. void source_window::select_line (int lineno)
  197. {
  198.   if (lineno != sel_lineno)
  199.     {
  200.       if (sel_lineno != -1)
  201.         {
  202.           const breakpoint *bpt
  203.             = cmd->breakpoints.find (short_filename, sel_lineno);
  204.           put (sel_lineno - 1, 0, LINENO_WIDTH + 2,
  205.                bpt != NULL ? bpt_attr : get_default_attr (), true);
  206.         }
  207.       if (lineno != -1)
  208.         {
  209.           const breakpoint *bpt
  210.             = cmd->breakpoints.find (short_filename, lineno);
  211.           put (lineno - 1, 0, LINENO_WIDTH + 2,
  212.                bpt != NULL ? sel_bpt_attr : sel_attr, true);
  213.         }
  214.       sel_lineno = lineno;
  215.     }
  216. }
  217.  
  218.  
  219. ULONG source_window::selected_addr ()
  220. {
  221.   if (sel_lineno == -1)
  222.     return 0;
  223.   return gdb->address_of_line (short_filename, sel_lineno);
  224. }
  225.  
  226.  
  227. MRESULT source_window::goto_msg (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  228. {
  229.   char buf[80];
  230.  
  231.   switch (msg)
  232.     {
  233.     case WM_INITDLG:
  234.       dlg_sys_menu (hwnd);
  235.       WinSetWindowPtr (hwnd, QWL_USER, this);
  236.       break;
  237.  
  238.     case WM_COMMAND:
  239.       switch (SHORT1FROMMP (mp1))
  240.         {
  241.         case DID_OK:
  242.           WinQueryDlgItemText (hwnd, IDC_LINENO, sizeof (buf), (PSZ)buf);
  243.           int lineno = atoi (buf);
  244.           if (lineno > 0)
  245.             parent::show_line (lineno - 1, 1, get_window_lines () / 2);
  246.           WinDismissDlg (hwnd, DID_OK);
  247.           return 0;
  248.         }
  249.       break;
  250.     }
  251.   return WinDefDlgProc (hwnd, msg, mp1, mp2);
  252. }
  253.  
  254.  
  255. MRESULT EXPENTRY dlg_goto (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  256. {
  257.   source_window *p;
  258.  
  259.   if (msg == WM_INITDLG)
  260.     p = (source_window *)((struct pm_create *)PVOIDFROMMP (mp2))->ptr;
  261.   else
  262.     p = (source_window *)WinQueryWindowPtr (hwnd, QWL_USER);
  263.   return p->goto_msg (hwnd, msg, mp1, mp2);
  264. }
  265.  
  266.  
  267. MRESULT source_window::find_msg (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  268. {
  269.   char buf[200];
  270.  
  271.   switch (msg)
  272.     {
  273.     case WM_INITDLG:
  274.       dlg_sys_menu (hwnd);
  275.       WinSendDlgItemMsg (hwnd, IDC_STRING, EM_SETTEXTLIMIT,
  276.                          MPFROMSHORT (sizeof (buf) - 1), 0);
  277.       WinSetDlgItemText (hwnd, IDC_STRING, (PCSZ)find_string);
  278.       WinSetWindowPtr (hwnd, QWL_USER, this);
  279.       break;
  280.  
  281.     case WM_COMMAND:
  282.       switch (SHORT1FROMMP (mp1))
  283.         {
  284.         case DID_OK:
  285.           WinQueryDlgItemText (hwnd, IDC_STRING, sizeof (buf), (PSZ)buf);
  286.           if (buf[0] != 0)
  287.             {
  288.               find_string = buf;
  289.               WinDismissDlg (hwnd, DID_OK);
  290.             }
  291.           else
  292.             WinDismissDlg (hwnd, DID_CANCEL);
  293.           return 0;
  294.         }
  295.       break;
  296.     }
  297.   return WinDefDlgProc (hwnd, msg, mp1, mp2);
  298. }
  299.  
  300.  
  301. MRESULT EXPENTRY dlg_find (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  302. {
  303.   source_window *p;
  304.  
  305.   if (msg == WM_INITDLG)
  306.     p = (source_window *)((struct pm_create *)PVOIDFROMMP (mp2))->ptr;
  307.   else
  308.     p = (source_window *)WinQueryWindowPtr (hwnd, QWL_USER);
  309.   return p->find_msg (hwnd, msg, mp1, mp2);
  310. }
  311.  
  312.  
  313. MRESULT source_window::wm_activate (HWND hwnd, ULONG msg,
  314.                                     MPARAM mp1, MPARAM mp2)
  315. {
  316.   if (SHORT1FROMMP (mp1))
  317.     cmd->associate_help (get_hwndFrame ());
  318.   return WinDefWindowProc (hwnd, msg, mp1, mp2);
  319. }
  320.  
  321.  
  322. MRESULT source_window::wm_char (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  323. {
  324.   if ((SHORT1FROMMP (mp1) & (KC_VIRTUALKEY|KC_KEYUP)) == KC_VIRTUALKEY)
  325.     {
  326.       HWND hwndTarget = NULLHANDLE;
  327.       switch (SHORT2FROMMP (mp2))
  328.         {
  329.         case VK_UP:
  330.         case VK_DOWN:
  331.           hwndTarget = get_hwndVbar ();
  332.           break;
  333.  
  334.         case VK_PAGEUP:
  335.         case VK_PAGEDOWN:
  336.           if (SHORT1FROMMP (mp1) & KC_CTRL)
  337.             hwndTarget = get_hwndHbar ();
  338.           else
  339.             hwndTarget = get_hwndVbar ();
  340.           break;
  341.  
  342.         case VK_LEFT:
  343.         case VK_RIGHT:
  344.           hwndTarget = get_hwndHbar ();
  345.           break;
  346.         }
  347.       if (hwndTarget != NULLHANDLE && WinIsWindowEnabled (hwndTarget))
  348.         WinPostMsg (hwndTarget, msg, mp1, mp2);
  349.     }
  350.   return WinDefWindowProc (hwnd, msg, mp1, mp2);
  351. }
  352.  
  353.  
  354. MRESULT source_window::wm_command (HWND hwnd, ULONG msg,
  355.                                    MPARAM mp1, MPARAM mp2)
  356. {
  357.   ULONG addr;
  358.   pm_create create;
  359.  
  360.   switch (SHORT1FROMMP (mp1))
  361.     {
  362.     case IDM_GOTO:
  363.       create.cb = sizeof (create);
  364.       create.ptr = (void *)this;
  365.       WinDlgBox (HWND_DESKTOP, get_hwndClient (), dlg_goto, 0, IDD_GOTO,
  366.                  &create);
  367.       return 0;
  368.  
  369.     case IDM_FIND:
  370.       create.cb = sizeof (create);
  371.       create.ptr = (void *)this;
  372.       if (WinDlgBox (HWND_DESKTOP, get_hwndClient (), dlg_find, 0, IDD_FIND,
  373.                      &create) == DID_OK)
  374.         find (true, true);
  375.       return 0;
  376.  
  377.     case IDM_FINDNEXT:
  378.       find (false, true);
  379.       return 0;
  380.  
  381.     case IDM_FINDPREV:
  382.       find (false, false);
  383.       return 0;
  384.  
  385.     case IDM_JUMP:
  386.       // TODO: Don't do this in the PM thread (time!)
  387.       addr = selected_addr ();
  388.       if (addr == 0 || !gdb->call_cmd ("server set var $pc=0x%lx", addr))
  389.         WinAlarm (HWND_DESKTOP, WA_ERROR);
  390.       else
  391.         cmd->where ();
  392.       return 0;
  393.  
  394.     case IDM_UNTIL:
  395.       // TODO: Don't do this in the PM thread (time!)
  396.       addr = selected_addr ();
  397.       if (addr == 0)
  398.         WinAlarm (HWND_DESKTOP, WA_ERROR);
  399.       else
  400.         {
  401.           gdb->prepare_run ();
  402.           gdb->send_cmd ("server until *0x%lx", addr);
  403.         }
  404.       return 0;
  405.  
  406.     case IDM_DSP_SHOW:
  407.       cmd->dsp->show (true);
  408.       return 0;
  409.  
  410.     case IDM_DSP_ADD:
  411.       if (cmd->dsp->add (hwnd))
  412.         cmd->dsp->show (true);
  413.       return 0;
  414.  
  415.     case IDM_BRKPT_LINE:
  416.       cmd->brk->add_line (short_filename, sel_lineno);
  417.       return 0;
  418.  
  419.     default:
  420.       return cmd->wm_command (hwnd, msg, mp1, mp2);
  421.     }
  422. }
  423.  
  424.  
  425. bool source_window::wm_user (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  426. {
  427.   unsigned change;
  428.  
  429.   if (parent::wm_user (hwnd, msg, mp1, mp2))
  430.     return true;
  431.   switch (msg)
  432.     {
  433.     case UWM_STATE:
  434.       change = LONGFROMMP (mp1);
  435.       if (change & command_window::GSC_PROMPT)
  436.         menu_enable (IDM_RUNMENU, gdb->is_ready ());
  437.       if (change & command_window::GSC_RUNNING)
  438.         {
  439.           if (gdb->is_nochild ())
  440.             show_line (-1);
  441.           // TODO: IDM_GO
  442.           bool running = !gdb->is_nochild ();
  443.           menu_enable (IDM_STEPOVER, running);
  444.           menu_enable (IDM_STEPINTO, running);
  445.           menu_enable (IDM_ISTEPOVER, running);
  446.           menu_enable (IDM_ISTEPINTO, running);
  447.           // TODO:
  448.           menu_enable (IDM_UNTIL, running);
  449.           menu_enable (IDM_JUMP, running);
  450.           menu_enable (IDM_FINISH, running);
  451.         }
  452.       if (change & command_window::GSC_EXEC_FILE)
  453.         {
  454.           menu_enable (IDM_RESTART, cmd->get_debuggee () != NULL);
  455.           menu_enable (IDM_GO, cmd->get_debuggee () != NULL);
  456.         }
  457.       return true;
  458.  
  459.     default:
  460.       return false;
  461.     }
  462. }
  463.  
  464.  
  465. MRESULT source_window::wm_close (HWND, ULONG, MPARAM, MPARAM)
  466. {
  467.   WinPostMsg (cmd->get_hwndClient (), UWM_CLOSE_SRC, MPFROMP (this), 0);
  468.   return 0;
  469. }
  470.  
  471.  
  472. static bool is_symbol (int c)
  473. {
  474.   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
  475. }
  476.  
  477.  
  478. void source_window::button1_lineno (int line, int clicks)
  479. {
  480.   int lineno = line + 1;
  481.   if (clicks == 0)
  482.     {
  483.       if (lineno == sel_lineno)
  484.         select_line (-1);
  485.       else
  486.         select_line (lineno);
  487.     }
  488.   else if (clicks == 2)
  489.     {
  490.       const breakpoint *brk
  491.         = cmd->breakpoints.find (short_filename, lineno);
  492.       // TODO: enabled/disabled
  493.       if (brk != NULL)
  494.         gdb->send_cmd ("server delete %d", brk->get_number ());
  495.       else
  496.         gdb->send_cmd ("server break %s:%d",
  497.                        (const char *)short_filename, lineno);
  498.     }
  499. }
  500.  
  501.  
  502. void source_window::button1_source (int line, int column, int clicks)
  503. {
  504.   if (clicks == 2)
  505.     {
  506.       if (exp_lineno != -1)
  507.         {
  508.           put (exp_lineno - 1, exp_column, exp_len,
  509.                exp_lineno == cur_lineno ? hilite_attr : get_default_attr (),
  510.                true);
  511.           exp_lineno = -1;
  512.         }
  513.       if (is_symbol (get_char (line, column)))
  514.         {
  515.           int start = column;
  516.           while (start > 0)
  517.             {
  518.               int c = get_char (line, start - 1);
  519.               if (is_symbol (c))
  520.                 --start;
  521.               // TODO: blanks
  522.               else if (c == '.'
  523.                        && is_symbol (get_char (line, start - 2)))
  524.                 start -= 2;
  525.               // TODO: blanks
  526.               else if (c == '>'
  527.                        && get_char (line, start - 2) == '-'
  528.                        && is_symbol (get_char (line, start - 3)))
  529.                 start -= 3;
  530.               else
  531.                 break;
  532.             }
  533.           int end = column + 1;
  534.           for (;;)
  535.             {
  536.               int c = get_char (line, end);
  537.               if (is_symbol (c) || (c >= '0' && c <= '9'))
  538.                 ++end;
  539.               else
  540.                 break;
  541.             }
  542.           char *buf = (char *)alloca (end - start + 1);
  543.           if (get_string (line, start, buf, end - start))
  544.             {
  545.               exp_lineno = line + 1;
  546.               exp_column = start; exp_len = end - start;
  547.               put (line, start, exp_len, sel_attr, true);
  548.               // TODO: Context (class, function, ...)
  549.               gdb->send_cmd ("server display %s", buf);
  550.               cmd->dsp->show (true);
  551.             }
  552.         }
  553.     }
  554. }
  555.  
  556.  
  557. void source_window::button_event (int line, int column, int, int button,
  558.                                   int clicks)
  559. {
  560.   if (line >= 0 && column >= 0 && button == 1)
  561.     {
  562.       // TODO: Context menu (run editor, set/edit breakpoint, ...)
  563.       if (column < LINENO_WIDTH + 2)
  564.         button1_lineno (line, clicks);
  565.       else if (column >= SOURCE_COLUMN - 1)
  566.         button1_source (line, column, clicks);
  567.     }
  568. }
  569.  
  570.  
  571. void source_window::set_breakpoint (int lineno, bool set, bool paint)
  572. {
  573.   put (lineno - 1, 0, LINENO_WIDTH + 2,
  574.        set ? bpt_attr : lineno == sel_lineno ? sel_attr : get_default_attr (),
  575.        paint);
  576. }
  577.  
  578.  
  579. // TODO: Don't do this in the PM thread
  580.  
  581. void source_window::find (bool start, bool forward)
  582. {
  583.   capture *capt = gdb->capture_cmd ("server list %s:%d,1",
  584.                                     (const char *)short_filename,
  585.                                     start ? 1 : find_lineno);
  586.   delete_capture (capt);
  587.   capt = gdb->capture_cmd ("server %s %s",
  588.                            forward ? "search" : "reverse-search",
  589.                            (const char *)find_string);
  590.   long n;
  591.   if (capt != NULL && (n = strtol (gdb->get_output (), NULL, 10)) >= 1)
  592.     {
  593.       find_lineno = (int)n;
  594.       select_line ((int)n);
  595.       parent::show_line (n - 1, 1, get_window_lines () / 2);
  596.       menu_enable (IDM_FINDNEXT, true);
  597.       menu_enable (IDM_FINDPREV, !start);
  598.     }
  599.   else
  600.     {
  601.       WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
  602.                      (PSZ)"Not found.", (PSZ)"pmgdb", 0,
  603.                      MB_MOVEABLE | MB_OK | MB_ICONEXCLAMATION);
  604.       if (forward || start)
  605.         menu_enable (IDM_FINDNEXT, false);
  606.       if (!forward || start)
  607.         menu_enable (IDM_FINDPREV, false);
  608.     }
  609.   delete_capture (capt);
  610. }
  611.