Added ANSI parsers and rendering ANSI frames

This commit is contained in:
Deon George 2018-12-14 00:02:42 +11:00
parent e0306908bd
commit 6cc793c47f
14 changed files with 333 additions and 119 deletions

View File

@ -35,7 +35,8 @@ use App\Models\CUG;
abstract class Frame abstract class Frame
{ {
protected $frame = NULL; protected $frame = NULL;
protected $output = NULL; protected $output = '';
protected $startline = 1;
// All this vars should be overridden in the child class // All this vars should be overridden in the child class
/* /*
@ -71,17 +72,11 @@ abstract class Frame
// @todo Move this to the database // @todo Move this to the database
private $header = RED.'T'.BLUE.'E'.GREEN.'S'.YELLOW.'T'.MAGENTA.'!'; private $header = RED.'T'.BLUE.'E'.GREEN.'S'.YELLOW.'T'.MAGENTA.'!';
public function __construct(\App\Models\Frame $o,string $msg=NULL) public function __construct(\App\Models\Frame $o)
{ {
$this->frame = $o; $this->frame = $o;
$this->output = $this->hasFlag('clear') ? CLS : HOME; $this->output = $this->frame->cls ? CLS : HOME;
// If we have a message to display on the bottom line.
if ($msg)
$this->output .= UP.$msg.HOME;
$startline = 0;
if (! $this->hasFlag('ip') AND (! $this->isCUG(0) OR $this->type() !== self::FRAMETYPE_LOGIN)) { if (! $this->hasFlag('ip') AND (! $this->isCUG(0) OR $this->type() !== self::FRAMETYPE_LOGIN)) {
// Set the page header: CUG/Site Name | Page # | Cost // Set the page header: CUG/Site Name | Page # | Cost
@ -89,12 +84,16 @@ abstract class Frame
$this->render_page($this->frame->frame,$this->frame->index). $this->render_page($this->frame->frame,$this->frame->index).
$this->render_cost($this->frame->cost); $this->render_cost($this->frame->cost);
$startline = 1; $this->startline = 2;
} elseif ($this->isCUG(0) AND $this->type() === self::FRAMETYPE_LOGIN) {
$this->startline = 2;
$this->output .= str_repeat(DOWN,$this->startline-1);
} }
// Calculate fields and render output. // Calculate fields and render output.
$this->fields = collect(); // Fields in this frame. $this->fields = collect(); // Fields in this frame.
$this->fields($startline); $this->fields($this->startline);
} }
/** /**
@ -403,17 +402,18 @@ abstract class Frame
$o->index = 'a'; $o->index = 'a';
$o->access = 1; $o->access = 1;
$o->closed = 0; $o->closed = 0;
$o->cls = 1;
// Header // Header
$sid = R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T'; $sid = R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T';
$o->content .= substr($sid.'-'.str_repeat('12345678901234567890',4),0,static::$header_length+(strlen($sid)-$so->strlenv($sid))). $o->content .= substr($sid.'-'.str_repeat('12345678901234567890',4),0,static::$header_length+(strlen($sid)-$so->strlenv($sid))).
R_WHITE.'999999999a'.R_RED.sprintf('%07.0f',999).'u'; R_WHITE.'999999999a'.R_RED.sprintf('%07.0f',999).'u';
$o->content .= str_repeat('+-',18).' '.R_RED.'01'; $o->content .= R_WHITE.str_repeat('+-',static::$frame_width/2-3).' '.R_RED.'01';
$o->content .= 'Name: '.ESC.str_repeat('u',5).str_repeat('+-',14); $o->content .= R_WHITE.'Name: '.ESC.str_repeat('u',5).' |'.str_repeat('+-',static::$frame_width/2-8).'|';
$o->content .= 'Date: '.ESC.str_repeat('d',25).str_repeat('+-',4); $o->content .= R_WHITE.'Date: '.ESC.str_repeat('d',17).' |'.str_repeat('+-',static::$frame_width/2-14).'|';
$o->content .= 'Address: '.ESC.str_repeat('a',19).' '.str_repeat('+-',5); $o->content .= R_WHITE.'Address: '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|';
$o->content .= ' : '.ESC.str_repeat('a',19).' '.str_repeat('+-',5); $o->content .= R_WHITE.' : '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|';
return $o; return $o;
} }

View File

@ -46,6 +46,7 @@ class Login extends Action
return FALSE; return FALSE;
} }
$this->so->log('info','User Login: '.$this->uo->name);
$this->page = ['frame'=>1,'index'=>'a']; // @todo Get from DB. $this->page = ['frame'=>1,'index'=>'a']; // @todo Get from DB.
$this->action = 2; // ACTION_GOTO $this->action = 2; // ACTION_GOTO

View File

@ -5,6 +5,7 @@ namespace App\Classes\Frame;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Classes\Frame as AbstractFrame; use App\Classes\Frame as AbstractFrame;
use App\Classes\Parser\Ansi as AnsiParser;
class Ansi extends AbstractFrame class Ansi extends AbstractFrame
{ {
@ -18,9 +19,21 @@ class Ansi extends AbstractFrame
public static $if_filler = '.'; public static $if_filler = '.';
public function fields($startline=0) public function __construct(\App\Models\Frame $o,string $msg='')
{ {
$this->output .= str_replace(LF,CR.LF,$this->frame->content); parent::__construct($o);
// If we have a message to display on the bottom line.
if ($msg)
$this->output .= ESC.'[24;0f'.$msg.HOME;
}
public function fields($startline=1)
{
$o = new AnsiParser($this->frame->content,$startline);
$this->output .= (string)$o;
$this->fields = $o->fields;
} }
public function strlenv($text):int { public function strlenv($text):int {

View File

@ -19,26 +19,32 @@ class Videotex extends AbstractFrame
public static $if_filler = '.'; public static $if_filler = '.';
public function fields($startline=0) public function __construct(\App\Models\Frame $o,string $msg='')
{
parent::__construct($o);
// If we have a message to display on the bottom line.
if ($msg)
$this->output .= HOME.UP.$msg.HOME;
}
public function fields($startline=1)
{ {
$infield = FALSE; // In a field $infield = FALSE; // In a field
$fieldtype = NULL; // Type of field $fieldtype = NULL; // Type of field
$fieldlength = 0; // Length of field $fieldlength = 0; // Length of field
if ($startline)
$this->output .= str_repeat(DOWN,$startline);
// $fieldadrline = 1; // $fieldadrline = 1;
// Scan the frame for a field start // Scan the frame for a field start
for ($y=$startline;$y<=static::$frame_length;$y++) for ($y=$startline-1;$y<=static::$frame_length;$y++)
{ {
// Fields can only be on a single line // Fields can only be on a single line
$fieldx = $fieldy = FALSE; $fieldx = $fieldy = FALSE;
for ($x=0;$x<static::$frame_width;$x++) for ($x=0;$x<static::$frame_width;$x++)
{ {
$posn = $y*40+$x; $posn = $y*static::$frame_width+$x;
// If the frame is not big enough, fill it with spaces. // If the frame is not big enough, fill it with spaces.
$byte = ord(isset($this->frame->content{$posn}) ? $this->frame->content{$posn} : ' ')%128; $byte = ord(isset($this->frame->content{$posn}) ? $this->frame->content{$posn} : ' ')%128;
@ -62,7 +68,6 @@ class Videotex extends AbstractFrame
} }
// Is this a magic field? // Is this a magic field?
// @todo For page redisplay *00, we should show entered contents - for refresh *09 we should show updated contents
if (array_get($this->fieldmap,chr($fieldtype)) ) { if (array_get($this->fieldmap,chr($fieldtype)) ) {
$field = $this->fieldmap[chr($fieldtype)]; $field = $this->fieldmap[chr($fieldtype)];
//dump(['infield','byte'=>$byte,'fieldtype'=>$fieldtype,'field'=>$field,'strpos'=>strpos($field,'#')]); //dump(['infield','byte'=>$byte,'fieldtype'=>$fieldtype,'field'=>$field,'strpos'=>strpos($field,'#')]);

View File

@ -15,4 +15,17 @@ class FrameFields
{ {
return array_get($this->fields,$key); return array_get($this->fields,$key);
} }
public function output(string $filler)
{
switch ($this->type) {
case 'd':
$out = date('D d M H:ia');
return substr($out.($this->length > strlen($out) ? str_repeat($filler,$this->length-strlen($out)) : ''),0,$this->length);
default:
return str_repeat($filler,$this->length);
}
}
} }

7
app/Classes/Parser.php Normal file
View File

@ -0,0 +1,7 @@
<?php
namespace App\Classes;
class Parser
{
}

156
app/Classes/Parser/Ansi.php Normal file
View File

@ -0,0 +1,156 @@
<?php
namespace App\Classes\Parser;
use Illuminate\Support\Facades\Log;
use App\Classes\FrameFields;
use App\Classes\Parser as AbstractParser;
use App\Classes\Frame\Ansi as AnsiFrame;
class Ansi extends AbstractParser {
private $content = '';
private $startline = 0;
public $fields = NULL;
public function __construct(string $content,int $startline=1)
{
$this->content = $content;
$this->startline = $startline;
$this->fields = collect();
}
public function __toString(): string
{
return $this->parse($this->startline);
}
/**
* Parse a string and look for the next character that is not $char
*
* @param string $char
* @param int $start
* @return bool|int
*/
private function findEOF(string $char,int $start)
{
for ($c=$start;$c <= strlen($this->content);$c++)
{
if ($this->content{$c} != $char)
return $c-$start;
}
return FALSE;
}
/**
* @param $startline
* @param int $offset
* @return string
*/
private function parse($startline): string
{
// Our starting coordinates
$x = 1;
$y = $startline;
$output = '';
// Scan the frame for a field start
for ($c=0; $c<=strlen($this->content); $c++)
{
// If the frame is not big enough, fill it with spaces.
$byte = isset($this->content{$c}) ? $this->content{$c} : ' ';
$advance = 0;
switch ($byte) {
case CR:
$x = 1;
break;
case LF:
$y++;
break;
case ESC:
$advance = 1;
// Is the next byte something we know about
$nextbyte = isset($this->content{$c+$advance}) ? $this->content{$c+$advance} : ' ';
switch ($nextbyte) {
case '[':
$advance++;
$chars = $nextbyte;
// Find our end CSI param
$matches = [];
$a = preg_match('/([0-9]+[;]?)+([a-zA-Z])/',$this->content,$matches,NULL,$c+$advance);
if (! $a)
break;
$advance += strlen($matches[0])-1;
$chars .= $matches[0];
switch ($matches[2]) {
// We ignore 'm' they are color CSIs
case 'm': break;
case 'C':
$x += $matches[1]; // Advance our position
break;
default:
dump('Unhandled CSI: '.$matches[2]);
}
break;
case ' ':
dump(['l'=>__LINE__,'LOOSE ESC?']);
break;
default:
$c--; // Allow for the original ESC
$advance++;
$fieldtype = ord($nextbyte)%128; // @todo Do we need the %128 for ANSI?
$fieldlength = $this->findEOF(chr($fieldtype),$c+1)+1;
$byte = '';
$this->fields->push(new FrameFields([
'type'=>chr($fieldtype),
'length'=>$fieldlength,
'x'=>$x, // Adjust for the ESC char
'y'=>$y,
]));
Log::debug(sprintf('Field found at [%s,%s], Type: %s, Length: %s',$x-1,$y,$fieldtype,$fieldlength));
$advance += $fieldlength-2;
$x += $fieldlength;
$chars = $this->fields->last()->output(AnsiFrame::$if_filler);
}
break;
default:
$x++;
}
$output .= $byte;
if ($advance) {
$output .= $chars;
$c += $advance;
}
if ($x > 80) {
$x = 1;
$y++;
}
}
return $output;
}
}

View File

@ -23,7 +23,7 @@ abstract class Server {
$this->mo = $o; $this->mo = $o;
define('MODE_BL', 1); // Typing a * command on the baseline define('MODE_BL', 1); // Typing a * command on the baseline
define('MODE_FIELD', 2); // typing into an imput field define('MODE_FIELD', 2); // typing into an input field
define('MODE_WARPTO', 3); // awaiting selection of a timewarp define('MODE_WARPTO', 3); // awaiting selection of a timewarp
define('MODE_COMPLETE', 4); // Entry of data is complete .. define('MODE_COMPLETE', 4); // Entry of data is complete ..
define('MODE_SUBMITRF', 5); // asking if should send or not. define('MODE_SUBMITRF', 5); // asking if should send or not.
@ -64,12 +64,12 @@ abstract class Server {
define('TCP_OPT_LINEMODE', chr(34)); define('TCP_OPT_LINEMODE', chr(34));
define('MSG_SENDORNOT', GREEN.'KEY 1 TO SEND, 2 NOT TO SEND'); define('MSG_SENDORNOT', GREEN.'KEY 1 TO SEND, 2 NOT TO SEND');
define('MSG_SENT', GREEN.'MESSAGE SENT - KEY _ TO CONTINUE'); define('MSG_SENT', GREEN.'MESSAGE SENT - KEY '.HASH.' TO CONTINUE');
define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY _ TO CONTINUE'); define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY '.HASH.' TO CONTINUE');
define('ERR_DATABASE', RED.'UNAVAILABLE AT PRESENT - PLSE TRY LATER'); define('ERR_DATABASE', RED.'UNAVAILABLE AT PRESENT - PLSE TRY LATER');
define('ERR_NOTSENT', WHITE.'MESSAGE NOT SENT DUE TO AN ERROR'); define('ERR_NOTSENT', WHITE.'MESSAGE NOT SENT DUE TO AN ERROR');
define('ERR_PRIVATE', WHITE.'PRIVATE PAGE'.GREEN.'- FOR EXPLANATION *37_..'); define('ERR_PRIVATE', WHITE.'PRIVATE PAGE'.GREEN.'- FOR EXPLANATION *37'.HASH.'..');
define('ERR_ROUTE', WHITE.'MISTAKE?'.GREEN.'TRY AGAIN OR TELL US ON *08'); define('ERR_ROUTE', WHITE.'MISTAKE?'.GREEN.'TRY AGAIN OR TELL US ON *08');
define('ERR_PAGE',ERR_ROUTE); define('ERR_PAGE',ERR_ROUTE);
define('ERR_USER_ALREADYMEMBER', RED.'ALREADY MEMBER OF CUG'); define('ERR_USER_ALREADYMEMBER', RED.'ALREADY MEMBER OF CUG');
@ -143,16 +143,17 @@ abstract class Server {
// @todo Get the login/start page, and if it is not available, throw the ERR_DATEBASE error. // @todo Get the login/start page, and if it is not available, throw the ERR_DATEBASE error.
if (isset($config['loginpage'])) { if (isset($config['loginpage'])) {
$page = ['frame'=>$config['loginpage'],'index'=>'a']; $page = ['frame'=>$config['loginpage']];
} else if (!empty($service['start_page'])) { } else if (!empty($service['start_page'])) {
$page = ['frame'=>$service['start_page'],'index'=>'a']; $page = ['frame'=>$service['start_page']];
} else { } else {
$page = ['frame'=>'980','index'=>'a']; // next page $page = ['frame'=>'980']; // next page
} }
while ($action != ACTION_TERMINATE) { while ($action != ACTION_TERMINATE) {
// Read a character from the client session // Read a character from the client session
$read = $client->read(1); $read = $client->read(1);
printf(". Got: %s (%s)\n",$read,ord($read));
// It appears that read will return '' instead of false when a disconnect has occurred. // It appears that read will return '' instead of false when a disconnect has occurred.
// We'll set it to NULL so its caught later // We'll set it to NULL so its caught later
@ -181,6 +182,7 @@ abstract class Server {
case TCP_SE: case TCP_SE:
$session_option = $session_init = FALSE; $session_option = $session_init = FALSE;
$this->log('debug',sprintf('Session Terminal: %s',$session_term)); $this->log('debug',sprintf('Session Terminal: %s',$session_term));
$read = '';
break; break;
@ -258,7 +260,7 @@ abstract class Server {
if ($current['field']->type == 'u' AND array_get($fielddata,$current['fieldnum']) == 'NEW') if ($current['field']->type == 'u' AND array_get($fielddata,$current['fieldnum']) == 'NEW')
{ {
$action = ACTION_GOTO; $action = ACTION_GOTO;
$page = ['frame'=>'981','index'=>'a']; // @todo This should be in the DB. $page = ['frame'=>'981']; // @todo This should be in the DB.
} }
} }
@ -269,6 +271,7 @@ abstract class Server {
case Frame::FRAMETYPE_ACTION: case Frame::FRAMETYPE_ACTION:
switch ($read) { switch ($read) {
// End of field entry. // End of field entry.
case LF:
case HASH: case HASH:
// Next Field // Next Field
$current['fieldnum']++; $current['fieldnum']++;
@ -391,11 +394,10 @@ abstract class Server {
$route = $fo->route(1); $route = $fo->route(1);
if ($route == '*' OR is_numeric($route)) { if ($route == '*' OR is_numeric($route)) {
$this->sendBaseline($client, RED . 'NO action performed'); $this->sendBaseline($client,RED.'NO ACTION PERFORMED');
$mode = MODE_RFSENT; $mode = MODE_RFSENT;
} elseif ($ao = FrameClass\Action::factory($fo->route(1),$this,$user,$action,$mode)) { } elseif ($ao = FrameClass\Action::factory($fo->route(1),$this,$user,$action,$mode)) {
$ao->handle($fielddata); $ao->handle($fielddata);
$mode = $ao->mode; $mode = $ao->mode;
$action = $ao->action; $action = $ao->action;
@ -431,28 +433,22 @@ abstract class Server {
$client->send(COFF); $client->send(COFF);
if ($read == HASH) { if ($read == HASH) {
if (! empty($pagedata['route1'])) { if ($route = $fo->route(2) AND $route !== '*' AND is_numeric($route)) {
$action = ACTION_GOTO; $page = ['frame'=>$route];
$page['frame'] = $pagedata['route1'];
$page['index'] = 'a';
} elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) { } elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) {
$action = ACTION_GOTO; $page = ['frame'=>$fo->frame(),'index'=>$fo->index_next()];
$page['frame'] = array_get($current,'page.frame');
$page['index'] = chr(1 + ord($page['index']));
} elseif (! empty($pagedata['route0'])) { } elseif ($route = $fo->route(0) AND $route !== '*' AND is_numeric($route)) {
$action = ACTION_GOTO; $page = ['frame'=>$route];
$page['frame'] = $pagedata['route0'];
$page['index'] = 'a';
// No further routes defined, go home. // No further routes defined, go home.
} else { } else {
$action = ACTION_GOTO; $page = ['frame'=>0];
$page['frame'] = '0';
$page['index'] = 'a';
} }
$action = ACTION_GOTO;
} elseif ($read == STAR) { } elseif ($read == STAR) {
$action = ACTION_STAR; $action = ACTION_STAR;
@ -469,28 +465,22 @@ abstract class Server {
$client->send(COFF); $client->send(COFF);
if ($read == HASH) { if ($read == HASH) {
if (! empty($pagedata['route2'])) { if ($route = $fo->route(2) AND $route !== '*' AND is_numeric($route)) {
$action = ACTION_GOTO; $page = ['frame'=>$route];
$page['frame'] = $pagedata['route2'];
$page['index'] = 'a';
} elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) { } elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) {
$action = ACTION_GOTO; $page = ['frame'=>$fo->frame(),'index'=>$fo->index_next()];
$page['frame'] = $fo->frame();
$page['index'] = $fo->index_next();
} elseif (! empty($pagedata['route0'])) { } elseif ($route = $fo->route(0) AND $route !== '*' AND is_numeric($route)) {
$action = ACTION_GOTO; $page = ['frame'=>$route];
$page['frame'] = $pagedata['route0'];
$page['index'] = 'a';
// No further routes defined, go home. // No further routes defined, go home.
} else { } else {
$action = ACTION_GOTO; $page = ['frame'=>0];
$page['frame'] = '0';
$page['index'] = 'a';
} }
$action = ACTION_GOTO;
} elseif ($read == STAR) { } elseif ($read == STAR) {
$action = ACTION_STAR; $action = ACTION_STAR;
@ -554,7 +544,7 @@ abstract class Server {
// Currently accepting baseline input after a * was received // Currently accepting baseline input after a * was received
case MODE_BL: case MODE_BL:
echo "was waiting for page number\n"; echo "- Waiting for Page Number\n";
// if it's a number, continue entry // if it's a number, continue entry
if (strpos('0123456789', $read) !== FALSE) { if (strpos('0123456789', $read) !== FALSE) {
@ -623,7 +613,7 @@ abstract class Server {
} }
// Complete request // Complete request
if ($read === HASH) { if ($read === HASH or $read === LF) {
$client->send(COFF); $client->send(COFF);
$timewarpalt = FALSE; $timewarpalt = FALSE;
@ -657,21 +647,22 @@ abstract class Server {
// This section performs some action if it is deemed necessary // This section performs some action if it is deemed necessary
if ($action) { if ($action) {
echo "Performing action $action\n"; printf("+ Performing action: %s\n",$action);
} }
switch ($action) { switch ($action) {
case ACTION_STAR: case ACTION_STAR:
echo " star command started\n"; echo "+ Star command...\n";
$this->sendBaseline($client,GREEN.STAR,true);
$this->sendBaseline($client,GREEN.STAR,TRUE);
$client->send(CON); $client->send(CON);
$action = false; $action = FALSE;
$mode = MODE_BL; $mode = MODE_BL;
break; break;
case ACTION_SUBMITRF: case ACTION_SUBMITRF:
$action = false; $action = FALSE;
$client->send(COFF); $client->send(COFF);
$this->sendBaseline($client,MSG_SENDORNOT); $this->sendBaseline($client,MSG_SENDORNOT);
$mode = MODE_SUBMITRF; $mode = MODE_SUBMITRF;
@ -705,7 +696,7 @@ abstract class Server {
try { try {
$fo = $timewarpalt $fo = $timewarpalt
? $this->mo->frame(FrameModel::findOrFail($timewarpalt)) ? $this->mo->frame(FrameModel::findOrFail($timewarpalt))
: $this->mo->frameLoad($page['frame'],$page['index'],$this); : $this->mo->frameLoad($page['frame'],array_get($page,'index','a'),$this);
$this->log('debug',sprintf('Fetched frame: %s (%s)',$fo->id(),$fo->page())); $this->log('debug',sprintf('Fetched frame: %s (%s)',$fo->id(),$fo->page()));
@ -784,19 +775,8 @@ abstract class Server {
// drop into // drop into
case ACTION_RELOAD: case ACTION_RELOAD:
// @todo Move this $output into the object. $this->sendBaseline($client,'');
if ($fo->hasFlag('clear')) $output = (string)$fo;
{
$this->blp = 0;
$output = CLS;
} else {
$output = HOME;
// Clear the baseline.
$this->sendBaseline($client,'');
}
$output .= (string)$fo;
if ($timewarpalt) { if ($timewarpalt) {
$this->sendBaseline($client,sprintf(MSG_TIMEWARP_TO,$fo->created() ? $fo->created()->format('Y-m-d H:i:s') : 'UNKNOWN')); $this->sendBaseline($client,sprintf(MSG_TIMEWARP_TO,$fo->created() ? $fo->created()->format('Y-m-d H:i:s') : 'UNKNOWN'));
@ -922,21 +902,7 @@ abstract class Server {
/** /**
* Move the cursor via the shortest path. * Move the cursor via the shortest path.
*/ */
function outputPosition($x,$y) { abstract function outputPosition($x,$y);
// Take the shortest path.
if ($y < 12) {
return HOME.
(($x < 21)
? str_repeat(DOWN,$y).str_repeat(RIGHT,$x)
: str_repeat(DOWN,$y+1).str_repeat(LEFT,40-$x));
} else {
return HOME.str_repeat(UP,24-$y).
(($x < 21)
? str_repeat(RIGHT,$x)
: str_repeat(LEFT,40-$x));
}
}
/** /**
* Send a message to the base line * Send a message to the base line

View File

@ -16,8 +16,8 @@ class Ansi extends AbstractServer {
define('HOME', ESC.'[0;0f'); define('HOME', ESC.'[0;0f');
define('LEFT', ESC.'[D'); // Move Cursor define('LEFT', ESC.'[D'); // Move Cursor
define('RIGHT', ESC.'[C'); // Move Cursor define('RIGHT', ESC.'[C'); // Move Cursor
define('DOWN', chr(10)); // Move Cursor define('DOWN', ESC.'[B'); // Move Cursor
define('UP', chr(11)); // Move Cursor define('UP', ESC.'[A'); // Move Cursor
define('CR', chr(13)); define('CR', chr(13));
define('LF', chr(10)); define('LF', chr(10));
define('CLS', ESC.'[2J'); define('CLS', ESC.'[2J');
@ -48,6 +48,10 @@ class Ansi extends AbstractServer {
parent::__construct($o); parent::__construct($o);
} }
function outputPosition($x,$y) {
return ESC.'['.$y.';'.$x.'f';
}
// Abstract function // Abstract function
public function sendBaseline($client,$text,$reposition=FALSE) { public function sendBaseline($client,$text,$reposition=FALSE) {
$client->send(ESC.'[24;0f'.$text. $client->send(ESC.'[24;0f'.$text.

View File

@ -48,6 +48,22 @@ class Videotex extends AbstractServer {
parent::__construct($o); parent::__construct($o);
} }
public function outputPosition($x,$y) {
// Take the shortest path.
if ($y < 12) {
return HOME.
(($x < 21)
? str_repeat(DOWN,$y).str_repeat(RIGHT,$x)
: str_repeat(DOWN,$y+1).str_repeat(LEFT,40-$x));
} else {
return HOME.str_repeat(UP,24-$y).
(($x < 21)
? str_repeat(RIGHT,$x)
: str_repeat(LEFT,40-$x));
}
}
public function sendBaseline($client,$text,$reposition=FALSE) { public function sendBaseline($client,$text,$reposition=FALSE) {
$client->send(HOME.UP.$text. $client->send(HOME.UP.$text.
($this->blp > $this->strlenv($text) ($this->blp > $this->strlenv($text)

View File

@ -61,6 +61,7 @@ class FrameImport extends Command
try { try {
$o = $o->where('frame',$this->argument('frame')) $o = $o->where('frame',$this->argument('frame'))
->where('index',$this->argument('index')) ->where('index',$this->argument('index'))
->where('mode_id',$this->option('mode'))
->firstOrFail(); ->firstOrFail();
} catch (ModelNotFoundException $e) { } catch (ModelNotFoundException $e) {
@ -71,6 +72,7 @@ class FrameImport extends Command
} else { } else {
$o->frame = $this->argument('frame'); $o->frame = $this->argument('frame');
$o->index = $this->argument('index'); $o->index = $this->argument('index');
$o->mode_id = $this->option('mode');
} }
$o->content = ($this->option('trim')) $o->content = ($this->option('trim'))
@ -80,7 +82,6 @@ class FrameImport extends Command
$o->access = $this->option('access'); $o->access = $this->option('access');
$o->closed = $this->option('closed'); $o->closed = $this->option('closed');
$o->cost = $this->option('cost'); $o->cost = $this->option('cost');
$o->mode_id = $this->option('mode');
$o->type = $this->option('type'); $o->type = $this->option('type');
$o->save(); $o->save();

View File

@ -44,11 +44,11 @@ class Mode extends Model
* *
* @param int $frame * @param int $frame
* @param string $index * @param string $index
* @param Server $so
* @return FrameClass * @return FrameClass
* @throws \Exception * @throws \Exception
*/ */
//@todo Move Server $so first public function frameLoad(int $frame,string $index,Server $so): FrameClass
public function frameLoad(int $frame,string $index='a',Server $so): FrameClass
{ {
return $this->frame( return $this->frame(
// Return our internal test frame. // Return our internal test frame.

View File

@ -16,19 +16,19 @@ class CreateFramemeta extends Migration
$this->down(); $this->down();
Schema::create('framemeta', function (Blueprint $table) { Schema::create('framemeta', function (Blueprint $table) {
$table->integer('frame_id')->primary(); $table->integer('frame_id')->primary();
$table->string('r0')->default('*'); $table->string('r0')->default('*');
$table->string('r1')->default('*'); $table->string('r1')->default('*');
$table->string('r2')->default('*'); $table->string('r2')->default('*');
$table->string('r3')->default('*'); $table->string('r3')->default('*');
$table->string('r4')->default('*'); $table->string('r4')->default('*');
$table->string('r5')->default('*'); $table->string('r5')->default('*');
$table->string('r6')->default('*'); $table->string('r6')->default('*');
$table->string('r7')->default('*'); $table->string('r7')->default('*');
$table->string('r8')->default('*'); $table->string('r8')->default('*');
$table->string('r9')->default('*'); $table->string('r9')->default('*');
$table->foreign('frame_id')->references('id')->on('frames'); $table->foreign('frame_id')->references('id')->on('frames');
}); });
} }

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class FrameAddClear extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('frames', function (Blueprint $table) {
$table->boolean('cls')->default(TRUE);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('frames', function (Blueprint $table) {
$table->dropColumn('cls');
});
}
}