TutorCat

Chapter 13


Macros That Make Decisions:
Using the If Command

In this chapter:

A common theme in old science fiction movies was a mad scientist creating a mechanical creature, then endowing it with intelligence. In most of these stories, the creature ended up taking revenge on its creator -- apparently robots aren't happy when they are forced to think.


The If macro command gives you a chance to play the mad scientist. Instead of creating smart robots, you use the If command to create smart macros. I have not yet seen a "smart macro" turn against its creator, but if yours does, I refer you to the disclaimer at the beginning of the book. What you do with your macros is completely up to you!


The Anatomy of the If Command

The notion of killer macros aside, the If command is most commonly used as decision-makers, based on some kind of condition. That condition can be internal -- the macro detects that the file hasn't been saved yet, for example -- or it can be external: the user responds to a prompt, and the macro reacts accordingly.

The If command is composed of three general parts:

These three parts, taken together, form an If structure. The structure begins with an If command, and ends with an EndIf command. Every If command must have an associated EndIf command.

Note
Not all If statements must contain all three parts described above. If structures can be built using only two of the three. The expression must always be included. The structure can also contain the Condition=True part, and/or the Condition=False part. More on this in the next section.

Here's a working example of an If structure. Notice the expression after the If command. This expression is evaluated to be true or false, depending on the particular conditions when the macro is run.

If (?Name="")
	MessageBox (;; "Please save and name this file.")
Else
	FileSave ()
EndIf


This macro determines if the document has ever been saved, using the ?Name system variable. If the ?Name system variable returns a blank, the document has no name, and therefore has never been saved. This is the expression (the "test") that the If command evaluates.

In plain English, this expression reads "If the result of ?Name system variable is equal to a blank string." The "equal to" part comes from the = character used in the If expression. The = character is known as an operator. WordPerfect understands a number of operators used in If expressions; the = operator is the most commonly used.

The MessageBox command specifies what happens if the expression is true -- that is, the document has no name. The MessageBox command displays a message box with a prompt, telling the user to save and name the file.


The FileSave command specifies what happens if the expression is false -- that is, the document has a name. Should the document already have a name, the macro saves the document (using the same name) with the FileSave command.


Notice the Else command, which sits between the MessageBox and FileSave commands. Else indicates that the command(s) that follow are to be performed should the If expression be false. All of the commands between the Else and the EndIf are carried out if the expression is false.


Commands for True Or False, But Not Both

In the previous example, the macro performed one step if the If expression was true, and another step if the If expression was false. Not all If structures include commands for both true and false conditions. Some If structures provide commands for either true or false, but not both. It all depends on what your macro is supposed to do if a condition is met, or is not met.

Suppose you want your macro to display a message only if a condition is true. The If structure for this technique contains an If and EndIf command, but no Else command. The Else command is omitted because there's nothing to do if the condition is false. The following example types a line of text if the contents of the Name variable is "George." If the name variable does not contain "George," WordPerfect skips over the Type command command, and no text is inserted into the document.

If (Name="George")
	Type ("Hello, George")
EndIf


You use a similar approach if you're only want something to happen should the If condition be false. One way to do it:

If (Name="George")
Else
	Type ("Your name is not George")
EndIf


This macro tests if the Name variable contains the text "George." If it does, the If condition is true, and nothing happens, because there are no commands between the If command, and the Else command. If the Name variable contains some other text, the If condition is false, and the macro types "Your name is not George.")

You can also use a technique called "negative logic." Since you're only interested in whether or not the If condition is false, you can "negate" the If expression -- turning a false into a true, and therefore saving yourself some steps. This is easier shown than explained:

If (Name<>"George")
	Type ("Your name is not George")
EndIf

The <> operator used above stands for "not equal to." The <> operator is therefore is the inverse, logically speaking, of the = operator. Because you are testing whether the Name variable does not contain the name "George," the Type command is carried out should the condition be true. The Else command is not used.

Note
Watch out for negative logic. It can be confusing, and is a potential source for macro errors. Use this technique only when you become proficient at writing WordPerfect macros.

