DECLARE SUB LoadLinks (LinkArray() AS ANY)
DECLARE SUB Main (LinkArray() AS ANY)
DECLARE SUB Parse (link%, LinkArray() AS ANY)
DECLARE FUNCTION OnLink% (Row AS INTEGER, Col AS INTEGER, LinkArray() AS ANY)
DECLARE FUNCTION TabLink% (Row AS INTEGER, Col AS INTEGER, LinkArray() AS ANY)
DEFINT A-Z
'$INCLUDE: 'dialog.bi'
'$DYNAMIC
TYPE LinkStringType
text AS STRING * 200
Row AS INTEGER
Col AS INTEGER
WordLen AS INTEGER
Pointer AS INTEGER
END TYPE
CONST DEFAULT = 1, MAXLINKS = 50, TABSPACE = 4
DIM SHARED LinkCount AS INTEGER
DIM LinkArray(0) AS LinkStringType
CALL Parse(DEFAULT, LinkArray())
CALL Main(LinkArray())
END
LinkData:
DATA "<name='default'><span>QBLinks<hr>"
DATA "<tab>QBLinks is a utility designed for QB programmers to implement an on screen"
DATA "link system. It uses tags similar to those found in HTML to interpret where"
DATA "links are and where they point to."
DATA "<tab>Use the arrow keys to move the cursor around the screen, or press the TAB"
DATA "key to goto the next link. Then select a link by pressing ENTER or SPACEBAR.<br>"
DATA "<link ref='tags'>QBLink Tags</link>"
DATA "<link ref='whitesp'>White Space</link>"
DATA "<link ref='data'>DATA Statements</link>"
DATA "<link ref='limits'>Limitations</link></span>"
DATA "<name='tags'><span>QBLink Tags<col 40><link ref='default'>Main Page</link><hr>"
DATA "<tab>When QBLinks is used without any tags, it will just print the text on the"
DATA "screen. The following table is a list of tags available to both format your"
DATA "text and insert links.<br>"
DATA "<link ref='hr'> <hr> </link><col 15>Horizonal Rules (lines)"
DATA "<link ref='tab'> <tab> </link><col 15>Tabs"
DATA "<link ref='link'> <link> </link><col 15>Links"
DATA "<link ref='char'> <char> </link><col 15>Screen Characters"
DATA "<link ref='name'> <name> </link><col 15>Naming the Links"
DATA "<link ref='col'> <col> </link><col 15>Column Alignment"
DATA "<link ref='span'> <span> </link><col 15>Multiple DATA line pages"
DATA "<link ref='br'> <br> </link><col 15>New Lines"
DATA "<link ref='src'> <src> </link><col 15>Using an external data file"
DATA "</span>"
DATA "<name='whitesp'><span>White Space<col 40><link ref='default'>Main Page</link><hr>"
DATA "<tab>White Space is generally the term used when writing text for an application"
DATA "that interprets tags in the text for special purposes. As in HTML, the author"
DATA "of the page can write the page in notepad, inserting tags as required, and use"
DATA "spacing to easily see the code. Web browsers will ignore this extra whitespace"
DATA "when they interpret the page and it's tags. So how the text spacing looks in"
DATA "the text editor will not be how it looks in the browser.<br>"
DATA "<tab>QBLinks does not do this. All the whitespace the author puts in the page"
DATA "will be displayed on the screen.</span>
DATA "<name='data'><span>DATA Statements<col 40><link ref='default'>Main Page</link><hr>"
DATA "<tab>QBLinks initially reads it's data from the QB DATA statement."
DATA "The first line of data it reads MUST come from a data statement, while"
DATA "subsequent pages and even the default page may come from a data file."
DATA "<tab>The first page displayed is, naturally, the default page. This page"
DATA "may come from either a DATA statement, or an external file using the <link ref='src'>Source</link>"
DATA "tag.</span>"
DATA "<name='limits'><span>Limits to QBLinks<col 40><link ref='default'>Main Page</link><hr>"
DATA "<tab>The limits of QBLinks is the same as that of the QB enviornment as well"
DATA "as a the few listed below.<br>"
DATA "<char 7> Page Size. The page size is limited to 32767 characters long, or 32k."
DATA "<tab>On a 25x80 resolution text screen (the default for QB and QBLinks, this is"
DATA "<tab>about 30 'screens' long. It would be best to keep your entire page within"
DATA "<tab>one (1) screen. The limit on the number of pages is restricted to the"
DATA "<tab>amount of memory QB provides.<br>"
DATA "<char 7> Number of Links. The number of links allowed on a page defaults to 50."
DATA "<tab>This can be easily increased or decreased by changing the constant"
DATA "<tab>MAXLINKS, found at the beginning of the program.</span>"
DATA "<name='hr'><span>The Horizonal Rule<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>
DATA "<char 7> Syntax: \<hr [len] [/]><br>"
DATA "<tab>The Horizontal Rule is nothing more than a line going across the screen."
DATA "It defaults to going all the way from the left side to the right, 80 characters"
DATA "long, and it prints a <link ref='br'>NewLine character</link>. These defaults can be overridden"
DATA "to force the line to a specific length at the end of the current line, or to"
DATA "prevent the newline.<br>"
DATA "<tab>Default horizonal rule: \<hr><hr>"
DATA "<tab>Horizonal rule with no newline:\<hr/><hr/>"
DATA "<br><tab>Specify a line five (5) characters long: \<hr 5><hr 5>"
DATA "<tab>Horizontal rule five (5) characters long and no newline: \<hr 5/><hr 5/>Text"
DATA "<br><tab>To fully understand how this works, you will have to actually use it in"
DATA "your own variations.</span>"
DATA "<name='tab'><span>Tab<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<tab><br>"
DATA "<tab>The Tab tag will automatically move your cursor a set number of spaces to"
DATA "the right from the current cursor position. The number of spaces a single"
DATA "\<tab> will move the cursor depends on the value of the global constant,"
DATA "TABSPACES, found in the beginning of the program.</span>"
DATA "<name='link'><span>Links<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<link { ref | number } [nosides]> text \</link><br>"
DATA "<tab>The \<link> tag is the most important tag in QBLinks. It is the tag that"
DATA "the user will interact with to navigate around your help system.<br>"
DATA "<tab>It is important that the link know which page to load once the user has"
DATA "selected it. This can be done by either specifying the <link ref='name'>name</link> of the page"
DATA "using 'ref', or by specifying the link 'number' relative to the beginning"
DATA "of your DATA statements.<br>"
DATA "<char 7> Using 'ref': \<link ref='howto'>See how to do it\</link>"
DATA "<char 7> Using 'number': \<link 2>Go to the page in the second DATA statement.\</link>"
DATA "<br><tab>By default, all links have the arrows on the sides. This is so users"
DATA "can easily see where a link is. But sometimes, borders are unnecessary;"
DATA "so borders can be turned off for a single link by using the 'nosides' attribute.</span>"
DATA "<name='char'><span>Extra Characters<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<char { ascii code }><br>"
DATA "<tab>The \<char> tag is used to display ASCII characters on the screen that would"
DATA "normally have an OS related function associated with them, such as characters"
DATA "1-31. These characters also have a printable 'character' as well. But the QB"
DATA "enviornment will always intercept these codes before they can be printed to"
DATA "the screen. That is where \<char> comes in to play. Use this tag to specify"
DATA "the ASCII code of any one (1) character to print. The most common use will"
DATA "probably be bullets: <char 7></span>"
DATA "<name='name'><span>Naming the pages<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<name='{ name }'><br>
DATA "<tab>Use the \<name> tag to specify the name for a page. Using a name is much"
DATA "more simple than having to keep track of how many DATA statements you have, or"
DATA "how long your data file is if you read all your pages in using the <link ref='src'>Source</link>"
DATA "tag. This tag is must be used before attempting to reference a page with the
DATA "<link ref='link'>Link</link> tag and using the 'ref={ name }' attribute.</span>"
DATA "<name='col'><span>Column Alignment<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<col { column number }><br>"
DATA "<tab>Use the \<col> tag to move the cursor to the specified column on the current"
DATA "row. This tag is usefull to help keep text aligned vertically when working"
DATA "with multiple columns. If the column specified is out of range (less than 1"
DATA "or greater than 80), this tag will have no effect.</span>"
DATA "<name='span'><span>Multiple DATA line pages<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<span>page text<br>"
DATA "<tab>This tag is very important. It allows the page author to use multiple DATA"
DATA "statements to write a help page. Without using this tag, the author is"
DATA "restricted to a 256 character help page (the max length allowed in the QB"
DATA "enviornment).<br>"
DATA "<tab>Be sure to always have the closing tag \</span> when using this tag to"
DATA "prevent QBLinks from reading all the way through your DATA statements."
DATA "<br><tab><char 7> View the source code to see exactly how this tag works.</span>"
DATA "<name='br'><span>NewLine<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<br><br>"
DATA "<tab>The newline tag is one of the more simple tags, yet very usefull."
DATA "It allows you to separate the lines in the help page so the user can see"
DATA "your page more clearly.</span>"
DATA "<name='src'><span>Using an external data file<col 40><link ref='default'>Main Page</link> <link ref='tags'>Tags</link><hr>"
DATA "<char 7> Syntax: \<src='{ filename }'><br>"
DATA "<tab>You can specify an external data file as a source for your help page,"
DATA "rather than relying on multiple QB DATA statements. This external file must be"
DATA "written using all the same tags as in the QB DATA statements except for the"
DATA "\<span> tag, which is used only for DATA statements.<br>"
DATA "<tab>Users of QB4.5 can take great advantage of this feature because of the QB"
DATA "enviornment's ability to load and modify text documents with the QBLinks"
DATA "program loaded. This allows users to build their text file then test it"
DATA "immediately to ensure it looks right. Users of older versions will have"
DATA "to write the file in an external editor, then run QB to test it."
DATA "</span>"
DATA "EOF"
REM $STATIC
SUB Main (LinkArray() AS LinkStringType)
DIM Row AS INTEGER, Col AS INTEGER
DIM kb AS STRING
DIM LinkX AS INTEGER
Row = 1
Col = 1
LinkX = TabLink(Row, Col, LinkArray())
IF LinkX THEN
Row = LinkArray(LinkX).Row
Col = LinkArray(LinkX).Col + 1
END IF
DO
LOCATE Row, Col, 1
DO
kb$ = INKEY$
LOOP WHILE kb$ = ""
IF LEFT$(kb$, 1) = CHR$(0) THEN
SELECT CASE RIGHT$(kb$, 1)
CASE CHR$(cstUP)
IF Row > 1 THEN Row = Row - 1
CASE CHR$(cstDOWN)
IF Row < 25 THEN Row = Row + 1
CASE CHR$(cstLEFT)
IF Col > 1 THEN Col = Col - 1
CASE CHR$(cstRIGHT)
IF Col < 80 THEN Col = Col + 1
END SELECT
ELSEIF kb$ = CHR$(cstENTER) OR kb$ = CHR$(cstSPACE) THEN
LinkX = OnLink(Row, Col, LinkArray())
IF LinkX THEN CALL Parse(LinkX, LinkArray())
Row = 1: Col = 1
LinkX = TabLink(Row, Col, LinkArray())
IF LinkX THEN
Row = LinkArray(LinkX).Row
Col = LinkArray(LinkX).Col + 1
END IF
ELSEIF kb$ = CHR$(cstTAB) THEN
LinkX = TabLink(Row, Col, LinkArray())
IF LinkX THEN
Row = LinkArray(LinkX).Row
Col = LinkArray(LinkX).Col + 1
END IF
END IF
LOOP UNTIL kb$ = CHR$(cstESC)
END SUB
FUNCTION OnLink (Row AS INTEGER, Col AS INTEGER, LinkArray() AS LinkStringType)
OnLink = 0
FOR x = 1 TO LinkCount
IF Row = LinkArray(x).Row THEN
IF Col >= LinkArray(x).Col AND Col <= LinkArray(x).Col + LinkArray(x).WordLen + 1 THEN
OnLink = LinkArray(x).Pointer
EXIT FOR
END IF
END IF
NEXT x
END FUNCTION
SUB Parse (Parent, LinkArray() AS LinkStringType)
DIM file AS STRING
DIM tag AS STRING
DIM Letter AS STRING * 1
DIM link AS STRING
DIM x AS INTEGER, Row AS INTEGER, Col AS INTEGER
x = 1
Row = 1
Col = 1
RESTORE LinkData
FOR x = 1 TO Parent - 1
READ link
LinkLine = LinkLine + 1
NEXT x
DIM TempLinks(1 TO MAXLINKS) AS LinkStringType
LinkCount = 0
CLS
DataSpan = 0
DO
LinkLine = LinkLine + 1
READ link
IF link = "EOF" THEN EXIT DO
IF INSTR(link, "<name=") THEN
x = INSTR(5, link, ">") + 1
link = MID$(link, x)
END IF
x = 1
DO UNTIL x > LEN(link)
Letter = MID$(link, x, 1)
IF Letter = "<" AND Literal = FALSE THEN
tag = ""
DO UNTIL Letter = ">"
Letter = MID$(link, x, 1)
tag = tag + Letter
x = x + 1
LOOP
IF tag = "<br>" THEN
Col = 1: Row = Row + 1
ELSEIF tag = "<tab>" THEN
Col = Col + TABSPACE
IF Col > 80 THEN Col = 1: Row = Row + 1
ELSEIF LEFT$(tag, 4) = "<col" THEN
tag = LEFT$(tag, LEN(tag) - 1)
tag = MID$(tag, 6)
xCol = VAL(tag)
IF xCol > 0 AND xCol < 81 THEN Col = xCol
ELSEIF LEFT$(tag, 5) = "<char" THEN
ch = VAL(MID$(tag, 6))
LOCATE Row, Col
CALL scrPrint(ch, 7, 0)
Col = Col + 1
ELSEIF LEFT$(tag, 3) = "<hr" THEN
newline = TRUE
IF MID$(tag, 4, 1) = "/" THEN
newline = FALSE
tag = LEFT$(tag, 3) + MID$(tag, 5)
END IF
IF LEN(tag) > 4 THEN
tag = LEFT$(tag, LEN(tag) - 1)
tag = MID$(tag, 4)
ruler = VAL(tag)
ELSE
'Col = 0
'Row = Row + 1
ruler = 80
END IF
LOCATE Row, Col + 1
PRINT STRING$(ruler, CHR$(196));
Col = Col + 1
IF newline THEN Row = Row + 1
ELSEIF LEFT$(tag, 4) = "<src" THEN
FileNum = FREEFILE
ftstart = INSTR(tag, "='") + 2
ftend = INSTR(tag, "'>")
FileName$ = MID$(tag, ftstart, ftend - ftstart)
OPEN FileName$ FOR INPUT AS #FileNum
DIM Lk AS STRING
link = ""
DO UNTIL EOF(FileNum)
LINE INPUT #FileNum, Lk
link = link + Lk + " "
LOOP
CLOSE #FileNum
LinkCount = 0
CLS : x = 1: Col = 1: Row = 1
ELSEIF LEFT$(tag, 5) = "<span" THEN
DataSpan = 0
tag$ = LEFT$(tag, LEN(tag$) - 1)
tag$ = MID$(tag, 6)
IF tag$ = "" THEN
DataSpan = TRUE
ELSE
DataSpan = VAL(tag$)
END IF
ELSEIF tag = "</span>" THEN
DataSpan = 0
ELSEIF LEFT$(tag, 5) = "<link" THEN
LinkCount = LinkCount + 1
InTag$ = ""
nosides = FALSE
InX = 6
num = 0
InXStr$ = ""
opt$ = ""
DO UNTIL InXStr$ = ">"
InXStr$ = MID$(tag, InX, 1)
IF InXStr$ = " " OR InXStr$ = ">" THEN
IF opt$ = "nosides" THEN
nosides = TRUE
ELSEIF LEFT$(opt$, 4) = "ref=" THEN
RefX = 0
RefXLink$ = ""
RESTORE LinkData
Search$ = "<name=" + MID$(opt$, 5)
DO UNTIL INSTR(RefXLink$, Search$) OR RefXLink$ = "EOF"
READ RefXLink$
RefX = RefX + 1
LOOP
num = RefX
RESTORE LinkData
FOR px = 1 TO LinkLine
READ pd$
NEXT px
ELSE
num = VAL(opt$)
END IF
opt$ = ""
ELSE
opt$ = opt$ + InXStr$
END IF
InX = InX + 1
LOOP
Col = Col + nosides
TempLinks(LinkCount).Pointer = num
TempLinks(LinkCount).Row = Row
TempLinks(LinkCount).Col = Col
endword = INSTR(x, link, "</link>")
Word$ = MID$(link, x, endword - x)
MID$(Word$, 1, 1) = UCASE$(LEFT$(Word$, 1))
TempLinks(LinkCount).WordLen = LEN(Word$) + nosides
x = endword
LOCATE Row, Col
IF NOT nosides THEN CALL scrPrint(17, 2, 0)
LOCATE , Col + 1 + noside: PRINT Word$;
IF NOT nosides THEN CALL scrPrint(16, 2, 0)
Col = Col + LEN(Word$) + 2 + nosides
END IF
ELSE
IF Letter = "\" AND Literal = FALSE THEN
Literal = TRUE
x = x + 1
ELSE
LOCATE Row, Col
PRINT Letter;
x = x + 1
Col = Col + 1
IF Col = 81 THEN Col = 1: Row = Row + 1
Literal = FALSE
END IF
END IF
LOOP
IF DataSpan > 0 THEN DataSpan = DataSpan - 1
Row = Row + 1: Col = 1
LOOP WHILE DataSpan <> 0
IF LinkCount > 0 THEN
REDIM LinkArray(1 TO LinkCount) AS LinkStringType
FOR x = 1 TO LinkCount
LinkArray(x) = TempLinks(x)
NEXT x
END IF
END SUB
FUNCTION TabLink (Row AS INTEGER, Col AS INTEGER, LinkArray() AS LinkStringType)
TabLink = 0
pRow = Row
pCol = Col
LinkFound = FALSE
IF LinkCount > 0 THEN
DO UNTIL LinkFound
FOR pRow = Row TO 25
FOR xCol = pCol TO 80
FOR hp = 1 TO LinkCount
IF pRow = LinkArray(hp).Row AND xCol <= LinkArray(hp).Col THEN
TabLink = hp
LinkFound = TRUE
EXIT FUNCTION
END IF
NEXT hp
NEXT xCol
pCol = 1
NEXT pRow
Row = 1
LOOP
END IF
END FUNCTION