/* Paul Placeway, Ohio State -- added option to flashing cursor, made */ /* key macros use Pascal strings, so that a NUL (0x00) can be sent */ /* Enhanced by Clayton M. Elwell, Ohio State University 24 Nov 1987 -- */ /* added insert character */ /* Matthias Aebi, ECOFIN Research and Consulting, Ltd., Oct 1987 -- */ /* ported to MPW, changed the way keys work */ /* Version 0.8(35) - Jim Noble at Planning Research Corporation, June 1987. */ /* Ported to Megamax native Macintosh C compiler. */ /* From: DPVC@UORDBV.BITNET */ /* DPVC at U of R, Oct 1, add blinking cursor and mouse cursor movement */ /* DPVC at U of R, Sept. 26, fixed book-keeping for scrolling and inserting */ /* characters and lines */ /* DPVC at U of R, Sept. 25, to fix cursor positioning off the screen, and */ /* a few other, minor VT100 incompatibilities */ /* DPVC at the University of Rochester, Sept. 9, to add Block Cursor and */ /* ability to do VT100 graphics characters */ /* By CAM2 and DPVC at the University of Rochester on Sept 6, */ /* changed bolding from using TextStyle attributes to using a separate bold */ /* font */ /* By Frank on June 20 - Add parity to all outbound chars using software */ /* Also, ignore DEL (0177) characters on input. */ /* By Bill on May 29 - Add Key set translation */ /* By WBC3 on Apr 24 - Add ^^, ^@ and ^_. Also use Pascal strings for */ /* output in the terminal emulator */ /* By WBC3 on Apr 23 - Add query terminal and be more fastidious about */ /* ignoring sequences we don't know about */ /* By WBC3 on Apr 22 - Fix tab stops to conform to the rest of the world! */ /* By Bill on Apr 21 - Fix immediate echo problems. */ /* do less cursor_erase, cursor_draw stuff */ /* * FILE ckmcon.c * * Module of mackermit: contains code for the terminal simulation * routine. */ #include "ckcdeb.h" #define __SEG__ ckmcon #include #include #include #include #include #include #include #include "ckmdef.h" #include "ckmasm.h" /* Assembler code */ #define MAXLIN 24 #define MAXCOL 80 #define LINEHEIGHT 12 #define CHARWIDTH 6 #define TOPMARGIN 3 /* Terminal display constants */ #define bottomMARGIN (LINEHEIGHT * MAXLIN + TOPMARGIN) #define LEFTMARGIN 3 #define rightMARGIN (CHARWIDTH * MAXCOL + LEFTMARGIN) #define LINEADJ 3 /* Amount of char below base line */ /* Font Numbers (UoR Mod) to fix bolding problems */ /* These should be placed in the RESOURCE FORK of the executable */ #define VT100FONT 128 /* VT100 Terminal Font (not-bold) */ #define VT100BOLD 129 /* VT100 Bold Font */ /* Tab settings */ /* #define NUMTABS 9 short tabstops[NUMTABS] = {8,16,24,32,40,48,56,64,72}; *//* (UoR) remove old method of tab stops */ /* (UoR) do tapstops via an array: 0 means no tab, 1 means tab at that column */ short tabstops[MAXCOL + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }; #define USA_SET 0 /* (UoR) VT100 character set numbers */ #define UK_SET 1 #define GRAF_SET 2 int topmargin = TOPMARGIN, /* Edges of adjustable window */ bottommargin = bottomMARGIN, textstyle = 0, currentfont = VT100FONT, /* (UoR) currently active font */ graphicsinset[2] = {USA_SET, USA_SET}, /* (UoR) current character sets */ current_set = 0, /* (UoR) current chosen set */ doinvert = FALSE, /* Flag for inverted terminal mode */ dounder = FALSE, /* Flag for underlining (PWP) */ screeninvert = FALSE, /* (UoR) inverted screen flag */ insert = FALSE, newline = FALSE, /* (UoR) linefeed mode by default */ autowrap = TRUE, /* Autowrap on by default */ relorigin = FALSE, /* (UoR) relative origin off */ autorepeat = TRUE, /* (UoR) auto repeat flag */ smoothscroll = FALSE, /* do smooth scrolling (PWP: or not) */ transparent = TRUE, /* do not show control characters */ blockcursor = TRUE, /* show block or underline cursor */ mouse_arrows = FALSE, /* mouse down in screen does arrow keys */ visible_bell = FALSE, /* true if we do blink instead of bell */ nat_chars = FALSE, /* half transparent -- show undef. control * chars */ blinkcursor = TRUE; /* true if we make the cursor blink */ char *querystring = "\033[?1;2c"; /* Answer we are a VT100 with AVO */ /* (UoR) used to be VT102 */ char *reportstring = "\033[0n"; /* (UoR) report that we're OK */ char *noprinter = "\033[?13n"; /* (UoR) report no printer */ Rect ScreenRect; /* * (UoR) don't need scrollrect any more (use scroll_up and scroll_down), use * ScreenRect for mouse check */ /* Screen book keeping variables */ char scr[MAXLIN][MAXCOL + 1]; /* Characters on the screen */ short nxtlin[MAXLIN], toplin, botlin; /* Linked list of lines */ int curlin, curcol, abslin; /* Cursor position */ int savcol, savlin; /* Cursor save variables */ int savsty, savfnt, savgrf, savmod, savset[2]; /* (UoR) cursor save * variables */ int savund; /* PWP for saved underlining */ int scrtop, scrbot; /* Absolute scrolling region bounds */ int cursor_invert = FALSE, /* (UoR) for flashing cursor */ cur_drawn = FALSE; long last_flash = 0; int oldlin = -1; int oldcol = 0; /* (UoR) for last mouse position */ RgnHandle dummyRgn; /* dummy region for ScrollRect */ /* Initialized in mac_init */ # define CARETTIME 20 /* (UoR) ticks between flashes */ /* Stuff for escape character processing */ #define CF_OUTC 0 /* Just output the char */ #define CF_SESC 1 /* In a single char escape seq */ #define CF_MESC 2 /* In a multi char '[' escape seq */ #define CF_TOSS 3 /* Toss this char */ #define CF_GRF0 4 /* (UoR) for graphics sequence 0 */ #define CF_GRF1 5 /* (UoR) for graphics sequence 1 */ char prvchr, numone[6], numtwo[6], *numptr; int num1, num2, charflg = CF_OUTC; /* extern CSParam controlparam; */ extern unsigned char dopar (); typedef int (*PFI) (); /* Terminal function declarations. */ int tab (), back_space (), carriage_return (), line_feed (), bell (), escape_seq (), text_mode (), clear_line (), erase_display (), cursor_position (), cursor_up (), cursor_down (), cursor_right (), cursor_left (), cursor_save (), cursor_restore (), set_scroll_region (), reverse_line_feed (), dummy (), delete_char (), insert_mode (), end_insert_mode (), insert_line (), delete_line (), query_terminal (), multi_char (), toss_char (), insert_chars (), /* (UoR) for VT100 graphic character set */ graphic_G0 (), graphic_G1 (), control_N (), control_O (), /* (UoR) for other VT100 functions */ new_line (), request_report (), set_tab (), clear_tab (); /* (UoR) constansts that point to the function definitions for arrow keys */ /* Used by mouse cursor positioning function (Pascal strings) */ # define UPARROW "\003\033OA" # define DOWNARROW "\003\033OB" # define leftARROW "\003\033OD" # define rightARROW "\003\033OC" /* Terminal control character function command table. */ #define MINSINGCMDS 000 #define MAXSINGCMDS 037 PFI controltable[MAXSINGCMDS - MINSINGCMDS + 1] = { dummy, /* 0 */ dummy, /* 1 */ dummy, /* 2 */ dummy, /* 3 */ dummy, /* 4 */ dummy, /* 5 */ dummy, /* 6 */ bell, /* 7 */ back_space, /* 10 */ tab, /* 11 */ line_feed, /* 12 */ line_feed, /* 13 (Vertical tab) */ line_feed, /* 14 (Form feed) */ carriage_return, /* 15 */ control_N, /* 16 (graphic set 1) *//* (UoR) */ control_O, /* 17 (graphic set 0) *//* (UoR) */ dummy, /* 20 */ dummy, /* 21 */ dummy, /* 22 */ dummy, /* 23 */ dummy, /* 24 */ dummy, /* 25 */ dummy, /* 26 */ dummy, /* 27 */ dummy, /* 30 */ dummy, /* 31 */ dummy, /* 32 */ escape_seq, /* 33 (Escape) */ dummy, /* 34 */ dummy, /* 35 */ dummy, /* 36 */ dummy /* 37 */ }; #define MINSINGESCS 0040 #define MAXSINGESCS 0137 PFI singescapetable[MAXSINGESCS - MINSINGESCS + 1] = { dummy, /* 40 */ dummy, /* 41 */ dummy, /* 42 */ toss_char, /* 43 '#' */ dummy, /* 44 */ dummy, /* 45 */ dummy, /* 46 */ dummy, /* 47 */ graphic_G0, /* 50 '(' *//* (UoR) */ graphic_G1, /* 51 ')' *//* (UoR) */ dummy, /* 52 */ dummy, /* 53 */ dummy, /* 54 */ dummy, /* 55 */ dummy, /* 56 */ dummy, /* 57 */ dummy, /* 60 */ dummy, /* 61 */ dummy, /* 62 */ dummy, /* 63 */ dummy, /* 64 */ dummy, /* 65 */ dummy, /* 66 */ cursor_save, /* 67 '7' */ cursor_restore, /* 70 '8' */ dummy, /* 71 */ dummy, /* 72 */ dummy, /* 73 */ dummy, /* 74 '<' */ dummy, /* 75 '=' */ dummy, /* 76 '>' */ dummy, /* 77 */ dummy, /* 100 */ dummy, /* 101 */ dummy, /* 102 */ dummy, /* 103 */ line_feed, /* 104 'D' */ new_line, /* 105 'E' *//* (UoR) */ dummy, /* 106 */ dummy, /* 107 */ set_tab, /* 110 'H' *//* (UoR) */ dummy, /* 111 */ dummy, /* 112 */ dummy, /* 113 */ dummy, /* 114 */ reverse_line_feed, /* 115 'M' */ toss_char, /* 116 'N' *//* CME */ toss_char, /* 117 'O' *//* (UoR) ignore these */ dummy, /* 120 */ dummy, /* 121 */ dummy, /* 122 */ dummy, /* 123 */ dummy, /* 124 */ dummy, /* 125 */ dummy, /* 126 */ dummy, /* 127 */ dummy, /* 130 */ dummy, /* 131 */ query_terminal, /* 132 'Z' */ multi_char, /* 133 '[' */ dummy, /* 134 */ dummy, /* 135 */ dummy, /* 136 */ dummy /* 137 */ }; /* Terminal escape sequence function command table */ #define MINMULTESCS 0100 #define MAXMULTESCS 0177 PFI escapetable[MAXMULTESCS - MINMULTESCS + 1] = { insert_chars, /* 100 *//* CME */ cursor_up, /* 101 'A' */ cursor_down, /* 102 'B' */ cursor_right, /* 103 'C' */ cursor_left, /* 104 'D' */ dummy, /* 105 */ dummy, /* 106 */ dummy, /* 107 */ cursor_position, /* 110 'H' */ dummy, /* 111 */ erase_display, /* 112 'J' */ clear_line, /* 113 'K' */ insert_line, /* 114 'L' */ delete_line, /* 115 'M' */ dummy, /* 116 */ dummy, /* 117 */ delete_char, /* 120 'P' */ dummy, /* 121 */ dummy, /* 122 */ dummy, /* 123 */ dummy, /* 124 */ dummy, /* 125 */ dummy, /* 126 */ dummy, /* 127 */ dummy, /* 130 */ dummy, /* 131 */ dummy, /* 132 */ dummy, /* 133 */ dummy, /* 134 */ dummy, /* 135 */ dummy, /* 136 */ dummy, /* 137 */ dummy, /* 140 */ dummy, /* 141 */ dummy, /* 142 */ query_terminal, /* 143 'c' */ dummy, /* 144 */ dummy, /* 145 */ cursor_position, /* 146 'f' */ clear_tab, /* 147 'g' *//* (UoR) */ insert_mode, /* 150 'h' */ dummy, /* 151 */ dummy, /* 152 */ dummy, /* 153 */ end_insert_mode, /* 154 'l' */ text_mode, /* 155 'm' */ request_report, /* 156 'n' *//* (UoR) */ dummy, /* 157 */ dummy, /* 160 */ dummy, /* 161 */ set_scroll_region, /* 162 'r' */ dummy, /* 163 */ dummy, /* 164 */ dummy, /* 165 */ dummy, /* 166 */ dummy, /* 167 */ dummy, /* 170 */ dummy, /* 171 */ dummy, /* 172 */ dummy, /* 173 */ dummy, /* 174 */ dummy, /* 175 */ dummy, /* 176 */ dummy /* 177 */ }; /****************************************************************************/ /* Connect support routines */ /****************************************************************************/ consetup () { PenMode (patXor); flushio (); /* Get rid of pending characters */ init_term (); /* Set up some terminal variables */ TextFont (VT100FONT); /* (UoR) Set initial font to VT100 */ TextMode (srcXor); /* (UoR) use XOR mode (for inverse) */ TextFace (0); /* PWP: be safe. We allways stay like this */ clear_screen (); /* Clear the screen */ home_cursor (); /* Go to the upper left */ cursor_save (); /* Save this position */ cursor_draw (); /* (UoR) be sure to draw it */ } /* consetup */ /****************************************************************************/ /* Input and process all the characters pending on the tty line */ /****************************************************************************/ inpchars () { int rdcnt; if ((rdcnt = ttchk ()) == 0)/* How many chars there? */ return; /* Ret if 0 */ cursor_erase (); /* remove cursor from screen */ while (rdcnt-- > 0) /* Output all those characters */ printit (ttinc (0)); flushbuf (); /* Flush any remaining characters */ cursor_draw (); /* put it back */ } /* inpchars */ /****************************************************************************/ /* writeps - write a pascal form string to the serial port. * */ /****************************************************************************/ writeps (s) char *s; { long wcnt, w2; int err; char *s2; w2 = wcnt = *s++; /* get count */ for (s2 = s; w2 > 0; w2--, s2++) /* add parity */ *s2 = dopar (*s2); err = FSWrite (outnum, &wcnt, s); /* write the characters */ if (err != noErr) printerr ("Bad FSWrite in writeps: ", err); return; } /* writeps */ /****************************************************************************/ /* * (UoR) * * Print a string to the screen (used to echo function and meta strings * in duplex mode). * */ /****************************************************************************/ printps (s) char *s; { long w2; char *s2; cursor_erase (); w2 = *s++; /* get count */ for (s2 = s; w2 > 0; w2--, s2++) printit (*s2); /* print it out, and perform special * functions */ flushbuf (); cursor_draw (); return; } /* printps */ /****************************************************************************/ /* return the ASCII character which is generated by the keyCode specified */ /* with no modifiers pressed */ /****************************************************************************/ unsigned char DeModifyChar (keyCode) short keyCode; { ProcHandle KeyTrans; long c; if (keyCode > 64) KeyTrans = 0x2A2; /* keypad decode */ else KeyTrans = 0x29E; /* keyboard decode */ SaveRegs (); /* save all registers */ AllRegs (); /* setup regs for procedure call */ loadD1 ((long) 0); /* no modifiers */ loadD2 ((long) keyCode); /* set the keycode */ loadA0 (*KeyTrans); /* load the content of Key1Trans to A0 */ /* run the translation routine */ execute (); /* call the Key1Trans procedure */ /* move the result from reg D0 to c */ loadA0 (&c); /* set destination address */ pushD0 (); /* move register D0 to stack */ poptoA0 (); /* load the stacktop to (A0) */ RestoreRegs (); /* restore all registers */ AllRegs (); return (c); } /* DeModifyChar */ unsigned char obuf[2] = {1, 0}; /* single char output buffer */ /****************************************************************************/ /* send a character to the line if it is in ASCII range. Do local echo if */ /* necessary */ /****************************************************************************/ OutputChar (c) unsigned char c; { /* * PWP: NO 7 bit masking!!! If we do this, then I can't use Emacs, and * the European users will be VERY unhappy, 'cause they won't be able to * send all of their characters. */ #ifdef COMMENT_OUT if (c > 127) { /* reject non-ASCII characters */ SysBeep (1); return; } #endif /* COMMENT_OUT */ obuf[1] = c; /* store character */ writeps (obuf); /* and write it out */ if (duplex != 0) { cursor_erase (); /* remove from screen */ printit ((char) c); /* Echo the char to the screen */ flushbuf (); /* flush the character */ cursor_draw (); /* put it back */ } } /* OutputChar */ extern char keytable[512]; /* the key redefintion flag table */ extern modrec modtable[NUMOFMODS]; /* modifier records */ #define myKeyCodeMask 0x7F00 #define keyModifierMask 0x1F00 #define ctrlCodeMask 0x1F #define metaOrBits 0x80 #define UnmodMask 0x80 /* action bits */ #define CapsMask 0x40 #define CtrlMask 0x20 #define MetaMask 0x10 /****************************************************************************/ /* Process a character received from the keyboard */ /****************************************************************************/ handle_char (evt) EventRecord *evt; { short i; short len; short theCode; short modCode; short theModBits; char flags; char tmpstr[256]; unsigned char c; /* (UoR) check for auto repeated keys */ if ((autorepeat == FALSE) && (evt->what == autoKey)) return; ObscureCursor (); /* PWP: hide the cursor until next move */ modCode = evt->modifiers & keyModifierMask; theCode = ((evt->message & myKeyCodeMask) >> 8) + (modCode >> 1); /* check for a special code for this key */ if (BitTst (&keytable, theCode)) { GetMacro (theCode, &flags, tmpstr); /* get the macrostring */ if (flags) { /* check special flags */ if (flags & shortBreak) { /* short break ? */ sendbreak (5); return; } if (flags & longBreak) { /* long break ? */ sendbreak (70); return; } } /* send key macro string */ /* * PWP: note, we DON'T have to convert it to a Pascal string, 'cause * the macros are now stored as Pascal strings */ writeps (tmpstr); /* send it to the line */ if (duplex != 0) printps (tmpstr); /* echo it locally */ return; } for (i = 0; i < NUMOFMODS; i++) { /* shift what to look for into high byte */ theModBits = modtable[i].modbits << 4; len = strlen (modtable[i].prefix); if ((theModBits || len) && ((theModBits & modCode) == (theModBits & keyModifierMask))) { /* send prefix if there is one */ if (len) { /* PWP: these are saved as Pascal strings now */ BlockMove (modtable[i].prefix, tmpstr, (modtable[i].prefix[0] + 1)); writeps (tmpstr); /* send it to the line */ if (duplex != 0) printps (tmpstr); /* echo it locally */ } /* * get the unmodified ASCII code if the unmodify action bit is * active */ if (theModBits & UnmodMask) c = DeModifyChar ((evt->message & myKeyCodeMask) >> 8); else c = evt->message & charCodeMask; /* otherwise get the * standard char */ /* make an uppercase character if the caps action bit is active */ if ((theModBits & CapsMask) && islower (c)) c = _toupper (c); /* make a control character if the control action bit is active */ if (theModBits & CtrlMask) c &= ctrlCodeMask; /* PWP: for Meta characters (yes, I use Emacs) */ if (theModBits & MetaMask) c |= metaOrBits; OutputChar (c); return; } /* if */ } /* for */ /* get the ASCII code and send it */ OutputChar (evt->message & charCodeMask); } /* handle_char */ char outbuf[MAXCOL + 1]; int outcnt = 0, outcol; /****************************************************************************/ /* flushbuf() -- draw all the buffered characters on the screen */ /****************************************************************************/ flushbuf () { Rect r; if (outcnt == 0) return; /* Nothing to flush */ /* Erase a hole large enough for outcnt chars */ makerect (&r, abslin, outcol, 1, outcnt); EraseRect (&r); /* (UoR) Use InvertRect instead of fillRect */ DrawText (outbuf, 0, outcnt); /* Output the string */ if (doinvert) /* PWP: moved this... */ InvertRect (&r); if (dounder) { /* PWP: do underlining */ makertou (&r); /* make into an underline */ InvertRect (&r); } outcnt = 0; /* Say no more chars to output */ } /* flushbuf */ /****************************************************************************/ /* save a character in the buffer */ /****************************************************************************/ buf_char (c) char c; { if (outcnt == 0) outcol = curcol; /* No chars in buffer, init column */ outbuf[outcnt++] = c; /* Put in the buffer to output later */ } /* buf_char */ /****************************************************************************/ /* * Printit: * Draws character and updates buffer */ /****************************************************************************/ printit (c) char c; { PFI funp, lookup (); long lnum1, lnum2; c &= 0177; if (c != 0) { /* (UoR) ignore null characters */ switch (charflg) { case CF_OUTC: /* Just output the char */ MDrawChar (c); break; case CF_SESC: /* In a single char escape seq */ charflg = CF_OUTC; /* Reset flag to simple outputting */ if (funp = lookup (c, singescapetable, MINSINGESCS, MAXSINGESCS)) (*funp) (); /* Do escape sequence function */ break; case CF_GRF0: /* (UoR) process graphic characters */ case CF_GRF1: switch (c) { case 'A': graphicsinset[charflg - CF_GRF0] = UK_SET; break; case 'B': case '1': graphicsinset[charflg - CF_GRF0] = USA_SET; break; case '0': case '2': graphicsinset[charflg - CF_GRF0] = GRAF_SET; break; } charflg = CF_OUTC; /* Reset flag for next character */ break; case CF_MESC: /* Multichar escape sequence */ if (c >= 0x20 && c < 0x40) { /* Deal with the modifiers */ if (c >= '<' && c <= '?') { prvchr = c; /* Handle priv char */ } else if ((numptr == numone || numptr == numtwo) && (c == '0' || c == '-' || c == '+')) { /* if at start of sequence */ if (c == '-') /* then we only record leading - */ *numptr++ = c; } else if (c >= '0' && c <= '9') { /* PWP: was also '+' or '-' */ *numptr++ = c; /* Add the char to the num */ } else if (c == ';') { *numptr = '\0'; /* Terminate the string */ numptr = numtwo; /* Go to next number */ } else { charflg = CF_OUTC; /* (UoR) */ } } else if (c >= 0x40) { /* End of sequence */ /* PWP: according to VTTEST, we ignore control characters here */ if (funp = lookup (c, escapetable, MINMULTESCS, MAXMULTESCS)) { *numptr = '\0'; /* Terminate the string */ StringToNum (numone, &lnum1); /* Translate the numbers */ StringToNum (numtwo, &lnum2); num1 = (int) lnum1; num2 = (int) lnum2; (*funp) (); /* Do the escape sequence function */ } charflg = CF_OUTC; /* Back to simple outputting */ } break; case CF_TOSS: /* Ignore this char */ charflg = CF_OUTC; /* Reset flag */ break; } } } /* printit */ /****************************************************************************/ /* * Routine makerect * * Make a rectangle in r starting on line lin and column col extending * numlin lines and numcol characters. * */ /****************************************************************************/ makerect (r, lin, col, numlin, numcol) Rect *r; int lin; int col; int numlin; int numcol; { r->top = lin * LINEHEIGHT + TOPMARGIN; r->left = col * CHARWIDTH + LEFTMARGIN; r->bottom = r->top + numlin * LINEHEIGHT; r->right = r->left + numcol * CHARWIDTH; } /* makerect */ /* Make rect r (made by makerect()) into the right shape for underlining */ makertou (r) Rect *r; { r->top = r->bottom - 1; } /****************************************************************************/ /* * Lookup: * Lookup a given character in the apropriate character table, and * return a pointer to the appropriate function, if it exists. */ /****************************************************************************/ PFI lookup (index, table, min, max) char index; PFI table[]; int min; int max; { if (index > max || index < min) return ((PFI) NULL); /* Don't index out of range */ return (table[index - min]); } /* lookup */ /****************************************************************************/ /* * Flushio: * Initialize some communications constants, and clear screen and * character buffers. */ /****************************************************************************/ flushio () { int err; err = KillIO (-6); if (err) printerr ("Bad input clear", err); err = KillIO (-7); if (err) printerr ("Bad ouput clear", err); } /* flushio */ /****************************************************************************/ /* sendbreak - sends a break across the communictions line. * * The argument is in units of approximately 0.05 seconds (or 50 * milliseconds). To send a break of duration 250 milliseconds the * argument would be 5; a break of duration 3.5 seconds would be (umm, * lets see now) 70. * */ /****************************************************************************/ sendbreak (msunit) { long finalticks; /* delay wants 1/60th units. We have 3/60 (50 ms.) units, convert */ msunit = msunit * 3; SerSetBrk (outnum); /* start breaking */ Delay ((long) msunit, &finalticks); /* delay */ SerClrBrk (outnum); /* stop breaking */ } /* sendbreak */ /****************************************************************************/ /* draw a characer on the screen (or buffer it) */ /****************************************************************************/ MDrawChar (chr) char chr; { PFI funp; /* If it's a control char, do the apropriate function. */ if ((chr < ' ') && (transparent)) { /* Is it a control character */ flushbuf (); if (funp = lookup (chr, controltable, MINSINGCMDS, MAXSINGCMDS)) { if (funp != dummy) {/* PWP */ (*funp) (); return; } } if (!nat_chars) /* PWP: half transparent -- show undefd * controls */ return; if (chr == '\0') /* PWP: never show nulls */ return; } if (chr < 0177) { /* Don't do Mac graphic characters */ switch (graphicsinset[current_set]) { case GRAF_SET: /* Do VT100 graphics (offset to character in * VT100 font) */ if ((chr >= '_') && (chr <= '~')) chr += 128; break; case UK_SET: /* Use pound symbol from VT100 font */ if (chr == '#') chr = 0375; /* VT100 pound symbol = 0375 */ break; } if (curcol >= MAXCOL) { /* Are we about to wrap around? */ if (autowrap) { /* If autowrap indicated wrap */ flushbuf (); if (newline == FALSE) carriage_return (); line_feed (); } else { flushbuf (); /* (UoR) make sure last char is shown */ back_space (); /* Otherwise just overwrite */ } } if (insert) { /* Insert mode? */ insert_char (); /* Open hole for char if requested */ erase_char (); /* Erase the old char */ DrawChar (chr); } else buf_char (chr); /* Otherwise just buffer the char */ scr[curlin][curcol++] = chr; } } /* MDrawChar */ /****************************************************************************/ /* * Control character functions: * Each of the following allow the mac to simulate * the behavior of a terminal when given the proper * control character. */ /****************************************************************************/ back_space () { if (curcol > 0) relmove (-1, 0); } /* back_space */ erase_char () { Rect r; scr[curlin][curcol] = ' '; /* Erase char for update */ makerect (&r, abslin, curcol, 1, 1); /* One char by one line */ EraseRect (&r); /* (UoR) use InvertRect instead of FillRect */ if (doinvert) InvertRect (&r); } /* erase_char */ tab () { int i; /* for (i=0; i curcol) { absmove(tabstops[i],abslin); return; } * }*/ /* (UoR) remove old method of tabbing */ /* (UoR) find next tabstop */ for (i = curcol + 1; (i < MAXCOL) && (tabstops[i] == 0); i++); absmove (i, abslin); } /* tab */ line_feed () { if (newline) absmove (0, abslin); /* (UoR) perform newline function */ if (curlin == scrbot) scroll_up (scrtop, curlin); /* (UoR) scroll lines up */ else relmove (0, 1); } /* line_feed */ reverse_line_feed () { if (curlin == scrtop) scroll_down (curlin, scrbot); /* (UoR) scroll down in region */ else relmove (0, -1); } /* reverse_line_feed */ carriage_return () { if (newline) line_feed (); /* (UoR) perform newline function */ else absmove (0, abslin); } /* carriage_return */ new_line () { carriage_return (); line_feed (); } /* new_line */ clear_screen () { register int i; Rect r; makerect (&r, 0, 0, MAXLIN, MAXCOL); /* The whole screen */ EraseRect (&r); for (i = 0; i < MAXLIN; i++) zeroline (i); /* Clear up the update records */ } /* clear_screen */ home_cursor () { if (relorigin) absmove (0, fndabs (scrtop)); else absmove (0, 0); /* (UoR) correct for relative origin */ } /* home_cursor */ /****************************************************************************/ /* PWP -- like waitasec(), but don't get any characters. Used for visable bell. */ /****************************************************************************/ waitnoinput () { long end_time; end_time = TickCount () + 2;/* pause for 1/30th second */ while (TickCount () < end_time); } /* waitnoinput */ bell () { Rect r; if (visible_bell) { makerect (&r, 0, 0, MAXLIN, MAXCOL); /* The whole screen */ InvertRect (&r); waitnoinput (); /* sleep for a bit (1/30 sec) */ InvertRect (&r); } else { SysBeep (3); } } /* bell */ escape_seq () { charflg = CF_SESC; /* Say we are in an escape sequence */ } /* escape_seq */ graphic_G0 () /* (UoR) do VT100 graphic characters */ { charflg = CF_GRF0; } /* graphic_G0 */ graphic_G1 () { charflg = CF_GRF1; } /* graphic_G1 */ control_N () { current_set = 1; /* set to graphics set 1 */ } /* control_N */ control_O () { current_set = 0; /* set to graphics set 0 */ } /* control_O */ clear_line () { int i; Rect r; switch (num1) { case 0: /* Clear: here to the right */ makerect (&r, abslin, curcol, 1, MAXCOL - curcol); for (i = curcol; i < MAXCOL; i++) scr[curlin][i] = ' '; break; case 1: /* Clear: left to here */ makerect (&r, abslin, 0, 1, curcol + 1); for (i = 0; i <= curcol; i++) scr[curlin][i] = ' '; break; case 2: /* Clear: entire line */ makerect (&r, abslin, 0, 1, MAXCOL); zeroline (curlin); break; } EraseRect (&r); } /* clear_line */ erase_display () { int i; Rect r; switch (num1) { case 0: clear_line (); /* Same num1 causes correct clear */ makerect (&r, abslin + 1, 0, MAXLIN - abslin - 1, MAXCOL); /* (UoR) -1 added */ EraseRect (&r); for (i = abslin + 1; i < MAXLIN; i++) zeroline (fndrel (i)); break; case 1: clear_line (); /* Same num1 causes correct clear */ makerect (&r, 0, 0, abslin, MAXCOL); EraseRect (&r); for (i = 0; i < abslin; i++) zeroline (fndrel (i)); break; case 2: clear_screen (); break; } } /* erase_display */ /****************************************************************************/ /**** All cursor moves need to check that they don't go beyond the margins */ /****************************************************************************/ cursor_right () { if (num1 == 0) num1 = 1; relmove (num1, 0); } /* cursor_right */ cursor_left () { if (num1 == 0) num1 = 1; relmove (-num1, 0); } /* cursor_left */ cursor_up () { int abstop; /* (UoR) check that we don't pass scrtop */ abstop = fndabs (scrtop); if (num1 == 0) num1 = 1; if ((abslin >= abstop) && (abslin - num1 < abstop)) absmove (curcol, abstop); else relmove (0, -num1); } /* cursor_up */ cursor_down () { int absbot; /* (UoR) check that we don't pass scrbot */ absbot = fndabs (scrbot); if (num1 == 0) num1 = 1; if ((abslin <= absbot) && (abslin + num1 > absbot)) absmove (curcol, absbot); else relmove (0, num1); } /* cursor_down */ cursor_position () { /* if (--num1 < 0) num1 = 0; * if (--num2 < 0) num2 = 0; *//* This is taken care of by absmove */ if (relorigin) absmove (--num2, fndabs (scrtop) + num1 - 1); /* (UoR) */ else absmove (--num2, --num1); /* (UoR) moved "--" here from prev * lines */ } /* cursor_position */ cursor_save () { savcol = curcol; /* Save the current line and column */ savlin = abslin; /* savsty = textstyle; *//* (UoR) additions */ savfnt = currentfont; savmod = doinvert; savund = dounder; /* PWP */ savgrf = current_set; savset[0] = graphicsinset[0]; savset[1] = graphicsinset[1]; } /* cursor_save */ cursor_restore () { absmove (savcol, savlin); /* Move to the old cursor position */ textstyle = savsty; /* (UoR) additions */ currentfont = savfnt; doinvert = savmod; TextFont (currentfont); /* TextFace(textstyle); */ dounder = savund; /* PWP */ current_set = savgrf; graphicsinset[0] = savset[0]; graphicsinset[1] = savset[1]; } /* cursor_restore */ cursor_rect (line, col, r) Rect *r; { makerect (r, line, col, 1, 1); /* Get character rectangle */ if (blockcursor) { /* r->left--; *//* make r a little wider (PWP: or not) */ /* r->top--; */ } else r->top = r->bottom - 1; } /* cursor_rect */ cursor_draw () { /* Line(CHARWIDTH,0);*//* Draw cursor */ Rect r; if (cursor_invert == FALSE) { cursor_rect (abslin, curcol, &r); InvertRect (&r); } if (oldlin >= 0) { /* (UoR) replace mouse cursor */ cursor_rect (oldlin, oldcol, &r); PenMode (patXor); FrameRect (&r); PenMode (patCopy); } cursor_invert = TRUE; cur_drawn = TRUE; } /* cursor_draw */ cursor_erase () { /* Line(-CHARWIDTH,0);*//* Erase cursor */ Rect r; if (cursor_invert) { cursor_rect (abslin, curcol, &r); InvertRect (&r); } if (oldlin >= 0) { /* (UoR) remove mouse cursor */ makerect (&r, oldlin, oldcol, 1, 1); cursor_rect (oldlin, oldcol, &r); PenMode (patXor); FrameRect (&r); PenMode (patCopy); } cursor_invert = FALSE; cur_drawn = FALSE; } /* cursor_erase */ flash_cursor (theWindow) WindowPtr theWindow; { register long tc; Rect r; if (theWindow == (WindowPtr) NIL) { last_flash = TickCount (); return; } #ifdef COMMENT /* PWP: this eats up gobbs of time */ if (FrontWindow () != theWindow) { last_flash = TickCount (); return; } #endif tc = TickCount (); if (((tc - last_flash) > CARETTIME) || (tc - last_flash) < 0) { last_flash = tc; if (cur_drawn) { cursor_rect (abslin, curcol, &r); if (blinkcursor) { /* PWP: only blink if asked for */ InvertRect (&r); if (cursor_invert) cursor_invert = FALSE; else cursor_invert = TRUE; } else if (!cursor_invert) { /* make sure that the cursor * shows up */ InvertRect (&r); cursor_invert = TRUE; } } } } /* flash_cursor */ /****************************************************************************/ /* Bittest returns the setting of an element in a Pascal PACKED ARRAY [0..n] OF Boolean such as the KeyMap argument returned by GetKeys(). */ /****************************************************************************/ Boolean bittest (bitmap, bitnum) char bitmap[]; int bitnum; { return (0x01 & (bitmap[bitnum / 8] >> (bitnum % 8))); } /* bittest */ /****************************************************************************/ /* check to see if the cursor is in the window and is going to send a mouse- arrow keys combination */ /****************************************************************************/ check_pointer (theWindow) WindowPtr theWindow; { Boolean mouse_in_window; int newlin; int newcol; Point MousePt; Rect r; /* * PWP: NOTE!!! since the common case is to do nothing, we do NOT want to * have the PenMode() calls outside of the tests. We will be only doing * one or the other anyway, so it won't slow us down any. */ GetMouse (&MousePt); mouse_in_window = PtInRect (&MousePt, &ScreenRect); newlin = (MousePt.v - TOPMARGIN) / LINEHEIGHT; newcol = (MousePt.h - LEFTMARGIN) / CHARWIDTH; if ((FrontWindow () == theWindow) && (mouse_in_window) && (cur_drawn) && (mouse_arrows) && Button ()) { PenMode (patXor); /* For FrameRect calls */ if ((oldlin != newlin) || (oldcol != newcol)) { if (oldlin >= 0) { cursor_rect (oldlin, oldcol, &r); FrameRect (&r); } else HideCursor (); cursor_rect (newlin, newcol, &r); FrameRect (&r); oldlin = newlin; oldcol = newcol; } PenMode (patCopy); /* reset to normal pen mode */ } if (oldlin >= 0) { /* optomize: easy tests first */ if ((FrontWindow () != theWindow) || (!mouse_in_window) || (!cur_drawn) || (!mouse_arrows) || (!Button ())) { PenMode (patXor); /* For FrameRect calls */ cursor_rect (oldlin, oldcol, &r); FrameRect (&r); oldlin = -1; InitCursor (); /* show the arrow cursor immediately */ /* (reset crsr level) */ PenMode (patCopy); /* reset to normal pen mode */ } } } /* check_pointer */ mouse_cursor_move (evt) EventRecord *evt; { int mouselin; int mousecol; int tempcol; int templin; int i; Point MousePt; if (!mouse_arrows) /* PWP: make this an option */ return; MousePt = evt->where; GlobalToLocal (&MousePt); mouselin = (MousePt.v - TOPMARGIN) / LINEHEIGHT; mousecol = (MousePt.h - LEFTMARGIN) / CHARWIDTH; tempcol = curcol; templin = abslin; if (mousecol < tempcol) for (i = tempcol; i > mousecol; i--) { writeps (leftARROW); waitasec (); /* If tabs are used, we may go too far, so end loop */ if (curcol <= mousecol) i = mousecol; } if (mouselin < templin) for (i = templin; i > mouselin; i--) { writeps (UPARROW); waitasec (); } else if (mouselin > templin) for (i = templin; i < mouselin; i++) { writeps (DOWNARROW); waitasec (); } if (abslin == mouselin) tempcol = curcol; /* for short lines */ if (tempcol < mousecol) for (i = tempcol; i < mousecol; i++) { writeps (rightARROW); waitasec (); /* If tabs are used, we may go too far, so end loop */ if (curcol >= mousecol) i = mousecol; } } /* mouse_cursor_move */ /****************************************************************************/ /* (UoR) get any characters, and pause for a while */ /****************************************************************************/ waitasec () { long end_time; end_time = TickCount () + 2;/* pause for 1/30th second */ while (TickCount () < end_time); inpchars (); } /* waitasec */ set_scroll_region () { if (--num1 < 0) num1 = 0; /* Make top of line (prev line) */ if (num2 == 0) num2 = 24; /* Zero means entire screen */ if (num1 < num2 - 1) { /* (UoR) make sure region is legal */ topmargin = (num1 * LINEHEIGHT) + TOPMARGIN; bottommargin = (num2 * LINEHEIGHT) + TOPMARGIN; scrtop = fndrel (num1); scrbot = fndrel (num2 - 1); home_cursor (); /* We're supposed to home it! */ } } /* set_scroll_region */ /****************************************************************************/ /* aka Select Graphic Rendition */ /****************************************************************************/ text_mode () { another: switch (num1) { case 0: /* primary rendition */ doinvert = FALSE; TextFont (VT100FONT); /* (Uor) Use plain font */ currentfont = VT100FONT; dounder = FALSE; /* textstyle=0; TextFace(0); */ break; case 1: /* bold or increased intensity */ TextFont (VT100BOLD); /* use bold font instead */ currentfont = VT100BOLD; break; case 2: /* faint or decreased intensity or secondary * color */ case 3: /* italic */ case 4: /* underscore */ /* textstyle+=underline; *//* use = not += (avoid roll-over) */ /* textstyle = underline; /* (UoR) */ /* TextFace(textstyle); */ dounder = TRUE; break; case 5: /* slow blink (< 150/sec); (UoR) blink is * inverse */ case 6: /* fast blink (>= 150/sec) */ case 7: /* reverse image */ doinvert = TRUE; break; case 21: case 22: TextFont (VT100FONT); /* reset to plain font */ currentfont = VT100FONT; break; case 24: /* TextFace(0); /* just reset to plain style */ /* since bolding is done via a separate font */ /* textstyle = 0; */ dounder = FALSE; break; case 25: case 27: doinvert = FALSE; break; } if (num2 != 0) { /* Check for funny VAXTPU syntax. */ num1 = num2; num2 = 0; goto another; } } /* text_mode */ /****************************************************************************/ /* * (UoR) * * Insert and Delete lines (replacements for originals, which have * which have been deleted) * */ /****************************************************************************/ insert_line () { int i, absbot; absbot = fndabs (scrbot); if ((abslin >= fndabs (scrtop)) && (abslin <= absbot)) { if (num1 == 0) num1 = 1; if (num1 > absbot - abslin + 1) num1 = absbot - abslin + 1; for (i = 0; i < num1; i++) scroll_down (curlin, scrbot); } } /* insert_line */ delete_line () { int i, absbot; absbot = fndabs (scrbot); if ((abslin >= fndabs (scrtop)) && (abslin <= absbot)) { if (num1 == 0) num1 = 1; if (num1 > absbot - abslin + 1) num1 = absbot - abslin + 1; for (i = 0; i < num1; i++) scroll_up (curlin, scrbot); } } /* delete_line */ delete_char () { int i; Rect r; if (num1 == 0) num1 = 1; makerect (&r, abslin, curcol, 1, MAXCOL - curcol); if (num1 > MAXCOL - curcol - 1) num1 = MAXCOL - curcol - 1; /* Scroll them out */ ScrollRect (&r, -CHARWIDTH * num1, 0, dummyRgn); /* Shift them down *//* (UoR) used to assign using abscol */ for (i = curcol; i < MAXCOL - num1; i++) scr[curlin][i] = scr[curlin][i + num1]; /* Fill in holes with spaces */ while (i < MAXCOL) scr[curlin][i++] = ' '; } /* delete_char */ /****************************************************************************/ /* CME */ /****************************************************************************/ insert_chars () { int i; Rect r; if (num1 == 0) num1 = 1; makerect (&r, abslin, curcol, 1, MAXCOL - curcol); if (num1 > MAXCOL - curcol - 1) num1 = MAXCOL - curcol - 1; /* Scroll them out */ ScrollRect (&r, CHARWIDTH * num1, 0, dummyRgn); /* Shift them up *//* (UoR) used to assign using abscol */ for (i = MAXCOL - 1; i >= curcol + num1; i--) scr[curlin][i] = scr[curlin][i - num1]; /* Fill in holes with spaces */ while (i > curcol) scr[curlin][--i] = ' '; } /* delete_char */ insert_char () { int i; Rect r; makerect (&r, abslin, curcol, 1, MAXCOL - curcol); ScrollRect (&r, CHARWIDTH, 0, dummyRgn); /* Shift em up *//* (UoR) used to assign ...[i-1]=...[i] */ /* (UoR) used to assign using abscol */ for (i = MAXCOL - 1; i > curcol; i--) scr[curlin][i] = scr[curlin][i - 1]; scr[curlin][curcol] = ' '; } /* insert_char */ insert_mode () { if (prvchr == '?') set_mode (); /* (UoR) do some of these calls */ switch (num1) { case 20: newline = TRUE; break; case 4: insert = TRUE; break; } } /* insert_mode */ end_insert_mode () { if (prvchr == '?') reset_mode (); /* (UoR) do some of these calls */ switch (num1) { case 20: newline = FALSE; break; case 4: insert = FALSE; break; } } /* end_insert_mode */ invert_term () { num1 = 5; if (screeninvert) reset_mode (); else set_mode (); } /* invert_term */ set_mode () { Rect r; switch (num1) { case 5: if (screeninvert == FALSE) { BackPat (qd.black); /* (UoR) use black background */ makerect (&r, 0, 0, MAXLIN, MAXCOL); InvertRect (&r); screeninvert = TRUE; } break; case 6: relorigin = TRUE; home_cursor (); break; case 7: autowrap = TRUE; break; case 8: autorepeat = TRUE; break; } } /* set_mode */ reset_mode () { Rect r; switch (num1) { case 5: if (screeninvert) { BackPat (qd.white); makerect (&r, 0, 0, MAXLIN, MAXCOL); InvertRect (&r); screeninvert = FALSE; } break; case 6: relorigin = FALSE; home_cursor (); break; case 7: autowrap = FALSE; break; case 8: autorepeat = FALSE; break; } } /* reset_mode */ set_tab () { tabstops[curcol] = 1; } /* set_tab */ clear_tab () { int i; switch (num1) { case 0: tabstops[curcol] = 0; break; case 3: for (i = 0; i < MAXCOL; i++) tabstops[i] = 0; break; } } /* clear_tab */ /****************************************************************************/ /* (UoR) use for respoding to information requests */ /****************************************************************************/ writereply (s) char *s; { long wrcnt, w2; int err; char *s2; w2 = wrcnt = strlen (s); /* How long is the string? */ for (s2 = s; w2 > 0; w2--, s2++) /* add parity */ *s2 = dopar (*s2); err = FSWrite (outnum, &wrcnt, s); /* Respond to the query */ if (err) printerr ("Bad Writeout:", err); } /* writereply */ query_terminal () { writereply (querystring); } /* query_terminal */ /****************************************************************************/ /* (UoR) reports */ /****************************************************************************/ request_report () { switch (num1) { case 5: /* (UoR) report that we're OK */ writereply (reportstring); break; case 6: /* (UoR) reprt the cursor position */ position_report (); break; case 15: /* (UoR) report printer status */ if (prvchr == '?') writereply (noprinter); break; } } /* request_report */ position_report () { int i; char buf[9]; char *report; i = 0; buf[i++] = '\033'; buf[i++] = '['; if (abslin > 9) buf[i++] = '0' + (abslin + 1) / 10; buf[i++] = '0' + (abslin + 1) % 10; buf[i++] = ';'; if (curcol > 9) buf[i++] = '0' + (curcol + 1) / 10; buf[i++] = '0' + (curcol + 1) % 10; buf[i++] = 'R'; buf[i] = '\0'; report = buf; writereply (report); } /* position_report */ /****************************************************************************/ /* does nothing. */ /****************************************************************************/ dummy () { } /* dummy */ multi_char () { numone[0] = numtwo[0] = '0';/* Initialize the numbers to zero */ numone[1] = numtwo[1] = '\0'; numptr = numone; /* Place to put the next number */ prvchr = '\0'; /* No priv char yet */ charflg = CF_MESC; /* Say we are in a ESC [ swequence */ } /* multi_char */ toss_char () { charflg = CF_TOSS; } /* toss_char */ /****************************************************************************/ /* Routine zeroline * * Zero (set to space) all the characters in relative line lin. * */ /****************************************************************************/ zeroline (lin) int lin; { register int i; Rect r; for (i = 0; i < MAXCOL; i++) scr[lin][i] = ' '; } /* zeroline */ /****************************************************************************/ /* Move a relative number of lines and chars. Both can be negative. */ /****************************************************************************/ relmove (hor, ver) { absmove (curcol + hor, abslin + ver); /* (UoR) use absmove, which * checks */ /* for cursor moving off screen */ } /* relmove */ /****************************************************************************/ /* Move to absolute position hor char and ver line. */ /****************************************************************************/ absmove (hor, ver) { if (hor > MAXCOL - 1) hor = MAXCOL - 1; /* (UoR) make sure its on the screen */ if (hor < 0) hor = 0; if (ver > MAXLIN - 1) ver = MAXLIN - 1; if (ver < 0) ver = 0; if (relorigin) { if (ver < fndabs (scrtop)) ver = fndabs (scrtop); if (ver > fndabs (scrbot)) ver = fndabs (scrbot); } MoveTo (hor * CHARWIDTH + LEFTMARGIN, (ver + 1) * LINEHEIGHT + TOPMARGIN - LINEADJ); curcol = hor; abslin = ver; curlin = fndrel (ver); } /* absmove */ /****************************************************************************/ /* dump the whole screen to the session log file */ /****************************************************************************/ scrtolog () { int lin, i; lin = toplin; for (i = 0; i < MAXLIN; i++) { slog (scr[lin], MAXCOL);/* write this line to session log */ lin = nxtlin[lin]; } } /* scrtolog */ /****************************************************************************/ /* * (UoR) * * Scroll lines within the scroll region upwards from line tlin * to line blin (lines are assumed to be in the region) * */ /****************************************************************************/ scroll_up (tlin, blin) int tlin; int blin; { register int i, now; int newtop; int abstop; Rect r; GrafPtr currWindow; abstop = fndabs (tlin); makerect (&r, abstop, 0, fndabs (blin) - abstop + 1, MAXCOL); ObscureCursor (); /* compensate update region for scrolling */ GetPort (&currWindow); OffsetRgn ((WindowPeek) currWindow->updateRgn, 0, -LINEHEIGHT); /* do the scrolling */ if (smoothscroll) { for (i = 1; i <= LINEHEIGHT; i += 2) { /* PWP: wait for a vertical reblank (in a sneaky way) */ now = TickCount (); while (TickCount () == now) /* wait... */ ; ScrollRect (&r, 0, -2, dummyRgn); } } else { ScrollRect (&r, 0, -LINEHEIGHT, dummyRgn); } if (tlin == blin) { /* if only one line, just clear it */ zeroline (blin); return; } newtop = nxtlin[tlin]; /* new top line */ if (tlin == scrtop) scrtop = newtop; /* reset scrtop, if needed */ if (tlin == toplin) toplin = newtop; /* reset toplin, if needed */ else nxtlin[fndprv (tlin)] = newtop; /* else de-link tlin line */ nxtlin[tlin] = nxtlin[blin];/* link tlin in after blin */ nxtlin[blin] = tlin; if (blin == scrbot) { /* reset pointers to bottom of regions */ if (blin == botlin) botlin = tlin; scrbot = tlin; } if (seslog) /* if logging is active then */ slog (scr[tlin], MAXCOL); /* write line to session log */ zeroline (tlin); /* clear the line */ curlin = fndrel (abslin); } /* scroll_up */ /****************************************************************************/ /* (UoR) Scroll lines in scroll region down from line tlin to */ /* line blin (lines are assumed to be within the scroll region) */ /****************************************************************************/ scroll_down (tlin, blin) int tlin; int blin; { int i; int abstop; int newbot; Rect r; GrafPtr currWindow; abstop = fndabs (tlin); makerect (&r, abstop, 0, fndabs (blin) - abstop + 1, MAXCOL); ObscureCursor (); /* compensate update region for scrolling */ GetPort (&currWindow); OffsetRgn ((WindowPeek) currWindow->updateRgn, 0, LINEHEIGHT); /* do the scrolling */ if (smoothscroll) for (i = 1; i <= LINEHEIGHT; i += 2) ScrollRect (&r, 0, 2, dummyRgn); else ScrollRect (&r, 0, LINEHEIGHT, dummyRgn); if (tlin == blin) { /* if only one line, just clear it */ zeroline (tlin); return; } newbot = fndprv (blin); /* new bottom line */ if (tlin == scrtop) scrtop = blin; /* reset scrtop, if needed */ if (tlin == toplin) toplin = blin; /* reset toplin, if needed */ else nxtlin[fndprv (tlin)] = blin; /* else de-link top line */ nxtlin[newbot] = nxtlin[blin]; /* link blin above tlin */ nxtlin[blin] = tlin; if (blin == scrbot) { /* reset bottom of region pointers */ if (blin == botlin) botlin = newbot; scrbot = newbot; } zeroline (blin); curlin = fndrel (abslin); } /* scroll_down */ /****************************************************************************/ /* * Find the relative line number given the absolute one. * */ /****************************************************************************/ fndrel (linum) int linum; { register int i, lin; lin = toplin; for (i = 0; i < linum; i++) lin = nxtlin[lin]; return (lin); } /* fndrel */ /****************************************************************************/ /* * Find the absolute line number given the relative one. * */ /****************************************************************************/ fndabs (linum) int linum; { int i, lin; lin = toplin; i = 0; while (lin != linum) { i++; lin = nxtlin[lin]; } return (i); } /* fndabs */ /****************************************************************************/ /* * Find the previous relative line number from relative line linum. * */ /****************************************************************************/ fndprv (linum) int linum; { int lin; lin = toplin; while (nxtlin[lin] != linum) lin = nxtlin[lin]; return (lin); } /* fndprv */ /****************************************************************************/ /* redraw the terminal screen (we got a redraw event) */ /****************************************************************************/ term_redraw () { int i, lin; Rect r; makerect (&r, 0, 0, MAXLIN, MAXCOL); /* PWP: clear the screen first */ EraseRect (&r); lin = toplin; for (i = 0; i < MAXLIN; i++) { MoveTo (LEFTMARGIN, (i + 1) * LINEHEIGHT + TOPMARGIN - LINEADJ); DrawString (scr[lin]); #ifdef COMMENT if (screeninvert) { /* (UoR) refresh screen in invert mode */ makerect (&r, i, 0, 1, MAXCOL); InvertRect (&r); /* PWP: was Erase, but that does no good */ } #endif lin = nxtlin[lin]; } MoveTo (curcol * CHARWIDTH + LEFTMARGIN, (abslin + 1) * LINEHEIGHT + TOPMARGIN - LINEADJ); if (cur_drawn && cursor_invert) { /* (UoR) only if cursor is showing */ cursor_invert = FALSE; /* (UoR) make sure we draw it */ cursor_draw (); /* redraw cursor */ last_flash = TickCount (); /* (UoR) reset timer */ } } /* term_redraw */ /****************************************************************************/ /* initalize the terminal emulator. */ /****************************************************************************/ init_term () { int i; for (i = 0; i < MAXLIN; i++) { nxtlin[i] = i + 1; /* Tie together the linked list */ scr[i][MAXCOL] = '\0'; /* Terminate the lines as strings */ } toplin = 0; /* Initialize the top and bottom ptr */ botlin = MAXLIN - 1; scrtop = toplin; /* Scrolling region equals all */ scrbot = botlin; nxtlin[botlin] = -1; /* Indicate this is the end */ makerect (&ScreenRect, 0, 0, MAXLIN, MAXCOL); /* (UoR) full screen rectangle */ } /* init_term */