IBM eNetwork Host Access Beans Reference

Host Access Beans for Java


Appendix A. Macro Script Syntax

After a macro script has been created using the Host On-Demand Macro Editor graphical user interface, a text editor, or the Macro bean, you can manually edit it. Only advanced users should manually edit macro scripts.

This guide to the macro script syntax contains the following topics:

Introduction

Host On-Demand uses XML because a macro is better suited to the state machine model (the main reason for the move: XML is tailor made for a state machine).

The idea of a state machine may be fairly new to you. The idea behind a state machine, especially in the Host On-Demand macro context, is simple. Think of how you use a host system from a terminal or a terminal emulator (like Host On-Demand). The process you follow when you interact with a host system is illustrated in these steps:

  1. The host sends an expected screen down to you at your terminal.
  2. You look at and understand which screen is presented to you.
  3. You take the required actions based on your understanding (type keystrokes, and so forth).
  4. Another screen is presented after these actions.
  5. If you see the screen you expected, repeat steps 2, 3, and 4.
  6. If you do not see the screen you expected, call the help desk or handle the error.

This is the idea behind a state machine in the Macro context (although the Macro can't call the help desk for you). The states are the screens you expect to see, and you take actions on those screens to change from one state, or screen, to another. That's it, see a screen, perform the action, see the next screen. It is easier to understand (and program) a macro with this approach than having several if-then-else and do-while programming statements. Remember, see a screen, perform the action, see the next screen.

Now take a look at how well suited XML is to coding a macro. Here is an example of how to specify a logon macro:

<HAScript>
<screen name="Logon" startscreen="true">
	<description>
		<string value="Please Logon" casesense="true"/>
		<cursor row="12" col="10"/>
	</description>
	<actions>
		<prompt name="ID" row="12" col="10" len="8"/>
		<prompt name="Password" row="13" col="10" len="8"/>
		<input value="[enter]"/>
	</actions>
	<nextscreens>
		<nextscreen name="Logon.Complete"/>
	</nextscreens>
</screen>
</HAScript>

These few lines of code demonstrate the power of this new syntax. All the screens you expect to see for a task (like logging on) are coded within <screen> elements in XML. You describe the screen in a <description> element, specify the actions for the screen in an <actions> element, and specify the screen you want to see next in a <nextscreens> element.

Keep in mind that the actions are executed in sequence. The <screen> element describes a logon screen with the text Please Logon on the screen and the screen's cursor position at row 12, column 10. If the Macro logic sees a screen matching this description, it prompts the user for an ID and Password, places the prompt results at the specified row and column positions, and sends the ENTER key, effectively logging on the user. The <nextscreens> element specifies the name of another screen element that appears later in the macro. If the next screen does not appear, the Macro logic fires an error.

Although there are many valid XML elements, XML itself is not complicated. A screen is specified with a description, actions, and the next screens. When a macro is played and a screen matching the description appears, the actions are executed for that screen and the Macro logic monitors the host for any next screens specified.

Macro Syntax

The following are valid macro elements:

<HAScript>
  <vars>
     <create>
  <screen>
     <comment>
     <description>
 	 <oia>
	 <cursor>
	 <numfields>
	 <numinputfields>
	 <string>
	 <attrib>
	 <customreco>
	 <varupdate>
  <actions>
	 <prompt>
	 <input>
	 <extract>
	 <message>
	 <trace>
	 <filexfer>
	 <pause>
	 <mouseclick>
	 <boxselection>
	 <commwait>
	 <custom>
	 <varupdate>
         <playmacro>
         <if>
         <else>
         <runprogram>
  <nextscreens>
 	 <nextscreen>
  <recolimit>

These XML elements and their attributes are valid in the Host On-Demand Macro XML namespace. This description of the elements is structured like an actual macro file. Element and attribute values are not case sensitive.

Note: All characters in a macro must be UNICODE characters. Most text editors support this by default, because they use the ASCII character set, which is at the lower end of the UNICODE character set.


<HAScript> element

The main enclosing element for the macro. All other elements at this level that are not <HAScript> are ignored by the parser.

Attributes:

Note: You cannot use variables as the values of <HAScript> attributes.

Text Between Elements

Example

<HAScript name="Logon Macro" description="Logs me on"
	  author="btwebb" creationdate="12/29/1998"
	  promptall="true" pausetime="500" timeout="10000" 
          usevars="true"> ... </HAScript>

<vars> element

Defines variables that are used in the macro if the usevars attribute of the <HAScript> tag is set to true. (If usevars is set to false and the macro parser finds a <vars> element in the macro, the parser displays an error message telling you to set usevars to true.) 

Including a <vars> block in a macro has the same effect as defining variables through the Variables tab in the Host On-Demand Macro Editor. The <vars> element must occur before the <screen> element in a macro.

Use the <create> element to declare variables and assign initial values to them. See Using variables for more detailed information on how variables can be used in macros.

Variables can be inherited from another macro; see the description of the <playmacro> element for details.

Attributes

Text Between Elements

Examples

<HAScript usevars="true">
  <vars>
      ... #Variable declarations 
  </vars>
</HAScript>

<create> element

Declares variables and assigns initial values to them. See Using variables for detailed information on how variables can be used in macros.

Attributes

Text Between Elements

Example

   <vars>
     <create name="$var_boolean$ type="boolean" value="true"/>
     <create name="$var_int$" type="integer" value="1"/>
     <create name="$var_double$" type="double" value="1.0"/>
     <create name="$var_string$" type="string" value="'some_texts'"/>
     <create name="$var_field$" type="field"/>
  </vars>

<screen> element

The enclosing element for the screen.

Attributes

Text Between Elements

Example

<screen name="screen1" entryscreen="true" exitscreen="false" transient="false">
	... </screen>

<comment> element

The comment element for the screen. This can contain any valid unicode character.

Attributes

Text Between Elements

Example

<comment> ... </comment>

<description> element

The enclosing element for the description associated with the screen.

By default, when the Macro Manager records a macro, the OIA and Field Counts descriptors are defined to identify the screen. It is recommended that you add String descriptors for more strict and accurate screen recognition.

Attributes

Text Between Elements

Example

<description> ... </description>

<numfields> element

The total number of fields on the screen. This element is optional. The number of fields is not used if not specified.

Attributes

Text Between Elements

Example

<numfields number="10" optional="false" invertmatch="false" />

<numinputfields> element

The total number of input fields on the screen. This element is optional. The number of input fields is not used if not specified.

Attributes

Text Between Elements

Example

<numinputfields number="10" optional="false" invertmatch="false" />

<oia> element

Specifies an OIA condition to match. This element is optional, default is to wait for inhibit status.

Attributes

Text Between Elements

Example

<oia status="NOTINHIBITED" optional="false" invertmatch="false" />

<string> element

Describes the screen based on a string.

Attributes

Text Between Elements

Example

<string value="'hello'" row="1" col="1" optional="false" invertmatch="false" />
<string value="'hello'" row="1" col="1" erow="11" ecol="11"
	casesense="false" optional="false" invertmatch="false" />

	<string value="hello" />

<cursor> element

Describes the screen based on the position of the cursor.

Attributes

Text Between Elements

Example

<cursor row="1" col="1" optional="false" invertmatch="false" />

<attrib> element

Describes the screen based on an attribute. This is an advanced feature and should only be used if needed. Usually all the other description elements are enough to describe a screen.

Attributes

Text Between Elements

Example

<attrib value="0x01" row="1" col="1" plane="COLOR_PLANE" optional="false"
	invertmatch="false" />

<customreco> element

The Macro logic will call out to any custom recognition listeners for the custom element to have the listener do its own custom screen recognition logic.

Attributes

Text Between Elements

Example

<customreco id="id1" optional="false" invertmatch="false"/>

<varupdate> element

Modifies the values of variables. This element may be used anywhere within <description> and <actions> blocks. For more information about macro variables, see Using variables.

By default, <varupdate> commands are the first commands to be executed in the <description> section - regardless of where they occur sequentially in the section. For example, if you create a String descriptor and use a variable for the string, then update the variable right after that descriptor, the variable is updated before the String descriptor is checked for a match.  You can change the order of execution of <varupdate> elements by using the <description> element's uselogic attribute; see Advanced Screen Recognition for details.

Note: When a <varupdate> tag is used in a <description> block, the variable's value is updated when the macro attempts to match that screen, not when the screen is actually matched.  This means that the variable is updated even if the screen doesn't match.

Attributes

Text Between Elements

Example

<screen>
  <description> or <actions>
    <varupdate name="$var_boolean$" value="false" />
    <varupdate name="$var_int$" value="5" />
    <varupdate name="$var_double$" value="5" />
    <varupdate name="$var_string$" value="'new_texts'" />
    <varupdate name="$var_field$" value="4,5" />
  </description> or </actions> 
</screen>

<actions> element

The enclosing element for the actions associated with the screen

Attributes

Text Between Elements

Example

<actions promptall="true"> ... </actions>

<prompt> element

Specifies a prompt to be handled for the screen.

Attributes

Text Between Elements

Example

<prompt name="'ID'" row="1" col="1" len="8" description="'ID for Logon'"
        default="'btwebb'" clearfield="true" encrypted="true" 
        assigntovar="$userID$" varupdateonly="true"/>

<extract> element

Specifies an area where the screen's contents are to be extracted.

Attributes

Text Between Elements

Example

<extract name="'Get Data'" srow="1" scol="1" erow="11" ecol="11" 
         assignto=$data_var$ />

<input> element

Specifies keystrokes to be placed on the screen.

Attributes

Text Between Elements

Example

<input value="'Host On-Demand[tab]is useful[enter]'" row="1" col="1" movecursor="true"
	xlatehostkeys="true" />

<message> element

Specifies a message to be sent to the user.

Attributes

Text Between Elements

Example

<message value="'Accessing Host System'" title="'Message from IBM'" />

<trace> element

Specifies a string to be sent to one of several trace facilities.

Attributes

Text Between Elements

Example

<trace value="'hello'+$HelloMsg$" type="HODTRACE" />

<filexfer> element

Transfers a file to or from a host system.

Attributes

Text Between Elements

Example

<filexfer direction="send" pcfile="'c:\\myfile.txt'" hostfile="'myfile text A0'" 
          clear="true" timeout="10000" pccodepage="437"  />

<pause> element

Causes the Macro bean to sleep for the given amount of milliseconds. This action is useful for pausing in between several file transfers.

Attributes

Text Between Elements

Example

<pause value="2000" />

<mouseclick> element

Simulates a user mouse click on the Terminal bean. This essentially sets the cursor at a given row and column position.

Attributes

Text Between Elements

Example

<mouseclick row="20" col="16" />

<boxselection> element

Used for either marking or unmarking the marking rectangle on the Terminal bean.

Attributes

Text Between Elements

Example

<boxselection srow="1" scol="1" erow="11" ecol="11" type="SELECT" />

<commwait> element

Used for performing a communication status wait during a macro's execution.

Attributes

Text Between Elements

Example

<commwait value="CONNECTION_READY" timeout="10000" /> 

<custom> element

Enables the user to have an exit to Java code, see Javadoc for the MacroActionCustom class.

Attributes

Text Between Elements

Example

<custom id="custom1" args="'IBM world class computers'" /> 

<nextscreens> element

Contains all the valid next screens to be recognized after the current screen's actions have been executed.

Attributes

Text Between Elements

Example

<nextscreens> ... </nextscreens> 

<nextscreen> element

Screen that forces a next screen. Multiple nextscreen elements are allowed. If a screen appears that is in the macro but is not a next screen, the macro will go into an error state. If the next screen refers to a screen element that doesn't exist, the Macro will have a parse error.

Attributes

Text Between Elements

Example

<nextscreen name="Screen1" />

<recolimit> element

Advanced use only.

Used to enforce a limited amount of time a screen can be recognized in a row before it goes to the screen indicated in the goto attribute. This element is useful for screen looping where you know exactly how many times you'll see a given screen in a row. It also is a safeguard against infinite screen recognition.

Attributes

Text Between Elements

Example

<recolimit value="3" goto="endscreen" />

<varupdate> element

This element can be used anywhere within <description> and <actions> blocks. See the description of the <varupdate> element under the <description> element for details.

For more information about macro variables, see Using variables.


<playmacro> element

Runs a macro from within another macro. This process is called chaining. The currently running macro (the parent macro) stops and the macro specified in the <playmacro> element (the child macro) begins playing. Only macros that are available to run in a particular session can be chained. 

In general, a <playmacro> element must be the last action within the same screen. Any actions after a <playmacro> tag will cause errors to occur.  The exception is if a <playmacro> element is contained within an <if>-<else> block (that is, a condition must be satisfied for the macro to play).  You can include as many <playmacro> elements in a screen as you like as long as each one is contained within an <if>-<else> block.  Each <if>-<else> block can only contain one <playmacro> element and the <playmacro> element must be the last action in the block.  Control immediately passes to the child macro if it is executed from within an <if>-<else> block; subsequent elements in the parent macro are ignored.

If you wish to chain macros in an application that uses the Host On-Demand Beans or HACL APIs, you need to do the following:

Attributes

Note: You cannot use variables as the values of <playmacro> attributes.

Text Between Elements

Example

<actions>
      <playmacro name="Macro1" startscreen="intro_screen" 
                 transfervars="Transfer" />
</actions>

<if> element

Allows the macro to perform operations based on the truth or falsehood of some condition.  If the condition evaluates to true, the operations within the <if> block are performed.  If it evaluates to false, they are not.  Optionally, an <else> element can be used with an <if> block to specify operations to be performed if the <if> statement evaluates to false.  See Using conditional (if - else) statements for more information and examples.

Attributes

Text Between Elements

Example

<actions>
   <if condition="($var_int$ == 1) || (!$var_bool$)">
       . . .  # If the value of var_int equals 1 OR the value 
              # of var_bool is false, perform macro operations
   </if>
</actions>

<else> element

An <else> element can be used with an <if> element to specify operations that are performed if the <if> conditional statement evaluates to false. This element can only be used immediately after an  <if> element.  See Using conditional (if - else) statements for more information and examples.

Attributes

Text Between Elements

Example

<actions>
   <if conditions="($var_int$ > 10)">
       . . .  # Perform macro operations if
              # $var_int$ is greater than 10
   </if>
   <else>  
       . . .  # Perform other macro operations if
              # $var_int$ is less than or equal 
              # to 10
   </else>
</actions>

<runprogram> element

Runs an application from a macro.

Attributes

Text Between Elements

Example

<runprogram exe="'C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe'" 
            param="'new_file.doc'" wait="true" 
            assignexitvalue="$exitstatus$"/>

The Most Powerful Macro

This section gets its name because the following example demonstrates how most of these elements and their attributes can be used in a macro.

<HAScript name="King Logon Macro" description="Most Powerful Macro" 
          timeout="60000" pausetime="300" promptall="false" 
          author="khpark and ryehle" creationdate="May 17, 2002" 
          supressclearevents="false" usevars="true" >

    <vars>
        <create name="$userid$" type="string" value="" />

        <create name="$timedatestamp$" type="string" value="" />

        <create name="$promptresponse$" type="string" value="" />

        <create name="$exitcode$" type="string" value="" />

        <create name="$screencount$" type="integer" value="0" />
    </vars>

    <screen name="Logon" entryscreen="true" exitscreen="false" transient="false">

        <comment>
            Prompts the user for ID and password.  The ID is stored into a variable 
            for later use. Demonstrates mouse click, box select, and copy/paste 
            by copying text from one area of the screen and pasting to another.  
            The screencount variable increments by one, as it does on every screen,
            to keep track of the number of screens passed through, and the screencount
            and screenname are traced to SYSOUT.  The screen description for this 
            screen is a little out of control, but it demonstrates how to use 
            almost everything.
        </comment>

        <description>
            <oia status="NOTINHIBITED" optional="false" invertmatch="false" />
            <cursor row="20" col="16" optional="false" invertmatch="false" />
            <numfields number="61" optional="false" invertmatch="false" />
            <numinputfields number="16" optional="false" invertmatch="false" />
            <string value="'Fill in your USERID and PASSWORD'" row="1" col="1" erow="-1" ecol="-1" casesense="true" optional="false" invertmatch="false" />
            <attrib value="0x2" row="3" col="30" plane="COLOR_PLANE" optional="false" invertmatch="false" />
        </description>

        <actions promptall="true">
            <varupdate name="$screencount$" value="$screencount$ + 1" />

            <trace type="SYSOUT" value="$screencount$+': Screen Logon'"  />

            <prompt name="'User ID'" description="'Enter User ID here'" 
                    row="20" col="16" len="8" default="" clearfield="false" 
                    encrypted="false" movecursor="true" xlatehostkeys="true" 
                    assigntovar="$userid$" varupdateonly="false" />

            <input value="'[tab]'" row="0" col="0" movecursor="true" 
                   xlatehostkeys="true" encrypted="false" />

            <prompt name="'Password'" description="'Enter Password here'" 
                    row="21" col="16" len="8" default="" clearfield="false" 
                    encrypted="true" movecursor="true" xlatehostkeys="true" 
                    assigntovar="" varupdateonly="false" />

            <boxselection type="SELECT" srow="3" scol="30" erow="3" ecol="51" />

            <input value="'[copy]'" row="0" col="0" movecursor="true" 
                   xlatehostkeys="true" encrypted="false" />

            <boxselection type="DESELECT" />

            <mouseclick row="23" col="16" />

            <input value="'[paste]'" row="0" col="0" movecursor="true" 
                   xlatehostkeys="true" encrypted="false" />

            <pause value="3000" />

            <input value="'[enter]'" row="0" col="0" movecursor="true" 
                   xlatehostkeys="true" encrypted="false" />
        </actions>

        <nextscreens timeout="0" >
            <nextscreen name="Logon.Complete" />

            <nextscreen name="Logon.Failed" />
        </nextscreens>

    </screen>

    <screen name="Logon.Complete" entryscreen="false" exitscreen="true" 
            transient="false">

        <comment>
            User has logged on successfully. The time and date is extracted 
            from the screen and stored in the timedatestamp variable, which 
            is then displayed along with userid to the user in a welcome message.
            The user is prompted to either send or receive a file; based on response
            a file is sent to or received from the host.  The file is then opened 
            for editing.  The macro waits for the user to close the file, then 
            provides an appropriate reaction depending on whether the file was 
            opened or closed normally.
        </comment>

        <description>

            <oia status="NOTINHIBITED" optional="false" invertmatch="false" />

            <numfields number="7" optional="false" invertmatch="false" />

            <numinputfields number="1" optional="false" invertmatch="false" />

            <string value="'LOGON AT'" row="1" col="1" erow="-1" ecol="-1" 
                    casesense="false" optional="false" invertmatch="false" />

        </description>

        <actions>

            <varupdate name="$screencount$" value="$screencount$ + 1" />

            <trace type="SYSOUT" value="$screencount$+': Screen Logon.Complete'"  />

            <extract name="'Extract'" planetype="TEXT_PLANE" srow="1" scol="10" 
                     erow="1" ecol="37" unwrap="false" assigntovar="$timedatestamp$" />

            <message title="'Greeting'" 
                     value="'Welcome '+$userid$+'!  It is currently '+$timedatestamp$+'.'" />

            <commwait  value="CONNECTION_READY" timeout="10000" />

            <prompt name="'Would you like to Send (S) or Receive (R) a file?'" 
                    description="" row="0" col="0" len="80" default="'S'" 
                    clearfield="false" encrypted="false" movecursor="true" 
                    xlatehostkeys="true" assigntovar="$promptresponse$" 
                    varupdateonly="true" />

            <if condition="$promptresponse$ == 'S'" >

                  <filexfer direction="send" hostfile="'LogonFile txt a0'" 
                            pcfile="'C:\\LogonFile.txt'" options="" clear="true" 
                            timeout="10000" pccodepage="437"  />

            </if>

            <else>

                  <filexfer direction="receive" hostfile="'LogonFile txt a0'" 
                            pcfile="'C:\\LogonFile.txt'" options="" clear="true" 
                            timeout="10000" pccodepage="437"  />

            </else>

            <runprogram exe="'notepad'" param="'C:\\LogonFile.txt'" 
                        wait="true" assignexitvalue="$exitcode$" />

            <if condition="$exitcode$ == 0" >

                  <trace type="SYSOUT" value="'Program exited gracefully.'"  />

            </if>

            <else>

                  <message title="'Error'" value="'Error Opening File in Notepad. Error Code '+$exitcode$" />

            </else>

        </actions>

        <nextscreens timeout="0" >

        </nextscreens>

    </screen>

    <screen name="Logon.Failed" entryscreen="false" exitscreen="true" 
            transient="false">

        <comment>
            This screen is encountered when a user attempts to logon with 
            a userid that is already logged on.  We logoff by chaining to 
            a simple logoff macro. A macro named "logoff" must exist already, 
            otherwise an error message will show up  when trying to save 
            and play this macro.
        </comment>

        <description>

            <oia status="NOTINHIBITED" optional="false" invertmatch="false" />

            <numfields number="5" optional="false" invertmatch="false" />

            <numinputfields number="1" optional="false" invertmatch="false" />

            <string value="'Already logged on'" row="1" col="1" erow="-1" 
                    ecol="-1" casesense="false" optional="false" 
                    invertmatch="false" />

        </description>

        <actions>

            <varupdate name="$screencount$" value="$screencount$ + 1" />

            <trace type="SYSOUT" value="$screencount$+': Screen Logon.Failed'"  />

            <playmacro name="logoff" startScreen="*DEFAULT*" transferVars="No Transfer" />

        </actions>

        <nextscreens timeout="0" >

        </nextscreens>

    </screen>

    <screen name="Transient.Message" entryscreen="false" exitscreen="false" 
            transient="true">

        <comment>
            This screen demonstrates the idea of a transient screen.
            Say our host system can send us asynchronous messages
            while we're logging on, we just want to clear them.
            This screen handles this and is valid anytime a message 
            screen appears.  No nextscreens needed here.
        </comment>

        <description>

            <oia status="NOTINHIBITED" optional="false" invertmatch="false" />

            <string value="'More...'" row="1" col="1" erow="-1" ecol="-1" 
                    casesense="false" optional="false" invertmatch="false" />

        </description>

        <actions>

            <varupdate name="$screencount$" value="$screencount$ + 1" />

            <trace type="SYSOUT" value="$screencount$+': Screen Transient.Message'"  />

            <input value="'[clear]'" row="0" col="0" movecursor="true" 
                   xlatehostkeys="true" encrypted="false" />

        </actions>

        <nextscreens timeout="0" >

        </nextscreens>

    </screen>

</HAScript>

Recolimit Demonstration

This macro demonstrates how to extract a list that exists on multiple screens using the recolimit and invertmatch attributes. The behavior of this macro is as follows:

  1. Assume we get to the ExtractScreen.Main screen (recolimit is 1).
  2. Data is extracted and PF8 is sent to page down.
  3. The ExtractScreen.Main is matched again (recolimit is 2), and so on.
  4. If recolimit becomes 25, meaning that ExtractScreen.Main was recognized 25 times, the actions for ExtractScreen.Main will not be executed the 25th time. Instead, the actions for ExtractScreen.Complete will be executed. The actions are not executed for ExtractScreen.Main to keep from extracting twice if the ExtractScreen.Complete screen is reached before the recolimit is reached.
  5. If ExtractScreen.Complete is matched before the recolimit reaches 25, then we'll just get all the data in the system.
<HAScript name="Extracter Macro" description="Gets me data from a list"
          author="btwebb" creationdate="12/29/1998" promptall="false"
          pausetime="500" timeout="10000" >
<screen name="ExtractScreen.Main">
	<comment>
		We'll assume there would be other screens that log us on
		 and get us to this point.
		This screen is the main extraction screen,
		 and extracts data only if there is no blank
		line at the bottom of the screen indicating
		 there isn't any more data (ala invertmatch="true").
		To be safe we'll apply a recolimit of 25.
		This screen does an extract, then pages down with PF8.
	</comment>
	<description>
		<oia status="NOTINHIBITED" optional="false" invertmatch="false" />
		<string value="'Data Screen'"/>
		<string value="'           '" row="24" col="1" 
                        erow="24" ecol="11" invertmatch="true" />
	</description>
	<actions promptall="true">
		<extract name="'Get Data'" srow="2" scol="1" erow="24" 
                         ecol="80" />
		<input value="[pf8]"/>
	</actions>
	<nextscreens timeout="20000">
		<nextscreen name="ExtractScreen.Main"/>
		<nextscreen name="ExtractScreen.Complete"/>
	</nextscreens>
	<recolimit value="25" goto="ExtractScreen.Complete"/>
</screen>
<screen name="ExtractScreen.Complete">
	<comment>
		This screen is the final extraction screen,
		 and extracts data and sends an exit command.

                Note: It is only different from the main screen in 
                that the blanks must be there. Assume there would 
                be other screens to take care of logging off.
	</comment>
	<description>
		<oia status="NOTINHIBITED" optional="false" invertmatch="false" />
		<string value="'Data Screen'"/>
		<string value="'           '" row="24" col="1" erow="24" ecol="11"/>
	</description>
	<actions promptall="true">
		<extract name="'Get Data'" srow="2" scol="1" erow="24" ecol="80" />
		<input value="exit[enter]"/>
	</actions>
	<nextscreens timeout="20000">
		<nextscreen name="ExtractScreen.Complete"/>
	</nextscreens>
</screen>
</HAScript> 

Advanced Screen Recognition

The <description> element defines the recognition criteria for a screen. The optional attribute of other elements within the <description> element allows you to constrain the descriptors in a limited way. For example, consider the following description:

<description>
	<oia status="NOTINHIBITED" optional="false" />
	<string value="aaaaaaaaaaa" optional="false" />
	<string value="bbbbbbbbbbb" optional="true" />
</description>

This screen description matches a screen with an OIA status of NOTINHIBITED and a string value of "aaaaaaaaaaa" OR a screen with a string vaue of "bbbbbbbbbbb" The screen recognition logic first tries to see if all the optional="false" descriptors are satisfied. Otherwise it attempts to match any one optional="true" descriptor.

You cannot use the optional attribute to decribe a screen as follows: OIA status NOTINHIBITED and string "aaaaaaaaaaa" OR not oia NOTINHIBITED and string "bbbbbbbbbbb". 

Optionally, you can set up more sophisticated matching conditions for screen descriptions by using the uselogic attribute of the <description> tag.  This optional attribute allows you to match screens by specifying logical relationships among the screen descriptors such as the following:

<description uselogic="(1 and 2) or (!1 and 3)" />
	<oia status="NOTINHIBITED" />
	<string value="aaaaaaaaaaa" />
	<string value="bbbbbbbbbbb" />
</description>

The "!" in "(1 and 2) or (!1 and 3)" stands for not. It is the equivalent of the invertmatch attribute. The numbers represent the descriptors, in the order specified. In this example, the screen description matches if the OIA status is  NOTINHIBITED and the string value is "aaaaaaaaaaa" OR the OIA status is not NOTINHIBITED and the string value is "bbbbbbbbbbb".   The key words AND and OR can be used to represent the logical AND and logical OR operations. These key words are not case sensitive.

Keep the following in mind if you decide to use the uselogic attribute:


Using variables

Variables can be used in macro commands to replace hard-coded values and store the results of operations, just like in any other programming language. They can be created by using the graphical user interface of the Macro Editor or by including the <vars> element in an existing macro and declaring them with the <create> element. Variables can also be inherited from other macros; see the description of the <playmacro> element for details.

To use variables within a macro (including inherited variables), set the usevars attribute of the <HAScript> element to true. The values of macro element attributes are then parsed for variable names and arithmetic operators.   The value of the usevars attribute is automatically set to false unless a variable was created by using the Host On-Demand Macro Editor.  If the value of usevars is false and the macro parser finds a <vars> element in the macro, the parser displays an error message telling you to set usevars to true.

Note: When you create a macro or edit an existing macro in the Macro Editor, the first time that you check "Use Variables and Arithmetic Expressions in Macro" in the Macro Editor (setting the usevars attribute of the <HAScript> element to "true"), Host On-Demand displays a warning that the macro is about to be converted for use with variables and other advanced macro features. (Macros created under version 6 and earlier of Host On-Demand will still run if they are not converted; the conversion is necessary only to use variables and some other new features introduced in version 7.)

After the first time that you choose to have your macro converted, you will not be given that option again (for example, turning usevars off and back on does not reconvert the macro). When you uncheck usevars, you are warned that you may be damaging your macro code.  

Variables can be used anywhere within a <screen> element. However, a variable can only be used as a value of an attribute, not as an attribute name. You also cannot use variables to assign values to <HAScript> attributes, <playmacro> attributes, the uselogic attribute of the <description> element, or macro screen names.

Variable names are specified in a macro as $varname$, where varname is the name assigned to the variable when it was declared using the <create> element. The following example shows how a variable can be created and used to assign a value to an attribute of a macro element (in this case, the <pause> element):

<HAScript usevars="true">
  <vars>
     <create type="integer" name="$pause_length$" value="1000"/>
  </vars>
  <screen>
     ...
     <pause value="$pause_length$">
     ...
  </screen>
</HAScript>

Variables that are not defined within a macro can be assigned as attribute values because the variables may be inherited from a parent macro (see the description of the <playmacro> element for details). However, when you create a variable, you cannot set its value to that of an inherited variable because variables are created and initialized when the macro is parsed, not at run-time.

Variable types

The following types of variables are supported:

Updating variables

Variable values can be updated in four different ways:

Updating variables is especially important for field variables, which cannot be given a default value and must be assigned a screen position at run-time.

The following example shows the different ways that variables can be updated.

<HAScript usevars="true">
  <vars>
     <create name="$var_bool$ type="boolean" value="true"/>
     <create name="$var_int$" type="integer" value="1"/>
     <create name="$final_count$" type="integer"/>
     <create name="$var_double$" type="double" value="1.0"/>
     <create name="$var_string$" type="string" value="'some texts'"/>
     <create name="$var_field$" type="field"/>
  </vars>
  <screen>
    <description>
       <varupdate name="$var_bool$" value="false" />
    </description> 
  </screen>
  <actions>
    <prompt name="'textstring'" row="1" col="1" len="72" 
        description="'Enter a text string'"  
        clearfield="true" encrypted="false" 
        assigntovar="$var_string$" />
    <prompt name="'intnumber'" row="2" col="1" len="24" 
        description="'Enter an integer'"  
        clearfield="true" encrypted="false" 
        assigntovar="$var_int$" />
    <varupdate name="$var_field$" value="4,5" />
    <extract name="'Get Double value'" srow="4" scol="1" 
        erow="4" ecol="18" assigntovar=$var_double$ />
    <runprogram exe="'C:\\myapps\\counter.exe'" 
        wait="true" assignexitvalue="$final_count$"/>
  </actions>
</HAScript>

Arithmetic operations

Arithemetic operations can be performed on numbers, integer variables, double variables, field variable, and string variables. Boolean variables can be used in concatenation operations. The following operations are supported:

Parentheses can be used in expressions. 

To display these characters on the screen, specify them as literal strings enclosed in single quotes (') - for example, to display the plus sign (+) on the screen, specify the string '+' in the macro. (For instructions on how to use the reserved characters single quote (') and backslash (\), see Using Special Characters.)