Getting to Know Operators

The key of the If command is the expression. This is the part that appears in parenthesis and is placed right after the If command. As mentioned earlier, If expressions must result in either one or two things: true or false. The true or false result is determined using expressions that contain "logical" or "relational" operators. The most common relational operator is the = (equals) sign. Another widely used relational operator is <> (not equals).

WordPerfect supports a number of relational operators, as shown below. The v1 and v2 represent values. These values can be contained in variables, or they can be included as part of the macro. In previous examples, for instance, we've tested if the Name variable contains the text "George." Applying that to v1 and v2, the Name variable would be represented by v1, and "George" would be represented by v2.


Operator Function
v1 = v2 Test that v1 and v2 are equal.
v1 <> v2 Test that v1 and v2 are not equal.
v1 > v2 Test that v1 is greater than v2.
v1 >= v2 Test that v1 is greater than or equal to v2.
v1 < v2 Test that v1 is less than v2.
v1 <= v2 Test that v1 is less than or equal to v2.
NOT value Evaluates the logical NOT of value. The logical NOT is the inverse of an expression: True becomes False, and vice versa.
v1 AND v2 Evaluates the logical AND of v1 and v2.
v1 OR v2 Evaluates the logical OR of v1 and v2.

The last three operators are reserved for special circumstances. You won't use them much. But they are provided by WordPerfect so that you can create very complex If expressions. For example, you can use the AND operator to test if two complete conditions are met. You'll see an example of this later in this chapter.

Note
It's a good idea to learn about relational operators, because they're used with more than just the If command. You also use them in Repeat/Until and While/EndWhile loops, for instance, allowing you to build macros that repeat steps until a certain condition is met/not met.

Examples of relational operators, as used in If expressions:

If Expression What it Means
If (Name="Fred") Is Name variable equal to Fred?
If (Name<>"Fred") Is Name variable not equal to Fred?
If (Amount>500) Is Amount variable greater than 500?
If (Amount>=500) Is Amount variable greater than or equal to 500?
If (Amount<500) Is Amount variable less than 500?
If (Amount<=500) Is Amount variable less than or equal to 500?
If (NOT (Name="Fred")) Is Name variable not equal to Fred? (Use <> instead)
If ((Name="Fred") AND (Amount=500)) If Name variable equal to Fred and Amount variable equal to 500
If ((Name="Fred") OR (Amount=500)) If Name variable equal to Fred or Amount variable equal to 500


Real World If: The TWOKEY.WCM Macro

The TWOKEY.WCM macro, which follows, is a good example of the If command in action. The macro uses the If command to test if a given macro file exists. If the macro exists, it is played. If it does not exist, a message box -- indicating that the file can't be found -- appears instead. This example also shows how to use the Char command to display a dialog box that prompts for a single key response. A sample dialog box using the Char command (line 3 of the macro) is shown in Figure 13.1.

TWOKEY.WCM

