Skip to content

gmslWriteClass

The Write service class contains the basic methods needed to write structured reports and text files of various sorts using binary information. It is used very extensively by gmBasic during every phase of its operation and is fully exposed via gmSL. Ultimately, at any given point in time, only one coded output report can be written at one time. Logically, a structured text output, be it a free-form text representation or a tabular representation containing fixed fields, is viewed as having four levels:

LevelDescription
FileThere are 5 totally independent file structures that may be in use. Initially only 1 of these, unit 1,
is active. It is managed via the gmPL Output statement. Internally, gmBasic
uses unit 5 as a scratch output file. This unit is never left open outside of a given task within the
process. The other units are available as needed. (Note to tool implementers that there is a constant
WRT_PROVIDERS, currently set to 5, that may be changed when doing a tool build. It is unit
1 and unit WRT_PROVIDERS whose use is restricted to gmBasic.) Each file has a physical
file associated with it, which is either a named file or the Standard Output file. At any given
point in time only one file unit is active, unit 1 is always the default, and all write operations are
performed on that unit. The term selected unit is used to refer to the currently active one.
StreamBy default records are written to the physical file associated with the selected unit; however, in many
cases what is needed is an internal representation of what is to be written to the file. This representation,
referred to as a text stream, can then be saved, edited, audited, and perhaps eventually physically
written to a file. At any point in time, the selected unit is either writing to its physical file or
to a text stream. During its life a file unit can spawn as many text streams as desired, but can only
process one at a time.
RecordEach file unit has a record buffer associated with it. This buffer stores the characters being written
until it is physically written to the active stream or is disposed of in some other manner such as
being copied to the runtime data queue. Low level methods in this service class all add their output
to the record associated with the selected unit. The records in the different units are completely
independent of each other. The maximum number of characters that may stored in a record at one time is
8192. (Note to tool implementers there is a constant MAX_BUFFER that defines this value.)
FieldUltimately each method that adds characters to a record is said to be “writing a field” at the back
of the record of the selected unit. Characters can be entered into fields either free-form, or
left-justified in a fixed-width field with a white space to the right, or right-justified in a fixed-width
field with white space to the left.


gmSL: void Write_ChangeMargin(int delta)


When authoring gmBasic does not attempt to reproduce the leading white space in the source code;
rather, it keeps track of the margin nesting level via the p and q escape characters
in the surface patterns or via calls to this method and then uses this margin level times the indentation
width specified via the Select Indent attribute to determine the number of leading blanks or tabs
to add.


This method adds the value of delta to the current margin level. If delta is negative,
the indentation will be decreased, and if it is positive, the indentation will be increased. If the
computed margin level ends up being negative, it is set back to zero.


As an example, the following method displays unindented and indented lines.

void DemoWriteChangeMargin(string comment)
{
Write_Line("Unindented Line: " + comment);
Write_ChangeMargin(1);
Write_Line("Indented Line: " + comment);
Write_ChangeMargin(-1);
Write_Line("Unindented Line: " + comment);
}

Then the gmPL statements

<Select Indent="3" />
<Output Status="New" Filename="Demo001.out" />
<RunCommand Id="scmCode.DemoWriteChangeMargin" prams="Indent is selected at 3"/>
<Select Indent="8" />
<Output Status="Old" Filename="Demo001.out" />
<RunCommand Id="scmCode.DemoWriteChangeMargin" prams="Indent is selected at 8"/>
<Select Indent="0" />
<Output Status="Old" Filename="Demo001.out" />
<RunCommand Id="scmCode.DemoWriteChangeMargin" prams="Indent is selected at 0"/>

generate the following output

Unindented Line: Indent is selected at 3
Indented Line: Indent is selected at 3
Unindented Line: Indent is selected at 3
Unindented Line: Indent is selected at 8
Indented Line: Indent is selected at 8
Unindented Line: Indent is selected at 8
Unindented Line: Indent is selected at 0
Indented Line: Indent is selected at 0
Unindented Line: Indent is selected at 0

Note that the value of the selected indent is applied when the output file is opened. Using the Old status forces this open to occur while still writing to the back of the file.