Operator precedence is as follows:

  1. Parentheses. Operations within parentheses are evaluated first, then the result is used in any subsequent operations.
  2. Multiply, divide, mod
  3. Add, concatenate, subtract

  The following examples show how to use arithmetic operations on variables. Each example gives the syntax of the operation and shows its result. In these examples, the name of the variable is also what the variable evaluates to (for example., $5$ has a value of 5).

"(1 + 2) + ', ' + (3 + 5)" = 3, 8
"'Hello ' + $Fred$ + '!'" = Hello Fred!
"$Hi$ $There$" = Error, need a + sign to join strings
"$Hi$+$There$" = HiThere
"$Hi$+'+'+$There$" = Hi+There
"'8.13' + 12" = 8.1312 ('8.13' is a string)
"1 + 2 * 5" = 11
"(1 + 2) * 5" = 15
"10 - (2 / 4)" = 9.5
"(10 - 2) / 4" = 2
"11 / 4" = 2.75
"11 % 4" = 3
"11.0 / 4" = 2.75
"11 / 4.0" = 2.75
"11.0 % 4" = 3.0
"'abc1.08e4' + 3.4e5" = abc1.08e4340000.0
"'5*3'" ="5*3"
"5 + $3$" = 53, where $3$ is a string variable 
"5 + $3$" = 8, where $3$ is an integer variable 
"'abc\\de'" = abc\de 
"'that\'s'" = that's  

