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