php/envClass.php
<?php
/*
output handling using a class structure
*** unfinished draft ***********
*/
class PutEcho {
public function put($txt) {
echo $txt;
}
}
class PutMem {
public $out;
function __construct() {
$this->out = fOpen('php://memory', 'w+');
}
public function put($txt) {
fwrite($this->out, $txt);
}
public function close() {
fclose($this->out);
}
public function cont() {
$sz = ftell($this->out);
rewind($this->out);
$c = fread($this->out, $sz);
ftruncate($this->out, 0);
rewind($this->out);
return $c;
}
}
class Out {
public static $out ;
static $list = [];
public static function outAdd($nm, $o) {
Out::$out = Out::$list[$nm] = $o;
}
}
class OutStack {
protected $stack = [];
protected $oFun;
protected $popped;
const Lipop = ['Li' => 1]
, List = ['Li']
, LLpop = ['Li' => 1, 'LL' => 1]
, TRpop = ['Li' => 1, 'LL' => 1, 'TD' => 1, 'TR' => 1]
, TRst = ['TR']
, TBok = ['Tb' => 1]
, TDpop = ['Li' => 1, 'LL' => 1, 'TD' => 1, ]
, TRok = ['TR' => 1]
, TDok = ['TD' => 1]
, THok = ['TH' => 1]
;
function __construct() {
$this->o = new PutEcho();
}
protected function pop($pop, $to = null, $toPop = 0) {
while ((false !== $tos = end($this->stack)) and isset($pop[$tos[0]]))
$this->{"xyt$tos[0]End"}();
if ($to !== null and ($tos === false or $tos[0] !== $to))
err("pop tos = ", $tos, 'and not ', $to);
return $toPop ? $this->popped = array_pop($this->stack) : $tos;
}
public function o($txt) {
($this->oFun)($txt);
}
public function xyt($txt) {
$this->oo($txt);
}
public function xytW($txt) {
$this->oW($txt);
}
public function xytNL($txt) {
$this->oNL($txt);
}
public function xytH($txt) {
$this->pop(self::LLpop);
$this->oH($txt);
}
public function xytLL($fmt) {
array_push($this->stack, ['LL', $fmt]);
$this->oLL($fmt);
}
public function xytLLEnd() {
$this->oLLEnd($this->pop(self::Lipop, 'LL', 1)[1]);
}
public function xytLi($txt) {
$tos = $this->pop(self::Lipop, 'LL');
array_push($this->stack, self::List);
$this->oLi($txt);
}
public function xytLiEnd() {
$tos = $this->pop(null, 'Li', 1);
$this->oLiEnd();
}
public function xytTb() { # table begin
array_push($this->stack, ['Tb', -1, -1, null]);
$this->oTb();
}
public function xytTbEnd() { # table end
$this->pop(self::TRpop, 'Tb', 1);
$this->oTbEnd();
}
public function xytTCF($fmt) { # table row formats
if ('Tb' !== ($tb = &$this->stack[array_key_last($this->stack)])[0])
err("xytTCF top of stack", $tb, "not table");
$tb[3] = $fmt;
}
public function xytTR() { # table row
$this->pop(self::TRpop, 'Tb');
$tb = &$this->stack[array_key_last($this->stack)];
$tb[1]++ ;
$tb[2] = -1 ;
array_push($this->stack, self::TRst);
$this->oTR();
}
public function xytTREnd() { # table row
$this->pop(self::TDpop, 'TR', 1);
$this->oTREnd();
}
public function xytTD($fmt, $tx) { # table data
if ('Tb' === end($this->stack)[0])
$this->xytTR();
else
$this->pop(self::TDpop, 'TR');
if ('Tb' !== ($tb = &$this->stack[array_key_last($this->stack)-1])[0])
err("xytTD stack has", $tb, "not table");
$tb[2]++ ;
$fmt .= $tb[3][$tb[2]] ?? '';
$fmt = (strpos($fmt, '!') === false ? '' : '!') . (strpos($fmt, 'r') === false ? 'l' : 'r');
array_push($this->stack, $tos = ['TD', $fmt[0] === '!' ? 'th' : 'td', $fmt]);
$this->oTD($tos, "r$tb[1]c$tb[2] $tx");
}
public function xytTDEnd() { # table row
$this->oTDEnd($this->pop(self::LLpop, 'TD', 1));
}
}
class OutHtml extends OutStack {
public function oo($txt) { $this->o->put("$txt\n<br>"); }
public function oNL($txt) { $this->o->put("\n<br>$txt"); }
public function oW($txt) { $this->o->put($txt); }
public function oH($txt) { $this->o->put("\n<h2>$txt</h2>"); }
public function oLL($fmt) { $this->o->put("\n<$fmt>"); }
public function oLLEnd($fmt) { $this->o->put("\n</$fmt>"); }
public function oLi($txt) { $this->o->put("\n<li>$txt"); }
public function oLiEnd() { $this->o->put("</li>"); }
public function oTb() { $this->o->put("\n<table border=2>"); }
public function oTbEnd() { $this->o->put("\n</table>"); }
public function oTR() { $this->o->put("\n<tr>"); }
public function oTREnd() { $this->o->put("\n</tr>"); }
public function oTD($e, $txt) { $this->o->put("\n<$e[1]" . ($e[2][-1] === 'r' ? " style='text-align: right;'" : '') . ">$txt"); }
public function oTDEnd() { $this->o->put("</{$this->popped[1]}>"); }
}
class OutCli extends OutStack {
protected $lvl = 0;
protected $intend = '';
protected $lastNL = false;
public function level($l) {
$this->lvl = $l >= 0 ? $l : $this->lvl + 10 + $l;
$this->intend = str_pad('', 4 * $this->lvl);
}
public function o($txt) {
($this->oFun)($txt);
$this->lastNL = false;
}
public function oo($txt) { $this->o->put("$txt\n$this->intend"); }
public function oNL($txt) { $this->o->put("\n$this->intend$txt"); }
public function oW($txt) { $this->o->put($txt); }
public function oH($txt) {$this->o->put("\n\n--- $txt ---\n"); }
public function oLL($fmt) {
$this->level(-9); // +1
array_push($this->stack[array_key_last($this->stack)], $this->lvl, 0);
}
public function oLLEnd() {
if ($this->popped[2] !== $this->lvl)
err('oOLEnd lvl mismatch');
$this->level(-11); // -1
}
public function oLi($txt) {
$ll = &$this->stack[array_key_last($this->stack)-1];
$rp = max(1, 4-$this->lvl);
# echo "\noLi $iL ". a2str($this->stack);
$this->o->put(($this->lastNL ? '' : "\n") . substr($this->intend, 0, -2)
. ($ll[1] === 'OL' ? (++$rp[3]) . str_repeat('.', $rp) : str_repeat('*', $rp)) . " $txt");
}
public function oLiEnd() {
if (! $this->lastNL) {
$this->o->put("\n");
$this->lastNL = true;
}
}
public function oTb() {
if ('Tb' !== ($tb = &$this->stack[array_key_last($this->stack)])[0] or count($tb) !== 4)
err("oTb stack has", $tb, "not table with 4 eles");
array_push($tb, [], [], $this->o, $this->lvl);
$this->o = new PutMem();
$this->level(0);
}
public function oTbEnd() {
if ('Tb' !== ($tb = $this->popped)[0] or count($tb) !== 8)
err("oTbEnd popped", $tb, "not table with 8 eles");
if (0 !== ftell($this->o->out))
err("oTbEnd o not empty but", $this->o->cont());
$this->o->close();
$this->o = $tb[6];
$this->level($tb[7]);
$this->tbGen($this->popped[4], $this->popped[5]);
}
public function oTR() {
if ('Tb' !== ($tb = &$this->stack[array_key_last($this->stack)-1])[0] or count($tb) !== 8)
err("oTR stack -1 has", $tb, "not table with 8 eles");
$tb[4][] = [];
$tb[5][] = [];
}
public function oTREnd() {
}
public function oTD($e, $txt) {
if ('Tb' !== ($tb = &$this->stack[array_key_last($this->stack)-2])[0] or count($tb) !== 8)
err("oTD stack -2 has", $tb, "not table with 8 eles");
$tb[5][$tb[1]][$tb[2]] = $e[2];
$this->o->put($txt);
}
public function oTDEnd() {
if ('Tb' !== ($tb = &$this->stack[array_key_last($this->stack)-1])[0] or count($tb) !== 8)
err("oTb stack has", $tb, "not table with 8 eles");
$tb[4][$tb[1]][$tb[2]] = $this->o->cont();
}
function tbGen($tb, $fm) {
xyt('tbGen table', $tb, 'fmt', $fm);
$cLen = [];
$rLin = [];
foreach ($tb as $rx => $rw) {
foreach ($rw as $cx => $ce) {
$tb[$rx][$cx] = preg_split("/\R/", $ce);
if (count($tb[$rx][$cx]) > ($rLin[$rx] ?? -1))
$rLin[$rx] = count($tb[$rx][$cx]);
$l = array_reduce($tb[$rx][$cx], fn($r, $e) => ($r > $l = strlen($e)) ? $r : $l, 0);
if ($l > ($cLen[$cx] ?? -1))
$cLen[$cx] = $l;
}
}
xyt('tbGen table', $tb, 'cLen', $cLen, 'rLin', $rLin);
$sep = '+';
foreach ($cLen as $cx => $cl)
$sep .= str_repeat('-', $cl+2) . '+';
$this->xyt('');
for ($rx=0; $rx<count($rLin); $rx++) {
$this->xyt($sep);
for ($lx=0; $lx< $rLin[$rx]; $lx++) {
$tx = '| ';
foreach ($cLen as $cx => $cl) {
$tx .= str_pad($tb[$rx][$cx][$lx] ?? '', $cl) . ' | ';
}
$this->xyt($tx);
}
}
$this->xyt($sep);
}
}
Out::outAdd('before', EnvCL ? new OutCli : new OutHtml());
function xyt() { # data and nl
Out::$out->xyt(func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2str(func_get_args()) : ''));
}
function xytNL() { #nl and data
Out::$out->xytNL(func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2str(func_get_args()) : ''));
}
function xytEC() { # data in format $ = $, ... and nl
Out::$out->xyt(func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2strEC(func_get_args()) : ''));
}
function xytW() { # data (without any nl)
Out::$out->xytW(func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2str(func_get_args()) : ''));
}
function xytH() { # header
Out::$out->xytH(func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2str(func_get_args()) : ''));
}
function xytOL() { # ordered=numbered list, optional with first item
Out::$out->xytLL('ol');
if (func_num_args() > 0)
Out::$out->xytLi(func_num_args() === 1 ? a2str(func_get_arg(0)) : i2str(func_get_args()));
}
function xytOLEnd() { # end ordered list
if (func_num_args() > 0)
Out::$out->xytLi(func_num_args() === 1 ? a2str(func_get_arg(0)) : i2str(func_get_args()));
Out::$out->xytLLEnd();
}
function xytLi() { # listitem (in ol or ul)
Out::$out->xytLi(func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2str(func_get_args()) : ''));
}
function xytUL() { # undordered= bulleted list, optional with first item
Out::$out->xytLL('ul');
if (func_num_args() > 0)
Out::$out->xytLi(func_num_args() === 1 ? a2str(func_get_arg(0)) : i2str(func_get_args()));
}
function xytULEnd() { # end undordered list
if (func_num_args() > 0)
Out::$out->xytLi(func_num_args() === 1 ? a2str(func_get_arg(0)) : i2str(func_get_args()));
Out::$out->xytLLEnd();
}
function xytTb() { # table begin, optional with first td
Out::$out->xytTb();
if (func_num_args() > 0)
Out::$out->xytTD('', func_num_args() == 1 ? a2str(func_get_arg(0)) : i2str(func_get_args()));
}
function xytTbEnd() { # table end
if (func_num_args() > 0)
Out::$out->xytTD('', func_num_args() == 1 ? a2str(func_get_arg(0)) : i2str(func_get_args()));
Out::$out->xytTbEnd();
}
function xytTCF() { # table column format, currently only l (left align default) and r (right align)
$f = func_get_args();
foreach ($f as $e)
if ($e !== 'l' and $e !== 'r' and $e !== '!' and $e !== '!l' and $e !== '!r' )
err("bad format $e in xytTCF(", $f, ')');
Out::$out->xytTCF($f);
}
function xytTR() { # row begin, optional with first td
Out::$out->xytTR();
if (func_num_args() > 0)
Out::$out->xytTD('', func_num_args() == 1 ? a2str(func_get_arg(0)) : i2str(func_get_args()));
}
function xytTRD() { # row begin, with 0 to n datacells
Out::$out->xytTR();
foreach (func_get_args() as $d)
Out::$out->xytTD('', $d);
}
function xytTRH() { # row begin, with 0 to n headercells
xytTR();
foreach (func_get_args() as $h)
xytTH('!', $h);
}
function xytTD() { # td = dataCell begin, optional with first words
Out::$out->xytTD('', func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2str(func_get_args()) : ''));
}
function xytTDD() { # tdd = 0 to n dataCells
foreach (func_get_args() as $d)
xytTD('', a2str($d));
}
function xytTH() { # th = headerCell begin, optional with first words
Out::$out->xytTD('!', func_num_args() === 1 ? a2str(func_get_arg(0)) : (func_num_args() > 1 ? i2str(func_get_args()) : ''));
}
function xytTHH() { # 0 to n headerCell
foreach (func_get_args() as $h)
xytTD('!', a2str($h));
}
echo a2str(OutStack::TRpop);
xyt('wie gehts?', 'oder nicht');
xytNL('outNL', 'vorher und nicht nachher');
xyt('zweitens wie gehts?', 'oder nicht');
xytH('und', 'outH');
xytEC('eins', 1, 'zwei', 2);
xyt('und schluesxs gehts?', 'oder nicht');
xytH('Listen');
xyt('ordered');
xytOL('ordered list eins');
xytLi('zwei');
xytNL('nach nl zwei');
xytOL('nested ordered list drei');
xytLi(32);
xytOLEnd();
xytOLEnd('vier');
xytUL();
xytLi('unordered list eins');
xytLi('ul zwei');
xytNL('+ nl');
xytULEnd();
xytH('table');
xytTb();
xytTCF('l','r');
xytTR();
xytTD('eins' , 'zwei');
xytNL(11, 12, 13);
xytNL(14, 15, 16);
xytTD('dreri' , 'vier');
xytTrD(21,23,24);
xytTbEnd();
xyt('ente');