The following example shows some of the ways that arithmetic operations can be used when creating, using, and updating variables.

<vars>
   <create name="$var_boolean$" type="boolean" value="false" />
   <create name="$var_int$" type="integer" value="100" />
   <create name="$var2_int$" type="integer" value="$var_int$*5" />
     #OK to use $var_int$ since it is defined already. Result = 500
   <create name="$var_double$" type="double" value="100.9" /> 
     #Result = 100.9
   <create name="$var2_double$" type="double" value="$var_int$*5" /> 
     #Result = 500.0
   <create name="$var_string$" type="string">
   <create name="$var1_string$" type="string" value="'FirstString'" />
</vars>
<screen>
  <description>
     <varupdate name="$var_string$" value="$var_boolean$+$var1_string$+'+'" />
       #Result = "falseFirstString+"
     <varupdate name="$var2_int$" value="$var_int$+400" />
       #Result = 500
  </description>
  <actions>
    <varupdate name="$var2_double$" value="$var2_int$" /> 
      #Result = 500.0
    <varupdate name="$var_int$" value="$var_double$" /> 
      #Result = 100 (only gets a whole number part)
    <varupdate name="$var2_int$" value="$var_double$*2" /> 
      #Result = 100.9 *2 = 201 (not 201.8 or 202)
    <pause value="$var_int$" /> 
       #OK
    <pause value="$var_int$* 5" /> 
       #OK 
    </actions>
