1 /*
2 Copyright (C) 1998,1999,2000,2001
3 T. Scott Dattalo and Ralf Forsberg
4
5 This file is part of gpsim.
6
7 gpsim is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 gpsim is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with gpsim; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include <cstdio>
23
24 #include "../config.h"
25
26
27 #ifdef HAVE_GUI
28
29 #include <gtk/gtk.h>
30 #include <gdk/gdk.h>
31 #include <gdk/gdkkeysyms.h>
32 #include <glib.h>
33
34 #include "gui.h"
35 #include "gui_src.h"
36 #include "gui_profile.h"
37 #include "gui_symbols.h"
38 #include "gui_statusbar.h"
39 #include "gui_watch.h"
40
41 #include <cassert>
42 #include <cctype>
43 #include <cstring>
44
45 #include <algorithm>
46 #include <list>
47 #include <string>
48
49 #include "../src/fopen-path.h"
50
51 //======================================================================
52 //
53 // When a user right-clicks in the source browser, a menu will popup.
54 // There can only be one menu active at any given time.
55
56
57 //
58 // 'aPopupMenu' pointer is a local pointer to a GtkMenu.
59 //
60
61 static GtkWidget *aPopupMenu;
62
63 //
64 // 'pViewContainingPopup' is a pointer to the GtkTextView that was active
65 // when the popup menu was opened.
66 //
67
68 static GtkTextView *pViewContainingPopup;
69
70 //------------------------------------------------------------------------
71 //
strReverse(const char * start,char * dest,int nChars)72 static char *strReverse(const char *start, char *dest, int nChars)
73 {
74 *dest-- = 0;
75 while (nChars--)
76 *dest-- = *start++;
77 dest++;
78 return dest;
79 }
80
81 //========================================================================
82
83 class SourceXREF : public CrossReferenceToGUI
84 {
85 public:
86
Update(int new_value)87 void Update(int new_value)
88 {
89 SourceWindow *sbaw = static_cast<SourceWindow *>(parent_window);
90
91 if(sbaw->bSourceLoaded())
92 sbaw->SetPC(new_value);
93 }
94
Remove()95 void Remove() {}
96 };
97
98
99
100 #define BP_PIXEL_SIZE 10
101 #define PC_PIXEL_SIZE 10
102 #define MARGIN_WIDTH (PC_PIXEL_SIZE + BP_PIXEL_SIZE)
103 #define PC_START (MARGIN_WIDTH - PC_PIXEL_SIZE)
104 #define BP_START (MARGIN_WIDTH - PC_PIXEL_SIZE-BP_PIXEL_SIZE)
105
106
107 /* This function is taken from gtk+/tests/testtext.c */
108 static void
gtk_source_view_get_lines(GtkTextView * text_view,gint first_y,gint last_y,std::vector<gint> & buffer_coords,std::vector<gint> & numbers)109 gtk_source_view_get_lines(GtkTextView *text_view,
110 gint first_y,
111 gint last_y,
112 std::vector<gint> &buffer_coords,
113 std::vector<gint> &numbers)
114 {
115 GtkTextIter iter;
116 gint last_line_num = -1;
117
118 buffer_coords.clear();
119 numbers.clear();
120
121 /* Get iter at first y */
122 gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
123
124 /* For each iter, get its location and add it to the arrays.
125 * Stop when we pass last_y
126 */
127 while (!gtk_text_iter_is_end (&iter))
128 {
129 gint y, height;
130
131 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
132
133 last_line_num = gtk_text_iter_get_line (&iter);
134
135 buffer_coords.push_back(y);
136 numbers.push_back(last_line_num);
137
138 if ((y + height) >= last_y)
139 break;
140
141 gtk_text_iter_forward_line (&iter);
142 }
143
144 if (gtk_text_iter_is_end (&iter))
145 {
146 gint y, height;
147 gint line_num;
148
149 gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
150
151 line_num = gtk_text_iter_get_line (&iter);
152
153 if (line_num != last_line_num)
154 {
155 buffer_coords.push_back(y);
156 numbers.push_back(line_num);
157 }
158 }
159 }
160
161
162 //------------------------------------------------------------------------
163 //
164 gboolean
KeyPressHandler(GtkTextView * pView,GdkEventKey * key,NSourcePage * page)165 NSourcePage::KeyPressHandler(GtkTextView *pView, GdkEventKey *key,
166 NSourcePage *page)
167 {
168 guint modifiers = gtk_accelerator_get_default_mod_mask();
169
170 if ((key->state & modifiers) != 0) {
171 return FALSE;
172 }
173
174 GtkTextBuffer *pBuffer = gtk_text_view_get_buffer(pView);
175 GtkTextMark *pMark = gtk_text_buffer_get_insert(pBuffer);
176 GtkTextIter iter;
177 gtk_text_buffer_get_iter_at_mark (pBuffer, &iter, pMark);
178 int line = gtk_text_iter_get_line (&iter);
179
180 Dprintf(("Received key press for view. line=%d page%p\n",line,page));
181
182 switch (key->keyval) {
183 case 'b':
184 case 'B':
185 page->m_Parent->toggleBreak(page, line);
186 break;
187 default:
188 return FALSE;
189 }
190
191 return TRUE;
192 }
193
194 gint
ViewExposeEventHandler(GtkTextView * pView,GdkEventExpose * pEvent,NSourcePage * pPage)195 NSourcePage::ViewExposeEventHandler(GtkTextView *pView, GdkEventExpose *pEvent,
196 NSourcePage *pPage)
197 {
198 if (pEvent->window == gtk_text_view_get_window (pView,
199 GTK_TEXT_WINDOW_LEFT))
200 {
201 //gtk_source_view_paint_margin (view, event);
202 //event_handled = TRUE;
203 Dprintf(("Expose event for view margin %p\n",pSW));
204
205 gint y1 = pEvent->area.y;
206 gint y2 = y1 + pEvent->area.height;
207
208 gtk_text_view_window_to_buffer_coords (pView,
209 GTK_TEXT_WINDOW_LEFT,
210 0,
211 y1,
212 NULL,
213 &y1);
214
215 gtk_text_view_window_to_buffer_coords (pView,
216 GTK_TEXT_WINDOW_LEFT,
217 0,
218 y2,
219 NULL,
220 &y2);
221
222 pPage->updateMargin(y1,y2);
223
224 }
225 else {
226 Dprintf(("Expose event for view %p\n",pSW));
227 }
228 return FALSE;
229 }
230
231 //------------------------------------------------------------------------
232 //
233 gboolean
KeyPressHandler(GtkWidget *,GdkEventKey * key,SourceWindow * pSW)234 SourceWindow::KeyPressHandler(GtkWidget *,
235 GdkEventKey *key,
236 SourceWindow *pSW)
237 {
238 if (!pSW || !key)
239 return FALSE;
240
241 guint modifiers = gtk_accelerator_get_default_mod_mask();
242 if ((key->state & modifiers) == GDK_CONTROL_MASK && key->keyval == 'f') {
243 NSourcePage *page = pSW->pages[pSW->m_currentPage];
244 if (!page)
245 return FALSE;
246 pViewContainingPopup = page->getView();
247 pSW->findText();
248 return TRUE;
249 }
250
251 if ((key->state & modifiers) != 0) {
252 return FALSE;
253 }
254
255 switch (key->keyval) {
256 case '1':
257 case '2':
258 case '3':
259 case '4':
260 case '5':
261 case '6':
262 case '7':
263 case '8':
264 case '9':
265 pSW->step(key->keyval - '0');
266 break;
267 case 's':
268 case 'S':
269 case GDK_KEY_F7:
270 pSW->step();
271 break;
272 case 'o':
273 case 'O':
274 case GDK_KEY_F8:
275 pSW->step_over();
276 break;
277 case 'r':
278 case 'R':
279 case GDK_KEY_F9:
280 pSW->run();
281 break;
282 case 'f':
283 case 'F':
284 pSW->finish();
285 break;
286 case GDK_KEY_Escape:
287 pSW->stop();
288 break;
289 default:
290 return FALSE;
291 }
292
293 return TRUE;
294 }
295
296 typedef enum {
297 MENU_FIND_TEXT,
298 MENU_FIND_PC,
299 MENU_MOVE_PC,
300 MENU_RUN_HERE,
301 MENU_BP_HERE,
302 MENU_SELECT_SYMBOL,
303 MENU_STEP,
304 MENU_STEP_OVER,
305 MENU_RUN,
306 MENU_STOP,
307 MENU_FINISH,
308 MENU_RESET,
309 MENU_PROFILE_START_HERE,
310 MENU_PROFILE_STOP_HERE,
311 MENU_ADD_TO_WATCH,
312 } menu_id;
313
314
315 typedef struct _menu_item {
316 const char *name;
317 menu_id id;
318 } menu_item;
319
320 static const menu_item menu_items[] = {
321 {"Find PC", MENU_FIND_PC},
322 {"Run to here", MENU_RUN_HERE},
323 {"Move PC here", MENU_MOVE_PC},
324 {"Breakpoint here", MENU_BP_HERE},
325 {"Profile start here", MENU_PROFILE_START_HERE},
326 {"Profile stop here", MENU_PROFILE_STOP_HERE},
327 {"Add to watch", MENU_ADD_TO_WATCH},
328 {"Find text...", MENU_FIND_TEXT},
329 };
330
331 static const menu_item submenu_items[] = {
332 {"Step", MENU_STEP},
333 {"Step Over", MENU_STEP_OVER},
334 {"Run", MENU_RUN},
335 {"Stop", MENU_STOP},
336 {"Reset", MENU_RESET},
337 {"Finish", MENU_FINISH},
338 };
339
340
341 //------------------------------------------------------------------------
342 // ButtonPressHandler
343 // Event handler for text view mouse clicks.
344 gint
ButtonPressHandler(GtkTextView * pView,GdkEventButton * pButton,NSourcePage * pPage)345 NSourcePage::ButtonPressHandler(GtkTextView *pView, GdkEventButton *pButton,
346 NSourcePage *pPage)
347 {
348
349 if (pButton->window == gtk_text_view_get_window (pView,
350 GTK_TEXT_WINDOW_LEFT))
351 {
352 // Margin
353 gint y;
354
355 gtk_text_view_window_to_buffer_coords (pView,
356 GTK_TEXT_WINDOW_LEFT,
357 (gint) pButton->x,
358 (gint) pButton->y,
359 NULL,
360 &y);
361 GtkTextIter iter;
362
363 gtk_text_view_get_line_at_y (pView, &iter, y, NULL);
364 gint line = gtk_text_iter_get_line (&iter);
365 pPage->m_Parent->toggleBreak(pPage, line);
366
367 } else {
368 // Text (i.e. not the margin
369 if (pButton->button == 3 && aPopupMenu && GTK_IS_TEXT_VIEW(pView)) {
370 GtkTextIter iter;
371 gint y;
372
373 pViewContainingPopup = pView;
374 gtk_text_view_window_to_buffer_coords(pView,
375 GTK_TEXT_WINDOW_LEFT,
376 (gint) pButton->x,
377 (gint) pButton->y,
378 NULL,
379 &y);
380
381 gtk_text_view_get_line_at_y(pView, &iter, y, NULL);
382 pPage->getParent()->m_LineAtButtonClick = gtk_text_iter_get_line(&iter);
383
384 gtk_menu_popup(GTK_MENU(aPopupMenu), 0, 0, 0, 0,
385 3, pButton->time);
386
387 GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(pView);
388 gboolean selected = gtk_text_buffer_get_has_selection(text_buffer);
389
390 // Move cursor if no text is selected
391 if (!selected) {
392 gtk_text_buffer_place_cursor(text_buffer, &iter);
393 }
394 return TRUE;
395 }
396
397 }
398
399 return FALSE;
400 }
401
402 //========================================================================
403 // Helper functions for parsing
isString(const char * cP)404 static int isString(const char *cP)
405 {
406 int i=0;
407
408 if (isalpha(*cP) || *cP=='_')
409 while (isalnum(cP[i]) || cP[i]=='_')
410 i++;
411 return i;
412 }
413
isWhiteSpace(const char * cP)414 static int isWhiteSpace(const char *cP)
415 {
416 int i=0;
417
418 while (cP[i]==' ' || cP[i]=='\t')
419 i++;
420 return i;
421 }
422
isHexNumber(const char * c)423 static int isHexNumber(const char *c)
424 {
425 const char *start = c;
426
427 if (*c == '0') {
428 ++c;
429 if (*c == 'x' || *c == 'X')
430 ++c;
431 else
432 return 1;
433 } else if (*c == '$') {
434 ++c;
435 } else if (*c == 'H') {
436 ++c;
437 if (*c == '\'')
438 ++c;
439 else
440 return 0;
441 }
442
443 if (!isxdigit(*c))
444 return 0;
445
446 while (isxdigit(*c)) {
447 ++c;
448 }
449 return c - start;
450 }
isNumber(const char * cP)451 static int isNumber(const char *cP)
452 {
453 int i=isHexNumber(cP);
454 if (!i)
455 while (isdigit(cP[i]))
456 i++;
457 return i;
458 }
459
isEnd(const char c)460 static bool isEnd(const char c)
461 {
462 return c=='\n' || c==0;
463 }
464
isComment(const char * cP)465 static int isComment(const char *cP)
466 {
467 int i = (*cP==';') ? 1 : 0;
468 if (i)
469 while (!isEnd(cP[i]))
470 i++;
471 return i;
472 }
473
474 //------------------------------------------------------------------------
475 class SearchDialog
476 {
477 public:
478 SearchDialog();
479 void Show(SourceWindow *);
480 bool bDirection();
481 bool bCase();
482 private:
483 int m_iStart;
484
485 GtkWidget *m_Window; // The Search Dialog Window
486 GtkWidget *m_Entry; // Widget that holds the search text.
487 GtkWidget *m_BackButton; //
488 GtkWidget *m_CaseButton; //
489
490 SourceWindow *m_pSourceWindow; // The last source window that requested a search.
491
492 void find(const char *);
493
494 static void response(GtkDialog *dialog, gint response, SearchDialog *sd);
495 static void activate(GtkEntry *entry, SearchDialog *sd);
496 static void icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos,
497 GdkEvent *event, gpointer user_data);
498 };
499
500 //------------------------------------------------------------------------
SearchDialog()501 SearchDialog::SearchDialog()
502 : m_iStart(0), m_pSourceWindow(0)
503 {
504 m_Window = gtk_dialog_new_with_buttons(
505 "Find", NULL,
506 GtkDialogFlags(0),
507 "_Find", 1,
508 "_Close", GTK_RESPONSE_CLOSE,
509 NULL);
510
511 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(m_Window));
512 gtk_dialog_set_default_response(GTK_DIALOG(m_Window), 1);
513
514 g_signal_connect(m_Window, "response", G_CALLBACK(response), this);
515 g_signal_connect_swapped(m_Window,
516 "delete_event", G_CALLBACK (gtk_widget_hide),
517 GTK_OBJECT(m_Window));
518
519 GtkWidget *hbox = gtk_hbox_new(FALSE, 6);
520 gtk_box_pack_start(GTK_BOX(content_area), hbox,
521 FALSE, TRUE, 0);
522 GtkWidget *label = gtk_label_new("Find:");
523 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
524 m_Entry = gtk_entry_new();
525 gtk_box_pack_start(GTK_BOX(hbox), m_Entry, TRUE, TRUE, 0);
526 gtk_widget_grab_focus(m_Entry);
527 gtk_entry_set_icon_from_stock(GTK_ENTRY(m_Entry), GTK_ENTRY_ICON_PRIMARY,
528 GTK_STOCK_FIND);
529 gtk_entry_set_icon_from_stock(GTK_ENTRY(m_Entry), GTK_ENTRY_ICON_SECONDARY,
530 GTK_STOCK_CLEAR);
531 gtk_entry_set_icon_activatable(GTK_ENTRY(m_Entry), GTK_ENTRY_ICON_SECONDARY,
532 TRUE);
533 gtk_entry_set_icon_sensitive(GTK_ENTRY(m_Entry), GTK_ENTRY_ICON_SECONDARY,
534 TRUE);
535 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(m_Entry), GTK_ENTRY_ICON_SECONDARY,
536 "Clear text");
537 g_signal_connect(m_Entry, "activate", G_CALLBACK(activate), this);
538 g_signal_connect(m_Entry, "icon-press", G_CALLBACK(icon_press), NULL);
539
540 hbox = gtk_hbox_new(FALSE, 6);
541 gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, TRUE, 0);
542 m_CaseButton = gtk_check_button_new_with_label("Case Sensitive");
543 gtk_box_pack_start(GTK_BOX(hbox), m_CaseButton, FALSE, FALSE, 0);
544 m_BackButton = gtk_check_button_new_with_label("Find Backwards");
545 gtk_box_pack_start(GTK_BOX(hbox), m_BackButton, FALSE, FALSE, 0);
546 }
547
bDirection()548 bool SearchDialog::bDirection()
549 {
550 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_BackButton)) == TRUE;
551 }
552
bCase()553 bool SearchDialog::bCase()
554 {
555 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_CaseButton)) == TRUE;
556 }
557
find(const char * cpPattern)558 void SearchDialog::find(const char *cpPattern)
559 {
560 if (m_pSourceWindow)
561 m_iStart = m_pSourceWindow->findText(cpPattern,m_iStart,!bDirection(), bCase());
562 }
563
response(GtkDialog * dialog,gint response,SearchDialog * sd)564 void SearchDialog::response(GtkDialog *dialog, gint response, SearchDialog *sd)
565 {
566 switch (response) {
567 case 1:
568 {
569 const char *p = gtk_entry_get_text(GTK_ENTRY(sd->m_Entry));
570 sd->find(p);
571 }
572 break;
573 default:
574 gtk_widget_hide(GTK_WIDGET(dialog));
575 }
576 }
577
activate(GtkEntry * entry,SearchDialog * sd)578 void SearchDialog::activate(GtkEntry *entry, SearchDialog *sd)
579 {
580 const char *p = gtk_entry_get_text(entry);
581 sd->find(p);
582 }
583
icon_press(GtkEntry * entry,GtkEntryIconPosition,GdkEvent *,gpointer)584 void SearchDialog::icon_press(GtkEntry *entry, GtkEntryIconPosition ,
585 GdkEvent *, gpointer)
586 {
587 gtk_entry_set_text(entry, "");
588 }
589
Show(SourceWindow * pSourceWindow)590 void SearchDialog::Show(SourceWindow *pSourceWindow)
591 {
592 m_pSourceWindow = pSourceWindow;
593 m_iStart = 0;
594
595 gtk_widget_show_all(m_Window);
596 }
597
598 //========================================================================
599 //========================================================================
SourcePageMargin()600 SourcePageMargin::SourcePageMargin()
601 : m_bShowLineNumbers(true), m_bShowAddresses(false), m_bShowOpcodes(true)
602 {
603 }
604 //========================================================================
605 //========================================================================
SourceBuffer(GtkTextTagTable * pTagTable,FileContext * pFC,SourceBrowserParent_Window * pParent)606 SourceBuffer::SourceBuffer(GtkTextTagTable *pTagTable, FileContext *pFC,
607 SourceBrowserParent_Window *pParent)
608
609 : m_pParent(pParent), m_pFC(pFC), m_bParsed(false)
610 {
611
612 assert(pTagTable);
613 assert(pParent);
614 m_buffer = gtk_text_buffer_new (pTagTable);
615
616 assert(m_buffer);
617
618 }
619
620 // Addtag range applies the tag state to a range of text in the buffer
621 // using a given text style (i.e. the style contains a gtkTextTag)
addTagRange(const char * pStyle,int start_index,int end_index)622 void SourceBuffer::addTagRange(const char *pStyle,
623 int start_index, int end_index)
624 {
625 if (!pStyle)
626 return;
627
628 GtkTextIter start;
629 GtkTextIter end;
630 gtk_text_buffer_get_iter_at_offset (m_buffer, &start, start_index);
631 gtk_text_buffer_get_iter_at_offset (m_buffer, &end, end_index);
632
633 gtk_text_buffer_apply_tag_by_name(m_buffer, pStyle, &start, &end);
634 }
635
636 //------------------------------------------------------------------------
IsParsed()637 bool SourceBuffer::IsParsed()
638 {
639 return m_bParsed;
640 }
641
642 //------------------------------------------------------------------------
parse()643 void SourceBuffer::parse()
644 {
645 if (IsParsed() || !m_pParent || !m_pFC)
646 return;
647
648 Dprintf(("parsing source buffer %s\n",m_pFC->name().c_str()));
649 m_pParent->parseSource(this, m_pFC);
650 m_bParsed = true;
651
652 }
653
getBuffer()654 GtkTextBuffer *SourceBuffer::getBuffer()
655 {
656 parse();
657 return m_buffer;
658 }
659
660 //------------------------------------------------------------------------
SourceWindow(GUI_Processor * pgp,SourceBrowserParent_Window * pParent,bool bUseConfig,const char * newName)661 SourceWindow::SourceWindow(GUI_Processor *pgp,
662 SourceBrowserParent_Window *pParent, bool bUseConfig,
663 const char *newName)
664 : GUI_Object(newName ? newName : "source_browser"),
665 m_bLoadSource(false), m_bSourceLoaded(false),
666 m_LineAtButtonClick(-1), pma(0), status_bar(0),
667 last_simulation_mode(eSM_INITIAL), stPSearchDialog(0), m_Notebook(0),
668 m_pParent(pParent)
669 {
670 Dprintf(("Constructor \n"));
671
672 gp = pgp;
673
674 mProgramCounter.bIsActive = false;
675
676 if (bUseConfig) {
677 if (enabled)
678 Build();
679 }
680 }
681
682 //------------------------------------------------------------------------
step(int n)683 void SourceWindow::step(int n)
684 {
685 if (pma)
686 pma->step(n);
687 }
688 //------------------------------------------------------------------------
step_over()689 void SourceWindow::step_over()
690 {
691 if (pma)
692 pma->step_over();
693 }
694 //------------------------------------------------------------------------
stop()695 void SourceWindow::stop()
696 {
697 if (pma)
698 pma->stop();
699 }
700 //------------------------------------------------------------------------
run()701 void SourceWindow::run()
702 {
703 // if (pma)
704 // pma->run();
705 get_interface().start_simulation();
706 }
707 //------------------------------------------------------------------------
finish()708 void SourceWindow::finish()
709 {
710 if (pma)
711 pma->finish();
712 }
713
714 //------------------------------------------------------------------------
reset()715 void SourceWindow::reset()
716 {
717 if (gp && gp->cpu)
718 gp->cpu->reset(POR_RESET);
719 }
720
721 //------------------------------------------------------------------------
722 // toggleBreak
723 //
724 //
toggleBreak(NSourcePage * pPage,int line)725 void SourceWindow::toggleBreak(NSourcePage *pPage, int line)
726 {
727 if (pma && pPage) {
728 int address = pma->find_address_from_line(pPage->getFC(),line+1);
729 if (address >= 0)
730 pma->toggle_break_at_address(address);
731
732 }
733
734 }
735 //------------------------------------------------------------------------
736 // movePC
737 //
738 //
movePC(int)739 void SourceWindow::movePC(int)
740 {
741 }
742
743 //------------------------------------------------------------------------
findText()744 void SourceWindow::findText()
745 {
746 if (!stPSearchDialog)
747 stPSearchDialog = new SearchDialog();
748
749 stPSearchDialog->Show(this);
750 }
751
752
753 //------------------------------------------------------------------------
754 // strcasestr is a non standard function
755 //
756 #if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__
strcasestr(const char * searchee,const char * lookfor)757 char *strcasestr(const char *searchee, const char *lookfor)
758 {
759 if (*searchee == '\0')
760 {
761 if (*lookfor)
762 return NULL;
763 return (char *) searchee;
764 }
765
766 while (*searchee != '\0')
767 {
768 size_t i;
769
770 for (i = 0; ; ++i)
771 {
772 if (lookfor[i] == '\0')
773 return (char *) searchee;
774
775 if (tolower(lookfor[i]) != tolower(searchee[i]))
776 break;
777 }
778 searchee++;
779 }
780
781 return NULL;
782 }
783 #endif
784
785 //------------------------------------------------------------------------
786 // findText
787 //
788 // Search for the pattern 'pText' in the source window.
789 // if bDirection is true then search forward.
findText(const char * pText,int start,bool bDirection,bool bCase)790 int SourceWindow::findText(const char *pText, int start, bool bDirection, bool bCase)
791 {
792 if (!pText)
793 return 0;
794
795 unsigned int patternLen = strlen(pText);
796 char buff[1024];
797 patternLen = (patternLen < sizeof(buff)) ? patternLen : sizeof(buff) -1;
798 const char *pattern = bDirection ? pText :
799 strReverse(pText, &buff[patternLen], patternLen);
800
801 //printf("findText %s view:%p\n",pattern,pViewContainingPopup);
802
803 NSourcePage *pPage = pages[gtk_notebook_get_current_page(GTK_NOTEBOOK(m_Notebook))];
804
805 if (!pPage)
806 return 0;
807
808 GtkTextIter iStart;
809 GtkTextIter iEnd;
810 int line = 0;
811 int offset = 0;
812
813 int totalLines = gtk_text_buffer_get_line_count(pPage->buffer());
814 if (!start) {
815 if (bDirection) {
816 gtk_text_buffer_get_start_iter(pPage->buffer(),
817 &iStart);
818 gtk_text_buffer_get_iter_at_line(pPage->buffer(),
819 &iEnd,
820 line+1);
821 } else {
822
823 gtk_text_buffer_get_end_iter(pPage->buffer(),
824 &iEnd);
825 gtk_text_buffer_get_end_iter(pPage->buffer(),
826 &iStart);
827 gtk_text_iter_backward_line (&iStart);
828 line = totalLines-2;
829 }
830
831 } else {
832 gtk_text_buffer_get_iter_at_offset(pPage->buffer(),
833 &iStart,
834 start);
835 line = gtk_text_iter_get_line (&iStart);
836
837 if (bDirection) {
838 if (line >= totalLines) {
839 line = 0;
840 gtk_text_buffer_get_iter_at_offset(pPage->buffer(),
841 &iStart,
842 0);
843 }
844 } else {
845 if (line <= 0) {
846 line = totalLines-1;
847 gtk_text_buffer_get_iter_at_line(pPage->buffer(),
848 &iStart,
849 line--);
850 }
851 }
852
853 gtk_text_buffer_get_iter_at_line(pPage->buffer(),
854 &iEnd,
855 line);
856
857 offset = start - gtk_text_iter_get_offset (&iEnd);
858
859 gtk_text_buffer_get_iter_at_line(pPage->buffer(),
860 &iEnd,
861 line+1);
862 }
863
864
865 while (totalLines--) {
866
867 char *str = gtk_text_buffer_get_text(pPage->buffer(),
868 &iStart, &iEnd, FALSE);
869 unsigned int srcLen = strlen(str);
870
871 const char *cpSource = str;
872 char buffer2[1024];
873 if (!bDirection) {
874 srcLen = (srcLen < sizeof(buffer2)) ? srcLen : sizeof(buffer2)-1;
875 cpSource = strReverse(cpSource, &buffer2[srcLen], srcLen);
876 }
877
878 const char *pFound = bCase ? strstr(cpSource, pattern) : strcasestr(cpSource, pattern);
879
880 if (pFound) {
881 int pos = bDirection ? (pFound - cpSource) : (srcLen - (pFound - cpSource));
882 pos += offset;
883 //printf("Found %s in %s starting at %s, pos=%d\n",pattern, str, pFound,pos);
884
885 gtk_text_view_scroll_to_iter (pViewContainingPopup,
886 &iStart,
887 0.0,
888 TRUE,
889 0.0, 0.3);
890
891 gtk_text_buffer_get_iter_at_line_offset(pPage->buffer(),
892 &iStart,
893 line, pos);
894 gtk_text_buffer_get_iter_at_line_offset(pPage->buffer(),
895 &iEnd,
896 line,
897 pos+ (bDirection ? patternLen : -patternLen));
898
899 gtk_text_buffer_select_range (pPage->buffer(),
900 &iStart,
901 &iEnd);
902
903 g_free(str);
904 return gtk_text_iter_get_offset(bDirection ? &iEnd : &iStart);
905 }
906 g_free(str);
907
908 // Now we'll search whole lines.
909 offset = 0;
910
911 if (bDirection) {
912 if (gtk_text_iter_forward_line (&iStart)==FALSE)
913 return 0;
914 gtk_text_iter_forward_line (&iEnd);
915 line++;
916 } else {
917 if (gtk_text_iter_backward_line (&iStart)==FALSE)
918 return gtk_text_buffer_get_char_count(pPage->buffer()) - 1;
919
920 gtk_text_iter_backward_line (&iEnd);
921 line--;
922 }
923 }
924
925 printf("Did not find %s\n",pattern);
926
927 return 0;
928 }
929 //------------------------------------------------------------------------
cb_notebook_switchpage(GtkNotebook *,gpointer,guint page_num,SourceWindow * pSW)930 void SourceWindow::cb_notebook_switchpage(GtkNotebook *,
931 gpointer, guint page_num, SourceWindow *pSW)
932 {
933 pSW->switch_page_cb(page_num);
934 }
935
switch_page_cb(guint newPage)936 gint SourceWindow::switch_page_cb(guint newPage)
937 {
938 Dprintf((" Switch page call back-- page=%d\n",newPage));
939 if (m_currentPage != newPage) {
940 m_currentPage = newPage;
941
942 NSourcePage *pPage = pages[m_currentPage];
943
944 if (!pPage || !gp->cpu->files[pPage->get_file_id()])
945 return TRUE;
946 if(gp->cpu->files[pPage->get_file_id()]->IsHLL())
947 pma->set_hll_mode(ProgramMemoryAccess::HLL_MODE);
948 else
949 pma->set_hll_mode(ProgramMemoryAccess::ASM_MODE);
950 pPage->invalidateView();
951
952 }
953 return TRUE;
954 }
955
956 //------------------------------------------------------------------------
findRegister(std::string text)957 static Register *findRegister(std::string text)
958 {
959
960 Register *pReg = dynamic_cast<Register *>(globalSymbolTable().find(text));
961 if (!pReg)
962 pReg = dynamic_cast<Register *>(globalSymbolTable().find(text + std::string("_")));
963 if (!pReg) {
964 (void) toupper(text);
965 pReg = dynamic_cast<Register *>(globalSymbolTable().find(text));
966 }
967 if (!pReg)
968 pReg = dynamic_cast<Register *>(globalSymbolTable().find(text + std::string("_")));
969 if (!pReg) {
970 transform(text.begin(), text.end(), text.begin(), ::tolower);
971 pReg = dynamic_cast<Register *>(globalSymbolTable().find(text));
972 }
973 return pReg;
974 }
975 //------------------------------------------------------------------------
976
977 void
PopupMenuHandler(GtkWidget * widget,gpointer data)978 SourceWindow::PopupMenuHandler(GtkWidget *widget, gpointer data)
979 {
980 SourceWindow *This = static_cast<SourceWindow *>(data);
981 unsigned int address;
982
983 SourceWindow *pSW = 0;
984 NSourcePage *pPage = 0;
985
986 // pViewContainingPopup is initialized when the view_button_press()
987 // event handler is called. That function also initiates the event
988 // that invokes this callback.
989
990 if (!pViewContainingPopup) {
991 printf("Warning popup without a textview\n");
992 } else {
993
994 pPage = This->pages[gtk_notebook_get_current_page(GTK_NOTEBOOK(This->m_Notebook))];
995 pSW = pPage ? pPage->getParent() : 0;
996 }
997
998 if (!pSW) {
999 printf ("Warning (bug?): popup cannot be associate with any source\n");
1000 return;
1001 }
1002
1003 switch (GPOINTER_TO_SIZE(g_object_get_data(G_OBJECT(widget), "item"))) {
1004
1005 case MENU_FIND_TEXT:
1006 pSW->findText();
1007 break;
1008 case MENU_FIND_PC:
1009 address=pSW->pma->get_PC();
1010 pSW->SetPC(address);
1011 break;
1012 case MENU_MOVE_PC:
1013 if(-1 != pSW->m_LineAtButtonClick) {
1014 address = pSW->pma->find_closest_address_to_line(
1015 pPage->get_file_id(), pSW->m_LineAtButtonClick + 1);
1016 if(address!=INVALID_VALUE) {
1017 pSW->pma->set_PC(address);
1018 pSW->SetPC(pSW->pma->get_PC());
1019 }
1020 }
1021 break;
1022
1023 case MENU_RUN_HERE:
1024 if(-1 != pSW->m_LineAtButtonClick) {
1025 address = pSW->pma->find_closest_address_to_line(
1026 pPage->get_file_id(), pSW->m_LineAtButtonClick + 1);
1027 if(address!=INVALID_VALUE) {
1028 pSW->gp->cpu->run_to_address(address);
1029 pSW->SetPC(pSW->pma->get_PC()); // RP - update GUI after running
1030 }
1031 }
1032 break;
1033
1034 case MENU_BP_HERE:
1035 if(-1 != pSW->m_LineAtButtonClick) {
1036 pSW->toggleBreak(pPage, pSW->m_LineAtButtonClick);
1037 }
1038 break;
1039 case MENU_PROFILE_START_HERE:
1040 if(-1 != pSW->m_LineAtButtonClick) {
1041 address = pSW->pma->find_closest_address_to_line(
1042 pPage->get_file_id(), pSW->m_LineAtButtonClick + 1);
1043
1044 pSW->gp->profile_window->StartExe(address);
1045 }
1046 break;
1047
1048 case MENU_PROFILE_STOP_HERE:
1049 if(-1 != pSW->m_LineAtButtonClick) {
1050 address = pSW->pma->find_closest_address_to_line(
1051 pPage->get_file_id(), pSW->m_LineAtButtonClick + 1);
1052
1053 pSW->gp->profile_window->StopExe(address);
1054 }
1055 break;
1056
1057 case MENU_SELECT_SYMBOL:
1058 case MENU_ADD_TO_WATCH:
1059 {
1060 GtkTextBuffer *pBuffer = pPage->buffer();
1061 GtkTextIter itBegin, itEnd;
1062 if (gtk_text_buffer_get_selection_bounds(pBuffer, &itBegin, &itEnd)) {
1063 gchar *text = gtk_text_buffer_get_text(pBuffer, &itBegin, &itEnd, FALSE);
1064
1065 TrimWhiteSpaceFromString(text);
1066
1067 if (text[0] != '\0') {
1068 Register *pReg = findRegister(std::string(text));
1069
1070 if(!pReg) {
1071 GtkWidget *dialog = gtk_message_dialog_new( GTK_WINDOW(pSW->window),
1072 GTK_DIALOG_MODAL,
1073 GTK_MESSAGE_WARNING,
1074 GTK_BUTTONS_OK,
1075 "The symbol '%s' does not exist as a register symbol.\n"
1076 "Only register based symbols may be added to the Watch window.",
1077 text);
1078 gtk_dialog_run (GTK_DIALOG (dialog));
1079 gtk_widget_destroy (dialog);
1080 } else {
1081 pSW->gp->watch_window->Add(pReg);
1082 }
1083
1084 }
1085 g_free(text);
1086 }
1087 }
1088 break;
1089 case MENU_STEP:
1090 pSW->step();
1091 break;
1092 case MENU_STEP_OVER:
1093 pSW->step_over();
1094 break;
1095 case MENU_RUN:
1096 pSW->run();
1097 break;
1098 case MENU_STOP:
1099 pSW->stop();
1100 break;
1101 case MENU_RESET:
1102 pSW->reset();
1103 break;
1104 case MENU_FINISH:
1105 pSW->finish();
1106 break;
1107 default:
1108 puts("Unhandled menuitem?");
1109 break;
1110 }
1111
1112 }
1113
1114
1115 //------------------------------------------------------------------------
1116 GtkWidget *
BuildPopupMenu()1117 SourceWindow::BuildPopupMenu()
1118 {
1119 GtkWidget *menu;
1120 GtkWidget *submenu;
1121 GtkWidget *item;
1122 unsigned int i;
1123
1124 menu = gtk_menu_new();
1125 for (i = 0; i < G_N_ELEMENTS(menu_items); ++i) {
1126 item = gtk_menu_item_new_with_label(menu_items[i].name);
1127 g_object_set_data(G_OBJECT(item), "item", GSIZE_TO_POINTER(menu_items[i].id));
1128 g_signal_connect(item, "activate",
1129 G_CALLBACK(PopupMenuHandler), this);
1130
1131 gtk_widget_show(item);
1132 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1133 }
1134
1135 submenu = gtk_menu_new();
1136
1137 for (i = 0; i < G_N_ELEMENTS(submenu_items); ++i) {
1138 item = gtk_menu_item_new_with_label(submenu_items[i].name);
1139 g_object_set_data(G_OBJECT(item), "item", GSIZE_TO_POINTER(submenu_items[i].id));
1140 g_signal_connect(item, "activate",
1141 G_CALLBACK (PopupMenuHandler), this);
1142
1143 gtk_widget_set_can_focus(item, TRUE);
1144
1145 gtk_widget_show(item);
1146 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
1147 }
1148 item = gtk_menu_item_new_with_label ("Controls");
1149 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1150 gtk_widget_show (item);
1151 gtk_menu_item_set_submenu(GTK_MENU_ITEM (item), submenu);
1152
1153 return menu;
1154 }
1155
1156 //------------------------------------------------------------------------
1157 // Build
1158 //
1159 //
Build()1160 void SourceWindow::Build()
1161 {
1162 Dprintf((" \n"));
1163
1164 if (bIsBuilt)
1165 return;
1166
1167 Dprintf((" \n"));
1168
1169 g_signal_connect(window,"key_press_event",
1170 G_CALLBACK (KeyPressHandler),
1171 (gpointer) this);
1172
1173 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
1174
1175 SetTitle();
1176
1177 GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
1178 gtk_widget_show(vbox);
1179 gtk_container_add (GTK_CONTAINER (window), vbox);
1180
1181 m_Notebook = gtk_notebook_new();
1182 m_currentPage = 0;
1183 g_signal_connect (m_Notebook, "switch-page",
1184 G_CALLBACK (cb_notebook_switchpage),
1185 (gpointer) this);
1186
1187 gtk_notebook_set_tab_pos((GtkNotebook*)m_Notebook, GTK_POS_LEFT);
1188 gtk_notebook_set_scrollable ((GtkNotebook*)m_Notebook, TRUE);
1189 gtk_box_pack_start (GTK_BOX (vbox), m_Notebook, TRUE, TRUE, 0);
1190
1191 status_bar = new StatusBar_Window(vbox);
1192
1193 gtk_widget_show_all(window);
1194 gtk_widget_show_all(vbox);
1195 gtk_widget_show_all(m_Notebook);
1196
1197
1198 aPopupMenu = BuildPopupMenu();
1199
1200 bIsBuilt = true;
1201
1202 menu = "/menu/Windows/Source";
1203 gtk_window_set_title (GTK_WINDOW (window), "Source Browser");
1204 UpdateMenuItem();
1205 if(m_bLoadSource) {
1206 Dprintf((" \n"));
1207
1208 NewSource(gp);
1209 }
1210
1211 }
1212
1213 //------------------------------------------------------------------------
1214 //
SetTitle()1215 void SourceWindow::SetTitle()
1216 {
1217
1218 if (!gp || !gp->cpu || !pma)
1219 return;
1220
1221
1222 if (last_simulation_mode != eSM_INITIAL &&
1223 ((last_simulation_mode == eSM_RUNNING &&
1224 gp->cpu->simulation_mode == eSM_RUNNING) ||
1225 (last_simulation_mode != eSM_RUNNING &&
1226 gp->cpu->simulation_mode != eSM_RUNNING)) &&
1227 sLastPmaName == pma->name()) {
1228 return;
1229 }
1230
1231 last_simulation_mode = gp->cpu->simulation_mode;
1232 const char * sStatus;
1233 if (gp->cpu->simulation_mode == eSM_RUNNING)
1234 sStatus = "Run";
1235 else // if (gp->cpu->simulation_mode == eSM_STOPPED)
1236 sStatus = "Stopped";
1237 char buffer[256];
1238 g_snprintf(buffer, sizeof(buffer), "Source Browser: [%s] %s", sStatus, pma != NULL ?
1239 pma->name().c_str() : "" );
1240 sLastPmaName = pma->name();
1241 gtk_window_set_title (GTK_WINDOW (window), buffer);
1242
1243 }
1244
1245
1246 //------------------------------------------------------------------------
1247 //
set_pma(ProgramMemoryAccess * new_pma)1248 void SourceWindow::set_pma(ProgramMemoryAccess *new_pma)
1249 {
1250 Dprintf((" \n"));
1251
1252 pma = new_pma;
1253
1254 if(window && pma) {
1255
1256 SetTitle();
1257 }
1258
1259 if(status_bar)
1260 status_bar->NewProcessor(gp, pma);
1261 }
1262
SelectAddress(int)1263 void SourceWindow::SelectAddress(int)
1264 {
1265 Dprintf((" \n"));
1266 }
1267
SelectAddress(Value *)1268 void SourceWindow::SelectAddress(Value *)
1269 {
1270 Dprintf((" \n"));
1271 }
1272
1273 //------------------------------------------------------------------------
1274 // Update
1275 //
1276 // Called whenever the source window needs to be updated (like after break points).
Update()1277 void SourceWindow::Update()
1278 {
1279 Dprintf((" \n"));
1280 if (!window || !enabled)
1281 return;
1282
1283
1284 if (m_Notebook &&
1285 ((gtk_notebook_get_show_tabs(GTK_NOTEBOOK(m_Notebook))==false
1286 && m_pParent->getTabPosition()<0) ||
1287 (m_pParent->getTabPosition() != gtk_notebook_get_tab_pos(GTK_NOTEBOOK(m_Notebook))))) {
1288
1289 if (m_pParent->getTabPosition()<0) {
1290 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_Notebook),FALSE);
1291 } else {
1292 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_Notebook),TRUE);
1293 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(m_Notebook), (GtkPositionType) m_pParent->getTabPosition());
1294 }
1295 }
1296
1297 if (m_Notebook) {
1298 gint currPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(m_Notebook));
1299
1300 if (currPage >= 0) {
1301 pages[currPage]->setFont(m_pParent->getFont());
1302 }
1303 }
1304
1305 if(!gp || !pma || ! window)
1306 return;
1307
1308 SetTitle();
1309 SetPC(pma->get_PC());
1310 if(status_bar)
1311 status_bar->Update();
1312
1313
1314 }
1315
1316 //------------------------------------------------------------------------
UpdateLine(int address)1317 void SourceWindow::UpdateLine(int address)
1318 {
1319 assert(address>=0);
1320
1321 Dprintf((" UpdateLine at address=%d\n",address));
1322
1323 if(!bSourceLoaded() || !pma || !enabled)
1324 return;
1325
1326 gint currPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(m_Notebook));
1327 if (currPage < 0)
1328 return;
1329
1330 NSourcePage *pPage = pages[currPage];
1331
1332 if (!pPage)
1333 return;
1334
1335 int line = (pPage->getFC()->IsList()) ?
1336 pma->getFromAddress(address)->get_lst_line() :
1337 pma->get_src_line(address);
1338
1339 //int line = pma->get_src_line(address) - 1;
1340
1341 line -= 1;
1342
1343 GtkTextIter iBegin;
1344 gtk_text_buffer_get_iter_at_line
1345 (gtk_text_view_get_buffer(pPage->getView()),
1346 &iBegin,
1347 line);
1348
1349 int y, h;
1350
1351 gtk_text_view_get_line_yrange (pPage->getView(),
1352 &iBegin,
1353 &y,
1354 &h);
1355 if (pPage->get_margin_width()) {
1356
1357 GdkRectangle vRect;
1358
1359 gtk_text_view_buffer_to_window_coords
1360 (pPage->getView(),
1361 GTK_TEXT_WINDOW_LEFT,
1362 0,
1363 y,
1364 NULL,
1365 &y);
1366
1367 vRect.x=0;
1368 vRect.y=y;
1369 vRect.width = pPage->get_margin_width();
1370 vRect.height=h;
1371
1372 Dprintf((" UpdateLine line=%d invalidating region %d,%d %d,%d\n",line,0,y,vRect.width,h));
1373 // Send an expose event to repaint the whole margin
1374 gdk_window_invalidate_rect
1375 (gtk_text_view_get_window (pPage->getView(), GTK_TEXT_WINDOW_LEFT), &vRect, TRUE);
1376 }
1377
1378 return;
1379 }
1380
1381 //------------------------------------------------------------------------
1382 //
getPCLine(int page)1383 int SourceWindow::getPCLine(int page)
1384 {
1385 if (mProgramCounter.bIsActive && mProgramCounter.page == page)
1386 return mProgramCounter.line;
1387
1388 NSourcePage *pPage = pages[page];
1389
1390 return (pPage->getFC()->IsList()) ?
1391 pma->getFromAddress(pma->get_PC())->get_lst_line() :
1392 pma->get_src_line(pma->get_PC());
1393 }
getAddress(NSourcePage * pPage,int line)1394 int SourceWindow::getAddress(NSourcePage *pPage, int line)
1395 {
1396 return pma->find_address_from_line(pPage->getFC(),line);
1397 }
bAddressHasBreak(int address)1398 bool SourceWindow::bAddressHasBreak(int address)
1399 {
1400 return address>=0 && pma->address_has_break(address);
1401 }
getOpcode(int address)1402 int SourceWindow::getOpcode(int address)
1403 {
1404 return (address >= 0) ? gp->cpu->pma->get_opcode(address) : address;
1405 }
1406 //------------------------------------------------------------------------
formatMargin(char * str,int len,int line,int addr,int opcode,bool bBreak)1407 bool SourcePageMargin::formatMargin(char *str, int len, int line, int addr, int opcode, bool bBreak)
1408 {
1409 if (str) {
1410
1411 int pos = 0;
1412 int npos = 0;
1413
1414 *str=0;
1415
1416 npos = bBreak ? g_snprintf(&str[pos], len, "<span foreground=\"red\"><b>") : 0;
1417 pos += npos;
1418 len -= npos;
1419
1420 npos = m_bShowLineNumbers ? g_snprintf(&str[pos], len, "%d",line) : 0;
1421 pos += npos;
1422 len -= npos;
1423
1424 npos = (m_bShowAddresses && addr >= 0) ? g_snprintf(&str[pos], len, " %04X",addr) : 0;
1425 pos += npos;
1426 len -= npos;
1427
1428
1429 npos = (m_bShowOpcodes && opcode >= 0) ?
1430 g_snprintf(&str[pos], len, "%c%04X ", m_bShowAddresses?':':' ', opcode)
1431 : 0;
1432 pos += npos;
1433 len -= npos;
1434
1435 pos += bBreak ? g_snprintf(&str[pos], len, "</b></span>") : 0;
1436
1437 return pos != 0;
1438 }
1439
1440 return false;
1441 }
1442
1443 //========================================================================
NSourcePage(SourceWindow * pParent,SourceBuffer * pBuffer,int file_id,GtkWidget * pContainer)1444 NSourcePage::NSourcePage(SourceWindow *pParent, SourceBuffer *pBuffer,
1445 int file_id, GtkWidget *pContainer)
1446
1447 : m_pBuffer(pBuffer), m_Parent(pParent), m_fileid(file_id), m_marginWidth(0)
1448 {
1449 if (!m_pBuffer || !pContainer || !m_Parent)
1450 return;
1451
1452 m_pBuffer->parse();
1453
1454 m_view = (GtkTextView *)gtk_text_view_new_with_buffer(m_pBuffer->getBuffer());
1455 Dprintf(("NSourcePage::setSource() - view=%p\n",m_view));
1456 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (m_view),
1457 GTK_TEXT_WINDOW_LEFT,
1458 MARGIN_WIDTH);
1459
1460 g_signal_connect(GTK_OBJECT(m_view), "key_press_event",
1461 G_CALLBACK(KeyPressHandler), this);
1462
1463 g_signal_connect(GTK_OBJECT(m_view), "button_press_event",
1464 G_CALLBACK(ButtonPressHandler), this);
1465
1466 g_signal_connect(GTK_OBJECT(m_view), "expose_event",
1467 G_CALLBACK(ViewExposeEventHandler), this);
1468
1469 GtkWidget *pSW = gtk_scrolled_window_new (0,0);
1470 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pSW),
1471 GTK_POLICY_AUTOMATIC,
1472 GTK_POLICY_AUTOMATIC);
1473
1474 gtk_container_add (GTK_CONTAINER (pContainer), pSW);
1475 gtk_container_add (GTK_CONTAINER (pSW), GTK_WIDGET(m_view));
1476
1477 gtk_text_view_set_wrap_mode (m_view, GTK_WRAP_NONE);
1478 gtk_text_view_set_editable (m_view, FALSE);
1479
1480 setFont(m_Parent->getFont());
1481
1482 gtk_widget_show_all(pContainer);
1483 }
1484
invalidateView()1485 void NSourcePage::invalidateView()
1486 {
1487 if (m_view) {
1488 GdkRectangle vRect;
1489
1490 vRect.x=0;
1491 vRect.y=0;
1492 vRect.width=100;
1493 vRect.height=100;
1494 gdk_window_invalidate_rect
1495 (gtk_text_view_get_window (m_view,
1496 GTK_TEXT_WINDOW_LEFT),
1497 &vRect,
1498 TRUE);
1499 }
1500
1501 }
1502
getParent()1503 SourceWindow *NSourcePage::getParent()
1504 {
1505 return m_Parent;
1506 }
1507
buffer()1508 GtkTextBuffer *NSourcePage::buffer()
1509 {
1510 return m_pBuffer ? m_pBuffer->getBuffer() : 0;
1511 }
1512
getFC()1513 FileContext * NSourcePage::getFC()
1514 {
1515 return m_pBuffer ? m_pBuffer->m_pFC : 0;
1516 }
1517
1518 //------------------------------------------------------------------------
getView()1519 GtkTextView *NSourcePage::getView()
1520 {
1521 return m_view;
1522 }
1523
1524 //------------------------------------------------------------------------
updateMargin(int y1,int y2)1525 void NSourcePage::updateMargin(int y1, int y2)
1526 {
1527 Dprintf((" updateMargin y1=%d y2=%d\n",y1,y2));
1528
1529 GtkTextView * text_view = m_view;
1530 std::vector<gint> numbers;
1531 std::vector<gint> pixels;
1532
1533 int PCline = m_Parent->getPCLine(m_fileid);
1534
1535 GdkWindow *win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT);
1536
1537 /* get the line numbers and y coordinates. */
1538 gtk_source_view_get_lines (text_view,
1539 y1,
1540 y2,
1541 pixels,
1542 numbers);
1543
1544 /* set size. */
1545 gchar str [256];
1546 PangoLayout *layout=0;
1547 gint text_width=0;
1548 FileContext *pFC = getFC();
1549 gint addr_opcode = (pFC && !pFC->IsList()) ? 0x9999 : -1;
1550 if ( m_Parent->margin().formatMargin(str, sizeof(str),
1551 MAX (99, gtk_text_buffer_get_line_count (gtk_text_view_get_buffer(text_view))),
1552 addr_opcode, addr_opcode,false) ) {
1553
1554 layout = gtk_widget_create_pango_layout (GTK_WIDGET (text_view), str);
1555
1556 pango_layout_get_pixel_size (layout, &text_width, NULL);
1557 text_width+=2;
1558 }
1559
1560 m_marginWidth = text_width + MARGIN_WIDTH;
1561 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view),
1562 GTK_TEXT_WINDOW_LEFT,
1563 m_marginWidth);
1564
1565 for (size_t i = 0; i < numbers.size(); ++i) {
1566
1567 gint pos;
1568 gint line = numbers[i] + 1;
1569
1570 gtk_text_view_buffer_to_window_coords (text_view,
1571 GTK_TEXT_WINDOW_LEFT,
1572 0,
1573 pixels[i],
1574 NULL,
1575 &pos);
1576
1577 int address = pFC && !pFC->IsList() ? m_Parent->getAddress(this,line) : - 1;
1578 int opcode = pFC && !pFC->IsList() && !pFC->IsHLL() ? m_Parent->getOpcode(address) : -1;
1579 bool bHasBreak = m_Parent->bAddressHasBreak(m_Parent->getAddress(this,line));
1580
1581
1582 if (layout) {
1583
1584 if ( m_Parent->margin().formatMargin(str, sizeof(str),
1585 line, address,opcode,bHasBreak)) {
1586
1587 pango_layout_set_markup (layout, str, -1);
1588
1589 gtk_paint_layout(gtk_widget_get_style(GTK_WIDGET(text_view)),
1590 win,
1591 GTK_STATE_NORMAL,
1592 FALSE,
1593 NULL,
1594 GTK_WIDGET (text_view),
1595 NULL,
1596 2, //text_width + 2,
1597 pos,
1598 layout);
1599
1600 }
1601
1602 }
1603
1604
1605 if (line == PCline) {
1606 gtk_paint_arrow(
1607 gtk_widget_get_style(GTK_WIDGET(text_view)),
1608 win,
1609 GTK_STATE_NORMAL,
1610 GTK_SHADOW_OUT, // GtkShadowType shadow_type,
1611 NULL,
1612 GTK_WIDGET (text_view),
1613 NULL,
1614 GTK_ARROW_RIGHT, //GtkArrowType arrow_type,
1615 TRUE, //gboolean fill,
1616 text_width+PC_START,pos, PC_PIXEL_SIZE,15);
1617 Dprintf((" updating PC at line %d\n", line));
1618 }
1619
1620 if (m_Parent->getAddress(this,line) >= 0) {
1621 // There is code associated with this line.
1622
1623 gtk_paint_diamond(
1624 gtk_widget_get_style(GTK_WIDGET(text_view)),
1625 win,
1626 GTK_STATE_NORMAL,
1627 bHasBreak ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
1628 NULL,
1629 GTK_WIDGET (text_view),
1630 NULL,
1631 text_width+BP_START,
1632 pos,
1633 BP_PIXEL_SIZE,
1634 BP_PIXEL_SIZE);
1635 }
1636 }
1637
1638 if (layout)
1639 g_object_unref(layout);
1640 }
1641
1642 //------------------------------------------------------------------------
setFont(const char * cp_newFont)1643 void NSourcePage::setFont(const char *cp_newFont)
1644 {
1645 if (m_view && cp_newFont) {
1646
1647 if (m_cpFont == cp_newFont)
1648 return;
1649
1650 m_cpFont = cp_newFont;
1651
1652 /* Change default font throughout the widget */
1653 PangoFontDescription *font_desc;
1654 font_desc = pango_font_description_from_string (m_cpFont.c_str());
1655 gtk_widget_modify_font (GTK_WIDGET (m_view), font_desc);
1656 pango_font_description_free (font_desc);
1657
1658 }
1659 }
1660 //------------------------------------------------------------------------
1661 // SetPC
1662 //
1663 // Highlight the line corresponding to the current program counter.
1664 //
1665
SetPC(int address)1666 void SourceWindow::SetPC(int address)
1667 {
1668 Dprintf((" \n"));
1669
1670 if (!bSourceLoaded() || !pma)
1671 return;
1672
1673 int currPage = m_Notebook ?
1674 gtk_notebook_get_current_page (GTK_NOTEBOOK(m_Notebook)) :
1675 -1;
1676
1677 // Get the file id associated with the program counter address
1678 unsigned int sbawFileId = pma->get_file_id(address);
1679 if(sbawFileId == 0xffffffff)
1680 return;
1681
1682 int id = -1;
1683 int PCline=-1;
1684
1685 if (currPage>=0 && pages[currPage]->getFC()->IsList()) {
1686 // Don't automatically switch away from a page if it is a list file
1687 id = currPage;
1688 PCline = pma->getFromAddress(address)->get_lst_line();
1689 } else {
1690 std::map<int, NSourcePage *>::iterator i = pages.begin();
1691 for ( ; i != pages.end(); ++i) {
1692 if (i->second->get_file_id() == sbawFileId) {
1693 id = i->first;
1694 break;
1695 }
1696 }
1697
1698 if (id < 0)
1699 return; // page was not found.
1700
1701 // Switch to the source browser page that contains the program counter.
1702 if (currPage != id)
1703 gtk_notebook_set_current_page(GTK_NOTEBOOK(m_Notebook), id);
1704
1705 // Get the source line number associated with the program counter address.
1706 PCline = pma->get_src_line(address);
1707 if(PCline==(int)INVALID_VALUE)
1708 return;
1709 //PCline--;
1710 }
1711
1712 bool bFirstUpdate=true;
1713 if (mProgramCounter.bIsActive) {
1714 bFirstUpdate=false;
1715 } else {
1716 while (gtk_events_pending())
1717 gtk_main_iteration();
1718 }
1719
1720 mProgramCounter.page = id;
1721 mProgramCounter.line = PCline;
1722
1723 // Get a pointer to text_view margin window.
1724 GdkWindow *win = gtk_text_view_get_window (pages[id]->getView(), GTK_TEXT_WINDOW_LEFT);
1725 GdkRectangle PCloc;
1726
1727 mProgramCounter.bIsActive = true;
1728 mProgramCounter.pBuffer = pages[id]->buffer();
1729 gtk_text_buffer_get_iter_at_line(mProgramCounter.pBuffer,
1730 &mProgramCounter.iBegin,
1731 PCline);
1732
1733 // Now we're going to check if the program counter is in view or not.
1734
1735 // Get the program counter location
1736 gtk_text_view_get_iter_location (pages[id]->getView(),
1737 &mProgramCounter.iBegin,
1738 &PCloc);
1739 // Get the viewable region of the text buffer. The region is in buffer coordinates.
1740 GdkRectangle vRect;
1741 gtk_text_view_get_visible_rect (pages[id]->getView(),
1742 &vRect);
1743
1744 // Now normalize the program counter's location. If yloc is between
1745 // 0 and 1.0 then the program counter is viewable. If not, then we
1746 // we need to scroll the text view so that the program counter is
1747 // viewable.
1748 double yloc = (PCloc.y - vRect.y) / (double) (vRect.height);
1749
1750 if ( yloc < 0.05 || yloc > 0.95 || bFirstUpdate) {
1751 gtk_text_view_scroll_to_iter (pages[id]->getView(),
1752 &mProgramCounter.iBegin,
1753 0.0,
1754 TRUE,
1755 0.0, 0.3);
1756 gtk_text_view_get_visible_rect (pages[id]->getView(),
1757 &vRect);
1758
1759 }
1760
1761 // If there is a margin, then invalidate it so gtk will go off and redraw it.
1762 if (pages[id]->get_margin_width()) {
1763 vRect.x=0;
1764 vRect.y=0;
1765 vRect.width = pages[id]->get_margin_width();
1766 // Send an expose event to repaint the whole margin
1767 gdk_window_invalidate_rect
1768 (win, &vRect, TRUE);
1769 }
1770 }
1771
CloseSource()1772 void SourceWindow::CloseSource()
1773 {
1774 Dprintf((" \n"));
1775 }
1776
margin()1777 SourcePageMargin &SourceWindow::margin()
1778 {
1779 return m_pParent->margin();
1780 }
getFont()1781 const char *SourceWindow::getFont()
1782 {
1783 return m_pParent->getFont();
1784 }
1785
NewSource(GUI_Processor * gp)1786 void SourceWindow::NewSource(GUI_Processor *gp)
1787 {
1788 Dprintf((" \n"));
1789
1790 unsigned int address;
1791
1792 if(!gp || !gp->cpu || !gp->cpu->pma)
1793 return;
1794 Dprintf((" \n"));
1795
1796 Processor * pProc = gp->cpu;
1797 if(!enabled)
1798 {
1799 m_bLoadSource=true;
1800 return;
1801 }
1802 Dprintf((" \n"));
1803
1804 if(!pma)
1805 pma = pProc->pma;
1806
1807 CloseSource();
1808
1809 m_bLoadSource=true;
1810
1811 Dprintf(("NewSource\n"));
1812
1813 /* Now create a cross-reference link that the
1814 * simulator can use to send information back to the gui
1815 */
1816 if(pProc->pc) {
1817 SourceXREF *cross_reference = new SourceXREF();
1818 cross_reference->parent_window = (gpointer) this;
1819 cross_reference->data = 0;
1820
1821 pProc->pc->add_xref((gpointer) cross_reference);
1822 if(pProc->pc != pma->GetProgramCounter()) {
1823 pma->GetProgramCounter()->add_xref((gpointer) cross_reference);
1824 }
1825 }
1826
1827
1828 std::vector<SourceBuffer *>::iterator i = m_pParent->ppSourceBuffers.begin();
1829 std::vector<SourceBuffer *>::iterator iend = m_pParent->ppSourceBuffers.end();
1830
1831 for ( ; i != iend; ++i) {
1832 AddPage(*i);
1833 }
1834
1835 m_bSourceLoaded = 1;
1836
1837
1838 // update breakpoint widgets
1839 unsigned uPMMaxIndex = pProc->program_memory_size();
1840 for(unsigned int uPMIndex=0; uPMIndex < uPMMaxIndex; uPMIndex++) {
1841 int address = pProc->map_pm_index2address(uPMIndex);
1842 if(pma->address_has_break(address))
1843 UpdateLine(address);
1844 }
1845
1846 address=pProc->pma->get_PC();
1847 if(address==INVALID_VALUE)
1848 puts("Warning, PC is invalid?");
1849 else
1850 SetPC(address);
1851
1852 Dprintf((" Source is loaded\n"));
1853
1854 }
1855
1856
1857
1858 //------------------------------------------------------------------------
1859 // AddPage
1860 // Adds a page to the notebook, and returns notebook-id for that page.
1861 //
AddPage(SourceBuffer * pSourceBuffer)1862 int SourceWindow::AddPage(SourceBuffer *pSourceBuffer)
1863 {
1864 if (pSourceBuffer && pSourceBuffer->m_pFC)
1865 return AddPage(pSourceBuffer, pSourceBuffer->m_pFC->name());
1866 return -1;
1867 }
1868
AddPage(SourceBuffer * pSourceBuffer,const std::string & fName)1869 int SourceWindow::AddPage(SourceBuffer *pSourceBuffer, const std::string &fName)
1870 {
1871 if (!bIsBuilt || !pSourceBuffer)
1872 return -1;
1873
1874 GtkWidget *label;
1875
1876 std::string::size_type pos = fName.find_last_of("/\\");
1877 if (pos != std::string::npos)
1878 label = gtk_label_new(fName.substr(pos + 1).c_str());
1879 else
1880 label = gtk_label_new(fName.c_str());
1881
1882 GtkWidget *pFrame = gtk_frame_new(NULL);
1883
1884 int id = gtk_notebook_append_page(GTK_NOTEBOOK(m_Notebook),pFrame,label);
1885
1886 pages[id] = new NSourcePage(this, pSourceBuffer, id, pFrame);
1887
1888 gtk_widget_show_all(pFrame);
1889
1890 return id;
1891 }
1892
1893 /*********************** gui message dialog *************************/
1894
gui_message(const char * message)1895 void gui_message(const char *message)
1896 {
1897 GtkWidget *dialog = gtk_dialog_new_with_buttons(
1898 "", NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1899 "_OK", GTK_RESPONSE_OK,
1900 NULL
1901 );
1902
1903 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1904 GtkWidget *label = gtk_label_new(message);
1905 gtk_container_add(GTK_CONTAINER(content_area), label);
1906
1907 gtk_widget_show_all(dialog);
1908 gtk_dialog_run(GTK_DIALOG(dialog));
1909 gtk_widget_destroy(dialog);
1910 }
1911
1912 // gui question dialog
1913 // modal dialog, asking a yes/no question
gui_question(const char * question,const char * a,const char * b)1914 int gui_question(const char *question, const char *a, const char *b)
1915 {
1916 GtkWidget *dialog = gtk_dialog_new_with_buttons(
1917 "", NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1918 a, TRUE,
1919 b, FALSE,
1920 NULL
1921 );
1922
1923 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1924 GtkWidget *label = gtk_label_new(question);
1925 gtk_container_add(GTK_CONTAINER(content_area), label);
1926
1927 gtk_widget_show_all(dialog);
1928 int retval = gtk_dialog_run(GTK_DIALOG(dialog));
1929
1930 gtk_widget_destroy(dialog);
1931
1932 return retval;
1933 }
1934
set_pma(ProgramMemoryAccess * new_pma)1935 void SourceBrowser_Window::set_pma(ProgramMemoryAccess *new_pma)
1936 {
1937 pma = new_pma;
1938
1939 if(window && pma) {
1940
1941 SetTitle();
1942 }
1943 }
1944
1945 //========================================================================
1946 //
1947 // SourceBrowserParent_Window
1948 //
1949 // Here is some experimental code that allows multiple source browser
1950 // windows.
1951
SourceBrowserParent_Window(GUI_Processor * _gp)1952 SourceBrowserParent_Window::SourceBrowserParent_Window(GUI_Processor *_gp)
1953 : GUI_Object("source_browser_parent")
1954 {
1955
1956 gp = _gp;
1957
1958 pma = 0;
1959 m_TabType = GTK_POS_BOTTOM;
1960 mpTagTable = gtk_text_tag_table_new();
1961
1962 const char *sName = "source_config";
1963 char *fg=0;
1964 GdkColor color;
1965 GtkTextTag *tag;
1966
1967 tag = gtk_text_tag_new("Label");
1968 gdk_color_parse(config_get_string(sName, "label_fg", &fg)
1969 ? fg : "orange" , &color);
1970 g_object_set(tag, "foreground-gdk", &color, NULL);
1971 gtk_text_tag_table_add(mpTagTable, tag);
1972
1973 tag = gtk_text_tag_new("Mnemonic");
1974 gdk_color_parse(config_get_string(sName, "mnemonic_fg", &fg)
1975 ? fg : "red" , &color);
1976 g_object_set(tag, "foreground-gdk", &color, NULL);
1977 gtk_text_tag_table_add(mpTagTable, tag);
1978
1979 tag = gtk_text_tag_new("Symbols");
1980 gdk_color_parse(config_get_string(sName, "symbol_fg", &fg)
1981 ? fg : "dark green" , &color);
1982 g_object_set(tag, "foreground-gdk", &color, NULL);
1983 gtk_text_tag_table_add(mpTagTable, tag);
1984
1985 tag = gtk_text_tag_new("Comments");
1986 gdk_color_parse(config_get_string(sName, "comment_fg", &fg)
1987 ? fg : "dim gray" , &color);
1988 g_object_set(tag, "foreground-gdk", &color, NULL);
1989 gtk_text_tag_table_add(mpTagTable, tag);
1990
1991 tag = gtk_text_tag_new("Constants");
1992 gdk_color_parse(config_get_string(sName, "constant_fg", &fg)
1993 ? fg : "blue" , &color);
1994 g_object_set(tag, "foreground-gdk", &color, NULL);
1995 gtk_text_tag_table_add(mpTagTable, tag);
1996
1997 if (!config_get_variable(sName, "tab_position", &m_TabType))
1998 m_TabType = GTK_POS_LEFT;
1999 int b=1;
2000 config_get_variable(sName, "line_numbers", &b);
2001 margin().enableLineNumbers(b!=0);
2002
2003 config_get_variable(sName, "addresses", &b);
2004 margin().enableAddresses(b!=0);
2005
2006 config_get_variable(sName, "opcodes", &b);
2007 margin().enableOpcodes(b!=0);
2008
2009 if (config_get_string(sName, "font", &fg))
2010 setFont(fg);
2011 else
2012 setFont("Serif 8");
2013
2014 children.push_back(new SourceWindow(_gp, this, true));
2015 }
2016
Build()2017 void SourceBrowserParent_Window::Build()
2018 {
2019 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2020
2021 for ( ; sbaw_iterator != children.end();++sbaw_iterator)
2022 (*sbaw_iterator)->Build();
2023
2024 UpdateMenuItem();
2025 }
2026
NewProcessor(GUI_Processor * gp)2027 void SourceBrowserParent_Window::NewProcessor(GUI_Processor *gp)
2028 {
2029 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2030 std::list <ProgramMemoryAccess *>::iterator pma_iterator
2031 = gp->cpu->pma_context.begin();
2032
2033 CreateSourceBuffers(gp);
2034
2035 int child = 1;
2036 SourceWindow *sbaw=0;
2037 while( (sbaw_iterator != children.end()) ||
2038 (pma_iterator != gp->cpu->pma_context.end()))
2039 {
2040 if(sbaw_iterator == children.end())
2041 {
2042 char child_name[64];
2043 child++;
2044 g_snprintf(child_name, sizeof(child_name), "source_browser%d", child);
2045 sbaw = new SourceWindow(gp,this, true, child_name);
2046 children.push_back(sbaw);
2047 }
2048 else
2049 sbaw = *sbaw_iterator++;
2050
2051 if(pma_iterator != gp->cpu->pma_context.end())
2052 {
2053 sbaw->set_pma(*pma_iterator);
2054 ++pma_iterator;
2055 }
2056 else
2057 {
2058 sbaw->set_pma(gp->cpu->pma);
2059 }
2060
2061 }
2062 }
2063
SelectAddress(int address)2064 void SourceBrowserParent_Window::SelectAddress(int address)
2065 {
2066 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2067
2068 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2069 (*sbaw_iterator)->SelectAddress(address);
2070 }
2071
SelectAddress(Value * addrSym)2072 void SourceBrowserParent_Window::SelectAddress(Value *addrSym)
2073 {
2074 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2075
2076 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2077 (*sbaw_iterator)->SelectAddress(addrSym);
2078 }
2079
Update()2080 void SourceBrowserParent_Window::Update()
2081 {
2082 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2083
2084 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2085 (*sbaw_iterator)->Update();
2086 }
2087
UpdateLine(int address)2088 void SourceBrowserParent_Window::UpdateLine(int address)
2089 {
2090 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2091
2092 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2093 (*sbaw_iterator)->UpdateLine(address);
2094 }
2095
SetPC(int address)2096 void SourceBrowserParent_Window::SetPC(int address)
2097 {
2098 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2099
2100 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2101 (*sbaw_iterator)->SetPC(address);
2102 }
2103
CloseSource()2104 void SourceBrowserParent_Window::CloseSource()
2105 {
2106 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2107
2108 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2109 (*sbaw_iterator)->CloseSource();
2110 }
2111
NewSource(GUI_Processor * gp)2112 void SourceBrowserParent_Window::NewSource(GUI_Processor *gp)
2113 {
2114 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2115
2116 CreateSourceBuffers(gp);
2117 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2118 (*sbaw_iterator)->NewSource(gp);
2119 }
2120
ChangeView(int view_state)2121 void SourceBrowserParent_Window::ChangeView(int view_state)
2122 {
2123 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2124
2125 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2126 (*sbaw_iterator)->ChangeView(view_state);
2127 }
2128
get_color_string(const char * tag_name)2129 gchar *SourceBrowserParent_Window::get_color_string(const char *tag_name)
2130 {
2131 GdkColor *gdk_color;
2132 g_object_get(gtk_text_tag_table_lookup(mpTagTable, tag_name),
2133 "foreground-gdk", &gdk_color, NULL);
2134 gchar *color_string = gdk_color_to_string(gdk_color);
2135 gdk_color_free(gdk_color);
2136 return color_string;
2137 }
2138
set_config()2139 int SourceBrowserParent_Window::set_config()
2140 {
2141 std::vector<SourceWindow *>::iterator sbaw_iterator = children.begin();
2142
2143 for ( ; sbaw_iterator != children.end(); ++sbaw_iterator)
2144 (*sbaw_iterator)->set_config();
2145
2146 const char *sName = "source_config";
2147 char *buff;
2148
2149 buff = get_color_string("Mnemonic");
2150 config_set_string(sName,"mnemonic_fg", buff);
2151 g_free(buff);
2152 buff = get_color_string("Label");
2153 config_set_string(sName,"label_fg", buff);
2154 g_free(buff);
2155 buff = get_color_string("Symbols");
2156 config_set_string(sName,"symbol_fg", buff);
2157 g_free(buff);
2158 buff = get_color_string("Comments");
2159 config_set_string(sName,"comment_fg", buff);
2160 g_free(buff);
2161 buff = get_color_string("Constants");
2162 config_set_string(sName,"constant_fg", buff);
2163 g_free(buff);
2164
2165 config_set_string(sName,"font", getFont());
2166
2167 config_set_variable(sName, "tab_position", getTabPosition());
2168 config_set_variable(sName, "line_numbers", margin().bLineNumbers());
2169 config_set_variable(sName, "addresses", margin().bAddresses());
2170 config_set_variable(sName, "opcodes", margin().bOpcodes());
2171
2172
2173 return 0;
2174 }
2175
2176 //------------------------------------------------------------------------
2177 // parseLine
2178 //
2179 // Added a line of text to the source buffer. Apply syntax highlighting.
2180 //
2181
parseLine(const char * cP,int parseStyle)2182 void SourceBuffer::parseLine(const char *cP,
2183 int parseStyle)
2184 {
2185
2186 GtkTextIter iEnd;
2187 GtkTextBuffer *pTextBuffer = m_buffer;
2188 gtk_text_buffer_get_end_iter (pTextBuffer, &iEnd);
2189
2190 int offset = gtk_text_iter_get_offset (&iEnd);
2191
2192 gtk_text_buffer_insert (pTextBuffer, &iEnd, cP, -1);
2193
2194 if (parseStyle<0) {
2195 addTagRange("Comments", offset, offset + strlen(cP));
2196 return;
2197 }
2198
2199 int i=0;
2200 int j=0;
2201 bool bHaveMnemonic = false;
2202
2203 if (i != (j = isString(cP))) {
2204 addTagRange("Label", i + offset, j + offset);
2205 i=j;
2206 }
2207
2208 while (!isEnd(cP[i])) {
2209
2210 if ( (j=isWhiteSpace(&cP[i])) != 0) {
2211 i += j;
2212 } else if ( (j=isString(&cP[i])) != 0) {
2213 if (bHaveMnemonic)
2214 addTagRange("Symbols", i + offset, i + j + offset);
2215 else
2216 addTagRange("Mnemonic", i + offset, i + j + offset);
2217 bHaveMnemonic = true;
2218 i += j;
2219 } else if ( (j=isNumber(&cP[i])) != 0) {
2220 addTagRange("Constants", i + offset, i + j + offset);
2221 i += j;
2222 } else if ( (j=isComment(&cP[i])) != 0) {
2223 addTagRange("Comments", i + offset, i + j + offset);
2224 i += j;
2225 return;
2226 } else
2227 i++;
2228 }
2229 }
2230
2231 //------------------------------------------------------------------------
margin()2232 SourcePageMargin &SourceBrowserParent_Window::margin()
2233 {
2234 return m_margin;
2235 }
2236
2237 //------------------------------------------------------------------------
setTabPosition(int tt)2238 void SourceBrowserParent_Window::setTabPosition(int tt)
2239 {
2240 m_TabType = tt;
2241 Update();
2242 }
2243
2244 //------------------------------------------------------------------------
setFont(const char * cpNewFont)2245 void SourceBrowserParent_Window::setFont(const char *cpNewFont)
2246 {
2247 if (cpNewFont) {
2248 m_FontDescription = cpNewFont;
2249 Update();
2250 }
2251 }
getFont()2252 const char *SourceBrowserParent_Window::getFont()
2253 {
2254 return m_FontDescription.c_str();
2255 }
2256
2257 //------------------------------------------------------------------------
2258 // parseSource
parseSource(SourceBuffer * pBuffer,FileContext * pFC)2259 void SourceBrowserParent_Window::parseSource(SourceBuffer *pBuffer,FileContext *pFC)
2260 {
2261 pFC->rewind();
2262
2263 char text_buffer[256];
2264 int line = 1;
2265
2266 while(pFC->gets(text_buffer, sizeof(text_buffer))) {
2267
2268 int address;
2269 // The syntax highlighting doesn't work on list files or hll files
2270 address = pFC->IsList()||pFC->IsHLL() ? -1 : 1;//gp->cpu->pma->find_address_from_line(pFC,line);
2271
2272 // check if text_buffer in uft8 character set
2273 if (!g_utf8_validate(text_buffer, -1, NULL))
2274 {
2275 gsize bytes_read, bytes_written;
2276 gchar *new_buffer;
2277
2278 // try to convert to uft8 using current locale
2279 // if we succeed, do normal processing on converted text
2280 if ((new_buffer = g_locale_to_utf8((const gchar *)text_buffer,
2281 -1, &bytes_read, &bytes_written, NULL)))
2282 {
2283 pBuffer->parseLine(new_buffer,address);
2284 g_free(new_buffer);
2285 }
2286 // Conversion based on locale did not work
2287 else
2288 {
2289 // replace comment which may have unknown character set
2290 if((new_buffer = strchr(text_buffer, ';')))
2291 {
2292 *new_buffer = 0;
2293 strcat(text_buffer, "; comment stripped, characters from unknown locale\n");
2294 }
2295 // if still not OK replace entire line so line numbering still OK
2296 if (!g_utf8_validate(text_buffer, -1, NULL))
2297 {
2298 strcpy(text_buffer, "; non-comment characters from unknow locale\n");
2299 }
2300 pBuffer->parseLine(text_buffer,address);
2301 }
2302 }
2303 else
2304 pBuffer->parseLine(text_buffer,address);
2305
2306 line++;
2307 }
2308
2309 }
2310
2311 //------------------------------------------------------------------------
CreateSourceBuffers(GUI_Processor * gp)2312 void SourceBrowserParent_Window::CreateSourceBuffers(GUI_Processor *gp)
2313 {
2314 Dprintf((" \n"));
2315
2316 if(!gp || !gp->cpu || !gp->cpu->pma)
2317 return;
2318 Dprintf((" \n"));
2319
2320 Processor * pProc = gp->cpu;
2321 if(!pma)
2322 pma = pProc->pma;
2323
2324 CloseSource();
2325
2326 Dprintf(("NewSource\n"));
2327
2328 if(pProc->files.nsrc_files() != 0) {
2329
2330 for(int i = 0; i<pProc->files.nsrc_files(); i++) {
2331 FileContext *fc = pProc->files[i];
2332
2333 int pos = fc->name().size() - 4;
2334 if (pos > 0 && fc->name().compare(pos, 4, ".cod")
2335 && fc->name().compare(pos, 4, ".COD")) {
2336
2337 ppSourceBuffers.push_back(new SourceBuffer(mpTagTable, fc, this));
2338
2339 } else {
2340 if(verbose)
2341 printf ("SourceBrowserAsm_new_source: skipping file: <%s>\n",
2342 fc->name().c_str());
2343 }
2344 }
2345
2346 }
2347
2348
2349 Dprintf((" Source is loaded\n"));
2350
2351 }
2352
2353
2354 #endif // HAVE_GUI
2355