! OKBStyle      -       Library which allows style changes to be embedded in text.
! By Brendan "BrenBarn" Barnwell, alias OKB ([email protected])
!
!       From ideas and experimentation by himself, Adam "jwalrus" Biltcliffe, John "katre" Cater,
! Evin "thumper" Robinson, and Gunther "Gunther" Schmidl.
!
!       This library is Glulx-only.
!
!       This library is compatible with my Entry Inform library extension.
!!!!!
!
!                       THE FOUR MOST IMPORTANT THINGS
!
!       You must call OKBStyleRestore from your Initialise and IdentifyGlkObject routines, unless you
! are using Entry.
!
!       You need two other libraries to make this one work: infglk.h (by John Cater) and
! OKBGlulx.h (by yours truly).  A zip package containing these two files and
! OKBStyle.h itself is available at http://members.aol.com/brenbarn/instyle.zip .  This library will
! automatically include OKBGlulx, which will automatically include infglk.
!
!       You must include OKBStyle after including Parser, but before including Verblib.
!
!!!!!
!
!       Currently, there are two ways to embed style tags into your strings:
! HTML-style and TeX-style.
!
!!!
!
!       HTML-style can be used just like normal HTML: <tag> starts the tag and
! </tag> ends it.  There are few syntaxes you CAN use with this library, however, that
! aren't legal in HTML.  For starters, only the first letter of the tag is meaningful (so you
! can use <bold>, <bogus>, or just plain </b>).  Second of all, the end tag does not
! have to be anything but </>.  If you want to use </bold>, </bogus>, or </b>, you
! can, but the effect is always the same: the style is reset to Normal.  (It is even possible
! to begin with, say <bold> and end with </unrelated>, if you feel the urge.)  Here is a
! full list of supported tags (only the required first letter is given):
!
!               <b> or <e>      =       Emphasized
!               <p>             =       Preformatted
!               <h>             =       Header
!               <s>             =       Subheader
!               <a>             =       Alert
!               <n>             =       Note
!               <q>             =       Quote
!               <i>             =       Input
!               <1>             =       User1
!               <2>             =       User2
!
!       None of the tags are case sensitive.
!
!       The only character you might need to escape using this method is <.  There
! are two ways to print out a <.  First, you can use <<, and this will print as a single <.
! Second, you can use <X, where x is any character other than those listed above (b, e,
! p, h, s, a, n, q, i, 1, 2 -- anagram time! :-), and this will print both the < and the
! following character.  (So "<k" will actually print "<k".)  Both of these techniques work
! in text between HTML-style tags as well as in unstyled text.  (So you can do --print
! "<p>cout <<<< ~I like a monkey!~ <<<< endl;</p>";--.)
!
!       You cannot, however, escape the < character within a tag.  All this means is that
! if you try to use <1 < 2> as a tag, it will go awry.  Hopefully no one was planning on
! doing that anyway.
!
!       You also cannot escape the > character within a tag.  This means that <2 > 0>
! will print "0>" in User2 style (it won't interpret the entire "2 > 0" package as the name
! of the tag.  Again, I don't foresee anyone trying this, but just in case. . .
!
!!!
!
!       TeX-style formatting is a lot like using TeX, or so I hear.  (I've never actually used
! TeX myself; I've had the syntax explained to me briefly by others.  If you find
! something wrong with this syntax, please let me know.)  The basic format is
! "|style{styled text}".  Note that instead of the backslash (\) I have used the pipe
! character (|) to begin the syntax.  This is because Inform has its own special meaning
! for a backslash, and won't allow the character to be used for other purposes.
!
!       You can specify a different character than | to be used for TeX-style styling by defining a
! constant called TeXChar (whose value is the character you want) before Including OKBStyle.  (Note
! that this character must be enclosed in single quotes, as in --Constant TeXChar '|'--.)
!
!       Like HTML-style formatting (described above), TeX-style formatting has some
! syntax shortcuts for you to use.  Well, actually, one syntax shortcut.  Again, only the
! first character of the style name is necessary.  So |bold is the same as |bogus or |b or
! even |BrendanBarnwell.  Here's the full list of available styles:
!
!               |b or |e        =       Emphasized
!               |p              =       Preformatted
!               |h              =       Header
!               |s              =       Subheader
!               |a              =       Alert
!               |n              =       Note
!               |q              =       Quote
!               |i              =       Input
!               |1              =       User1
!               |2              =       User2
!
!       None of these are case senstive.
!
!       If you are printing unformatted text and you want to print a |, you can use either
! || (which will print a single bar), or |X, where X is any character not listed above
! (which will print both the bar and the character, whatever it is).  If you need to print a
! } as part of some styled text (e.g., "This is a right brace: }"), you can escape it with a |.
! (So "|e{This is a right brace |}}" will print the above text in Emphasized style.)  Any
! | characters found between the { braces } (except those immediately preceding a } character) will be
! printed without any fuss (this means you can't nest styles, but that's okay, since Glulx doesn't allow
! that anyway).
!
!!!!!
!
!       Please send any questions, comments, or other communication to me at
! [email protected] .
!
!!!!!