</screen>

Be aware of the following:

Debugging Variables With MacroActionTrace

If you find that your variables do not seem to contain the right value when you use them, but cannot print the value with an <input> action without throwing off your macro, use MacroActionTrace to display their current values. MacroActionTrace displays variables with their current values as follows:

<vars>
<create name="$var1$" type="string" value="'original'" />
</vars>
.
.
.
<actions>
<trace type="SYSOUT" value="'Before update: '+$var1$" /> 
<varupdate name="$var1$" value="'updated'" />
<trace type="SYSOUT" value="'After update: '+$var1$" />
</actions> 

This prints the following to the Java console:

Before update: {$var1$ = original}
After update: {$var1$ = updated}

Using variables in programmed macros

New methods and classes have been added to the Host Access Beans and Host Access Class Library to allow the use of variables and arithmetic expressions in programmed macros.   The following example is a macro that prompts for the user's ID and password, logs the user on to the host, and says "Welcome!":

<HAScript name="Logon" description="" timeout="60000" pausetime="300" 
          promptall="true" author="" creationdate="" supressclearevents="false" 
          usevars="true" > 

  <screen name="Screen1" entryscreen="true" exitscreen="false" transient="false">

    <description>
      <oia status="NOTINHIBITED" optional="false" invertmatch="false" />
    </description>

    <actions>
      <prompt name="'UserID:'" description="" row="20" col="16" len="8" 
              default="" clearfield="false" encrypted="false" movecursor="true" 
              xlatehostkeys="true" assigntovar="" varupdateonly="false" />
      <input value="'[tab]'" row="0" col="0" movecursor="true" 
              xlatehostkeys="true" encrypted="false" />
      <prompt name="'Password:'" description="" row="21" col="16" len="8" 
              default="" clearfield="false" encrypted="true" movecursor="true" 
              xlatehostkeys="true" assigntovar="" varupdateonly="false" />
      <input value="'[enter]'" row="0" col="0" movecursor="true" 
              xlatehostkeys="true" encrypted="false" />
    </actions>
    <nextscreens timeout="0" >
      <nextscreen name="Screen2" />
    </nextscreens>
  </screen> 

  <screen name="Screen2" entryscreen="false" exitscreen="true" transient="false">
    <description>
      <oia status="NOTINHIBITED" optional="false" invertmatch="false" />
      <numfields number="7" optional="false" invertmatch="false" />
      <numinputfields number="1" optional="false" invertmatch="false" />
    </description>
    <actions>
      <message title="" value="'Welcome!'" />
    </actions>
    <nextscreens timeout="0" >
    </nextscreens>
  </screen> 

