home *** CD-ROM | disk | FTP | other *** search
- /* SPIM S20 MIPS simulator.
- Copyright (C) 1990 by James Larus (larus@cs.wisc.edu).
-
- Macintosh Version by Philip Delaquess (delaques@gcg.com)
- Copyright (C) 1993 by Saunders College Publishing and Morgan Kaufman Publishers.
-
- SPIM is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 1, or (at your option) any
- later version.
-
- SPIM is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to James R.
- Larus, Computer Sciences Department, University of Wisconsin--Madison,
- 1210 West Dayton Street, Madison, WI 53706, USA or to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- This file copes with the scrolling text windows.
- */
-
- #include <stdio.h>
-
- #include "mactext.h"
- #include "spim.h"
- #include "inst.h"
- #include "mem.h"
- #include "reg.h"
-
- #define MONACO 4
- #define COURIER 22
-
- #define FONT MONACO
- #define SIZE 9
-
- #define SESSION_LINES 100
- #define CONSOLE_LINES 100
-
- SPIMTextWindow Registers, Text, Data, Console, Session, Help;
-
- /* FormatRegisters
- *
- * formats the register contents into the register window.
- */
-
- void FormatRegisters()
- {
- Rect box;
- int i;
- char buffer[256], *buffP;
- char *grstr, *fpstr, *fgstr;
- char *grfill, *fpfill, *fgfill;
- static char *reg_names[] = {"r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"};
-
- grstr = "R%-2d (%2s): %08x ";
- fpstr = "FP%-2d: %-10.4f ";
- fgstr = "FG%-2d: %-10.4f ";
-
- TESetSelect(0, 32767, Registers.text);
- TEDelete(Registers.text);
- buffP = buffer;
- sprintf(buffP, "PC: %08X ", PC); buffP += strlen(buffP);
- sprintf(buffP, "EPC: %08X ", EPC); buffP += strlen(buffP);
- sprintf(buffP, "Cause: %08X ", Cause); buffP += strlen(buffP);
- sprintf(buffP, "BadVAddr: %08X\r", BadVAddr); buffP += strlen(buffP);
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, buffP - buffer, Registers.text);
- buffP = buffer;
- sprintf(buffP, "Status: %08X ", Status_Reg); buffP += strlen(buffP);
- sprintf(buffP, "HI: %08X ", HI); buffP += strlen(buffP);
- sprintf(buffP, "LO: %08X\r", LO); buffP += strlen(buffP);
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, buffP - buffer, Registers.text);
-
- sprintf(buffer, "\rGeneral Registers\r");
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, strlen(buffer), Registers.text);
- for (i = 0; i < 8; ++i) {
- buffP = buffer;
- sprintf(buffP, grstr, i, reg_names[i], R[i]);
- buffP += strlen(buffP);
- sprintf(buffP, grstr, i+8, reg_names[i+8], R[i+8]);
- buffP += strlen(buffP);
- sprintf(buffP, grstr, i+16, reg_names[i+16], R[i+16]);
- buffP += strlen(buffP);
- sprintf(buffP, grstr, i+24, reg_names[i+24], R[i+24]);
- buffP += strlen(buffP);
- sprintf(buffP, "\r");
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, strlen(buffer), Registers.text);
- }
-
- sprintf(buffer, "\rDouble Floating Point Registers\r");
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, strlen(buffer), Registers.text);
- for (i = 0; i < 4; ++i) {
- buffP = buffer;
- sprintf(buffP, fpstr, 2*i, FGR[i]);
- buffP += strlen(buffP);
- sprintf(buffP, fpstr, 2*i+8, FGR[i+4]);
- buffP += strlen(buffP);
- sprintf(buffP, fpstr, 2*i+16, FGR[i+8]);
- buffP += strlen(buffP);
- sprintf(buffP, fpstr, 2*i+24, FGR[i+12]);
- buffP += strlen(buffP);
- sprintf(buffP, "\r");
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, strlen(buffer), Registers.text);
- }
-
- sprintf(buffer, "\rSingle Floating Point Registers\r");
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, strlen(buffer), Registers.text);
- for (i = 0; i < 8; i += 2) {
- buffP = buffer;
- sprintf(buffP, fgstr, i, FGR[i]);
- buffP += strlen(buffP);
- sprintf(buffP, fgstr, i+8, FGR[i+8]);
- buffP += strlen(buffP);
- sprintf(buffP, fgstr, i+16, FGR[i+16]);
- buffP += strlen(buffP);
- sprintf(buffP, fgstr, i+24, FGR[i+24]);
- buffP += strlen(buffP);
- sprintf(buffP, "\r");
- TESetSelect(32767, 32767, Registers.text);
- TEInsert(buffer, strlen(buffer), Registers.text);
- }
- } /* FormatRegisters */
-
- /* This formats the instructions between addresses from and to, actually drawing those
- whose line numbers lie between first and last. Each line is drawn at the given
- hPos and vPos, the latter of which is updated. If first is -1, all we do is count
- the lines twixt from and to without bothering to draw them. If the pointer pcLine
- is non-null, we supply the line number that shows the PC.
- */
-
- static void formatInstructions(mem_addr from, mem_addr to,
- int first, int last,
- short hPos, short *vPos, int *nLines, int *pcLine)
- {
- Boolean drawing;
- instruction *inst;
- char buffer[256];
- mem_addr i;
- char *s;
-
- drawing = first != -1;
-
- for (i = from; i < to; i += BYTES_PER_WORD) {
- READ_MEM_INST(inst, i);
- if ( inst != NULL ) {
- if ( drawing && *nLines > last )
- return;
- if ( drawing && *nLines >= first ) {
- /* prepend a label to important lines */
- if ( i == EPC )
- strcpy(buffer, "<EPC> ");
- else if ( i == R[31] )
- strcpy(buffer, "<$ra> ");
- else if ( i == PC )
- strcpy(buffer, "<PC> ");
- else
- strcpy(buffer, " ");
- print_inst_internal(buffer + 5, inst, i);
- for (s = buffer; *s; ++s)
- if ( *s < ' ' ) *s = ' ';
- CtoPstr(buffer);
- MoveTo(hPos, *vPos);
- DrawString(buffer);
- *vPos += SIZE + 1;
- }
- if ( pcLine && i == PC ) {
- *pcLine = *nLines;
- return;
- }
- *nLines += 1;
- }
- }
- } /* formatInstructions */
-
- void drawText(int first, int last)
- {
- int nLines;
- GrafPtr savePort;
- short hPos, vPos;
-
- hPos = 5 - GetCtlValue(Text.hScroll) * CharWidth(' ');
- vPos = SIZE + 1;
- GetPort(&savePort);
- SetPort(Text.window);
- nLines = 0;
- formatInstructions(TEXT_BOT, text_top, first, last, hPos, &vPos, &nLines, 0);
- if ( nLines >= first && nLines <= last )
- vPos += SIZE + 1;
- nLines += 1;
- if ( nLines >= first && nLines <= last ) {
- MoveTo(hPos, vPos);
- DrawString("\pKERNEL TEXT");
- vPos += SIZE + 1;
- }
- nLines += 1;
- formatInstructions(K_TEXT_BOT, k_text_top, first, last, hPos, &vPos, &nLines, 0);
-
- SetPort(savePort);
- } /* drawText */
-
- void CountText()
- {
- int nLines;
- short vPos;
- GrafPtr savePort;
-
- nLines = 0;
- formatInstructions(TEXT_BOT, text_top, -1, -1, 0, &vPos, &nLines, 0);
- nLines += 2; /* KERNEL TEXT label */
- formatInstructions(K_TEXT_BOT, k_text_top, -1, -1, 0, &vPos, &nLines, 0);
-
- /* touch the vertical scroll */
- SetCtlMax(Text.vScroll, nLines);
-
- /* force a redraw */
- GetPort(&savePort);
- SetPort(Text.window);
- InvalRect(&(Text.window->portRect));
- SetPort(savePort);
- } /* CountText */
-
- /* This is called every time SPIM stops running. It makes sure that the PC line is
- scrolled into view (provided that the PC is in one of the text segments).
- */
-
- void RecenterText()
- {
- GrafPtr savePort;
- Rect inval;
- short vPos;
- int nLines, pcLine;
-
- /* find the line number showing the stupid PC */
- pcLine = -1;
- nLines = 0;
- formatInstructions(TEXT_BOT, text_top, -1, -1, 0, &vPos, &nLines, &pcLine);
- if ( pcLine == -1 )
- formatInstructions(K_TEXT_BOT, k_text_top, -1, -1, 0, &vPos, &nLines, &pcLine);
-
- /* if the PC is in a text seg, scroll so that it's visible */
- if ( pcLine != -1 ) {
- if ( pcLine < Text.linesPerPage )
- SetCtlValue(Text.vScroll, 0);
- else if ( pcLine < GetCtlValue(Text.vScroll) )
- SetCtlValue(Text.vScroll, pcLine - Text.linesPerPage / 2);
- else if ( pcLine > GetCtlValue(Text.vScroll) + Text.linesPerPage )
- SetCtlValue(Text.vScroll, pcLine - Text.linesPerPage / 2);
- }
-
- /* but, alas! always force a redraw because a $break instruction might have snuck in */
- GetPort(&savePort);
- SetPort(Text.window);
- inval = Text.window->portRect;
- inval.bottom -= 16;
- inval.right -= 16;
- InvalRect(&inval);
- SetPort(savePort);
- } /* RecenterText */
-
- /* This figures out how to draw a display of a data segment. */
-
- static void formatValues(mem_addr from, mem_addr to,
- int first, int last,
- short hPos, short *vPos, int *nLines)
- {
- mem_addr i, j;
- mem_word val;
- Boolean drawing;
- char buffer[256], *bufP;
- int line;
-
- drawing = first != -1;
-
- for (i = from & 0xfffffffc; i < to; i += BYTES_PER_WORD) {
- /* look for a block of four or more zero memory words */
- for (j = 0; i + j < to; j += BYTES_PER_WORD) {
- READ_MEM_WORD(val, i + j);
- if ( val != 0 )
- break;
- }
- if ( (i + j < to) && (j != 0) )
- j -= BYTES_PER_WORD;
- if ( j >= 4 * BYTES_PER_WORD ) {
- if ( drawing && *nLines > last )
- return;
- if ( drawing && *nLines >= first ) {
- sprintf(buffer, "[0x%08x]...[0x%08x] 0x00000000", i, i + j);
- CtoPstr(buffer);
- MoveTo(hPos, *vPos);
- DrawString(buffer);
- *vPos += SIZE + 1;
- }
- *nLines += 1;
- i += j;
- continue;
- }
- /* otherwise print the next four words on one line */
- if ( drawing && *nLines >= first && *nLines <= last ) {
- sprintf(buffer, "[0x%08x] 0x%08x", i, val);
- bufP = buffer + strlen(buffer);
- }
- for ( ; i % 16 != 12; ) {
- i += BYTES_PER_WORD;
- if ( drawing && *nLines >= first ) {
- READ_MEM_WORD(val, i);
- sprintf(bufP, " 0x%08x", val);
- bufP += 12;
- }
- }
- if ( drawing && *nLines > last )
- return;
- if ( drawing && *nLines >= first ) {
- CtoPstr(buffer);
- MoveTo(hPos, *vPos);
- DrawString(buffer);
- *vPos += SIZE + 1;
- }
- *nLines += 1;
- }
- } /* formatValues */
-
- void drawData(int first, int last)
- {
- int nLines;
- GrafPtr savePort;
- short hPos, vPos;
-
- hPos = 5 - GetCtlValue(Data.hScroll) * CharWidth(' ');
- vPos = SIZE + 1;
- GetPort(&savePort);
- SetPort(Data.window);
- if ( first == 0 ) {
- MoveTo(hPos, vPos);
- DrawString("\pDATA");
- vPos += SIZE + 1;
- }
- nLines = 1;
- formatValues(DATA_BOT, data_top, first, last, hPos, &vPos, &nLines);
- if ( nLines >= first && nLines <= last )
- vPos += SIZE + 1;
- nLines += 1;
- if ( nLines >= first && nLines <= last ) {
- MoveTo(hPos, vPos);
- DrawString("\pSTACK");
- vPos += SIZE + 1;
- }
- nLines += 1;
- formatValues(R[29] - BYTES_PER_WORD, STACK_TOP, first, last, hPos, &vPos, &nLines);
- if ( nLines >= first && nLines <= last )
- vPos += SIZE + 1;
- nLines += 1;
- if ( nLines >= first && nLines <= last ) {
- MoveTo(hPos, vPos);
- DrawString("\pKERNEL DATA");
- vPos += SIZE + 1;
- }
- nLines += 1;
- formatValues(K_DATA_BOT, k_data_top, first, last, hPos, &vPos, &nLines);
-
- SetPort(savePort);
- } /* drawData */
-
- /* This figures out how many lines of type are needed to display the data segments.
- It also sets the vertical scroll parameters and forces a redraw.
- We call it after initialization, after loading a file, and after running the CPU.
- */
-
- void CountData()
- {
- int nLines;
- short vPos;
- GrafPtr savePort;
-
- /* count the data lines */
- nLines = 1; /* DATA label */
- formatValues(DATA_BOT, data_top, -1, -1, 0, &vPos, &nLines);
- nLines += 2; /* STACK label */
- formatValues(R[29] - BYTES_PER_WORD, STACK_TOP, -1, -1, 0, &vPos, &nLines);
- nLines += 2; /* KERNEL DATA label */
- formatValues(K_DATA_BOT, k_data_top, -1, -1, 0, &vPos, &nLines);
-
- /* touch the vertical scroll */
- SetCtlMax(Data.vScroll, nLines);
-
- /* force data redraw */
- GetPort(&savePort);
- SetPort(Data.window);
- InvalRect(&(Data.window->portRect));
- SetPort(savePort);
- } /* CountData */
-
- static void makeWindow(Str255 title, SPIMTextWindow *stWindow, Boolean useTE)
- {
- Rect r, view, dest;
- static short nextHPos = 5, nextVPos = 45;
-
- stWindow->window = GetNewWindow(128, 0, (WindowPtr) -1);
- MoveWindow(stWindow->window, nextHPos, nextVPos, FALSE);
- SetWTitle(stWindow->window, title);
- SetWRefCon(stWindow->window, (long) stWindow);
- SetPort(stWindow->window);
- TextFont(FONT);
- TextSize(SIZE);
- r = stWindow->window->portRect;
-
- if ( useTE ) {
- SetRect(&dest, 5, 5, 2000, 2000);
- view = r;
- view.left += 5;
- view.top += 5;
- view.bottom -= 15;
- view.right -= 15;
- if ( stWindow == &Help )
- stWindow->text = TENew(&view, &view);
- else
- stWindow->text = TENew(&dest, &view);
- stWindow->linesPerPage = (r.bottom - r.top - 20);
- stWindow->linesPerPage /= (*(stWindow->text))->lineHeight;
- }
- else {
- stWindow->text = (TEHandle) 0;
- stWindow->linesPerPage = (r.bottom - r.top - 20) / (SIZE + 1);
- }
- stWindow->columnsPerPage = (r.right - r.left - 20) / CharWidth(' ');
-
- stWindow->vScroll = GetNewControl(128, stWindow->window);
- MoveControl(stWindow->vScroll, r.right - 15, -1);
- SizeControl(stWindow->vScroll, 16, r.bottom - 13);
- SetCRefCon(stWindow->vScroll, 1L);
-
- stWindow->hScroll = GetNewControl(128, stWindow->window);
- MoveControl(stWindow->hScroll, -1, r.bottom - 15);
- SizeControl(stWindow->hScroll, r.right - 13, 16);
- SetCRefCon(stWindow->hScroll, 0L);
- SetCtlMin(stWindow->hScroll, 0);
- SetCtlValue(stWindow->hScroll, 0);
- SetCtlMax(stWindow->hScroll, 256);
-
- nextHPos += 5;
- nextVPos += 20;
- } /* makeWindow */
-
- static void loadHelpText()
- {
- short refNum;
- long fileSize;
- OSErr err;
- Handle text;
-
- err = FSOpen("\phelp.text", (short) 0, &refNum);
- if ( err != noErr ) return;
- err = GetEOF(refNum, &fileSize);
- if ( err != noErr ) return;
- text = NewHandle(fileSize);
- if ( !text ) return;
- HLock(text);
- err = SetFPos(refNum, fsFromStart, 0L);
- if ( err != noErr ) return;
- err = FSRead(refNum, &fileSize, *text);
- if ( err != noErr ) return;
- FSClose(refNum);
-
- TESetText(*text, fileSize, Help.text);
- HUnlock(text);
- DisposHandle(text);
-
- SetCtlMax(Help.vScroll, (*(Help.text))->nLines - Help.linesPerPage);
- } /* loadHelpText */
-
- void InitTextWindows()
- {
- makeWindow("\pSPIM/SAL Registers", &Registers, TRUE);
- makeWindow("\pSPIM/SAL Text Segments", &Text, FALSE);
- makeWindow("\pSPIM/SAL Data Segments", &Data, FALSE);
- makeWindow("\pSPIM/SAL Session", &Session, TRUE);
- makeWindow("\pSPIM/SAL Console", &Console, TRUE);
-
- makeWindow("\pSPIM/SAL Help", &Help, TRUE);
- loadHelpText();
-
- SetCtlMax(Registers.vScroll, 28);
- SetCtlMax(Session.vScroll, SESSION_LINES);
- SetCtlMax(Console.vScroll, CONSOLE_LINES);
- } /* InitTextWindows */
-
- void SelectTextWindow(SPIMTextWindow *textWindow)
- {
- ShowWindow(textWindow->window);
- SelectWindow(textWindow->window);
- } /* SelectTextWindow */
-
- void ActivateTextWindow(WindowPtr window, Boolean active)
- {
- SPIMTextWindow *stWindow;
-
- stWindow = (SPIMTextWindow *) GetWRefCon(window);
-
- DrawGrowIcon(window);
- HiliteControl(stWindow->hScroll, active ? 0 : 255);
- HiliteControl(stWindow->vScroll, active ? 0 : 255);
- if ( active )
- SetPort(window);
- } /* ActivateTextWindow */
-
- void UpdateTextWindow(WindowPtr window)
- {
- SPIMTextWindow *stWindow;
- GrafPtr savePort;
- Rect r;
- short first;
-
- stWindow = (SPIMTextWindow *) GetWRefCon(window);
-
- BeginUpdate(window);
- GetPort(&savePort);
- SetPort(window);
- r = window->portRect;
- EraseRect(&r);
- if ( stWindow->text ) {
- r.right -= 16;
- r.bottom -= 16;
- TEUpdate(&r, stWindow->text);
- }
- else if ( stWindow == &Data ) {
- first = GetCtlValue(Data.vScroll);
- drawData(first, first + Data.linesPerPage);
- }
- else if ( stWindow == &Text ) {
- first = GetCtlValue(Text.vScroll);
- drawText(first, first + Text.linesPerPage);
- }
- DrawGrowIcon(window);
- DrawControls(window);
- SetPort(savePort);
- EndUpdate(window);
- } /* UpdateTextWindow */
-
- /* This repositions the controls and resets the arithmetic of a window whose size
- has just been changed.
- */
-
- void RecalculateTextWindow(WindowPtr window)
- {
- GrafPtr savePort;
- SPIMTextWindow *stWindow;
- Rect inval, view, r;
-
- stWindow = (SPIMTextWindow *) GetWRefCon(window);
-
- GetPort(&savePort);
- SetPort(window);
- r = window->portRect;
- ClipRect(&r);
- SetPort(savePort);
- MoveControl(stWindow->vScroll, r.right - 15, -1);
- SizeControl(stWindow->vScroll, 16, r.bottom - 13);
- MoveControl(stWindow->hScroll, -1, r.bottom - 15);
- SizeControl(stWindow->hScroll, r.right - 13, 16);
- if ( stWindow->text ) {
- view = r;
- view.left += 5;
- view.top += 5;
- view.bottom -= 15;
- view.right -= 15;
- (*(stWindow->text))->viewRect = view;
- stWindow->linesPerPage = (r.bottom - r.top - 20);
- stWindow->linesPerPage /= (*(stWindow->text))->lineHeight;
- }
- else
- stWindow->linesPerPage = (r.bottom - r.top - 20) / (SIZE + 1);
- stWindow->columnsPerPage = (r.right - r.left - 20) / CharWidth(' ');
- } /* RecalculateTextWindow */
-
- void SizeTextWindow(WindowPtr window, Point start)
- {
- SPIMTextWindow *stWindow;
- Rect limits, inval;
- long newSize;
-
- stWindow = (SPIMTextWindow *) GetWRefCon(window);
-
- SetRect(&limits, 100, 100, 1000, 1000);
- newSize = GrowWindow(window, start, &limits);
- if ( newSize ) {
- inval = window->portRect;
- inval.left = inval.right - 16;
- inval.top = inval.bottom - 16;
- InvalRect(&inval);
- SizeWindow(window, LoWord(newSize), HiWord(newSize), TRUE);
- RecalculateTextWindow(window);
- }
-
- } /* SizeTextWindow */
-
- void TileTextWindows(Boolean vertically)
- {
- short nOpen, total, width, height, i, h, v;
- WindowPtr openOnes[5];
-
- nOpen = 0;
- if ( ((WindowPeek) (Registers.window))->visible )
- openOnes[nOpen++] = Registers.window;
- if ( ((WindowPeek) (Text.window))->visible )
- openOnes[nOpen++] = Text.window;
- if ( ((WindowPeek) (Data.window))->visible )
- openOnes[nOpen++] = Data.window;
- if ( ((WindowPeek) (Session.window))->visible )
- openOnes[nOpen++] = Session.window;
- if ( ((WindowPeek) (Console.window))->visible )
- openOnes[nOpen++] = Console.window;
-
- if ( nOpen == 0 )
- return;
-
- h = 5; v = 45;
- if ( vertically ) {
- total = screenBits.bounds.bottom - 25;
- height = total / nOpen - 5;
- width = screenBits.bounds.right - 10;
- for (i = 0; i < nOpen; ++i) {
- MoveWindow(openOnes[i], h, v, FALSE);
- SizeWindow(openOnes[i], width, height - 20, TRUE);
- RecalculateTextWindow(openOnes[i]);
- v += height + 5;
- }
- }
- else {
- total = screenBits.bounds.right - 5;
- width = total / nOpen - 5;
- height = screenBits.bounds.bottom - 50;
- for (i = 0; i < nOpen; ++i) {
- MoveWindow(openOnes[i], h, v, FALSE);
- SizeWindow(openOnes[i], width, height, TRUE);
- RecalculateTextWindow(openOnes[i]);
- h += width + 5;
- }
- }
- } /* TileTextWindows */
-
- /* Action procs for the scroll bars. */
-
- static short scrollAmount;
- static SPIMTextWindow *scrollWindow;
- static RgnHandle scrollRgn;
-
- static pascal void verticalAction(ControlHandle ctrl, short partCode)
- {
- short delta, value;
- Rect scroll;
-
- delta = GetCtlValue(ctrl);
- SetCtlValue(ctrl, scrollAmount + GetCtlValue(ctrl));
- value = GetCtlValue(ctrl);
- delta -= value;
- if ( delta ) {
- /* value actually changed */
- if ( scrollWindow->text ) {
- delta *= (*(scrollWindow->text))->lineHeight;
- TEScroll(0, delta, scrollWindow->text);
- }
- else {
- /* redraw text or data */
- scroll = scrollWindow->window->portRect;
- scroll.right -= 15;
- scroll.bottom -= 15;
- ScrollRect(&scroll, 0, delta * (SIZE + 1), scrollRgn);
- ClipRect(&scroll);
- if ( scrollWindow == &Text )
- drawText(value, value + Text.linesPerPage);
- else
- drawData(value, value + Data.linesPerPage);
- ClipRect(&(scrollWindow->window->portRect));
- }
- }
- } /* verticalAction */
-
- static pascal void horizontalAction(ControlHandle ctrl, short partCode)
- {
- short delta, value, vPos;
- Rect scroll;
-
- delta = GetCtlValue(ctrl);
- SetCtlValue(ctrl, scrollAmount + GetCtlValue(ctrl));
- value = GetCtlValue(ctrl);
- delta -= value;
- if ( delta ) {
- /* value actually changed */
- if ( scrollWindow->text ) {
- delta *= CharWidth(' ');
- TEScroll(delta, 0, scrollWindow->text);
- }
- else {
- /* redraw text or data */
- scroll = scrollWindow->window->portRect;
- scroll.right -= 15;
- scroll.bottom -= 15;
- ScrollRect(&scroll, delta * CharWidth(' '), 0, scrollRgn);
- ClipRect(&scroll);
- vPos = GetCtlValue(scrollWindow->vScroll);
- if ( scrollWindow == &Text )
- drawText(vPos, vPos + Text.linesPerPage);
- else
- drawData(vPos, vPos + Data.linesPerPage);
- ClipRect(&(scrollWindow->window->portRect));
- }
- }
- } /* horizontalAction */
-
- /* This checks for mouse action in the scroll bars. */
-
- void ClickTextWindow(WindowPtr window, EventRecord *event)
- {
- SPIMTextWindow *stWindow;
- ControlHandle ctrl;
- short code, value, delta;
- Boolean vertical;
- Rect inval;
-
- stWindow = (SPIMTextWindow *) GetWRefCon(window);
- scrollWindow = stWindow;
-
- GlobalToLocal(&(event->where));
- code = FindControl(event->where, window, &ctrl);
- if ( code )
- vertical = GetCRefCon(ctrl) ? TRUE : FALSE;
- else
- return;
-
- scrollRgn = NewRgn();
- switch ( code ) {
- case inUpButton :
- scrollAmount = -1;
- TrackControl(ctrl, event->where, vertical ? verticalAction : horizontalAction);
- break;
- case inDownButton :
- scrollAmount = 1;
- TrackControl(ctrl, event->where, vertical ? verticalAction : horizontalAction);
- break;
- case inPageUp :
- if ( vertical )
- scrollAmount = -(stWindow->linesPerPage - 2);
- else
- scrollAmount = -(stWindow->columnsPerPage - 2);
- TrackControl(ctrl, event->where, vertical ? verticalAction : horizontalAction);
- break;
- case inPageDown :
- if ( vertical )
- scrollAmount = stWindow->linesPerPage - 2;
- else
- scrollAmount = stWindow->columnsPerPage - 2;
- TrackControl(ctrl, event->where, vertical ? verticalAction : horizontalAction);
- break;
- case inThumb :
- delta = GetCtlValue(ctrl);
- TrackControl(ctrl, event->where, 0);
- value = GetCtlValue(ctrl);
- delta -= value;
- if ( delta ) {
- if ( stWindow->text ) {
- delta *= vertical ? (*(stWindow->text))->lineHeight : CharWidth(' ');
- TEScroll(vertical ? 0 : delta, vertical ? delta : 0, stWindow->text);
- }
- else {
- inval = window->portRect;
- inval.right -= 15;
- inval.bottom -= 15;
- InvalRect(&inval);
- }
- }
- break;
- }
- DisposeRgn(scrollRgn);
- } /* ClickTextWindow */
-
- /* This forces the last line in the TE buff to be visible. */
-
- static void scrollIntoView(SPIMTextWindow *stWindow)
- {
- short nLines, height, value, delta;
-
- nLines = (*(stWindow->text))->nLines;
- height = (*(stWindow->text))->lineHeight;
- value = GetCtlValue(stWindow->vScroll);
- if ( nLines < stWindow->linesPerPage ) {
- /* scroll all the way back to zero */
- SetCtlValue(stWindow->vScroll, 0);
- delta = GetCtlValue(stWindow->vScroll) - value;
- TEScroll(0, -delta * height, stWindow->text);
- }
- else if ( nLines < value ) {
- /* scroll up so last line is in middle of screen */
- SetCtlValue(stWindow->vScroll, nLines - stWindow->linesPerPage / 2);
- delta = GetCtlValue(stWindow->vScroll) - value;
- TEScroll(0, -delta * height, stWindow->text);
- }
- else if ( nLines > value + stWindow->linesPerPage ) {
- /* scroll down so last line is in middle of screen */
- SetCtlValue(stWindow->vScroll, nLines - stWindow->linesPerPage / 2);
- delta = GetCtlValue(stWindow->vScroll) - value;
- TEScroll(0, -delta * height, stWindow->text);
- }
- } /* scrollIntoView */
-
- /* This writes output to either the Session or the Console window.
- As a sanity check, I restrict the number of lines of output that can be produced
- while assembling a source file.
- */
-
- Boolean Assembling = FALSE;
- short MessageCount;
-
- #define MAX_MESSAGES (SESSION_LINES - 10)
-
- void write_output(long whither, char *buf)
- {
- SPIMTextWindow *stWindow;
- char format[256], *ptr;
- short maxLines, excess, end;
- int i;
-
- if ( Assembling && (MessageCount >= MAX_MESSAGES) )
- return;
-
- /* convert '\n' to '\r', expand tabs */
- i = 0;
- while ( *buf ) {
- if ( *buf == '\n' ) {
- ++MessageCount;
- format[i++] = '\r';
- }
- else if ( *buf == '\t' ) {
- do
- format[i++] = ' ';
- while ( i % 8 );
- }
- else
- format[i++] = *buf;
- ++buf;
- }
- format[i] = '\0';
-
- if ( Assembling && (MessageCount >= MAX_MESSAGES) ) {
- ptr = "\r\r*** Too many errors! ***\r";
- i = strlen(ptr);
- }
- else
- ptr = format;
-
- stWindow = (SPIMTextWindow *) whither;
- maxLines = stWindow == &Session ? SESSION_LINES : CONSOLE_LINES;
- TESetSelect(32767, 32767, stWindow->text);
- TEInsert(ptr, i, stWindow->text);
- excess = (*(stWindow->text))->nLines - maxLines;
- if ( excess > 0 ) {
- end = (*(stWindow->text))->lineStarts[excess];
- TESetSelect(0, end, stWindow->text);
- TEDelete(stWindow->text);
- }
- scrollIntoView(stWindow);
- ShowWindow(stWindow->window);
- } /* write_output */
-
- /* This gets a string from the Console to supply a system call. */
-
- void read_input(char *buffer, int length)
- {
- extern DialogPtr RunningDlg;
- Point endPoint;
- Rect teRect;
- TEHandle teH;
- Boolean reading;
- EventRecord event;
- char typed;
- WindowPtr window;
-
- /* bring the Console window to the top */
- ShowWindow(Console.window);
- SelectWindow(Console.window);
- SetPort(Console.window);
- scrollIntoView(&Console);
-
- /* figure out where the input TE rectangle goes */
- endPoint = TEGetPoint(32767, Console.text);
- teRect.left = endPoint.h;
- teRect.right = Console.window->portRect.right - 15;
- teRect.bottom = endPoint.v + 4;
- teRect.top = teRect.bottom - (*(Console.text))->lineHeight - 4;
- teH = TENew(&teRect, &teRect);
- TEActivate(teH);
-
- /* fetch and handle events */
- reading = TRUE;
- while ( reading ) {
- TEIdle(teH);
- GetNextEvent(everyEvent, &event);
- switch ( event.what ) {
- case activateEvt :
- if ( event.message == (long) Console.window )
- ActivateTextWindow(Console.window, TRUE);
- break;
- case updateEvt :
- if ( event.message == (long) Console.window )
- UpdateTextWindow(Console.window);
- break;
- case keyDown :
- typed = event.message & charCodeMask;
- if ( typed == '\r' ) {
- reading = FALSE;
- typed = '\n';
- }
- TEKey(typed, teH);
- break;
- case mouseDown :
- if ( FindWindow(event.where, &window) == inContent ) {
- if ( window == Console.window ) {
- GlobalToLocal(&event.where);
- if ( PtInRect(event.where, &teRect) )
- TEClick(event.where, event.modifiers & shiftKey ? TRUE : FALSE,
- teH);
- }
- }
- break;
- default :
- break;
- }
- }
-
- /* get the string and echo it */
- strncpy(buffer, *((*teH)->hText), length);
- buffer[(*teH)->teLength] = '\0';
- write_output(console_out, buffer);
-
- /* put the running dialog back on top */
- TEDispose(teH);
- SelectWindow(RunningDlg);
- } /* read_input */
-
- void ClearConsole()
- {
- TESetSelect(0, 32767, Console.text);
- TEDelete(Console.text);
- scrollIntoView(&Console);
- }
-