redo ptse

git-svn-id: svn://qnap.local/TwoTerm/trunk@3173 5590a31f-7b70-45f8-8c82-aa3a8e5f4507
This commit is contained in:
Kelvin Sherlock 2017-02-18 18:02:01 +00:00
parent f941f462fb
commit a34341dd69
4 changed files with 432 additions and 388 deletions

View File

@ -47,6 +47,7 @@
B6C704EF15CCC64100CC0401 /* titlebar-center@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704EC15CCC64100CC0401 /* titlebar-center@2x.png */; };
B6C704F015CCC64100CC0401 /* titlebar-left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704ED15CCC64100CC0401 /* titlebar-left@2x.png */; };
B6C704F115CCC64100CC0401 /* titlebar-right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704EE15CCC64100CC0401 /* titlebar-right@2x.png */; };
B6D1CD071E577E7D00C4A6BC /* PTSE.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B612F45D12DD5DF1005D1B77 /* PTSE.mm.ragel */; };
B6EBE2B511E0EA9100EA0458 /* CharacterGenerator.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6EBE2B411E0EA9100EA0458 /* CharacterGenerator.mm */; };
B6ECFF271D2EEA2B00871A81 /* TextLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = B6ECFF261D2EEA2B00871A81 /* TextLabel.m */; };
/* End PBXBuildFile section */
@ -119,7 +120,7 @@
B612F45A12DD5DF1005D1B77 /* GNOConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GNOConsole.h; sourceTree = "<group>"; };
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = GNOConsole.mm.ragel; sourceTree = "<group>"; };
B612F45C12DD5DF1005D1B77 /* PTSE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTSE.h; sourceTree = "<group>"; };
B612F45D12DD5DF1005D1B77 /* PTSE.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PTSE.mm; sourceTree = "<group>"; };
B612F45D12DD5DF1005D1B77 /* PTSE.mm.ragel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PTSE.mm.ragel; sourceTree = "<group>"; };
B612F45E12DD5DF1005D1B77 /* VT05.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VT05.h; sourceTree = "<group>"; };
B612F45F12DD5DF1005D1B77 /* VT05.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VT05.mm; sourceTree = "<group>"; };
B612F46012DD5DF1005D1B77 /* VT100.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VT100.h; sourceTree = "<group>"; };
@ -295,16 +296,16 @@
B612F45512DD5DF1005D1B77 /* Emulators */ = {
isa = PBXGroup;
children = (
B612F45612DD5DF1005D1B77 /* Apple80.h */,
B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */,
B612F45812DD5DF1005D1B77 /* Emulator.h */,
B612F45912DD5DF1005D1B77 /* EmulatorManager.mm */,
B612F45612DD5DF1005D1B77 /* Apple80.h */,
B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */,
B612F45A12DD5DF1005D1B77 /* GNOConsole.h */,
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */,
B6C173901D31D2B80024E360 /* GSOSConsole.h */,
B6C173911D31D2B80024E360 /* GSOSConsole.mm.ragel */,
B612F45C12DD5DF1005D1B77 /* PTSE.h */,
B612F45D12DD5DF1005D1B77 /* PTSE.mm */,
B612F45D12DD5DF1005D1B77 /* PTSE.mm.ragel */,
B612F45E12DD5DF1005D1B77 /* VT05.h */,
B612F45F12DD5DF1005D1B77 /* VT05.mm */,
B612F46012DD5DF1005D1B77 /* VT100.h */,
@ -440,6 +441,7 @@
B675F4A91E561D20004B0D9C /* Apple80.mm.ragel in Sources */,
B675F4AA1E562159004B0D9C /* GNOConsole.mm.ragel in Sources */,
B675F4AC1E56A7F2004B0D9C /* GSOSConsole.mm.ragel in Sources */,
B6D1CD071E577E7D00C4A6BC /* PTSE.mm.ragel in Sources */,
8D11072D0486CEB800E47090 /* main.m in Sources */,
256AC3DA0F4B6AC300CF3369 /* TwoTermAppDelegate.mm in Sources */,
B676063B11DEAD3500D6B66C /* TermWindowController.mm in Sources */,

View File

@ -17,15 +17,11 @@
@interface PTSE : NSObject <Emulator>
{
unsigned _state;
iPoint _dca;
uint8_t _repeatChar;
#ifdef __cplusplus
TextPort _textPort;
#endif
context _context;
unsigned cs;
int _scratch[4];
}

View File

@ -1,376 +0,0 @@
//
// PTSE.mm
// 2Term
//
// Created by Kelvin Sherlock on 7/9/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#include <sys/ttydefaults.h>
#import "PTSE.h"
#include "OutputChannel.h"
#include "Screen.h"
@implementation PTSE
enum {
StateText,
StateDCAX,
StateDCAY,
StateRepeatChar,
StateRepeatCount,
StateTone1,
StateTone2,
StateToneDuration
};
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"Proterm Special Emulation";
}
-(NSString *)name
{
return @"Proterm Special Emulation";
}
-(const char *)termName
{
return "proterm-special";
}
-(void)reset: (Screen *)screen
{
[self reset];
if (screen)
{
screen->setFlag(Screen::FlagNormal);
screen->setTextPort(_textPort);
screen->erase(Screen::EraseAll);
}
}
-(void)reset
{
struct winsize ws = [self defaultSize];
_state = StateText;
_textPort.cursor = iPoint(0, 0);
_textPort.frame = iRect(0, 0, ws.ws_col, ws.ws_row);
_textPort.scroll = true;
_textPort.advanceCursor = true;
_textPort.clampX = true;
_textPort.clampY = true;
_textPort.leftMargin = TextPort::MarginWrap;
_textPort.rightMargin = TextPort::MarginWrap;
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
return ws;
}
-(id)init
{
[self reset];
return self;
}
-(void)initTerm: (struct termios *)term
{
// Control-U is used by the up-arrow key.
term->c_cc[VKILL] = CTRL('X');
}
-(void)processCharacter:(uint8_t)c screen:(Screen *)screen output:(OutputChannel *)output
{
if (_state == StateText)
{
switch (c)
{
case CTRL('N'):
//Set: inverse off, mousetext off.
screen->setFlag(Screen::FlagNormal);
break;
case CTRL('O'):
//Set: inverse on, mousetext off.
screen->setFlag(Screen::FlagInverse);
break;
case CTRL('P'):
//Set inverse off, mousetext on.
screen->setFlag(Screen::FlagMouseText | Screen::FlagInverse);
break;
case CTRL('H'):
//Move cursor left one character.
screen->decrementX(&_textPort);
break;
case CTRL('U'):
//Move cursor right one character.
screen->incrementX(&_textPort);
break;
case CTRL('K'):
//Move cursor up one line.
screen->decrementY(&_textPort);
break;
case CTRL('J'):
//Move cursor down one line.
//screen->incrementY();
screen->lineFeed(&_textPort);
break;
case CTRL('I'):
//Move cursor to next tab stop (every 8 chars).
screen->tabTo(&_textPort, (_textPort.cursor.x + 8) & ~0x07);
break;
case CTRL('A'):
//Move cursor to beginning of line.
screen->setX(&_textPort, 0);
break;
case CTRL('B'):
//Move cursor to end of line.
screen->setX(&_textPort, _textPort.frame.width() - 1);
break;
case CTRL('X'):
//Move cursor to upper-left corner.
screen->setCursor(&_textPort, 0, 0);
break;
case CTRL('^'):
// CONTROL-^, X + 32, Y + 32
//Position cursor to the X, Y coordinates.
_state = StateDCAX;
break;
case CTRL('M'):
//screen->lineFeed();
screen->setX(&_textPort, 0);
break;
case CTRL('D'):
//Delete current character (under cursor).
// TODO -- does this shift the rest of the row? Assuming yes.
screen->deletec(&_textPort);
break;
case CTRL('F'):
//Insert space at cursor.
// TODO -- does this wrap? Assuming no.
screen->insertc(&_textPort, ' ');
break;
case CTRL('Z'):
//Delete current line.
// TODO -- textPort
screen->deleteLine(&_textPort, _textPort.cursor.y);
break;
case CTRL('V'):
//Insert blank line.
// TODO -- verify if the line is before or after the current line,
// TODO -- verify if x/y change
// TODO -- verify scrolling behavior.
// TODO -- textPort
screen->insertLine(&_textPort, _textPort.cursor.y);
break;
case CTRL('Y'):
//Clear to end of line.
screen->erase(&_textPort, Screen::EraseLineAfterCursor);
break;
case CTRL('W'):
//Clear to end of screen.
screen->erase(&_textPort, Screen::EraseAfterCursor);
break;
case CTRL('L'):
//Clear the screen (and home cursor)
screen->setCursor(&_textPort, 0, 0);
screen->erase(&_textPort, Screen::EraseAll);
break;
case CTRL('E'):
//Inquire if using ProTERM Special Emulation
/*
* When you send out [CONTROL-E] to a caller using ProTERM
* Special, the callers ProTERM will send back [CONTROL-“]”]
* (ASCII code 29). This allows a BBS to transparently
* detect the use of PSE.
*/
output->write(29);
break;
case CTRL('R'):
//CONTROL-R, character, count
//Display character, count times.
/*
* This allows a three character code to be used to display
* multiple characters. For example, to display a window frame,
* it is necessary to show the top and bottom borders which are
* long lines of the same character (dashes, underlines, etc.).
* To draw a 64-character line consisting of equal signs, send
* [CONTROL-R = @] where “@” is the ASCII code for 64.
*/
_state = StateRepeatChar;
break;
case CTRL('G'):
//Sound the Bell.
NSBeep();
break;
case CTRL('T'):
//Sound single/dual-tone for duration.
/*
* The tone command has two forms. The first invokes the single-tone
* generator, which produces relatively pure tones. The second
* invokes the dual-tone generator, which produces some rather
* interesting sounds. The three parameters, tone1, tone2, and
* duration, can all take values from 1 through 127. There is
* currently no known translation between pitch/duration values
* and actual frequencies/times.
*/
//NB - parsed but ignored, for now.
_state = StateTone1;
break;
default:
if (c >= 0x20 && c < 0x7f)
{
screen->putc(&_textPort, c);
}
break;
}
return;
}
switch (_state)
{
case StateDCAX:
_dca.x = c - 32;
_state = StateDCAY;
break;
case StateDCAY:
_dca.y = c - 32;
screen->setCursor(&_textPort, _dca);
_state = StateText;
break;
case StateRepeatChar:
_repeatChar = c;
_state = StateRepeatCount;
break;
case StateRepeatCount:
for (unsigned i = 0; i < c; ++i)
{
screen->putc(&_textPort, _repeatChar);
}
_state = StateText;
break;
case StateTone1:
_state = StateTone2;
break;
case StateTone2:
// CONTROL-A indicates same as tone1.
_state = StateToneDuration;
break;
case StateToneDuration:
_state = StateText;
break;
}
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
switch (uc)
{
case NSEnterCharacter:
output->write(CTRL('M'));
break;
case NSDeleteCharacter:
output->write(0x7f);
break;
// backspace and left arrow use the same code, alas.
case NSBackspaceCharacter:
output->write(0x7f);
break;
case NSLeftArrowFunctionKey:
output->write(CTRL('H'));
break;
case NSRightArrowFunctionKey:
output->write(CTRL('U'));
break;
case NSUpArrowFunctionKey:
output->write(CTRL('K'));
break;
case NSDownArrowFunctionKey:
output->write(CTRL('J'));
break;
default:
if (uc <= 0x7f)
{
char c = uc;
if (flags & NSControlKeyMask)
c = CTRL(c);
output->write(c);
}
break;
}
}
}
@end

