aboutsummaryrefslogtreecommitdiffstats
path: root/runnerline_print.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'runnerline_print.cpp')
-rw-r--r--runnerline_print.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/runnerline_print.cpp b/runnerline_print.cpp
new file mode 100644
index 0000000..f2628e1
--- /dev/null
+++ b/runnerline_print.cpp
@@ -0,0 +1,367 @@
+// runnerline_print.cpp
+// Revision 7-feb-2005
+
+#include "runnerline_impl.h"
+
+#include "using.h"
+#include "sysvar.h"
+#include "util.h"
+using util::to_string;
+
+#include "trace.h"
+
+#include <cassert>
+#define ASSERT assert
+
+namespace sysvar= blassic::sysvar;
+using namespace blassic::file;
+
+
+#define requiretoken(c) if (token.code == c) ; else throw ErrSyntax
+
+#define expecttoken(c) \
+ do { \
+ gettoken (); \
+ if (token.code != c) throw ErrSyntax; \
+ } while (0)
+
+void RunnerLineImpl::print_using (BlFile & out)
+{
+ TRACEFUNC (tr, "RunnerLineImpl::print_using");
+
+ std::string format= expectstring ();
+ VectorUsing usingf;
+ parseusing (format, usingf);
+ if (token.code == ',' || token.code == ';')
+ gettoken ();
+ const size_t l= usingf.size ();
+ size_t ind= 0;
+ Using * pf= usingf [ind];
+ for (;;)
+ {
+ if (ind == 0 && pf->isliteral () )
+ {
+ pf->putliteral (out);
+ ind= (ind + 1) % l;
+ if (ind == 0)
+ throw ErrFunctionCall;
+ pf= usingf [ind];
+ }
+ BlResult result;
+ eval (result);
+ switch (result.type () )
+ {
+ case VarNumber:
+ pf->putnumeric (out, result.number () );
+ break;
+ case VarInteger:
+ pf->putnumeric (out, result.number () );
+ break;
+ case VarString:
+ pf->putstring (out, result.str () );
+ break;
+ default:
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ ind= (ind + 1) % l;
+ pf= usingf [ind];
+ if (ind != 0 && pf->isliteral () )
+ {
+ pf->putliteral (out);
+ ind= (ind + 1) % l;
+ // Seen unnecessary, and is erroneous.
+ //if (ind == 0)
+ // throw ErrFunctionCall;
+ pf= usingf [ind];
+ }
+ if (endsentence () )
+ {
+ //out << '\n';
+ out.endline ();
+ break;
+ }
+ if (token.code == ';' || token.code == ',')
+ {
+ gettoken ();
+ if (endsentence () )
+ break;
+ }
+ }
+}
+
+namespace {
+
+class ChannelSave {
+ BlFile & bf;
+ bool inversesaved;
+ bool inversevalue;
+ bool inksaved;
+ int inkvalue;
+ bool papersaved;
+ int papervalue;
+ bool brightsaved;
+ bool brightvalue;
+public:
+ ChannelSave (BlFile & bf) :
+ bf (bf),
+ inversesaved (false),
+ inksaved (false),
+ papersaved (false),
+ brightsaved (false)
+ {
+ TRACEFUNC (tr, "ChannelSave::ChannelSave");
+ }
+ ~ChannelSave ()
+ {
+ TRACEFUNC (tr, "ChannelSave::~ChannelSave");
+
+ if (inversesaved)
+ bf.inverse (inversevalue);
+ if (brightsaved)
+ bf.bright (brightvalue);
+ if (inksaved)
+ bf.setcolor (inkvalue);
+ if (papersaved)
+ bf.setbackground (papervalue);
+ }
+ void inverse (bool inv)
+ {
+ if (! inversesaved)
+ {
+ inversevalue= bf.getinverse ();
+ inversesaved= true;
+ }
+ bf.inverse (inv);
+ }
+ void ink (int color)
+ {
+ if (! inksaved)
+ {
+ inkvalue= bf.getcolor ();
+ inksaved= true;
+ }
+ bf.setcolor (color);
+ }
+ void paper (int color)
+ {
+ if (! papersaved)
+ {
+ papervalue= bf.getbackground ();
+ papersaved= true;
+ }
+ bf.setbackground (color);
+ }
+ void bright (bool br)
+ {
+ if (! brightsaved)
+ {
+ brightvalue= bf.getbright ();
+ brightsaved= true;
+ }
+ bf.bright (br);
+ }
+};
+
+} // namespace
+
+bool RunnerLineImpl::do_PRINT ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_PRINT");
+
+ // Same function used for PRINT and LPRINT, differing only
+ // in the default channel.
+ BlChannel channel= (token.code == keyLPRINT) ?
+ PrinterChannel : DefaultChannel;
+ gettoken ();
+ if (token.code == '#')
+ {
+ channel= expectchannel ();
+ // Allow ';' for Spectrum compatibility.
+ if (token.code == ',' || token.code == ';')
+ gettoken ();
+ else
+ require_endsentence ();
+ }
+
+ TRMESSAGE (tr, "Channel: " + to_string (channel) );
+
+ BlFile & out= getfile (channel);
+
+ TRMESSAGE (tr, "Text window: " + to_string (out.istextwindow () ) );
+ TRMESSAGE (tr, "File: " + to_string (out.isfile () ) );
+
+ ChannelSave channelsave (out);
+
+ if (token.code == '@')
+ {
+ BlResult result;
+ expect (result);
+ BlInteger pos= result.integer ();
+ requiretoken (',');
+ gettoken ();
+ #if 0
+ BlInteger row= (pos / 32) + 1;
+ BlInteger col= (pos % 32) + 1;
+ if (graphics::ingraphicsmode () )
+ graphics::locate (row, col);
+ else
+ locate (row, col);
+ #else
+ out.gotoxy (pos % 32, pos / 32);
+ #endif
+ }
+ if (endsentence () )
+ {
+ //out << '\n';
+ out.endline ();
+ return false;
+ }
+
+ bool spacebeforenumber=
+ sysvar::hasFlags1 (sysvar::SpaceBefore);
+ BlResult result;
+ size_t n;
+ bool ended= false;
+ do {
+ switch (token.code) {
+ case ',':
+ case ';':
+ // Separators can be before any statement,
+ break;
+ case keyUSING:
+ print_using (out);
+ ended= true;
+ break;
+ case keyTAB:
+ //getparenarg (result);
+ // Not required to improve Sinclair ZX compatibility.
+ expect (result);
+ n= result.integer ();
+ if (! sysvar::hasFlags1 (sysvar::TabStyle) )
+ n-= 1;
+ out.tab (n);
+ break;
+ case keySPC:
+ getparenarg (result);
+ n= result.integer ();
+ //out << std::string (n, ' ');
+ out.putspaces (n);
+ break;
+ case keyAT:
+ out.flush ();
+ {
+ expect (result);
+ //BlInteger row= result.integer () + 1;
+ BlInteger row= result.integer ();
+ requiretoken (',');
+ expect (result);
+ //BlInteger col= result.integer () + 1;
+ BlInteger col= result.integer ();
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::locate (row, col);
+ else
+ locate (row, col);
+ #else
+ out.gotoxy (col, row);
+ #endif
+ }
+ break;
+ case keyINK:
+ out.flush ();
+ {
+ BlInteger color= expectinteger ();
+ channelsave.ink (color);
+ }
+ break;
+ case keyPAPER:
+ out.flush ();
+ {
+ BlInteger color= expectinteger ();
+ channelsave.paper (color);
+ }
+ break;
+ case keyINVERSE:
+ out.flush ();
+ {
+ BlInteger inv= expectinteger ();
+ channelsave.inverse (inv);
+ }
+ break;
+ case keyBRIGHT:
+ out.flush ();
+ {
+ BlInteger br= expectinteger ();
+ channelsave.bright (br);
+ }
+ break;
+ default:
+ eval (result);
+ switch (result.type () ) {
+ case VarString:
+ {
+ TRMESSAGE (tr, "string");
+ std::string txt= result.str ();
+ TRMESSAGE (tr, txt);
+ //out << result.str ();
+ out << txt;
+ }
+ break;
+ case VarNumber:
+ {
+ BlNumber n= result.number ();
+ if (spacebeforenumber && n >= 0)
+ out << ' ';
+ out << n;
+ }
+ break;
+ case VarInteger:
+ {
+ BlInteger n= result.integer ();
+ if (spacebeforenumber && n >= 0)
+ out << ' ';
+ out << n;
+ }
+ break;
+ default:
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ }
+ if (ended)
+ break;
+ if (endsentence () )
+ {
+ //out << '\n';
+ out.endline ();
+ break;
+ }
+ #if 0
+ if (token.code != ';' && token.code != ',')
+ throw ErrSyntax;
+ if (token.code == ',')
+ out.tab ();
+ gettoken ();
+ #else
+ // Now separator is not required
+ switch (token.code)
+ {
+ case ',':
+ out.tab ();
+ gettoken ();
+ break;
+ case ';':
+ gettoken ();
+ break;
+ default:
+ ; // Nothing
+ }
+ #endif
+ } while (! endsentence () );
+ TRMESSAGE (tr, "Flushing channel");
+ out.flush ();
+ return false;
+}
+
+// End of runnerline_print.cpp
Un proyecto texto-plano.xyz