</HAScript>

Assume that you want to use this macro in a Host Access Beans program and you want to store the user ID into a variable and save for later use (for example, in the Welcome message). You could do this directly by modifying the macro, but one reason for doing this programmatically would be to avoid having to maintain many different macros for different situations. You could instead have a base "skeletal" macro and modify it programmatically depending on the situation. The following is an example of how you can do this:

// Assume macro is an instantiated Macro with the appropriate listeners set up. 
// (See the Javadoc for the Macro bean and the Macro variables demo program,
// MacroVariablesDemo.java, in the Host Access Toolkit samples directory
// for details.)
// Assume macroString is a String containing the previous macro script

macro.setMacro(macroString);
MacroScreens ms = macro.getParsedMacro();
ms.createVariableString("$userid$", null);   //creates a variable $userid$ with 
                                             //initial value of ""
MacroScreen mscrn = ms.get(0);   //get the first screen
MacroActions mas = mscrn.getActions();   //get the actions from the first screen
MacroActionPrompt map = (MacroActionPrompt)mas.get(0);   //get the first prompt action
map.setAssignToVar("$userid$"); //assign the prompt response to the variable $userid$
MacroScreen mscrn2 = ms.get(1); //get the second screen
MacroActions mas2 = mscrn2.getActions(); //get the actions from the second screen
MacroActionMessage mam = (MacroActionMessage)mas2.get(0); //get the message action
mam.setMessage("'Welcome ' + $userid$ + '!'"); //change the message to now be a 
                                               //personalized message using $userid$
