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 >
Wrap
C/C++ Source or Header
|
1996-09-11
|
17KB
|
611 lines
/* source.cc
Copyright (c) 1996 Eberhard Mattes
This file is part of pmgdb.
pmgdb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
pmgdb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pmgdb; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#define INCL_DOS
#define INCL_WIN
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include "string.h"
#include "pmapp.h"
#include "pmframe.h"
#include "pmtxt.h"
#include "pmtty.h"
#include "pmgdb.h"
#include "help.h"
#include "breakpoi.h"
#include "source.h"
#include "display.h"
#include "annotati.h"
#include "capture.h"
#include "gdbio.h"
#include "command.h"
#define LINENO_WIDTH 6
#define SOURCE_COLUMN (LINENO_WIDTH + 4)
source_window::source_window (pmapp *in_app, unsigned in_id,
const char *fontnamesize,
const char *short_fname, const char *long_fname,
command_window *in_cmd, gdbio *in_gdb)
: pmtxt (in_app, in_id, FCF_SHELLPOSITION, NULL, fontnamesize)
{
cmd = in_cmd; gdb = in_gdb;
short_filename = short_fname;
long_filename = long_fname;
astring title;
title = "pmgdb - ";
title.append (short_filename);
set_title (title);
set_keys_help_id (HELP_SRC_KEYS);
hilite_attr = get_default_attr ();
set_fg_color (hilite_attr, CLR_WHITE);
set_bg_color (hilite_attr, CLR_BLACK);
sel_attr = get_default_attr ();
set_fg_color (sel_attr, CLR_BLACK);
set_bg_color (sel_attr, CLR_PALEGRAY);
bpt_attr = get_default_attr ();
set_fg_color (bpt_attr, CLR_WHITE);
set_bg_color (bpt_attr, CLR_RED);
sel_bpt_attr = get_default_attr ();
set_fg_color (sel_bpt_attr, CLR_WHITE);
set_bg_color (sel_bpt_attr, CLR_PINK);
// Initialize menu
WinPostMsg (get_hwndClient (), UWM_STATE, MPFROMLONG (~0), 0);
load ();
set_font (*cmd);
show (true);
}
source_window::~source_window ()
{
}
void source_window::load ()
{
char buf[max_line_len+2]; // Line read from source file
char pfx[10]; // Line number
int c;
delete_all ();
cur_lineno = -1; sel_lineno = -1;
exp_lineno = -1; find_string = "";
menu_enable (IDM_FINDNEXT, false);
menu_enable (IDM_FINDPREV, false);
FILE *f = fopen (long_filename, "r");
if (f == NULL)
{
// TODO: Use GDB's value of `set directory'
// TODO: Dialog box, asking for file name
strcpy (buf, "Cannot open file");
put (0, 0, strlen (buf), buf, true);
}
else
{
int y = 0;
while (fgets (buf, sizeof (buf), f) != NULL)
{
size_t len = strlen (buf);
if (len > 0 && buf[len-1] == '\n')
--len;
else
{
// Line too long, skip rest
do
{
c = fgetc (f);
} while (c != EOF && c != '\n');
}
// Insert line number
int pfx_len = sprintf (pfx, "%*d ", LINENO_WIDTH, y + 1);
put (y, 0, pfx_len, pfx, false);
put_tab (y, LINENO_WIDTH + 1, false);
put_vrule (y, LINENO_WIDTH + 2, false);
// Insert source line
char *tab = (char *)memchr (buf, '\t', len);
if (tab == NULL)
put (y, SOURCE_COLUMN, len, buf, false);
else
{
// Expand TABs
int x = 0;
size_t i = 0;
while (tab != NULL)
{
size_t copy = tab - (buf + i);
if (copy != 0)
{
put (y, SOURCE_COLUMN + x, copy, buf + i, false);
i += copy; x += copy;
}
int tab_width = (x | 7) + 1 - x;
put (y, SOURCE_COLUMN + x, tab_width, " ", false);
++i; x += tab_width;
tab = (char *)memchr (buf + i, '\t', len - i);
}
if (i < len)
put (y, SOURCE_COLUMN + x, len - i, buf + i, false);
}
++y;
}
// TODO: ferror()
fclose (f);
}
cmd->get_breakpoints (this, false);
}
void source_window::show_line (int lineno)
{
if (lineno != cur_lineno)
{
if (cur_lineno != -1)
{
put (cur_lineno - 1, SOURCE_COLUMN - 1, max_line_len,
get_default_attr (), true);
set_eol_attr (cur_lineno - 1, get_default_attr (), true);
}
if (lineno != -1)
{
put (lineno - 1, SOURCE_COLUMN - 1, max_line_len, hilite_attr, true);
set_eol_attr (lineno - 1, hilite_attr, true);
}
cur_lineno = lineno;
if (lineno == exp_lineno)
exp_lineno = -1;
}
if (lineno != -1)
parent::show_line (lineno - 1, 1, get_window_lines () * 2 / 3);
}
void source_window::select_line (int lineno)
{
if (lineno != sel_lineno)
{
if (sel_lineno != -1)
{
const breakpoint *bpt
= cmd->breakpoints.find (short_filename, sel_lineno);
put (sel_lineno - 1, 0, LINENO_WIDTH + 2,
bpt != NULL ? bpt_attr : get_default_attr (), true);
}
if (lineno != -1)
{
const breakpoint *bpt
= cmd->breakpoints.find (short_filename, lineno);
put (lineno - 1, 0, LINENO_WIDTH + 2,
bpt != NULL ? sel_bpt_attr : sel_attr, true);
}
sel_lineno = lineno;
}
}
ULONG source_window::selected_addr ()
{
if (sel_lineno == -1)
return 0;
return gdb->address_of_line (short_filename, sel_lineno);
}
MRESULT source_window::goto_msg (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
char buf[80];
switch (msg)
{
case WM_INITDLG:
dlg_sys_menu (hwnd);
WinSetWindowPtr (hwnd, QWL_USER, this);
break;
case WM_COMMAND:
switch (SHORT1FROMMP (mp1))
{
case DID_OK:
WinQueryDlgItemText (hwnd, IDC_LINENO, sizeof (buf), (PSZ)buf);
int lineno = atoi (buf);
if (lineno > 0)
parent::show_line (lineno - 1, 1, get_window_lines () / 2);
WinDismissDlg (hwnd, DID_OK);
return 0;
}
break;
}
return WinDefDlgProc (hwnd, msg, mp1, mp2);
}
MRESULT EXPENTRY dlg_goto (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
source_window *p;
if (msg == WM_INITDLG)
p = (source_window *)((struct pm_create *)PVOIDFROMMP (mp2))->ptr;
else
p = (source_window *)WinQueryWindowPtr (hwnd, QWL_USER);
return p->goto_msg (hwnd, msg, mp1, mp2);
}
MRESULT source_window::find_msg (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
char buf[200];
switch (msg)
{
case WM_INITDLG:
dlg_sys_menu (hwnd);
WinSendDlgItemMsg (hwnd, IDC_STRING, EM_SETTEXTLIMIT,
MPFROMSHORT (sizeof (buf) - 1), 0);
WinSetDlgItemText (hwnd, IDC_STRING, (PCSZ)find_string);
WinSetWindowPtr (hwnd, QWL_USER, this);
break;
case WM_COMMAND:
switch (SHORT1FROMMP (mp1))
{
case DID_OK:
WinQueryDlgItemText (hwnd, IDC_STRING, sizeof (buf), (PSZ)buf);
if (buf[0] != 0)
{
find_string = buf;
WinDismissDlg (hwnd, DID_OK);
}
else
WinDismissDlg (hwnd, DID_CANCEL);
return 0;
}
break;
}
return WinDefDlgProc (hwnd, msg, mp1, mp2);
}
MRESULT EXPENTRY dlg_find (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
source_window *p;
if (msg == WM_INITDLG)
p = (source_window *)((struct pm_create *)PVOIDFROMMP (mp2))->ptr;
else
p = (source_window *)WinQueryWindowPtr (hwnd, QWL_USER);
return p->find_msg (hwnd, msg, mp1, mp2);
}
MRESULT source_window::wm_activate (HWND hwnd, ULONG msg,
MPARAM mp1, MPARAM mp2)
{
if (SHORT1FROMMP (mp1))
cmd->associate_help (get_hwndFrame ());
return WinDefWindowProc (hwnd, msg, mp1, mp2);
}
MRESULT source_window::wm_char (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
if ((SHORT1FROMMP (mp1) & (KC_VIRTUALKEY|KC_KEYUP)) == KC_VIRTUALKEY)
{
HWND hwndTarget = NULLHANDLE;
switch (SHORT2FROMMP (mp2))
{
case VK_UP:
case VK_DOWN:
hwndTarget = get_hwndVbar ();
break;
case VK_PAGEUP:
case VK_PAGEDOWN:
if (SHORT1FROMMP (mp1) & KC_CTRL)
hwndTarget = get_hwndHbar ();
else
hwndTarget = get_hwndVbar ();
break;
case VK_LEFT:
case VK_RIGHT:
hwndTarget = get_hwndHbar ();
break;
}
if (hwndTarget != NULLHANDLE && WinIsWindowEnabled (hwndTarget))
WinPostMsg (hwndTarget, msg, mp1, mp2);
}
return WinDefWindowProc (hwnd, msg, mp1, mp2);
}
MRESULT source_window::wm_command (HWND hwnd, ULONG msg,
MPARAM mp1, MPARAM mp2)
{
ULONG addr;
pm_create create;
switch (SHORT1FROMMP (mp1))
{
case IDM_GOTO:
create.cb = sizeof (create);
create.ptr = (void *)this;
WinDlgBox (HWND_DESKTOP, get_hwndClient (), dlg_goto, 0, IDD_GOTO,
&create);
return 0;
case IDM_FIND:
create.cb = sizeof (create);
create.ptr = (void *)this;
if (WinDlgBox (HWND_DESKTOP, get_hwndClient (), dlg_find, 0, IDD_FIND,
&create) == DID_OK)
find (true, true);
return 0;
case IDM_FINDNEXT:
find (false, true);
return 0;
case IDM_FINDPREV:
find (false, false);
return 0;
case IDM_JUMP:
// TODO: Don't do this in the PM thread (time!)
addr = selected_addr ();
if (addr == 0 || !gdb->call_cmd ("server set var $pc=0x%lx", addr))
WinAlarm (HWND_DESKTOP, WA_ERROR);
else
cmd->where ();
return 0;
case IDM_UNTIL:
// TODO: Don't do this in the PM thread (time!)
addr = selected_addr ();
if (addr == 0)
WinAlarm (HWND_DESKTOP, WA_ERROR);
else
{
gdb->prepare_run ();
gdb->send_cmd ("server until *0x%lx", addr);
}
return 0;
case IDM_DSP_SHOW:
cmd->dsp->show (true);
return 0;
case IDM_DSP_ADD:
if (cmd->dsp->add (hwnd))
cmd->dsp->show (true);
return 0;
case IDM_BRKPT_LINE:
cmd->brk->add_line (short_filename, sel_lineno);
return 0;
default:
return cmd->wm_command (hwnd, msg, mp1, mp2);
}
}
bool source_window::wm_user (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
unsigned change;
if (parent::wm_user (hwnd, msg, mp1, mp2))
return true;
switch (msg)
{
case UWM_STATE:
change = LONGFROMMP (mp1);
if (change & command_window::GSC_PROMPT)
menu_enable (IDM_RUNMENU, gdb->is_ready ());
if (change & command_window::GSC_RUNNING)
{
if (gdb->is_nochild ())
show_line (-1);
// TODO: IDM_GO
bool running = !gdb->is_nochild ();
menu_enable (IDM_STEPOVER, running);
menu_enable (IDM_STEPINTO, running);
menu_enable (IDM_ISTEPOVER, running);
menu_enable (IDM_ISTEPINTO, running);
// TODO:
menu_enable (IDM_UNTIL, running);
menu_enable (IDM_JUMP, running);
menu_enable (IDM_FINISH, running);
}
if (change & command_window::GSC_EXEC_FILE)
{
menu_enable (IDM_RESTART, cmd->get_debuggee () != NULL);
menu_enable (IDM_GO, cmd->get_debuggee () != NULL);
}
return true;
default:
return false;
}
}
MRESULT source_window::wm_close (HWND, ULONG, MPARAM, MPARAM)
{
WinPostMsg (cmd->get_hwndClient (), UWM_CLOSE_SRC, MPFROMP (this), 0);
return 0;
}
static bool is_symbol (int c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
void source_window::button1_lineno (int line, int clicks)
{
int lineno = line + 1;
if (clicks == 0)
{
if (lineno == sel_lineno)
select_line (-1);
else
select_line (lineno);
}
else if (clicks == 2)
{
const breakpoint *brk
= cmd->breakpoints.find (short_filename, lineno);
// TODO: enabled/disabled
if (brk != NULL)
gdb->send_cmd ("server delete %d", brk->get_number ());
else
gdb->send_cmd ("server break %s:%d",
(const char *)short_filename, lineno);
}
}
void source_window::button1_source (int line, int column, int clicks)
{
if (clicks == 2)
{
if (exp_lineno != -1)
{
put (exp_lineno - 1, exp_column, exp_len,
exp_lineno == cur_lineno ? hilite_attr : get_default_attr (),
true);
exp_lineno = -1;
}
if (is_symbol (get_char (line, column)))
{
int start = column;
while (start > 0)
{
int c = get_char (line, start - 1);
if (is_symbol (c))
--start;
// TODO: blanks
else if (c == '.'
&& is_symbol (get_char (line, start - 2)))
start -= 2;
// TODO: blanks
else if (c == '>'
&& get_char (line, start - 2) == '-'
&& is_symbol (get_char (line, start - 3)))
start -= 3;
else
break;
}
int end = column + 1;
for (;;)
{
int c = get_char (line, end);
if (is_symbol (c) || (c >= '0' && c <= '9'))
++end;
else
break;
}
char *buf = (char *)alloca (end - start + 1);
if (get_string (line, start, buf, end - start))
{
exp_lineno = line + 1;
exp_column = start; exp_len = end - start;
put (line, start, exp_len, sel_attr, true);
// TODO: Context (class, function, ...)
gdb->send_cmd ("server display %s", buf);
cmd->dsp->show (true);
}
}
}
}
void source_window::button_event (int line, int column, int, int button,
int clicks)
{
if (line >= 0 && column >= 0 && button == 1)
{
// TODO: Context menu (run editor, set/edit breakpoint, ...)
if (column < LINENO_WIDTH + 2)
button1_lineno (line, clicks);
else if (column >= SOURCE_COLUMN - 1)
button1_source (line, column, clicks);
}
}
void source_window::set_breakpoint (int lineno, bool set, bool paint)
{
put (lineno - 1, 0, LINENO_WIDTH + 2,
set ? bpt_attr : lineno == sel_lineno ? sel_attr : get_default_attr (),
paint);
}
// TODO: Don't do this in the PM thread
void source_window::find (bool start, bool forward)
{
capture *capt = gdb->capture_cmd ("server list %s:%d,1",
(const char *)short_filename,
start ? 1 : find_lineno);
delete_capture (capt);
capt = gdb->capture_cmd ("server %s %s",
forward ? "search" : "reverse-search",
(const char *)find_string);
long n;
if (capt != NULL && (n = strtol (gdb->get_output (), NULL, 10)) >= 1)
{
find_lineno = (int)n;
select_line ((int)n);
parent::show_line (n - 1, 1, get_window_lines () / 2);
menu_enable (IDM_FINDNEXT, true);
menu_enable (IDM_FINDPREV, !start);
}
else
{
WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
(PSZ)"Not found.", (PSZ)"pmgdb", 0,
MB_MOVEABLE | MB_OK | MB_ICONEXCLAMATION);
if (forward || start)
menu_enable (IDM_FINDNEXT, false);
if (!forward || start)
menu_enable (IDM_FINDPREV, false);
}
delete_capture (capt);
}