gmSL: void Write_Character(int charValue


This method appends the ASCII character whose display code is specified by charValue to the current
output record. No actual write occurs at this time.


Note that if called from gmSL with a string argument, the string is not converted to an integer
as would be the normal convention; rather, the value of the first character in the string is passed.


As an example the following displays a character value

Sub DemoWriteCharacter(ByVal theCharacter)
Write_Text "Character Value is: "
Write_Character(theCharacter)
Write_Record
End Sub

Note that the parameter theCharacter is not typed in the code; therefore, it will take on its type based on the type of the argument passed in as shown in the following

<Output Status="New" Filename="Demo002.out" />
<RunCommand Id="vbCode.DemoWriteCharacter" prams="65"/>
<RunCommand Id="vbCode.DemoWriteCharacter" prams="F"/>
<RunCommand Id="vbCode.DemoWriteCharacter" prams="'65'"/>

which produces the following output

Character Value is: A
Character Value is: F
Character Value is: 6

A is the character with display code 65; whereas the string ‘65’ simply has its first character displayed.


gmSL: void Write_CloseFile()


The Write_CloseFile method closes the selected unit and any physical file associated with that unit.
Upon completion, unit 1, the unit associated with the gmPL Output statement, becomes the
selected unit.


The following code opens and writes records to three different files — two files that it maintains
under units 2 and 3 and the file associated with the Output statement. The important point made
in this example are the two writes done after the file closings. It is these writes that go to the
Output file.

void DemoWriteSelect(string file1,string file2)
{
Write_OpenFile(2,file1,True,OutStyle.Text);
Write_OpenFile(3,file2,True,OutStyle.Text);
Write_Select(2);
Write_Line("Line 1 in File " + file1);
Write_Select(3);
Write_Line("Line 1 in File " + file2);
Write_Select(2);
Write_Line("Line 2 in File " + file1);
Write_CloseFile();
Write_Line("Line 1 in Output File");
Write_Select(3);
Write_Line("Line 2 in File " + file2);
Write_CloseFile();
Write_Line("Line 2 in Output File");
}

The following gmPL statements then write output to three different files.

<Output Status="New" Filename="Demo017.out" />
<RunCommand Id="scmCode.DemoWriteSelect" prams="Demo017A.out;Demo017B.out" />

and the results are as expected. The file Demo017A.out contains

Line 1 in File Demo017A.out
Line 2 in File Demo017A.out

and file Demo017B.out contains

Line 1 in File Demo017B.out
Line 2 in File Demo017B.out

and file Demo017.out, the Output file contains

Line 1 in Output File
Line 2 in Output File

gmSL: int Write_CloseStream()

In gmBasic authored records are stored in text buffers within the current storage area. The CloseStream method closes the currently open text buffer and returns its integer handle. This handle must be saved by the caller to be used later to either reopen the text buffer or to physically write it to a file. If writes are currently being sent directly to the file specified in the Output statement, then this method does nothing.

The following code shows how text buffers as used.

void DemoWriteTextStreams(string theAuthor)
{
int textRoot;
Handle textStream;
Write_Line("Write record to Output file before opening a text buffer");
Write_OpenStream();
#TextStart
Hello World
This is a message from (%= theAuthor %)
GoodBye World
#TextEnd
textRoot = Write_CloseStream();
Write_Line("Write another record then write content of text buffer");
textStream = Text_Open(Store_GetHandle(),textRoot);
Write_TextStream(textStream,0,0);
Text_Close(textStream);
}

The records both before and after the write to the text buffer go to the Output file before the buffer itself is written using the Write_TextStream() method. Note it is the return value from this method that is needed to open the text buffer for later use. This code then

<Output Status="New" Filename="Demo003.out" />
<RunCommand Id="scmCode.DemoWriteTextStreams" prams="Kilroy"/>

produces the following output.

Write record to Output file before opening a text buffer
Write another record then write content of text buffer
Hello World
This is a message from Kilroy
GoodBye World

Notice also that the #TextStart .. #TextEnd block behaves in the same manner as text written explicitly using the Write service class.


gmSL: void Write_Field(string strValue, int nString, int iField)


This method is the lowest level utility within the Write service class. It appends a specified field of
characters to the current output record. No actual write occurs at this time. Within that field the
content of strValue may be preceded or followed by white space. nString specifies the
number of characters from strValue that are to be used. iField specifies how the characters
from strValue should be entered:

ValueMeaning
0Simply append the characters to the current content of the output record.
+nRight justify the characters in a field n characters wide appended to the back of the current
record.
-nLeft justify the characters in a field n characters wide appended to the back of the current record.

Note that when called via gmSL if nString is set to zero, then the length of the string will be used.


The following code uses this method to display a string in various ways

void DemoWriteField(string aLongString)
{
Write_Field(aLongString,0,0);
Write_Record();
Write_Field(aLongString,5,0);
Write_Record();
Write_Text("LEFT(");
Write_Field(aLongString,10,-12);
Write_Text(")RIGHT");
Write_Record();
Write_Text("LEFT(");
Write_Field(aLongString,10,12);
Write_Text(")RIGHT");
Write_Record();
}

When called as follows

<Output Status="New" Filename="Demo004.out" />
<RunCommand Id="scmCode.DemoWriteField" prams="Kilroy was here"/>

it produces this output

Kilroy was here
Kilro
LEFT(Kilroy was )RIGHT
LEFT( Kilroy was)RIGHT

gmSL: void Write_Integer(int iValue, int iField)
This method appends the base 10 display form of iValue in a specified field of characters
to the current output record. No actual write occurs at this time. No special formatting flags are
available. iField specifies how the characters of the display form should be entered:

ValueMeaning
0Simply append the characters to the current content of the output record.
+nRight justify the characters in a field n characters wide appended to the back of the current
record.
-nLeft justify the characters in a field n characters wide appended to the back of the current record.

The following code uses this method to display an integer value in various ways

void DemoWriteInteger(int iValue)
{
Write_Text("LEFT(");
Write_Integer(iValue,0);
Write_Text(")RIGHT");
Write_Record();
Write_Text("LEFT(");
Write_Integer(iValue,-10);
Write_Text(")RIGHT");
Write_Record();
Write_Text("LEFT(");
Write_Integer(iValue,10);
Write_Text(")RIGHT");
Write_Record();
}

When called as follows

<Output Status="New" Filename="Demo005.out" />
<RunCommand Id="scmCode.DemoWriteInteger" prams="12345" />

it produces this output

LEFT(12345)RIGHT
LEFT(12345 )RIGHT
LEFT( 12345)RIGHT

gmSL: void Write_Line(string strValue)


This method appends all characters from strValue to the current output record and then writes
the result either to the currently open text buffer or to the file specified in the Output statement.
No formatting is applied to the string.


The following code contrasts using a TextBlock versus using Write_Line() and Write_ChangeMargin().

void DemoWriteLine(string theAuthor)
{
#TextStart
Hello World
This is a message from (%= theAuthor %)
GoodBye World
#TextEnd
Write_Line("Hello World");
Write_ChangeMargin(1);
Write_Line("This is a message from " + theAuthor);
Write_ChangeMargin(-1);
Write_Line("GoodBye World");
}

When called as follows

<Output Status="New" Filename="Demo007.out" />
<RunCommand Id="scmCode.DemoWriteLine" prams="Kilroy" />

it produces this output

Hello World
This is a message from Kilroy
GoodBye World
Hello World
This is a message from Kilroy
GoodBye World

gmSL: void Write_LogMessage(string message) ****


The Write_LogMessage method writes a string message to the file. This is the same file used by
gmBasic for its messages. The following gmPL script shows how this method might be used to
debug a malfunctioning script.

<gmBasic>
<Storage Action="Create" />
<gmsl>Write_LogSetName("Demo018.log")</gmsl>
<gmsl>Write_LogMessage("<!-- translation options ")</gmsl>
<Select progress="1" />
<Select DevEnv="VS2010" />
<Select Dialect="csh" />
<Select BuildFile="global" />
<gmsl>Write_LogMessage("<!-- directories for deployment and external assemblies -->")</gmsl>
<Select DeployLocation="c:\gmProj\lab\deploy\externs\CrashV1003_csh" />
<Select Library="c:\gmProj\lab\deploy\externs" />
<select Target="c:\gmProj\lab\idf\FromCode" />
<Select Local="c:\gmProj\lab\idf\FromCode" />
<Select System="c:\gmProj\lab\idf\FromIdl" />
<gmsl>Write_LogMessage("<!-- processing commands -->")</gmsl>
<Compile Project="c:\gmSrc\GMTest\CrashV1003\CrashV1003.vbp" />
<gmsl>Write_LogSetName(Null)</gmsl>
<Analyse />
<gmsl>Write_LogMessage("<!-- authoring commands -->")</gmsl>
<Output Status="New" Filename="Demo018.bnd" />
<Author />
<Storage Action="Close" />
<gmsl>Write_LogMessage("<!-- End of script -->")</gmsl>
</gmBasic>

Note first of all, that gmSL command mode is being used in this script. Though the logging methods
can be used in runtime code as desired for messages, they are also ideal for direct use within scripts.
Running this script produces this Demo018.log file

<!-- translation options
<!-- directories for deployment and external assemblies -->
<!-- processing commands -->
Processing file: c:\gmSrc\GMTest\CrashV1003\CrashV1003.vbp
Loading reference:[stdole2.tlb] c:\gmProj\lab\idf\FromIdl\stdole2.tlb.xml
Loading reference:[scrrun.dll] c:\gmProj\lab\idf\FromIdl\scrrun.dll.xml
Reprocessing file: c:\gmSrc\GMTest\CrashV1003\clsCrashV1003.cls
Reprocessing file: c:\gmSrc\GMTest\CrashV1003\clsCrashV1003.cls

and then sends these remaining messages to Standard output.

<!-- authoring commands -->
<!-- End of script -->

Note that the messages written by this method coexist with the messages written by gmBasic and both use the same file.

gmSL: void Write_LogSetName(string fileName)


The Write_LogSetName methods sets a fileName for the file to receive all messages — progress,
warning, error, etc. — written during a given run. It also receives all messages written via the
Write_LogMessage() method. By default log messages are simply written to the Standard Output file;
however, when set to a named file, that file is opened for append access prior to each write and is then
closed after the write. This ensures that no output sent to a named log file is lost in cases where abnormal
exits are occurring. To set the log file back to using Standard Output pass it either Null or
Nothing.
The following script reproduced from the discussion of the Write_LogMessage() shows these two types of calls.

<gmBasic>
<Storage Action="Create" />
<gmsl>Write_LogSetName("Demo018.log")</gmsl>
<gmsl>Write_LogMessage("<!-- translation options ")</gmsl>
<Select progress="1" />
<Select DevEnv="VS2010" />
<Select Dialect="csh" />
<Select BuildFile="global" />
<gmsl>Write_LogMessage("<!-- directories for deployment and external assemblies -->")</gmsl>
<Select DeployLocation="c:\gmProj\lab\deploy\externs\CrashV1003_csh" />
<Select Library="c:\gmProj\lab\deploy\externs" />
<select Target="c:\gmProj\lab\idf\FromCode" />
<Select Local="c:\gmProj\lab\idf\FromCode" />
<Select System="c:\gmProj\lab\idf\FromIdl" />
<gmsl>Write_LogMessage("<!-- processing commands -->")</gmsl>
<Compile Project="c:\gmSrc\GMTest\CrashV1003\CrashV1003.vbp" />
<gmsl>Write_LogSetName(Null)</gmsl>
<Analyse />
<gmsl>Write_LogMessage("<!-- authoring commands -->")</gmsl>
<Output Status="New" Filename="Demo018.bnd" />
<Author />
<Storage Action="Close" />
<gmsl>Write_LogMessage("<!-- End of script -->")</gmsl>
</gmBasic>


gmSL: void Write_NText(string strValue, int nText)


This method appends the first nText characters from strValue to the current output record.
No actual write occurs at this time. No formatting is applied to the string. Note that care must be
taken that nText does not exceed the length of strValue. Since gmSL supports a string
type, this method is rarely needed. It is intended primarily for use by gmNI.

The following code uses this method to display an a string value fully and in truncated form

void DemoWriteNText(string aLongString)
{
Write_Text(aLongString);
Write_Record();
Write_NText(aLongString,5);
Write_Record();
}

When called as follows

<Output Status="New" Filename="Demo006.out" />
<RunCommand Id="scmCode.DemoWriteNText" prams="Kilroy was here" />

****it produces this output

Kilroy was here
Kilro

gmSL: void Write_OpenFile(int unit, string fileName,bool statusNew,gmsl.OutStyle syntax)
****There are 5 totally independent file structures that may be in use. The Write_OpenFilegmPL Output statement which uses unit 1.

The Unit parameter specifies which file unit is to be used. It must be a value between 1 and 5, though as the example below will show using unit 1 is equivalent to using the Output statement. The fileName parameter is the name of the file to be opened, and the statusNew parameter, if True request that a new file be created as opposed to opening an existing file for append access. The syntax parameter specifies the output style to be used when producing tabular reports. They can be produced in one of three styles: Tabbed simple tab delimited; Text text tabular; or Html html tabular.

The procedure below sows a simple method that could be used as a replacement for the gmPL Output statement.

void DemoWriteOpenFile(string fileName, bool statusNew)
{
Write_OpenFile(1,fileName,statusNew,OutStyle.Text);
}

and when used as follows

<gmBasic>
<Storage Action="Create" />
<Select GlobalSettings="GmslCode.vbi" />
<LoadEnvironment />
<RunCommand Id="scmCode.DemoWriteOpenFile" prams="Demo016.out;.T." />
<RunCommand Id="vbCode.DemoWriteCharacter" prams="65"/>
<RunCommand Id="vbCode.DemoWriteCharacter" prams="F"/>
<RunCommand Id="vbCode.DemoWriteCharacter" prams="'65'"/>
<Storage Action="Close" />
</gmBasic>

produces the same output as the statement

<Output Status="New" Filename="Demo016.out" />

would have produced.


gmSL: void Write_OpenStream()

In gmBasic authored records are stored in text buffers within the current storage area. The OpenStream method creates such a text buffer and makes it the current output stream. All subsequent writes will go to this stream until it is closed. At which point the current output stream will revert to the file specified in the Output statement.

The following code shows how text buffers as used.

void DemoWriteTextStreams(string theAuthor)
{
int textRoot;
Handle textStream;
Write_Line("Write record to Output file before opening a text buffer");
Write_OpenStream();
#TextStart
Hello World
This is a message from (%= theAuthor %)
GoodBye World
#TextEnd
textRoot = Write_CloseStream();
Write_Line("Write another record then write content of text buffer");
textStream = Text_Open(Store_GetHandle(),textRoot);
Write_TextStream(textStream,0,0);
Text_Close(textStream);
}

The records both before and after the write to the text buffer go to the Output file before the buffer itself is written using the Write_TextStream() method. This code then

<Output Status="New" Filename="Demo003.out" />
<RunCommand Id="scmCode.DemoWriteTextStreams" prams="Kilroy"/>

produces the following output.

Write record to Output file before opening a text buffer
Write another record then write content of text buffer
Hello World
This is a message from Kilroy
GoodBye World

gmSL: void Write_Pattern(string PatString, int nPattern, string Parameters)


This method enters the pattern string PatString starting at the current location in
into the current output record using editing directives within the string along with parameters
defined in Parameters. nPattern contains the number of characters in PatString
to be used. Parameters contains a semicolon-delimited string containing parameters
referenced via their number. If the PatString contains no such references it may be empty.
No actual write occurs at this time.


Directives within PatString are enclosed in % signs. The following are recognized:

DirectiveMeaning
%%Enter a percent sign
%USR_VERSION%Platform specified user version identifier
%PRM_VERSION%Platform specified system version identifier
%PRM_BUILDID%Platform build signature string
%DATE%Current date using currently selected formatting options
%TIME%Current time using currently selected formatting options
%envname%Value of environment variable envname. It must begin with an
alphabetic character and may contain no more than 31 characters.
%ndEnter the nth (1-based) parameter string

Note that when called via gmSL if nPattern is set to zero, then the length of PatString will be used.

The following code shows how a pattern can be used.

void DemoWritePattern(string what, string whom)
{
Write_Pattern("The event %1d happened at %TIME% on %DATE% to %2d", 0, what + ";" + Whom);
Write_Record();
}

As an example, the following commands

<Output Status="New" Filename="Demo008.out" />
<RunCommand Id="scmCode.DemoWritePattern" prams="Got Lost;Kilroy" />

produce the output

The event Got Lost happened at 13:33:03 on 2013-01-02 to Kilroy

Note that in this case the use of semicolons within the RunCommand prams attribute interferes with the use of semicolons in the Parameters parameter here, so some care must be taken.

gmSL: void Write_Record()

This method completes the authoring of the current output record and then writes the result either to the currently open text buffer or to the file specified in the Output statement. The steps performed before the write include: first, special codes that are used to represent single and double quotes in either escaped or un escaped form must be converted to the final form required by the target language; second, if the echo translation flag is set then the current margin nesting level and the record are written to the log file; third, if the author is writing ASP code then the record must be checked for a transition into or out or VBSCRIPT; and fourth, if the record is longer that the Select MaxOutputWidth value then it is broken into multiple records using the conventions of the target language.

The following code contrasts using Write_Text() and Write_Record() with using Write_Line().

void DemoWriteRecord(string theAuthor)
{
Write_Line("This is a message from " + theAuthor);
Write_Text("This is a message from ");
Write_Text(theAuthor);
Write_Record();
Write_Text("This is a message from " + theAuthor);
Write_Record();
}

Using this, the following commands

<Output Status="New" Filename="Demo009.out" />
<RunCommand Id="scmCode.DemoWriteRecord" prams="Kilroy" />

produce this set of identical lines

This is a message from Kilroy
This is a message from Kilroy
This is a message from Kilroy

gmSL: int Write_Select(int unit)


The Write_Select method selects one the available file structures as the current unit. All successive
write support will be performed by this unit until another call to this service is made or until the
unit is closed. Note that this service only selects the unit it does not open its output channels or change
it in any way. The unit parameter is the unit sequence number of the desired file structure. It must
have a value between 1 and 5. Note that unit 1 is connected to the gmPL Output statement and should
be used with care. Unit 5 is used by gmBasic as a temporary scratch unit — not open between tasks —
and should only be used in the same way here.


The following code, reproduced from the discussion of Write_CloseFile() shows how this method can
be used to flip back and forth between different files.

void DemoWriteSelect(string file1,string file2)
{
Write_OpenFile(2,file1,True,OutStyle.Text);
Write_OpenFile(3,file2,True,OutStyle.Text);
Write_Select(2);
Write_Line("Line 1 in File " + file1);
Write_Select(3);
Write_Line("Line 1 in File " + file2);
Write_Select(2);
Write_Line("Line 2 in File " + file1);
Write_CloseFile();
Write_Line("Line 1 in Output File");
Write_Select(3);
Write_Line("Line 2 in File " + file2);
Write_CloseFile();
Write_Line("Line 2 in Output File");
}

gmSL: void Write_SetIndentation(int indent, int offset)

This method sets the indentation widths for the current output stream. There are two width values: indent which specifies the number of spaces to indent per indentation level (a value of zero means use tabs); and offset which is used when a record is longer than the desired line-width. The following line can be set off this many additional spaces.

When an output file is first created, the default indent value is the Select Indent attribute and the default offset value is zero. When an text buffer is opened the initial values are the values from the current output file. The values specified here take immediate effect and can be changed within the same write sequence.

Consider the following code that writes an un indented line and then an indented one

void DemoWriteSetIndentation(string comment, int indent)
{
Write_SetIndentation(indent,0);
Write_Line("Unindented Line: " + comment);
Write_ChangeMargin(1);
Write_Line("Indented Line: " + comment);
Write_ChangeMargin(-1);
}

when called multiple times using various indent values

<Output Status="New" Filename="Demo010.out" />
<RunCommand Id="scmCode.DemoWriteSetIndentation" prams="Hello World;8" />
<RunCommand Id="scmCode.DemoWriteSetIndentation" prams="Hello World;1" />
<RunCommand Id="scmCode.DemoWriteSetIndentation" prams="Hello World;(%= Select.Indent %)" />

produces the following output

Unindented Line: Hello World
Indented Line: Hello World
Unindented Line: Hello World
Indented Line: Hello World
Unindented Line: Hello World
Indented Line: Hello World

The quantity Select.Indent sets the indentation level back to its original value.


gmSL: void Write_TableCell()

In many complex output situations it is often desirable to nest the output streams so that complex outputs can be nested within each other or can be constructed with independent sets of logic. This method allows for the writing of complex data cells within data tables. Rather than writing the current output record and thus clearing its internal buffers so that another record can be written, this method pushes the content of the current output record onto the runtime data queue and then clears it. Once a series of cells have been written, then the Write_TableRow() method writes a data row to the currently active output stream using the form required by the Output Syntax attribute set for it.

This method writes a table whose data cells contain information about all of the user defined variables in a completed translation.

Sub DemoWriteTable()
Dim iRoot As Integer
Dim levels(19) As Integer
DataQueue_SetBottom()
Write_Text "Audit of Variables in " & Store_GetDataName() & " storage area"
Write_TableCell()
Write_TableTitle()
DataQueue_PushString("Lev")
DataQueue_PushInteger(3)
DataQueue_PushString("Address")
DataQueue_PushInteger(8)
DataQueue_PushString("Full Symbol Identifier")
DataQueue_PushInteger(-100)
Write_TableHeadings()
iRoot = Store_FindFirstChild(levels,0)
Do while(iRoot <> 0)
If Store_GetObjectType(iRoot) = ObjectType.VARIABLE Then
Write_Integer(levels(0) - 1, 0)
Write_TableCell()
Write_Integer(iRoot,0)
Write_TableCell()
Write_Text(Symbol_FullName(iRoot,-1))
Write_TableCell()
Write_TableRow()
End If
iRoot = Store_FindNextChild(levels)
Loop
Write_TableEnd()
DataQueue_ClearBottom(1)
End Sub

A gmPL script that might use this method is as follows

<gmBasic>
<Storage Action="Open" Identifier="fmstock1.vbi" />
<Select GlobalSettings="GmslCode.vbi" />
<LoadEnvironment />
<Output Status="New" Filename="Demo011.out" stripTrail="on" />
<RunCommand Id="vbCode.DemoWriteTable" />
<Storage Action="Close" />
</gmBasic>

By convention all of the sample codes are compiled into a global settings file GmslCode.vbi. The class within that file which contains VB code is called vbCode. The fmstock1.vbi file is as it was produced within the FMSTOCK sample code. Nothing special was done to make it usable here. The Open action opens that file with Read Only permission. An abstract of the output follows.

Audit of Variables in fmstock1.vbi storage area:
Lev | Address | Full Symbol Identifier
--- | ------- | ----------------------
4 | 227293 | FMStocks_DB.Helpers.RegisterEventSource.lpUNCServerName
4 | 227382 | FMStocks_DB.Helpers.RegisterEventSource.lpSourceName
4 | 232756 | FMStocks_DB.Helpers.DeregisterEventSource.hEventLog
...
3 | 253093 | FMStocks_DB.logDebugMSG.strSource
3 | 253123 | FMStocks_DB.logDebugMSG.strMSG
2 | 264958 | FMStocks_DB.COMSVCSLib_AppServer

The actual cells written by the Write_TableCell method are the individual entries in each row of the table.


gmSL: void Write_TableEnd()


gmVB: Sub Write_TableEnd()

gmNI: void Write_TableEnd(void);

This method ends the authoring of a table of values. If the Output Syntax is Html then the Html closing tags are written; else this method does nothing.

Using the DemoWriteTable() subroutine with this script

<gmBasic>
<Storage Action="Open" Identifier="fmstock1.vbi" />
<Select GlobalSettings="GmslCode.vbi" />
<LoadEnvironment />
<Output Status="New" Filename="Demo012.html" Syntax="html" />
<RunCommand Id="vbCode.DemoWriteTable" />
<Output Status="Close" />
<Storage Action="Close" />
</gmBasic>

generates an output table with records like the following

<html>
...
<center><p><h4>Audit of Variables in fmstock1.vbi storage area</h4></p></center>
<center><table cellpadding="2" cellspacing="0" bordercolor="#5B5F8B" border="1">
<tr>
<th rowspan="1" colspan="1" class="spanner" nowrap="nowrap">Lev</th>
<th rowspan="1" colspan="1" class="spanner" nowrap="nowrap">Address</th>
<th rowspan="1" colspan="1" class="spanner" nowrap="nowrap">Full Symbol Identifier</th>
</tr>
<tr>
<td align="right" class="cell-odd" nowrap="nowrap">4</td>
<td align="right" class="cell-odd" nowrap="nowrap">227293</td>
<td align="left" class="cell-odd" nowrap="nowrap">FMStocks_DB.Helpers.RegisterEventSource.lpUNCServerName</td>
</tr>
...
<tr>
<td align="right" class="cell-odd" nowrap="nowrap">2</td>
<td align="right" class="cell-odd" nowrap="nowrap">264958</td>
<td align="left" class="cell-odd" nowrap="nowrap">FMStocks_DB.COMSVCSLib_AppServer</td>
</tr>
</table></center>
</body>
</html>

In this output the lines at the top before the title and those below the end of the table are produced by the gmPL Output statement. It is the closing table and center entries that are made by the Write_TableEnd() method. When writing code like DemoWriteTable() it is important to remember that its actual output form will be determined at gmPL RunCommand time so always include calls to methods like Write_TableEnd() in case the caller decides to use Html syntax.


gmSL: void Write_TableHeadings()


gmVB: Sub Write_TableHeadings()

gmNI: void Write_TableHeadings(void);

This method writes a column heading to the currently active output stream using the form required by the Output Syntax attribute set for it. The column headings themselves and their desired widths are stored in the runtime data queue. Reviewing again the DemoWriteTable() subprogram

Sub DemoWriteTable()
Dim iRoot As Integer
Dim levels(19) As Integer
DataQueue_SetBottom()
Write_Text "Audit of Variables in " & Store_GetDataName() & " storage area"
Write_TableCell()
Write_TableTitle()
DataQueue_PushString("Lev")
DataQueue_PushInteger(3)
DataQueue_PushString("Address")
DataQueue_PushInteger(8)
DataQueue_PushString("Full Symbol Identifier")
DataQueue_PushInteger(-100)
Write_TableHeadings()
iRoot = Store_FindFirstChild(levels,0)
Do while(iRoot <> 0)
If Store_GetObjectType(iRoot) = ObjectType.VARIABLE Then
Write_Integer(levels(0) - 1, 0)
Write_TableCell()
Write_Integer(iRoot,0)
Write_TableCell()
Write_Text(Symbol_FullName(iRoot,-1))
Write_TableCell()
Write_TableRow()
End If
iRoot = Store_FindNextChild(levels)
Loop
Write_TableEnd()
DataQueue_ClearBottom(1)
End Sub

It is the DataQueue service class calls that set up the call to Write_TableHeadings which expects the find a series of (String, Integer) pairs in the data queue. The number of pairs defines the number of columns in the table, each string entry defines the column heading, and the integer entry defines the field width and orientation to the used as follows:

ValueMeaning
+nRight justify the characters in a cell n characters wide.
-nLeft justify the characters in a cell n characters wide.

These values are actually only used when the Output Syntax is Text; however, since this syntax choice does not take effect until gmPL runtime, the values should always be supplied with reasonable values.


gmSL: void Write_TableRow()


gmVB: Sub Write_TableRow()

gmNI: void Write_TableRow(void);

This method writes a data row to the currently active output stream using the form required by the Output Syntax attribute set for it. The cell content making up the data row are stored as strings on the runtime data queue. Reviewing again the DemoWriteTable() subprogram

Sub DemoWriteTable()
Dim iRoot As Integer
Dim levels(19) As Integer
DataQueue_SetBottom()
Write_Text "Audit of Variables in " & Store_GetDataName() & " storage area"
Write_TableCell()
Write_TableTitle()
DataQueue_PushString("Lev")
DataQueue_PushInteger(3)
DataQueue_PushString("Address")
DataQueue_PushInteger(8)
DataQueue_PushString("Full Symbol Identifier")
DataQueue_PushInteger(-100)
Write_TableHeadings()
iRoot = Store_FindFirstChild(levels,0)
Do while(iRoot <> 0)
If Store_GetObjectType(iRoot) = ObjectType.VARIABLE Then
Write_Integer(levels(0) - 1, 0)
Write_TableCell()
Write_Integer(iRoot,0)
Write_TableCell()
Write_Text(Symbol_FullName(iRoot,-1))
Write_TableCell()
Write_TableRow()
End If
iRoot = Store_FindNextChild(levels)
Loop
Write_TableEnd()
DataQueue_ClearBottom(1)
End Sub

The individual calls to Write_TableRow() assume that they have been preceded by as many calls to Write_DataCell() as there were columns defined in the table via the DataQueue calls and the final call to Write_TableHeadings(). The actual output produced by this method is determined at gmPL runtime depending upon the setting of the Output Syntax attribute. Previous topics have shown the output for Text (see Write_TableCell()) and Html (see Write_TableEnd()). The script here uses Tabbed syntax.

<gmBasic>
<Storage Action="Open" Identifier="fmstock1.vbi" />
<Select GlobalSettings="GmslCode.vbi" />
<LoadEnvironment />
<Output Status="New" Filename="Demo013.out" Syntax="Tabbed" />
<RunCommand Id="vbCode.DemoWriteTable" />
<Output Status="Close" />
<Storage Action="Close" />
</gmBasic>

The following is an abstract of the output produced, note that the white space is produced by the tabs.

Audit of Variables in fmstock1.vbi storage area
Lev Address Full Symbol Identifier
4 227293 FMStocks_DB.Helpers.RegisterEventSource.lpUNCServerName
4 227382 FMStocks_DB.Helpers.RegisterEventSource.lpSourceName
4 232756 FMStocks_DB.Helpers.DeregisterEventSource.hEventLog
...
3 253093 FMStocks_DB.logDebugMSG.strSource
3 253123 FMStocks_DB.logDebugMSG.strMSG
2 264958 FMStocks_DB.COMSVCSLib_AppServer

Regardless of the output syntax used, it is implemented at runtime when the various Write_Table methods are used. It is important to remember this when writing code that uses them.


gmSL: void Write_TableTitle()


gmVB: Sub Write_TableTitle()

gmNI: void Write_TableTitle(void);

This method writes a title for a table of values along with any other control information that may be needed to begin the actual table display to the currently active output stream using the form required by the Output Syntax attribute set for it. The title itself is stored on the runtime data queue prior to the call to this method. The easiest way to do this is via the Write_TableCell() method though the DataQueue_PushString() could be used as well. Reviewing again the DemoWriteTable() subprogram,

Sub DemoWriteTable()
Dim iRoot As Integer
Dim levels(19) As Integer
DataQueue_SetBottom()
Write_Text "Audit of Variables in " & Store_GetDataName() & " storage area"
Write_TableCell()
Write_TableTitle()
....

the actual form of the output depends upon the Output Syntax attribute. For Text a colon is added to the back of the title string.

Audit of Variables in fmstock1.vbi storage area:

For tabbed the title string is unadorned.

Audit of Variables in fmstock1.vbi storage area

For Html it is displayed as an h4 centered heading.

<center><p><h4>Audit of Variables in fmstock1.vbi storage area</h4></p></center>

gmSL: void Write_Text(string strValue)


gmVB: Sub Write_Text(ByVal strValue As String)

gmNI: void Write_Text(char* strValue);

This method appends all characters from strValue to the current output record. No actual write occurs at this time. No formatting is applied to the string; however, the engine supporting gmSL performs concatenation and automatic conversions to string when processing addition within contexts that expect string arguments. For example the following code uses Write_Text

void DemoWriteText(int opcValue)
{
tOpcInfo opcInfo;
opcInfo = Opcode_GetInfo(opcValue);
Write_Text("The Opcode " + opcInfo.ident + " has value " + opcInfo.value);
Write_Record();
Write_Text(" length = " + opcInfo.length);
Write_Record();
Write_Text(" ident = " + opcInfo.ident);
Write_Record();
Write_Text(" value = " + opcInfo.value);
Write_Record();
Write_Text(" type = " + Symbol_NamedEntryLabel("opcTypes",opcInfo.type));
Write_Record();
Write_Text(" role = " + Symbol_NamedEntryLabel("opcRoles",opcInfo.role));
Write_Record();
}

to describe operation code properties. When called as follows

<Output Status="New" Filename="Demo014.out" />
<RunCommand Id="scmCode.DemoWriteText" prams="5"/>
<RunCommand Id="scmCode.DemoWriteText" prams="13"/>
<RunCommand Id="scmCode.DemoWriteText" prams="170"/>

the following output is produced.

The Opcode LIC has value 5
length = 17
ident = LIC
value = 5
type = ShortValue
role = LoadInt
The Opcode ADD has value 13
length = 17
ident = ADD
value = 13
type = Arithmetic
role = Binary
The Opcode USC has value 170
length = 17
ident = USC
value = 170
type = DoubleByte
role = Clsref

gmSL: void Write_TextStream(Handle textStream, int host, int margin)


gmVB: Sub Write_TextStream(ByVal textStream As Handle, ByVal host As Integer, ByVal margin As Integer)

gmNI: void Write_TextStream(void* textStream,int host, int margin)

This method writes the content of a text stream buffer to the current output file. The textStream parameter is obtained from one of the Text service class methods Text_Open() or Text_Create(). It is the handle to the text stream buffer to be written. The host parameter is the root offset of the symbol to which the text stream belongs. It may simply be zero. If nonzero, it is used to log this message

SYSERR#6067: Text storage malformed for <identifier of symbol>

in case the text stream is malformed. The margin parameter is the starting indentation margin to be used while writing the text stream. When gmBasic writes text streams it does not insert any leading white space to show marginal indentation; rather it simply records the margin level for each line. It is when the text stream is actually written that the margin level times the indentation width white space is actually applied to the front of the record. When doing this, the value of margin is added to the margin value recorded for each line.

The following method shows how the translation associated with a class file can be authored.

void DemoAuthorTextStream(int classRoot)
{
tInfoFile classFile;
Handle textStream;
classFile = Store_GetVector(classRoot);
textStream = Text_Open(Store_GetHandle(),classFile.tranBase);
Write_TextStream(textStream,classRoot,0);
Text_Close(textStream);
}

In the following script

<gmBasic>
<Storage Action="Open" Identifier="fmstock1.vbi" />
<Select GlobalSettings="GmslCode.vbi" />
<LoadEnvironment />
<Output Status="New" Filename="Demo015.out" />
<RunCommand Id="vbCode.DemoAuthorTextStream"
prams="(%= Symbol_FindIdentifier("[C:\gmSrc\fmstocks\vb6\FMStocks_DB\Version.cls]",0) %)" />
<Storage Action="Close" />
</gmBasic>

the gmPL preprocessor executes the Symbol_FindIdentifier method which returns the root offset of the specified symbol and inserts it in string form in the prams attribute. The RunCommand then passes that root offset as an integer value to the DemoAuthorTextStream() method. That method then writes the translation associated with the class just as it was produced when the actual translation script was executed. Here is an abstract of that output

cat >C:\gmProj\FmStocks\Deploy\FmStock1_csh\Version.cs <<'!)(!'
using System;
using System.Drawing;
...
namespace FMStocks_DB
{
public class Version
{
private const string m_modName = "FMStocks_DB.Version";
public string ConnectionString()
{
string ConnectionString = "";
DBHelper dbh = null;
try
{
MigrationSupport.Utils.ClearErrorObject();
dbh = new FMStocks_DB.DBHelper();
ConnectionString = dbh.GetConnectionString();
dbh = null;
return ConnectionString;
}
catch(Exception exc)
{
MigrationSupport.Utils.SetErrorObject(exc);
Helpers.RaiseError(m_modName,"ConnectionString()","",0,false);
}
return ConnectionString;
}
...
}
!)(!