macro.setParsedMacro(ms); //reset the macro with the updated MacroScreens
macro.play(); //play the macro with the changes for variables 

Suppose you now want to add a second message to the actions for Screen2. In this message, you want to display the time and date, which you extract from the screen. You would add the following lines before macro.setParsedMacro(ms):

ms.createVariableString("$datetimestamp$", null); //create a variable $datetimestamp$ with initial value ""
MacroActionExtract mae = new MacroActionExtract(2, 35, 2, 71, "'datetimeextract'"); //create new extract to get date and time from second row of screen
mae.setAssignToVar("$datetimestamp$"); //assign the date and time string to $datetimestamp$
mas2.add(mae); //add the extract after the first message
MacroActionMessage mam2 = new MacroActionMessage("'You have logged on at ' + $datetimestamp$", "'Date Time Stamp'"); //create a new message to //display the date and //timestamp
mas2.add(mam2); //add the message after the extract 

Note that at the point when the attribute containing the variable(s) is associated with the MacroScreens, you must have already created the variable (through one of the createVariable() methods). For example, this code sequence would also be valid:

MacroActionExtract mae = new MacroActionExtract(2, 35, 2, 71, "'datetimeextract'"); 
mae.setAssignToVar("$datetimestamp$"); 
ms.createVariableString("$datetimestamp$", null);
mas2.add(mae);
MacroActionMessage mam2 = new MacroActionMessage("'You have logged on at ' + $datetimestamp$", "'Date Time Stamp'"); 
mas2.add(mam2); 