! System_file; -- actual directive is at end of file for odd reasons.

#IfNDef OKBStyle;

#IfNDef OKBGlulx;
       Include "OKBGlulx";
#EndIf;

Message "[Including <OKBStyle>]";

#IfDef Enterer;

       Enterer OKBStyle;

       EnterInitialise -> OKBStyleInitialize
with precedes Game, follows OKBGlulx,
execute [; rfalse; ];           ! No intialization needed

       EnterIdentifyGlkObject -> OKBStyleIGO
with precedes Game OKBGlulx,
execute [phase type objref objrock; if (phase==2) @setiosys 1 OKBFilter; ];

#IfNot;
       Constant OKBStyle;
#EndIf;

Replace RestoreSub;
Replace SaveSub;

Constant NoStyle=0;
Constant HTMLStyle 801;
Constant TeXStyle 802;

Default TeXChar='|';

Global Stylin=0;                        ! Current "state" of style (e.g., where we are in parsing the tag)
Global StyleStyle=NoStyle;      ! Style of styling we're using (HTMLStyle or TeXStyle)

[OKBStyleRestore phase;
if (phase==2) @setiosys 1 OKBFilter; ];

[OKBFilter char;
! HTML-style
               if (char=='<') {                                        ! We see an HTML tag beginning
       switch (Stylin) {
0: Stylin=1; StyleStyle=HTMLStyle; rtrue;                       ! If we've just begun, we wait to see the tag
1: GlkChar('<'); Stylin=0; StyleStyle=NoStyle; rtrue;   ! If we read <<, print out one <
2: rtrue;
3: Stylin=4; rtrue;
4: GlkChar('<'); Stylin=3; rtrue;
5: rtrue;
       }
               }

if (Stylin==0 && StyleStyle==HTMLStyle) {GlkChar(char); rtrue;}

               if (Stylin==1 && StyleStyle==HTMLStyle) {
Stylin=2;
       switch (char) {
'e','b','E','B': GlkStyle(StyleEmphasized);
'p','P': GlkStyle(StylePreformatted);
'h','H': GlkStyle(StyleHeader);
's','S': GlkStyle(StyleSubheader);
'a','A': GlkStyle(StyleAlert);
'n','N': GlkStyle(StyleNote);
'q','Q': GlkStyle(StyleQuote);
'i','I': GlkStyle(StyleInput);
'1': GlkStyle(StyleUser1);
'2': GlkStyle(StyleUser2);
default: GlkChar('<');  GlkChar(char);
Stylin=0; StyleStyle=NoStyle; rtrue;
       }
               }

       if (Stylin==2 && StyleStyle==HTMLStyle) {
if (char=='>') {Stylin=3;}
rtrue;
       }

if (Stylin==3 && StyleStyle==HTMLStyle) {GlkChar(char); rtrue;}

               if (Stylin==4 && StyleStyle==HTMLStyle) {
       if (char=='/') {
Stylin=5;
GlkStyle(StyleNormal);
       }
       else {
GlkChar('<');
GlkChar(char);
Stylin=3;
       }
       rtrue;
               }

       if (Stylin==5 && StyleStyle==HTMLStyle) {
if (char=='>') {Stylin=0; StyleStyle=NoStyle;}
rtrue;
       }

! TeX-style
               if (char==TeXChar) {
       switch (Stylin) {
0: Stylin=1; StyleStyle=TeXStyle; rtrue;
1: GlkChar(TeXChar); Stylin=0; StyleStyle=NoStyle; rtrue;
2: rtrue;
3: Stylin=4; rtrue;
4: GlkChar(TeXChar); rtrue;
5: "Error!  You began a TeX-style formatting block inside the end tag of an HTML-style formatting block!";
       }
               }

if (Stylin==0 && StyleStyle==TeXStyle) {GlkChar(char); rtrue;}

               if (Stylin==1 && StyleStyle==TeXStyle) {
Stylin=2;
       switch (char) {
'e','b','E','B': GlkStyle(StyleEmphasized);
'p','P': GlkStyle(StylePreformatted);
'h','H': GlkStyle(StyleHeader);
's','S': GlkStyle(StyleSubheader);
'a','A': GlkStyle(StyleAlert);
'n','N': GlkStyle(StyleNote);
'q','Q': GlkStyle(StyleQuote);
'i','I': GlkStyle(StyleInput);
'1': GlkStyle(StyleUser1);
'2': GlkStyle(StyleUser2);
default: GlkChar(TeXChar);  GlkChar(char);
Stylin=0; StyleStyle=NoStyle; rtrue;
       }
               }

       if (Stylin==2 && StyleStyle==TeXStyle) {
if (char=='{') {Stylin=3;}
rtrue;
       }

       if (Stylin==3 && StyleStyle==TeXStyle) {
if (char=='}') {GlkStyle(StyleNormal); Stylin=0; StyleStyle=NoStyle;}
else {GlkChar(char);}
rtrue;
       }

       if (Stylin==4 && StyleStyle==TeXStyle) {
if (char=='}') {GlkChar('}');}
else {GlkChar(TeXChar); GlkChar(char);}
Stylin=3;
rtrue;
       }

if (StyleStyle==NoStyle) {GlkChar(char); rtrue;}
];

