diff options
| author | Charles Forsyth <charles.forsyth@gmail.com> | 2015-04-29 15:19:07 +0100 |
|---|---|---|
| committer | Charles Forsyth <charles.forsyth@gmail.com> | 2015-04-29 15:19:07 +0100 |
| commit | c714c442442ef137f20ca4ff9707d5480cb9ba7a (patch) | |
| tree | d0d285f05cb4292fa8f1f3c0bc70bec1251e956e /appl/wm/minitel/screen.b | |
| parent | 1ac9729e9325d84db36c04b5cda3b5b1bc0d041f (diff) | |
remove obsolete minitel, but leave source as example
Diffstat (limited to 'appl/wm/minitel/screen.b')
| -rw-r--r-- | appl/wm/minitel/screen.b | 1610 |
1 files changed, 0 insertions, 1610 deletions
diff --git a/appl/wm/minitel/screen.b b/appl/wm/minitel/screen.b deleted file mode 100644 index 4313d48d..00000000 --- a/appl/wm/minitel/screen.b +++ /dev/null @@ -1,1610 +0,0 @@ -# -# Occasional references are made to sections and tables in the -# France Telecom Minitel specification -# -# Copyright © 1998 Vita Nuova Limited. All rights reserved. -# - -include "mdisplay.m"; - -disp: MDisplay; - -Rect, Point : import Draw; - -# display character sets -videotex, semigraphic, french, american :import MDisplay; - -# display foreground colour attributes -fgBlack, fgBlue, fgRed, fgMagenta, -fgGreen, fgCyan, fgYellow, fgWhite :import MDisplay; - -# display background colour attributes -bgBlack, bgBlue, bgRed, bgMagenta, -bgGreen, bgCyan, bgYellow, bgWhite :import MDisplay; - -fgMask, bgMask : import MDisplay; - -# display formatting attributes -attrB, attrW, attrH, attrP, attrF, attrC, attrL, attrD :import MDisplay; - -# Initial attributes - white on black -ATTR0: con fgWhite|bgBlack&~(attrB|attrW|attrH|attrP|attrF|attrC|attrL|attrD); - -# special features -Cursor, Scroll, Insert - : con (1 << iota); - -# Screen states -Sstart, Sss2, Sesc, Srepeat, Saccent, Scsi0, Scsi1, Sus0, Sus1, Sskip, -Siso2022, Siso6429, Stransparent, Sdrcs, Sconceal, Swaitfor - : con iota; - -# Filter states -FSstart, FSesc, FSsep, FS6429, FS2022: con iota; - -Screen: adt { - m: ref Module; # common attributes - ctxt: ref Draw->Context; - in: chan of ref Event; # from the terminal - - image: ref Draw->Image; # Mdisplay image - dispr40, dispr80: Rect; # 40 and 80 column display region - oldtmode: int; # old terminal mode - rows: int; # number of screen rows (25 for minitel) - cols: int; # number of screen cols (40 or 80) - cset: int; # current display charset - - pos: Point; # current writing position (x:1, y:0) - attr: int; # display attribute set - spec: int; # special features - savepos: Point; # `pos' before moving to row zero - saveattr: int; # `attr' before moving to row zero - savech: int; # last character `Put' - delimit: int; # attr changed, make next space a delimiter - cursor: int; # update cursor soon - - state: int; # recogniser state - a0: int; # recogniser arg 0 - a1: int; # recogniser arg 1 - - fstate: int; # filter state - fsaved: array of byte; # filter `chars so far' - badp: int; # filter because of bad parameter - - ignoredata: int; # ignore data from - - init: fn(s: self ref Screen, ctxt: ref Draw->Context, r40, r80: Rect); - reset: fn(s: self ref Screen); - run: fn(s: self ref Screen); - quit: fn(s: self ref Screen); - setmode: fn(s: self ref Screen, tmode: int); - runstate: fn(s: self ref Screen, data: array of byte); - put: fn(s: self ref Screen, str: string); - msg: fn(s: self ref Screen, str: string); -}; - -Screen.init(s: self ref Screen, ctxt: ref Draw->Context, r40, r80: Rect) -{ - disp = load MDisplay MDisplay->PATH; - if(disp == nil) - fatal("can't load the display module: "+MDisplay->PATH); - - s.m = ref Module(0, 0); - s.ctxt = ctxt; - s.dispr40 = r40; - s.dispr80 = r80; - s.oldtmode = -1; - s.in = chan of ref Event; - disp->Init(s.ctxt); - s.reset(); - s.pos = Point(1, 1); - s.savech = 0; - s.cursor = 1; - s.ignoredata = 0; - s.fstate = FSstart; -} - -Screen.reset(s: self ref Screen) -{ - s.setmode(T.mode); - indicators(s); - s.state = Sstart; -} - -Screen.run(s: self ref Screen) -{ -Runloop: - for(;;) alt { - ev := <- s.in => - pick e := ev { - Equit => - break Runloop; - Eproto => - case e.cmd { - Creset => - s.reset(); - Cproto => - case e.a0 { - START => - case e.a1 { - SCROLLING => - s.spec |= Scroll; - } - STOP => - case e.a1 { - SCROLLING => - s.spec &= ~Scroll; - } - MIXED => - case e.a1 { - MIXED1 => # videotex -> mixed - if(T.mode != Mixed) - s.setmode(Mixed); - T.mode = Mixed; - MIXED2 => # mixed -> videotex - if(T.mode != Videotex) - s.setmode(Videotex); - T.mode = Videotex; - } - } - Ccursor => # update the cursor soon - s.cursor = 1; - Cindicators => - indicators(s); - Cscreenoff => - s.ignoredata = 1; - s.state = Sstart; - Cscreenon => - s.ignoredata = 0; - * => break; - } - Edata => - if(s.ignoredata) - continue; - oldpos := s.pos; - oldspec := s.spec; - da := filter(s, e.data); - while(len da > 0) { - s.runstate(da[0]); - da = da[1:]; - } - - if(s.pos.x != oldpos.x || s.pos.y != oldpos.y || (s.spec&Cursor)^(oldspec&Cursor)) - s.cursor = 1; - if(s.cursor) { - if(s.spec & Cursor) - disp->Cursor(s.pos); - else - disp->Cursor(Point(-1,-1)); - s.cursor = 0; - refresh(); - } else if(e.from == Mkeyb) - refresh(); - } - } - send(nil); -} - -# row0 indicators (1.2.2) -indicators(s: ref Screen) -{ - col: int; - ch: string; - - attr := fgWhite|bgBlack; - case T.state { - Local => - ch = "F"; - Connecting => - ch = "C"; - attr |= attrF; - Online => - ch = "C"; - } - if(s.cols == 40) { - col = 39; - attr |= attrP; - } else - col = 77; - disp->Put(ch, Point(col, 0), videotex, attr, 0); -} - -Screen.setmode(s: self ref Screen, tmode: int) -{ - dispr: Rect; - delims: int; - ulheight: int; - s.rows = 25; - s.spec = 0; - s.attr = s.saveattr = ATTR0; - s.delimit = 0; - s.pos = s.savepos = Point(-1, -1); - s.cursor = 1; - case tmode { - Videotex => - s.cset = videotex; - s.cols = 40; - dispr = s.dispr40; - delims = 1; - ulheight = 2; - s.pos = Point(1,1); - s.spec &= ~Cursor; - Mixed => -# s.cset = french; - s.cset = videotex; - s.cols = 80; - dispr = s.dispr80; - delims = 0; - ulheight = 1; - s.spec |= Scroll; - s.pos = Point(1, 1); - Ascii => - s.cset = french; - s.cols = 80; - dispr = s.dispr80; - delims = 0; - ulheight = 1; - }; - if(tmode != s.oldtmode) { - (nil, s.image) = disp->Mode(((0,0),(0,0)), 0, 0, 0, 0, nil); - T.layout(s.cols); - fontpath := sprint("/fonts/minitel/f%dx%d", s.cols, s.rows); - (nil, s.image) = disp->Mode(dispr, s.cols, s.rows, ulheight, delims, fontpath); - T.setkbmode(tmode); - } - disp->Reveal(0); # concealing enabled (1.2.2) - disp->Cursor(Point(-1,-1)); - s.oldtmode = tmode; -} - -Screen.quit(nil: self ref Screen) -{ - disp->Quit(); -} - -Screen.runstate(s: self ref Screen, data: array of byte) -{ - while(len data > 0) - case T.mode { - Videotex => - data = vstate(s, data); - Mixed => - data = mstate(s, data); - Ascii => - data = astate(s, data); - }; -} - -# process a byte from set C0 -vc0(s: ref Screen, ch: int) -{ - case ch { -# SOH => # not in spec, wait for 16r04 -# s.a0 = 16r04; -# s.state = Swaitfor; - SS2 => - s.state = Sss2; - SYN => - s.state = Sss2; # not in the spec, but acts like SS2 - ESC => - s.state = Sesc; - SO => - s.cset = semigraphic; - s.attr &= ~(attrH|attrW|attrP); # 1.2.4.2 - s.attr &= ~attrL; # 1.2.4.3 - SI => - s.cset = videotex; - s.attr &= ~attrL; # 1.2.4.3 - s.attr &= ~(attrH|attrW|attrP); # some servers seem to assume this too - SEP or SS3 => # 1.2.7 - s.state = Sskip; - BS => - if(s.pos.x == 1) { - if(s.pos.y == 0) - break; - if(s.pos.y == 1) - s.pos.y = s.rows - 1; - else - s.pos.y -= 1; - s.pos.x = s.cols; - } else - s.pos.x -= 1; - HT => - if(s.pos.x == s.cols) { - if(s.pos.y == 0) - break; - if(s.pos.y == s.rows - 1) - s.pos.y = 1; - else - s.pos.y += 1; - s.pos.x = 1; - } else - s.pos.x += 1; - LF => - if(s.pos.y == s.rows - 1) - if(s.spec&Scroll) - scroll(1, 1); - else - s.pos.y = 1; - else if(s.pos.y == 0) { # restore attributes on leaving row zero - s.pos = s.savepos; - s.attr = s.saveattr; - } else - s.pos.y += 1; - VT => - if(s.pos.y == 1) - if(s.spec&Scroll) - scroll(1, -1); - else - s.pos.y = s.rows - 1; - else if(s.pos.y == 0) - break; - else - s.pos.y -= 1; - CR => - s.pos.x = 1; - CAN => - cols := s.cols - s.pos.x + 1; - disp->Put(dup(' ', cols), Point(s.pos.x,s.pos.y), s.cset, s.attr, 0); - US => - # expect US row, col - s.state = Sus0; - FF => - s.cset = videotex; - s.attr = ATTR0; - s.pos = Point(1,1); - s.spec &= ~Cursor; - s.cursor = 1; - clear(s); - RS => - s.cset = videotex; - s.attr = ATTR0; - s.pos = Point(1,1); - s.spec &= ~Cursor; - s.cursor = 1; - CON => - s.spec |= Cursor; - s.cursor = 1; - COFF => - s.spec &= ~Cursor; - s.cursor = 1; - REP => - # repeat - s.state = Srepeat; - NUL => - # padding character - ignore, but may appear anywhere - ; - BEL => - # ah ... - ; - } -} - -# process a byte from the set c1 - introduced by the ESC character -vc1(s: ref Screen, ch: int) -{ - if(ISC0(ch)) { - s.state = Sstart; - vc0(s, ch); - return; - } - if(ch >= 16r20 && ch <= 16r2f) { - if(ch == 16r25) - s.state = Stransparent; - else if(ch == 16r23) - s.state = Sconceal; - else - s.state = Siso2022; - s.a0 = s.a1 = 0; - return; - } - - fg := bg := -1; - case ch { - 16r35 or - 16r36 or - 16r37 => - s.state = Sskip; # skip next char unless C0 - return; - - 16r5b => # CSI sequence - s.a0 = s.a1 = 0; - if(s.pos.y > 0) # 1.2.5.2 - s.state = Scsi0; - return; - - # foreground colour - 16r40 => fg = fgBlack; - 16r41 => fg = fgRed; - 16r42 => fg = fgGreen; - 16r43 => fg = fgYellow; - 16r44 => fg = fgBlue; - 16r45 => fg = fgMagenta; - 16r46 => fg = fgCyan; - 16r47 => fg = fgWhite; - - # background colour - 16r50 => bg = bgBlack; - 16r51 => bg = bgRed; - 16r52 => bg = bgGreen; - 16r53 => bg = bgYellow; - 16r54 => bg = bgBlue; - 16r55 => bg = bgMagenta; - 16r56 => bg = bgCyan; - 16r57 => bg = bgWhite; - - # flashing - 16r48 => s.attr |= attrF; - 16r49 => s.attr &= ~attrF; - - # conceal (serial attribute) - 16r58 => s.attr |= attrC; - s.delimit = 1; - 16r5f => s.attr &= ~attrC; - s.delimit = 1; - - # start lining (+separated graphics) (serial attribute) - 16r5a => s.attr |= attrL; - s.delimit = 1; - 16r59 => s.attr &= ~attrL; - s.delimit = 1; - - # reverse polarity - 16r5d => s.attr |= attrP; - 16r5c => s.attr &= ~attrP; - - # normal size - 16r4c => - s.attr &= ~(attrW|attrH); - - # double height - 16r4d => - if(s.pos.y < 2) - break; - s.attr &= ~(attrW|attrH); - s.attr |= attrH; - - # double width - 16r4e => - if(s.pos.y < 1) - break; - s.attr &= ~(attrW|attrH); - s.attr |= attrW; - - # double size - 16r4f => - if(s.pos.y < 2) - break; - s.attr |= (attrW|attrH); - } - if(fg >= 0) { - s.attr &= ~fgMask; - s.attr |= fg; - } - if(bg >= 0) { - s.attr &= ~bgMask; - s.attr |= bg; - s.delimit = 1; - } - s.state = Sstart; -} - - -# process a SS2 character -vss2(s: ref Screen, ch: int) -{ - if(ISC0(ch)) { - s.state = Sstart; - vc0(s, ch); - return; - } - case ch { - 16r41 or # grave # 5.1.2 - 16r42 or # acute - 16r43 or # circumflex - 16r48 or # umlaut - 16r4b => # cedilla - s.a0 = ch; - s.state = Saccent; - return; - 16r23 => ch = '£'; # Figure 2.8 - 16r24 => ch = '$'; - 16r26 => ch = '#'; - 16r27 => ch = '§'; - 16r2c => ch = 16rc3; # '←'; - 16r2d => ch = 16rc0; # '↑'; - 16r2e => ch = 16rc4; # '→'; - 16r2f => ch = 16rc5; # '↓'; - 16r30 => ch = '°'; - 16r31 => ch = '±'; - 16r38 => ch = '÷'; - 16r3c => ch = '¼'; - 16r3d => ch = '½'; - 16r3e => ch = '¾'; - 16r7a => ch = 'œ'; - 16r6a => ch = 'Œ'; - 16r7b => ch = 'ß'; - } - s.put(tostr(ch)); - s.savech = ch; - s.state = Sstart; -} - -# process CSI functions -vcsi(s: ref Screen, ch: int) -{ - case s.state { - Scsi0 => - case ch { - # move cursor up n rows, stop at top of screen - 'A' => - s.pos.y -= s.a0; - if(s.pos.y < 1) - s.pos.y = 1; - - # move cursor down n rows, stop at bottom of screen - 'B' => - s.pos.y += s.a0; - if(s.pos.y >= s.rows) - s.pos.y = s.rows - 1; - - # move cursor n columns right, stop at edge of screen - 'C' => - s.pos.x += s.a0; - if(s.pos.x > s.cols) - s.pos.x = s.cols; - - # move cursor n columns left, stop at edge of screen - 'D' => - s.pos.x -= s.a0; - if(s.pos.x < 1) - s.pos.x = 1; - - # direct cursor addressing - ';' => - s.state = Scsi1; - return; - - 'J' => - case s.a0 { - # clears from the cursor to the end of the screen inclusive - 0 => - rowclear(s.pos.y, s.pos.x, s.cols); - for(r:=s.pos.y+1; r<s.rows; r++) - rowclear(r, 1, s.cols); - # clears from the beginning of the screen to the cursor inclusive - 1 => - for(r:=1; r<s.pos.y; r++) - rowclear(r, 1, s.cols); - rowclear(s.pos.y, 1, s.pos.x); - # clears the entire screen - 2 => - clear(s); - } - - 'K' => - case s.a0 { - # clears from the cursor to the end of the row - 0 => rowclear(s.pos.y, s.pos.x, s.cols); - - # clears from the start of the row to the cursor - 1 => rowclear(s.pos.y, 1, s.pos.x); - - # clears the entire row in which the cursor is positioned - 2 => rowclear(s.pos.y, 1, s.cols); - } - - # deletes n characters from cursor position - 'P' => - rowclear(s.pos.y, s.pos.x, s.pos.x+s.a0-1); - - # inserts n characters from cursor position - '@' => - disp->Put(dup(' ', s.a0), Point(s.pos.x,s.pos.y), s.cset, s.attr, 1); - - # starts cursor insert mode - 'h' => - if(s.a0 == 4) - s.spec |= Insert; - - 'l' => # ends cursor insert mode - if(s.a0 == 4) - s.spec &= ~Insert; - - # deletes n rows from cursor row - 'M' => - scroll(s.pos.y, s.a0); - - # inserts n rows from cursor row - 'L' => - scroll(s.pos.y, -1*s.a0); - } - s.state = Sstart; - Scsi1 => - case ch { - # direct cursor addressing - 'H' => - if(s.a0 > 0 && s.a0 < s.rows && s.a1 > 0 && s.a1 <= s.cols) - s.pos = Point(s.a1, s.a0); - } - s.state = Sstart; - } -} - -# Screen state - Videotex mode -vstate(s: ref Screen, data: array of byte): array of byte -{ - i: int; - for(i = 0; i < len data; i++) { - ch := int data[i]; - - if(debug['s']) { - cs:=""; - if(s.cset==videotex) cs = "v"; else cs="s"; - fprint(stderr, "vstate %d, %ux (%c) %.4ux %.4ux %s (%d,%d)\n", s.state, ch, ch, s.attr, s.spec, cs, s.pos.y, s.pos.x); - } - case s.state { - Sstart => - if(ISG0(ch) || ch == SP) { - n := 0; - str := ""; - while(i < len data) { - ch = int data[i]; - if(ISG0(ch) || ch == SP) - str[n++] = int data[i++]; - else { - i--; - break; - } - } - if(n > 0) { - if(debug['s']) - fprint(stderr, "vstate puts(%s)\n", str); - s.put(str); - s.savech = str[n-1]; - } - } else if(ISC0(ch)) - vc0(s, ch); - else if(ch == DEL) { - if(s.cset == semigraphic) - ch = 16r5f; - s.put(tostr(ch)); - s.savech = ch; - } - Sss2 => - if(ch == NUL) # 1.2.6.1 - continue; - if(s.cset == semigraphic) # 1.2.3.4 - continue; - vss2(s, ch); - Sesc => - if(ch == NUL) - continue; - vc1(s, ch); - Srepeat => - # byte from `columns' 4 to 7 gives repeat count on 6 bits - # of the last `Put' character - if(ch == NUL) - continue; - if(ISC0(ch)) { - s.state = Sstart; - vc0(s, ch); - break; - } - if(ch >= 16r40 && ch <= 16r7f) - s.put(dup(s.savech, (ch-16r40))); - s.state = Sstart; - Saccent => - case s.a0 { - 16r41 => # grave - case ch { - 'a' => ch = 'à'; - 'e' => ch = 'è'; - 'u' => ch = 'ù'; - } - 16r42 => # acute - case ch { - 'e' => ch = 'é'; - } - 16r43 => # circumflex - case ch { - 'a' => ch = 'â'; - 'e' => ch = 'ê'; - 'i' => ch = 'î'; - 'o' => ch = 'ô'; - 'u' => ch = 'û'; - } - 16r48 => # umlaut - case ch { - 'a' => ch = 'ä'; - 'e' => ch = 'ë'; - 'i' => ch = 'ï'; - 'o' => ch = 'ö'; - 'u' => ch = 'ü'; - } - 16r4b => # cedilla - case ch { - 'c' => ch = 'ç'; - } - } - s.put(tostr(ch)); - s.savech = ch; - s.state = Sstart; - Scsi0 => - if(ch >= 16r30 && ch <= 16r39) { - s.a0 *= 10; - s.a0 += (ch - 16r30); - } else if((ch >= 16r20 && ch <= 16r29) || (ch >= 16r3a && ch <= 16r3f)) { # 1.2.7 - s.a0 = 0; - s.state = Siso6429; - } else - vcsi(s, ch); - Scsi1 => - if(ch >= 16r30 && ch <= 16r39) { - s.a1 *= 10; - s.a1 += (ch - 16r30); - } else - vcsi(s, ch); - Sus0 => - if(ch == 16r23) { # start DRCS definition - s.state = Sdrcs; - s.a0 = 0; - break; - } - if(ch >= 16r40 && ch < 16r80) - s.a0 = (ch - 16r40); - else if(ch >= 16r30 && ch <= 16r32) - s.a0 = (ch - 16r30); - else - s.a0 = -1; - s.state = Sus1; - Sus1 => - if(ch >= 16r40 && ch < 16r80) - s.a1 = (ch - 16r40); - else if(ch >= 16r30 && ch <= 16r39) { - s.a1 = (ch - 16r30); - s.a0 = s.a0*10 + s.a1; # shouldn't be used any more - s.a1 = 1; - } else - s.a1 = -1; - # US row, col : this is how you get to row zero - if(s.a0 >= 0 && s.a0 < s.rows && s.a1 > 0 && s.a1 <= s.cols) { - if(s.a0 == 0 && s.pos.y > 0) { - s.savepos = s.pos; - s.saveattr = s.attr; - } - s.pos = Point(s.a1, s.a0); - s.delimit = 0; # 1.2.5.3, don't reset serial attributes - s.attr = ATTR0; - s.cset = videotex; - } - s.state = Sstart; - Sskip => - # swallow the next character unless from C0 - s.state = Sstart; - if(ISC0(ch)) - vc0(s, ch); - Swaitfor => - # ignore characters until the character in a0 inclusive - if(ch == s.a0) - s.state = Sstart; - Siso2022 => - # 1.2.7 - # swallow (upto) 3 characters from column 2, - # then 1 character from columns 3 to 7 - if(ch == NUL) - continue; - if(ISC0(ch)) { - s.state = Sstart; - vc0(s, ch); - break; - } - s.a0++; - if(s.a0 <= 3) { - if(ch >= 16r20 && ch <= 16r2f) - break; - } - if (s.a0 <= 4 && ch >= 16r30 && ch <= 16r7f) { - s.state = Sstart; - break; - } - s.state = Sstart; - s.put(tostr(DEL)); - Siso6429 => - # 1.2.7 - # swallow characters from column 3, - # or column 2, then 1 from column 4 to 7 - if(ISC0(ch)) { - s.state = Sstart; - vc0(s, ch); - break; - } - if(ch >= 16r20 && ch <= 16r3f) - break; - if(ch >= 16r40 && ch <= 16r7f) { - s.state = Sstart; - break; - } - s.state = Sstart; - s.put(tostr(DEL)); - Stransparent => - # 1.2.7 - # ignore all codes until ESC, 25, 40 or ESC, 2F, 3F - # progress in s.a0 and s.a1 - match := array [] of { - array [] of { ESC, 16r25, 16r40 }, - array [] of { ESC, 16r2f, 16r3f }, - }; - if(ch == ESC) { - s.a0 = s.a1 = 1; - break; - } - if(ch == match[0][s.a0]) - s.a0++; - else - s.a0 = 0; - if(ch == match[1][s.a1]) - s.a1++; - else - s.a1 = 0; - if(s.a0 == 3 || s.a1 == 3) - s.state = Sstart; - Sdrcs => - if(s.a0 > 0) { # fixed number of bytes to skip in a0 - s.a0--; - if(s.a0 == 0) { - s.state = Sstart; - break; - } - } else if(ch == US) # US XX YY - end of DRCS - s.state = Sus0; - else if(ch == 16r20) # US 23 20 20 20 4[23] 49 - s.a0 = 4; - Sconceal => - # 1.2.4.4 - # ESC 23 20 58 - Conceal fields - # ESC 23 20 5F - Reveal fields - # ESC 23 21 XX - Filter - # progress in s.a0 - case s.a0 { - 0 => - if(ch == 16r20 || ch == 16r21) - s.a0 = ch; - 16r20 => - case ch { - 16r58 => - disp->Reveal(0); - disp->Refresh(); - 16r5f => - disp->Reveal(1); - disp->Refresh(); - } - s.state = Sstart; - 16r21 => - s.state = Sstart; - } - } - } - if (i < len data) - return data[i:]; - else - return nil; -} - -# Screen state - Mixed mode -mstate(s: ref Screen, data: array of byte): array of byte -{ - i: int; -Stateloop: - for(i = 0; i < len data; i++) { - ch := int data[i]; - - if(debug['s']) { - cs:=""; - if(s.cset==videotex) cs = "v"; else cs="s"; - fprint(stderr, "mstate %d, %ux (%c) %.4ux %.4ux %s (%d,%d)\n", s.state, ch, ch, s.attr, s.fstate, cs, s.pos.y, s.pos.x); - } - case s.state { - Sstart => - if(ISG0(ch) || ch == SP) { - n := 0; - str := ""; - while(i < len data) { - ch = int data[i]; - if(ISG0(ch) || ch == SP) - str[n++] = int data[i++]; - else { - i--; - break; - } - } - if(n > 0) { - if(debug['s']) - fprint(stderr, "mstate puts(%s)\n", str); - s.put(str); - s.savech = str[n-1]; - } - } else if(ISC0(ch)) - mc0(s, ch); - else if(ch == DEL) { - if(s.cset == semigraphic) - ch = 16r5f; - s.put(tostr(ch)); - s.savech = ch; - } - Sesc => - if(ch == NUL) - continue; - mc1(s, ch); - Scsi0 => - if(ch >= 16r30 && ch <= 16r39) { - s.a0 *= 10; - s.a0 += (ch - 16r30); - } else if(ch == '?') { - s.a0 = '?'; - } else - mcsi(s, ch); - if(T.mode != Mixed) # CSI ? { changes to Videotex mode - break Stateloop; - Scsi1 => - if(ch >= 16r30 && ch <= 16r39) { - s.a1 *= 10; - s.a1 += (ch - 16r30); - } else - mcsi(s, ch); - Sus0 => - if(ch >= 16r40 && ch < 16r80) - s.a0 = (ch - 16r40); - else if(ch >= 16r30 && ch <= 16r32) - s.a0 = (ch - 16r30); - else - s.a0 = -1; - s.state = Sus1; - Sus1 => - if(ch >= 16r40 && ch < 16r80) - s.a1 = (ch - 16r40); - else if(ch >= 16r30 && ch <= 16r39) { - s.a1 = (ch - 16r30); - s.a0 = s.a0*10 + s.a1; # shouldn't be used any more - s.a1 = 1; - } else - s.a1 = -1; - # US row, col : this is how you get to row zero - if(s.a0 >= 0 && s.a0 < s.rows && s.a1 > 0 && s.a1 <= s.cols) { - if(s.a0 == 0 && s.pos.y > 0) { - s.savepos = s.pos; - s.saveattr = s.attr; - } - s.pos = Point(s.a1, s.a0); - s.delimit = 0; # 1.2.5.3, don't reset serial attributes - s.attr = ATTR0; - s.cset = videotex; - } - s.state = Sstart; - Siso6429 => - # 1.2.7 - # swallow characters from column 3, - # or column 2, then 1 from column 4 to 7 - if(ISC0(ch)) { - s.state = Sstart; - mc0(s, ch); - break; - } - if(ch >= 16r20 && ch <= 16r3f) - break; - if(ch >= 16r40 && ch <= 16r7f) { - s.state = Sstart; - break; - } - s.state = Sstart; - s.put(tostr(DEL)); - } - } - if (i < len data) - return data[i:]; - else - return nil; - return nil; -} - -# process a byte from set C0 - Mixed mode -mc0(s: ref Screen, ch: int) -{ - case ch { - ESC => - s.state = Sesc; - SO => -# s.cset = french; - ; - SI => -# s.cset = american; - ; - BS => - if(s.pos.x > 1) - s.pos.x -= 1; - HT => - s.pos.x += 8; - if(s.pos.x > s.cols) - s.pos.x = s.cols; - LF or VT or FF => - if(s.pos.y == s.rows - 1) - if(s.spec&Scroll) - scroll(1, 1); - else - s.pos.y = 1; - else if(s.pos.y == 0) { # restore attributes on leaving row zero - if(ch == LF) { # 4.5 - s.pos = s.savepos; - s.attr = s.saveattr; - } - } else - s.pos.y += 1; - CR => - s.pos.x = 1; - CAN or SUB => # displays the error symbol - filled in rectangle - disp->Put(dup(16r5f, 1), Point(s.pos.x,s.pos.y), s.cset, s.attr, 0); - NUL => - # padding character - ignore, but may appear anywhere - ; - BEL => - # ah ... - ; - XON => # screen copying - ; - XOFF => # screen copying - ; - US => - # expect US row, col - s.state = Sus0; - } -} - -# process a byte from the set c1 - introduced by the ESC character - Mixed mode -mc1(s: ref Screen, ch: int) -{ - if(ISC0(ch)) { - s.state = Sstart; - mc0(s, ch); - return; - } - case ch { - 16r5b => # CSI sequence - s.a0 = s.a1 = 0; - if(s.pos.y > 0) # 1.2.5.2 - s.state = Scsi0; - return; - - 16r44 or # IND like LF - 16r45 => # NEL like CR LF - if(ch == 16r45) - s.pos.x = 1; - if(s.pos.y == s.rows - 1) - if(s.spec&Scroll) - scroll(1, 1); - else - s.pos.y = 1; - else if(s.pos.y == 0) { # restore attributes on leaving row zero - s.pos = s.savepos; - s.attr = s.saveattr; - } else - s.pos.y += 1; - 16r4d => # RI - if(s.pos.y == 1) - if(s.spec&Scroll) - scroll(1, -1); - else - s.pos.y = s.rows - 1; - else if(s.pos.y == 0) - break; - else - s.pos.y -= 1; - } - s.state = Sstart; -} - - -# process CSI functions - Mixed mode -mcsi(s: ref Screen, ch: int) -{ - case s.state { - Scsi0 => - case ch { - # move cursor up n rows, stop at top of screen - 'A' => - if(s.a0 == 0) - s.a0 = 1; - s.pos.y -= s.a0; - if(s.pos.y < 1) - s.pos.y = 1; - - # move cursor down n rows, stop at bottom of screen - 'B' => - if(s.a0 == 0) - s.a0 = 1; - s.pos.y += s.a0; - if(s.pos.y >= s.rows) - s.pos.y = s.rows - 1; - - # move cursor n columns right, stop at edge of screen - 'C' => - if(s.a0 == 0) - s.a0 = 1; - s.pos.x += s.a0; - if(s.pos.x > s.cols) - s.pos.x = s.cols; - - # move cursor n columns left, stop at edge of screen - 'D' => - if(s.a0 == 0) - s.a0 = 1; - s.pos.x -= s.a0; - if(s.pos.x < 1) - s.pos.x = 1; - - # second parameter - ';' => - s.state = Scsi1; - return; - - 'J' => - case s.a0 { - # clears from the cursor to the end of the screen inclusive - 0 => - rowclear(s.pos.y, s.pos.x, s.cols); - for(r:=s.pos.y+1; r<s.rows; r++) - rowclear(r, 1, s.cols); - # clears from the beginning of the screen to the cursor inclusive - 1 => - for(r:=1; r<s.pos.y; r++) - rowclear(r, 1, s.cols); - rowclear(s.pos.y, 1, s.pos.x); - # clears the entire screen - 2 => - clear(s); - } - - 'K' => - case s.a0 { - # clears from the cursor to the end of the row - 0 => rowclear(s.pos.y, s.pos.x, s.cols); - - # clears from the start of the row to the cursor - 1 => rowclear(s.pos.y, 1, s.pos.x); - - # clears the entire row in which the cursor is positioned - 2 => rowclear(s.pos.y, 1, s.cols); - } - - # inserts n characters from cursor position - '@' => - disp->Put(dup(' ', s.a0), Point(s.pos.x,s.pos.y), s.cset, s.attr, 1); - - # starts cursor insert mode - 'h' => - if(s.a0 == 4) - s.spec |= Insert; - - 'l' => # ends cursor insert mode - if(s.a0 == 4) - s.spec &= ~Insert; - - # inserts n rows from cursor row - 'L' => - scroll(s.pos.y, -1*s.a0); - s.pos.x = 1; - - # deletes n rows from cursor row - 'M' => - scroll(s.pos.y, s.a0); - s.pos.x = 1; - - # deletes n characters from cursor position - 'P' => - rowclear(s.pos.y, s.pos.x, s.pos.x+s.a0-1); - - # select Videotex mode - '{' => - if(s.a0 == '?') { - T.mode = Videotex; - s.setmode(T.mode); - } - - # display attributes - 'm' => - case s.a0 { - 0 => s.attr &= ~(attrL|attrF|attrP|attrB); - 1 => s.attr |= attrB; - 4 => s.attr |= attrL; - 5 => s.attr |= attrF; - 7 => s.attr |= attrP; - 22 => s.attr &= ~attrB; - 24 => s.attr &= ~attrL; - 25 => s.attr &= ~attrF; - 27 => s.attr &= ~attrP; - } - # direct cursor addressing - 'H' => - if(s.a0 == 0) - s.a0 = 1; - if(s.a1 == 0) - s.a1 = 1; - if(s.a0 > 0 && s.a0 < s.rows && s.a1 > 0 && s.a1 <= s.cols) - s.pos = Point(s.a1, s.a0); - } - s.state = Sstart; - Scsi1 => - case ch { - # direct cursor addressing - 'H' => - if(s.a0 == 0) - s.a0 = 1; - if(s.a1 == 0) - s.a1 = 1; - if(s.a0 > 0 && s.a0 < s.rows && s.a1 > 0 && s.a1 <= s.cols) - s.pos = Point(s.a1, s.a0); - } - s.state = Sstart; - } -} - - -# Screen state - ASCII mode -astate(nil: ref Screen, nil: array of byte): array of byte -{ - return nil; -} - -# Put a string in the current attributes to the current writing position -Screen.put(s: self ref Screen, str: string) -{ - while((l := len str) > 0) { - n := s.cols - s.pos.x + 1; # characters that will fit on this row - if(s.attr & attrW) { - if(n > 1) # fit normal width character in last column - n /= 2; - } - if(n > l) - n = l; - if(s.delimit) { # set delimiter bit on 1st space (if any) - for(i:=0; i<n; i++) - if(str[i] == ' ') - break; - if(i > 0) { - disp->Put(str[0:i], s.pos, s.cset, s.attr, s.spec&Insert); - incpos(s, i); - } - if(i < n) { - if(debug['s']) { - cs:=""; - if(s.cset==videotex) cs = "v"; else cs="s"; - fprint(stderr, "D %ux %s\n", s.attr|attrD, cs); - } - disp->Put(tostr(str[i]), s.pos, s.cset, s.attr|attrD, s.spec&Insert); - incpos(s, 1); - s.delimit = 0; - # clear serial attributes once used - # hang onto background attribute - needed for semigraphics - case s.cset { - videotex => - s.attr &= ~(attrL|attrC); - semigraphic => - s.attr &= ~(attrC); - } - } - if(i < n-1) { - disp->Put(str[i+1:n], s.pos, s.cset, s.attr, s.spec&Insert); - incpos(s, n-(i+1)); - } - } else { - disp->Put(str[0:n], s.pos, s.cset, s.attr, s.spec&Insert); - incpos(s, n); - } - if(n < len str) - str = str[n:]; - else - str = nil; - } -# if(T.state == Local || T.spec&Echo) -# refresh(); -} - -# increment the current writing position by `n' cells. -# caller must ensure that `n' characters can fit -incpos(s: ref Screen, n: int) -{ - if(s.attr & attrW) - s.pos.x += 2*n; - else - s.pos.x += n; - if(s.pos.x > s.cols) - if(s.pos.y == 0) # no wraparound from row zero - s.pos.x = s.cols; - else { - s.pos.x = 1; - if(s.pos.y == s.rows - 1 && s.spec&Scroll) { - if(s.attr & attrH) { - scroll(1, 2); - } else { - scroll(1, 1); - rowclear(s.pos.y, 1, s.cols); - } - } else { - if(s.attr & attrH) - s.pos.y += 2; - else - s.pos.y += 1; - if(s.pos.y >= s.rows) - s.pos.y -= (s.rows-1); - } - } -} - -# clear row `r' from `first' to `last' column inclusive -rowclear(r, first, last: int) -{ - # 16r5f is the semi-graphic black rectangle - disp->Put(dup(16r5f, last-first+1), Point(first,r), semigraphic, fgBlack, 0); -# disp->Put(dup(' ', last-first+1), Point(first,r), S.cset, fgBlack, 0); -} - -clear(s: ref Screen) -{ - for(r:=1; r<s.rows; r++) - rowclear(r, 1, s.cols); -} - -# called to suggest a display update -refresh() -{ - disp->Refresh(); -} - -# scroll the screen -scroll(topline, nlines: int) -{ - disp->Scroll(topline, nlines); - disp->Refresh(); -} - -# filter the specified ISO6429 and ISO2022 codes from the screen input -# TODO: filter some ISO2022 sequences -filter(s: ref Screen, data: array of byte): array of array of byte -{ - case T.mode { - Videotex => - return vfilter(s, data); - Mixed => - return mfilter(s, data); - Ascii => - return afilter(s, data); - } - return nil; -} - -# filter the specified ISO6429 and ISO2022 codes from the screen input -vfilter(s: ref Screen, data: array of byte): array of array of byte -{ - ba := array [0] of array of byte; - changed := 0; - - d0 := 0; - for(i:=0; i<len data; i++) { - ch := int data[i]; - case s.fstate { - FSstart => - if(ch == ESC) { - s.fstate = FSesc; - changed = 1; - if(i > d0) - ba = dappend(ba, data[d0:i]); - d0 = i+1; - } - FSesc => - d0 = i+1; - changed = 1; - if(ch == '[') { - s.fstate = FS6429; - s.fsaved = array [0] of byte; - s.badp = 0; -# } else if(ch == 16r20) { -# s.fstate = FS2022; -# s.fsaved = array [0] of byte; - s.badp = 0; - } else if(ch == ESC) { - ba = dappend(ba, array [] of { byte ESC }); - s.fstate = FSesc; - } else { - # false alarm - don't filter - ba = dappend(ba, array [] of { byte ESC, byte ch }); - s.fstate = FSstart; - } - FS6429 => # filter out invalid CSI sequences - d0 = i+1; - changed = 1; - if(ch >= 16r20 && ch <= 16r3f) { - if((ch < 16r30 || ch > 16r39) && ch != ';') - s.badp = 1; - a := array [len s.fsaved + 1] of byte; - a[0:] = s.fsaved[0:]; - a[len a - 1] = byte ch; - s.fsaved = a; - } else { - valid := 1; - case ch { - 'A' => ; - 'B' => ; - 'C' => ; - 'D' => ; - 'H' => ; - 'J' => ; - 'K' => ; - 'P' => ; - '@' => ; - 'h' => ; - 'l' => ; - 'M' => ; - 'L' => ; - * => - valid = 0; - } - if(s.badp) - valid = 0; - if(debug['f']) - fprint(stderr, "vfilter %d: %s%c\n", valid, string s.fsaved, ch); - if(valid) { # false alarm - don't filter - ba = dappend(ba, array [] of { byte ESC, byte '[' }); - ba = dappend(ba, s.fsaved); - ba = dappend(ba, array [] of { byte ch } ); - } - s.fstate = FSstart; - } - FS2022 => ; - } - } - if(changed) { - if(i > d0) - ba = dappend(ba, data[d0:i]); - return ba; - } - return array [] of { data }; -} - -# filter the specified ISO6429 and ISO2022 codes from the screen input - Videotex -mfilter(s: ref Screen, data: array of byte): array of array of byte -{ - ba := array [0] of array of byte; - changed := 0; - - d0 := 0; - for(i:=0; i<len data; i++) { - ch := int data[i]; - case s.fstate { - FSstart => - case ch { - ESC => - s.fstate = FSesc; - changed = 1; - if(i > d0) - ba = dappend(ba, data[d0:i]); - d0 = i+1; - SEP => - s.fstate = FSsep; - changed = 1; - if(i > d0) - ba = dappend(ba, data[d0:i]); - d0 = i+1; - } - FSesc => - d0 = i+1; - changed = 1; - if(ch == '[') { - s.fstate = FS6429; - s.fsaved = array [0] of byte; - s.badp = 0; - } else if(ch == ESC) { - ba = dappend(ba, array [] of { byte ESC }); - s.fstate = FSesc; - } else { - # false alarm - don't filter - ba = dappend(ba, array [] of { byte ESC, byte ch }); - s.fstate = FSstart; - } - FSsep => - d0 = i+1; - changed = 1; - if(ch == ESC) { - ba = dappend(ba, array [] of { byte SEP }); - s.fstate = FSesc; - } else if(ch == SEP) { - ba = dappend(ba, array [] of { byte SEP }); - s.fstate = FSsep; - } else { - if(ch >= 16r00 && ch <= 16r1f) - ba = dappend(ba, array [] of { byte SEP , byte ch }); - # consume the character - s.fstate = FSstart; - } - FS6429 => # filter out invalid CSI sequences - d0 = i+1; - changed = 1; - if(ch >= 16r20 && ch <= 16r3f) { - if((ch < 16r30 || ch > 16r39) && ch != ';' && ch != '?') - s.badp = 1; - a := array [len s.fsaved + 1] of byte; - a[0:] = s.fsaved[0:]; - a[len a - 1] = byte ch; - s.fsaved = a; - } else { - valid := 1; - case ch { - 'm' => ; - 'A' => ; - 'B' => ; - 'C' => ; - 'D' => ; - 'H' => ; - 'J' => ; - 'K' => ; - '@' => ; - 'h' => ; - 'l' => ; - 'L' => ; - 'M' => ; - 'P' => ; - '{' => # allow CSI ? { - n := len s.fsaved; - if(n == 0 || s.fsaved[n-1] != byte '?') - s.badp = 1; - * => - valid = 0; - } - if(s.badp) # only decimal params - valid = 0; - if(debug['f']) - fprint(stderr, "mfilter %d: %s%c\n", valid, string s.fsaved, ch); - if(valid) { # false alarm - don't filter - ba = dappend(ba, array [] of { byte ESC, byte '[' }); - ba = dappend(ba, s.fsaved); - ba = dappend(ba, array [] of { byte ch } ); - } - s.fstate = FSstart; - } - FS2022 => ; - } - } - if(changed) { - if(i > d0) - ba = dappend(ba, data[d0:i]); - return ba; - } - return array [] of { data }; -} - -# filter the specified ISO6429 and ISO2022 codes from the screen input - Videotex -afilter(nil: ref Screen, data: array of byte): array of array of byte -{ - return array [] of { data }; -} - -# append to an array of array of byte -dappend(ba: array of array of byte, b: array of byte): array of array of byte -{ - l := len ba; - na := array [l+1] of array of byte; - na[0:] = ba[0:]; - na[l] = b; - return na; -} - -# Put a diagnostic string to row 0 -Screen.msg(s: self ref Screen, str: string) -{ - blank := string array [s.cols -4] of {* => byte ' '}; - n := len str; - if(n > s.cols - 4) - n = s.cols - 4; - disp->Put(blank, Point(1, 0), videotex, 0, 0); - if(str != nil) - disp->Put(str[0:n], Point(1, 0), videotex, fgWhite|attrB, 0); - disp->Refresh(); -}
\ No newline at end of file |