The above sequence is valid because $datetimestamp$ is created before the MacroActionExtract is added to the MacroActions (which are already associated with the MacroScreens because they were pulled from the MacroScreens originally). If the createVariable() method was called at the end of the sequence above, you would have an invalid sequence because the variable $datetimestamp$ would not have been available at the time that the MacroActionExtract and MacroActionMessage were added to the MacroActions and associated with the MacroScreens.

The default value of the MacroScreens method isUseVars() is false. However, if you call one of the createVariable() methods on your MacroScreens, isUseVars() will return true automatically. If you don't create any variables, but want to have your attributes scanned for variables and arithmetic anyway (e.g. you may be writing a chained child macro that has no variables of its own but is anticipating some from the parent), you must call setUseVars(true) on your MacroScreens.

Attributes that can now take variables or expressions as arguments have setAttribute(String) and either getAttributeRaw() or isAttributeRaw() methods available. If you wanted to use an expression now to represent the row attribute for a MacroActionInput, you could call setRow("$rowvar$ + 1"). Subsequently calling getRow() would return the evaluated value of this expression (an integer), whereas calling getRowRaw() would return "$rowvar$ + 1." Note that if you do the following you will get a NumberFormatException:

MacroActionInput mai = new MacroActionInput();
mai.setRow("$rowvar$ + 1");
int row = mai.getRow(); 

This is because mai has not yet been associated with any MacroScreens with isUseVars() returning true. Therefore, "$rowvar$ + 1" is being treated as a string rather than a variable plus one. Note also that if you had call the setAttribute() methods to set up variables and expressions after the object containing these attributes have been associated with the MacroScreens, you will likely experience a savings in processing time as the attributes would otherwise need to be reparsed for variables/expressions at the point when they are added to the MacroScreens.

The VariableException class is available for catching exceptions such as illegal expressions (e.g., "45 *") or illegal arithmetic operands (e.g., "'3a' * 2").

A sample program that uses programmed macros, MacroVariablesDemo.java, can be found in the Host Access Toolkit samples directory.   See the readme.txt file for instructions on how to use this sample application.