[ RestoreSub res fref;
@setiosys 2 0;
 fref = glk($0062, $01, $02, 0); ! fileref_create_by_prompt
 if (fref == 0)
   jump RFailed;
 gg_savestr = glk($0042, fref, $02, GG_SAVESTR_ROCK); ! stream_open_file
 glk($0063, fref); ! fileref_destroy
 if (gg_savestr == 0) {
   jump RFailed;
 }

 @restore gg_savestr res;

 glk($0044, gg_savestr, 0); ! stream_close
 gg_savestr = 0;

RFailed;
 L__M(##Restore,1);
@setiosys 1 OKBFilter;
];

[ SaveSub res fref;
@setiosys 2 0;
 fref = glk($0062, $01, $01, 0); ! fileref_create_by_prompt
 if (fref == 0)
   jump SFailed;
 gg_savestr = glk($0042, fref, $01, GG_SAVESTR_ROCK); ! stream_open_file
 glk($0063, fref); ! fileref_destroy
 if (gg_savestr == 0) {
   jump SFailed;
 }

 @save gg_savestr res;

 if (res == -1) {
   ! The player actually just typed "restore". We're going to print
   !  L__M(##Restore,2); the Z-Code Inform library does this correctly
   ! now. But first, we have to recover all the Glk objects; the values
   ! in our global variables are all wrong.
   GGRecoverObjects();
   glk($0044, gg_savestr, 0); ! stream_close
   gg_savestr = 0;
   return L__M(##Restore,2);
 }

 glk($0044, gg_savestr, 0); ! stream_close
 gg_savestr = 0;

 if (res == 0)
   return L__M(##Save,2);

SFailed;
 L__M(##Save,1);
@setiosys 1 OKBFilter;
];

System_file;