422
Emulators/PTSE.mm.ragel Normal file
View File

@ -0,0 +1,422 @@
//
// PTSE.mm
// 2Term
//
// Created by Kelvin Sherlock on 7/9/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#include <sys/ttydefaults.h>
#import "PTSE.h"
#include "OutputChannel.h"
#include "Screen.h"
#include "algorithm.h"
%%{
machine console;
alphtype unsigned int;
action nop {}
action advance {
// advance cursor
if (++cursor.x == 80) {
cursor.x = 0;
if (cursor.y >= 24-1) {
screen->scrollUp();
} else cursor.y++;
}
}
arg1 = any ${ _scratch[0] = fc; };
arg2 = any ${ _scratch[1] = fc; };
main := (
0x00 $nop
| 0x01 ${
// A - $01 Move cursor to beginning of line.
cursor.x = 0;
}
| 0x02 ${
// B - $02 Move cursor to end of line.
cursor.x = 79;
}
| 0x03 $nop
| 0x04 ${
// D - Delete current character (under cursor)
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
screen->scrollLeft(tmp);
}
| 0x05 ${
/* E - $05 */
//Inquire if using ProTERM Special Emulation
/*
* When you send out [CONTROL-E] to a caller using ProTERM
* Special, the callers ProTERM will send back [CONTROL-“]”]
* (ASCII code 29). This allows a BBS to transparently
* detect the use of PSE.
*/
output->write(29);
}
| 0x06 ${
/* F - $06 */
// Insert space at cursor
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
screen->scrollRight(tmp);
}
| 0x07 ${
/* G - $07 - beep 1000 hz for .1 seconds. */
NSBeep();
}
| 0x08 ${
/* H - $08 - Moves cursor left one column;
if cursor was at beginning of line, moves
it to end of previous line
*/
if (cursor.x) cursor.x--;
else {
cursor.x = 80-1;
if (cursor.y) cursor.y--;
else screen->scrollDown();
}
}
| 0x09 ${
// control-I
cursor.x = (cursor.x + 8) & ~7;
cursor.x = std::min(cursor.x, 72); // verified.
}
| 0x0a ${
/* J - $0A - Moves cursor down one row; scrolls if needed */
if (cursor.y >= 24-1) {
screen->scrollUp();
} else cursor.y++;
}
| 0x0b ${
/* K - $0B - Move cursor up one line */
if (cursor.y == 0) {
screen->scrollDown();
} else cursor.y--;
}
| 0x0c ${
// control-L
/* clear text port and home */
// n.b - PT "home" is 0, 1
screen->eraseScreen();
cursor = iPoint(0,0);
}
| 0x0d ${
// control-M
/* carriage return */
cursor.x = 0;
}
| 0x0e ${
// control-N
//Set: inverse off, mousetext off.
_context.flags = Screen::FlagNormal;
}
| 0x0f ${
// control-O
//Set: inverse on, mousetext off.
_context.flags = Screen::FlagInverse;
}
| 0x10 ${
// control-P
//Set inverse off, mousetext on.
_context.flags = Screen::FlagInverse | Screen::FlagMouseText;
}
| 0x11 $nop
| 0x12 arg1 arg2 ${
/* ^R */
/*
* This allows a three character code to be used to display
* multiple characters. For example, to display a window frame,
* it is necessary to show the top and bottom borders which are
* long lines of the same character (dashes, underlines, etc.).
* To draw a 64-character line consisting of equal signs, send
* [CONTROL-R = @] where “@” is the ASCII code for 64.
*/
uint8_t c = _scratch[0] & 0x7f;
int count = _scratch[1];
while (count--) {
screen->putc(c, _context);
if (cursor.x++ >= 80) {
cursor.x = 0;
if (cursor.y < 23) cursor.y++;
else screen->scrollUp();
}
}
}
| 0x13 $nop
| 0x14 any any any ${
//Sound single/dual-tone for duration.
// [Control-T Tl Control-A D] Sound tone Tl, for duration D
// [Control-T Tl T2 D] Sound dual tone Tl, T2 for duration D
/*
* The tone command has two forms. The first invokes the single-tone
* generator, which produces relatively pure tones. The second
* invokes the dual-tone generator, which produces some rather
* interesting sounds. The three parameters, tone1, tone2, and
* duration, can all take values from 1 through 127. There is
* currently no known translation between pitch/duration values
* and actual frequencies/times.
*/
}
| 0x15 ${
/* ^U - Move cursor right one character */
} $advance
| 0x16 ${
/* CTRL('V') */
// Insert blank line
iRect tmp;
tmp.origin = iPoint(0, cursor.y);
tmp.size = iSize(80, 24 - cursor.y);
screen->scrollDown(tmp);
}
| 0x17 ${
/* CTRL('W') */
// Clear to end of screen
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
screen->eraseRect(tmp);
tmp = iRect(0, 0, 80, 24);
tmp.origin.y = cursor.y+1;
tmp.size.height -= cursor.y+1;
screen->eraseRect(tmp);
}
| 0x18 ${
// CTRL('X'):
// Home cursor (move to upper left corner)
// n.b. -- Proterm status bar on line 1. "home" is y=1.
cursor = iPoint(0,0);
}
| 0x19 ${
// CTRL('Y'):
/* clear to end of line. */
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
screen->eraseRect(tmp);
}
| 0x1a ${
// CTRL('Z'):
/* Delete current line */
iRect tmp;
tmp.origin = iPoint(0, cursor.y);
tmp.size = iSize(80, 24 - cursor.y);
screen->scrollUp(tmp);
}
| 0x1b $nop
| 0x1c $nop
| 0x1d $nop
| 0x1e arg1 arg2 ${
// CTRL('^'):
/* goto x y */
// todo - verify behavior for illegal values.
cursor.x = clamp(_scratch[0]-32, 0, 80 - 1);
cursor.y = clamp(_scratch[1]-32, 0, 24 - 1);
}
| 0x1f $nop
| 0x20 .. 0x7f ${
screen->putc(fc, _context);
} $advance
| 0x80..0xff $nop
)* $err{ fgoto main; };
write data;
}%%
@implementation PTSE
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"Proterm Special Emulation";
}
-(NSString *)name
{
return @"Proterm Special Emulation";
}
-(const char *)termName
{
return "proterm-special";
}
-(void)reset: (Screen *)screen
{
[self reset];
if (screen) screen->eraseScreen();
}
-(void)reset
{
%%write init;
_context.cursor = iPoint(0,0);
_context.window = iRect(0,0,80,24);
_context.flags = 0;
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
return ws;
}
-(id)init
{
[self reset];
return self;
}
-(void)initTerm: (struct termios *)term
{
// Control-U is used by the up-arrow key.
term->c_cc[VKILL] = CTRL('X');
}
-(void)processData:(const uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
const uint8_t *eof = nullptr;
const uint8_t *p = data;
const uint8_t *pe = data + length;
auto &cursor = _context.cursor;
%%write exec;
screen->setCursor(cursor);
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
switch (uc)
{
case NSEnterCharacter:
output->write(CTRL('M'));
break;
case NSDeleteCharacter:
output->write(0x7f);
break;
// backspace and left arrow use the same code, alas.
case NSBackspaceCharacter:
output->write(0x7f);
break;
case NSLeftArrowFunctionKey:
output->write(CTRL('H'));
break;
case NSRightArrowFunctionKey:
output->write(CTRL('U'));
break;
case NSUpArrowFunctionKey:
output->write(CTRL('K'));
break;
case NSDownArrowFunctionKey:
output->write(CTRL('J'));
break;
default:
if (uc <= 0x7f)
{
char c = uc;
if (flags & NSControlKeyMask)
c = CTRL(c);
output->write(c);
}
break;
}
}
}
@end