1. Mainkey="A"
2. Application (WordPerfect; "WordPerfect"; Default!; "EN")
3. Char (Subkey; "Press a key")
4. MacroStatusPrompt (On!; "Press a key")
5. MacroName=ToUpper (?PathMacros + MainKey + Ntoc (Subkey) + ".wcm")
6. FileExists (FE;MacroName)
7. If (FE=True)
8. 		Chain (MacroName)
9. Else
10. 		MessageBox (Ret;"Two-Key Macro";"Macro '" + MacroName + "' not
11. 		found.";IconStop!)
12. EndIf

The idea behind the TWOKEY.WCM macro is giving you more keyboard macro shortcuts. Assign the TWOKEY.WCM macro to some unused Ctrl+key or Ctrl+Shift+key combination (see Chapter 2 for a list of available Ctrl+key combos). Macros are named AA.WCM, AB.WCM, AC.WCM, etc. When you play the macro, you press another key, and the associated macro is played. For example, play the TWOKEY.WCM macro, then press the G key. The AG.WCM macro is run for you.

By copying the TWOKEY.WCM macro and changing line 1 to another "prefix" character, you can access even more macros. For instance, change the prefix character to B (Mainkey="B"), and you play macros named BA.WCM, BB.WCM, BC.WCM, and so forth.

The all-important If structure is located on lines 7 through 12. This structure determines if a given macro exists. If it does, the macro is played, using the Chain command on line 8. If the it does not, the message in lines 10 and 11 is displayed instead.

The If Expression on line 7 contains the expression FE=True. FE is the name of a variable, obtained with the FileExists command, on the preceeding line. The FileExists command returns a logical (also called "Boolean") value of true or false, depending on whether the file exists. Therefore, the FE variable contains either True or False.

Note
In WordPerfect, True and False are unique values, and are not variables, although they look like they might be. I capitalize them to show they have special meaning.

Nesting If's

By far, most macros will contain simple, straight-forward If structures. There's the If command, with the expression enclosed in parentheses. Somewhere along the line there's the optional Else command, followed eventually by the EndIf command.

WordPerfect also allows you to "nest" If structures to do more and more complex decision-making. Nesting allows you to test for one condition, then another, possibly another, and so forth. If all the conditions are met -- bingo! -- the macro performs some action.

It's not uncommon to nest two If structures, in order to test for two different things. Here's an example:

If (ZipCode="99999")
	If (AreaCode="111")
		Type ("You're a winner!")
	EndIf
EndIf

Two If structures are used here. Indenting is used to show the layout of the macro. The stuff inside the first If structure is indenting one tab; the stuff inside the second If structure is indented two tabs. Only if both the ZipCode variable contains "99999" and the AreaCode variable contains "111" does the macro insert the text, "You're a winner!" If either one of these conditions is not met, nothing is typed. You can more easily see the relationship of the two If structures with the following macro. This macro is called IFTESTA.WCM.

IFTESTA.WCM

1. GetString (Val1; "Enter val 1")
2. GetString (Val2; "Enter val 2")
3. If (Val1=1)
4. 		MessageBox (;; "Val1 equals 1")
5. 		If (Val2=1)
6. 			MessageBox (;; "Val2 equals 1")
7. 		Else
8. 			MessageBox (;; "Val2 does not equal 1")
9. 		EndIf
10. Else
11. 		MessageBox (;; "Val1 does not equal 1")
12. EndIf


Play this macro and try the following values in response to the GetString messages:


Val1 Val2 Results
1 1 "Val1 equals 1"; "Val2 equals 1"
1 o "Val1 equals 1"; "Val2 does not equal 1"
0 1 "Val1 does not equal 1"

Notice that when the first If expression is false, the entire second If structure is skipped! This is an important facet of nested If structures. The If expressions that are nested (inside) another structure may or may not be executed, depending on the outcome of the first If expression.


Testing More than One Condition

Most of the time, you're only interested if both If expressions are true. For example, if both Val1 and Val2 are 1, your macro does one thing. But if either Val1 or Val2 is not 1, then your macro does another thing. Nested If structures, like that shown in the previous example, is one approach.

Another, and often better, approach is to combine two or more conditions in the same If expression. You use one If structure. Here's an example, which is functionally similar (but not identical) to the IFTESTA.WCM macro described above. Depending on your application, this approach may be preferable:

IFTESTB.WCM

1. GetString (Val1; "Enter val 1")
2. GetString (Val2; "Enter val 2")
3. If ((Val1=1) And (Val2=1))
4. 		MessageBox (;; "Both Val1 and Val2 equals 1")
5. Else
6. 		MessageBox (;; "Val1 or Val2 does not equal 1")
7. EndIf


Notice line 3. Here, the If expression is composed of two parts:

Both parts are enclosed in additional parentheses (see the double parentheses at the start and end of the If expression). Here's how this macro works:

Val1 Val2 Results
1 1 "Both Val1 and Val2 equals 1"
1 0 "Val1 or Val2 does not equal 1"
0 1 "Val1 or Val2 does not equal 1"
0 0 "Val1 or Val2 does not equal 1"

Notice that the "Both Val1 and Val2 equals 1" message appears only if both Val1 and Val2 are equal to 1. The macro accomplishes this using the And logical operator between the two If conditions.

A practical example of combining two conditions in one If expression is the following macro, which determines if the insertion point is at the end of the document. It works by testing the values of both the ?RightCode and ?RightChar system variables. If ?RightCode is 0, and ?RightChar is blank, the insertion point must be at the end of the document. Again, notice the double parentheses used in the If statement.

If ((?RightCode=0) And (?RightChar=""))
	MessageBox (;; "At end of document")
Else
	MessageBox (;; "Not at end of document")
EndIf


Instead of the And logical operator, you can use Or. The Or operator lets you test if either condition is met. If either condition is true, then the entire If statement is true.

ORTEST.WCM

1. GetString (Val1; "Enter val 1")
2. GetString (Val2; "Enter val 2")
3. If ((Val1=1) Or (Val2=1))
4. 		MessageBox (;; "Val1 and/or Val2 equals 1")
5. Else
6. 		MessageBox (;; "Both Val1 and Val2 does not equal 1")
7. EndIf

In this example you can see how the Or operator acts as the logical complement of the And operator. That is, only if both Val1 and Val2 are not 1 is the If statement false.


Val1 Val2 Results
1   "Val1 and/or Val2 equals 1"
1 0 "Val1 and/or Val2 equals 1"
0 1 "Val1 and/or Val2 equals 1"
0 0 "Both Val1 and Val2 does not equal 1"

Combining If conditions with Or has fewer applications in WordPerfect macros, but it can come in handy once in a while. For example, the following prints the current day in the format "Today is the 6th," or "Today is the 1st." The macro tests which day it is, using the ?DateDay system variable. It first starts by assigning a default value ("th") to the Day variable. It then performs a series of three separate If tests; all of the tests contain at least two conditions.

DATEORD.WCM

1. Application (WordPerfect; "WordPerfect"; Default!; "EN")
2. Day="th"
3. If ((?DateDay=1) Or (?DateDay=21) Or (?DateDay=31))
4. 		Day="st"
5. EndIf
6. If ((?DateDay=2) Or (?DateDay=22))
7. 		Day="nd"
8. EndIf
9. If ((?DateDay=3) Or (?DateDay=23))
10. 		Day="rd"
11. EndIf
12. Type ("Today is the " + ?DateDay+Day)

Self-Test Quiz

Quiz for Chapter 13. See Appendix B for answers to this quiz.


1. Which of the following is not part of an If expression:

A. The If expression part that states the condition.

B. A Switch statement

C. The Condition=True part contains the command(s) to be carried out if the condition is true.

D. The Condition=False part contains the command(s) to be carried out if the condition is false.

2. Which of the following will insert the word "Correct" into the document, assuming the Age variable contains the value 15:

A. If (Age <> 15)

B. If (Age < 15)

C. If (Age = 15)

D. None of the above

3. Which of the following operators means "not equal" (circle all that apply):

A. =

B. !=

C. <>

D. <=

4. True or false: the following macro example will run (chain) a macro only if the macro specified in the MacroName variable exists.

	FileExists (FE;MacroName)
	If (FE=True)
		Chain (MacroName)
	EndIf

5. The following macro example means:

	If (ZipCode="99999")
		If (AreaCode="111")
		Type ("You're a winner!")
		EndIf
	EndIf

A. If AreaCode is 111 AND ZipCode is 99999 insert "You're a winner!"

B. If AreaCode is 111 OR ZipCode is 99999 insert "You're a winner!"

C. If neither AreaCode nor ZipCode is 99999 insert "You're a winner!"

D. None of the above.

6. Another way to express the multiple If tests in question 5 is (be careful!):

A. If ((ZipCode="99999") Or (If (AreaCode="111"))

B. If ((ZipCode="99999") = (AreaCode="111"))

C. If ((ZipCode="99999") And (AreaCode="111"))

D. If ((ZipCode="99999") Or (AreaCode="111"))

-
Back