Using conditional (if-else) statements

You can use <if> and <else> elements to create conditional statements in macros. A conditional statement performs operations based on whether a certain condition (or set of conditions) evaluates to true or false.  If the condition evaluates to true, the operations within the <if> block are performed.  If it evaluates to false, they are not.  Optionally, an <else> block can be used with an <if> block to specify operations to be performed if the <if> statement evaluates to false. 

Conditional <if> - <else> statements are used in <actions> blocks and provide selection structures to control program flow.  When used in conjunction with variables, they are a powerful tool for creating sophisticated macros.

Every <if> statement specifies a condition (or set of conditions) to be evaluated at macro run-time. The entire set of conditions must resolve to a boolean value. Individual conditions are enclosed in parentheses (). You can assign boolean variables or boolean values as the conditions of an <if> element. In addition, the following equality and relational operators are supported:

== Equal to
!= Not equal to
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to
! Not

Conditions are evaluated from left to right as follows: 

For example, the following conditional evaluates to false because a string is being compared to a number:

'4.2e2' == 420 

The following conditional evaluates to true because a number is being compared to a number:

4.2e2 == 420 

The operators && (logical AND) and || (logical OR) can be used between conditions to evaluate their logical relationships.  If you are entering && through a code editor, you may need to enter it as &amp;&amp;. 

Parentheses are used to nest conditions. If you want to use an arithmetic expression with nested expressions (that is, an expression containing parentheses) as part of your condition, you must first assign that expression to a variable and use the variable instead  THe following example is invalid:

(5 + 2) * 3 == 21 

Instead, state the condition as follows:

$expression$ == 21 

where $expression$ is a variable that was updated with the value (5 + 2) * 3.

The following example shows an <if> element with a single condition:

<vars>
   <create name="$var_string$" type="string" value="'no'"/>
</vars>
<screen>
  <description>
      ...  #Screen elements
  </description> 
</screen>
<actions>
  <prompt name="'filesend'" row="1" col="1" len="10" 
          description="'Send a file? (yes/no)'"  
          clearfield="true" encrypted="false" 
          assignto=$var_string$ varupdateonly="true"/>
  <if condition="($var_string$ == 'yes')">
      <input value="'[clear]'"/>
      <xfer direction="send" pcfile="'C:\\myfile.txt'"
   	    hostfile="'myfile text a0'" />
  </if>
</actions>

The following example shows an  <if> - <else> statement with multiple conditions:

<vars>
    <create name="$condition1$" type="string"/>
    <create name="$condition2$" type="boolean" value="false"/>
    <create name="$condition3$" type="integer"/>
</vars>
<screen>
   <description>
        ... # Screen elements
   </description>
   <actions promptall="true">
        <extract name="Get condition 1" srow="2" scol="1" erow="2" 
                 ecol="80" assigntovar="$condition1$"/>
        <extract name="Get condition 2" srow="3" scol="1" erow="3" 
                 ecol="80" assigntovar="$condition2$"/>
        <extract name="Get condition 3" srow="4" scol="1" erow="4" 
                 ecol="80" assigntovar="$condition3$"/>

	<if condition="(($condition1$ !='')&&($condition2$)||($condition3$ < 100))">
             ... # Perform one set of macro actions if $condition1$ is
                 # not an empty string and $condition2$ evaluates to 
                 # "true", or if the value of $condition3$ is less 
                 # than 100
        </if>
        <else>
             ... # Perform a different set of macro actions if the 
                 # <if> element conditions are not met.
        </else>
   </actions>
</screen>

Converting Numbers to and from the Local National Language Format

Different NLS locales represent numbers in different ways.  For example, a decimal number such as 1234.56 can be represented as 1,234.56, 1234.56, or 1234,56 depending on where you are located.  Similarly, depending on the locale, negative numbers can be indicated with a minus sign either before or after the number (for example, -78 or 78-).

To enable macros to make use of numbers in local formats, Host On-Demand supplies two conversion methods:

The local format is determined by checking the NLS locale of the current Host On-Demand session.  The <HAScript> usevars attribute must be set to "true" to use these conversion methods.   Conversion methods can be nested.

These conversion methods can be used as the values of macro attributes in the same way as variables.  As their parameters, they can take numeric values, strings, or variable expressions that evaluate to a numeric value or string.  Parentheses are reserved.  To specify an argument string containing one of these characters (for example, an arithmetic expression), assign the argument string to a variable first, then use the variable as the argument.

In the following example, the value 3.24 is converted to its local equivalent (for example, 3,24) when it is sent to the screen:

<input value="$FormatNumberToString(3.24)$" row="1" col="1" 
       movecursor="true" xlatehostkeys="false" />

In the following example, the FormatStringToNumber method is used as a parameter of the FormatNumberToString method, converting the number $num$ from its local NLS format before performing the arithmetic operation:

$FormatNumberToString(1000 * $FormatStringToNumber($num$)$)$

In the following example, a user is extracting a negative integer value such as 3- from the screen. To find out whether the extracted value is really a negative number, it must first be converted to the standard representation of  -3 by using the FormatStringToNumber method.  The variable $value$ is a string variable that holds whatever is extracted from the screen.

<extract name="'Extract'" planetype="TEXT_PLANE" srow="1" scol="1" 
         erow="-1" ecol="-1" unwrap="false" assigntovar="$value$" />
 
<if condition="($FormatStringToNumber($value$)$ < 0)"> 
              #converting 3- to -3 and comparing its value

         ...  #Perform macro actions
</if>

Using Special Characters in Macros

Certain characters in Host On-Demand macros have special functions depending on whether variables are in use.  To use these characters in a macro, you must enter them in a specific format in the macro code.  This section describes the different ways in which, depending on the situation, various special (or reserved) characters are specified in macros.

If variables are in use

If variables are in use in the macro (that is, if the <HAScript> element's usevars attribute is set to "true"), special characters are used in a macro as follows:

If variables are not in use

If variables are not in use (that is, if the <HAScript> element's usevars attribute is not set to "true"), special characters are treated as follows:


[ Top of Page | Previous Page | Next Page | Table of Contents ]