If-Then Code

By: Mike Kimball - Revised: 2006-06-28 devin


RevRdist's built-in code for if-then expressions is fairly simple, though it has specific variable requirements, and of course a particular syntax. I'll start with the structure and then provide examples of how it can be used for things like IP address conditions, dealing with apps that use license or user ID files, or other custom configurations.

How It Works

Variables: Some variables are set by RevRdist, others are available to use in expressions.
  • H - Mac's IP address as a 32-bit integer (can be expressed as a signed decimal number or in a formula explained below).
  • S0 - Name of the RR Helper Extension if present; otherwise, the name of the RevRdist Prefs file.
  • S1 - The name of the startup disk volume.
  • S2 - Model name of the computer.
  • S3 - S9, SA - SF - Available to use (undefined until set by an expression). Can be reused throughout the distfile, their values reassigned through subsequent "set" expressions.
  • T0 - A numeric value that essentially lists the numeric digits that appear in S0.
  • T2 - Numeric index assigned to the Mac by the Gestalt('mach') function. Equivalent to S2 variable but more specific.
  • T3 - T9, TA - TF - Available to use (undefined until set by an expression).

    Other variables, expressions, and arithmetic operators are defined and described in greater detail in the RevRdist Administrator's Guide.
Syntax: As with any programming technique using variables, you have a variable declaration, then you call it.
  • The declaration looks like a comment since its line begins with the "#" symbol:
# {if S9 contains "loner" then set S8 "Ad" else set S8 "A." endif}

  • Calling the variable is then accomplished like so:
>  Lightwave 6.5       :{S8} =RevRdist Monkey:Special Items:Applications:Lightwave 6.5:Applications:Lightwave 6.5
<  Lightwave 6.5       :{S8}

Remember that the variable declaration must precede the section of code that calls it, or the variable will be "undefined" and RevRdist won't run. This also means that the first line of any set of declarations must always contain an "else" definition, even one that doesn't point to a file or folder or group that exists (unless you want to use undefined variables as a way to catch machines with incorrect IP addresses, for example...). I'll explain this in examples below. One other thing, when reusing temporary variables, keep the declarations close to the calls, otherwise you may end up with conflicting instructions (a common mistake in coding).
Refer to your RevRdist Documentation (download here) for more details. Read on for examples of how variables can be used...

IP Address

# ---------------------------------------------------------------------------
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 141 then set S9 "loner" else set S9 "lab" endif}
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 122 then set S9 "instructor" endif}
# ---------------------------------------------------------------------------

In this example, we are using the H variable along with a formula for determining the IP address. We use this instead of the signed decimal notation so that we can actually see the address (somewhat) plainly, as above where we have, and The S9 variable is used to identify the machine; it mainly gets called in the many if-then expressions as a condition of setting other variables (such as S7 and S8, which we use for file names and action lists, respectively).

This is a typical set of IP declarations for one of our labs, appearing in the top section of the distfile with its identifying comments. Basically we have a room with 21 machines in it, and only two of them are different from the rest. The one we designate as "instructor" has some special appearance and networking configurations, and the one we designate as "loner" is the one machine in the room that doesn't have a Lightwave dongle. We designate the else condition "lab" even though our code never specifically asks if S9 contains "lab" - this is so that the variable won't be undefined when it gets called by machines that don't fit the "loner" or "instructor" condition.

Desktop Customization

# {if S9 contains "instructor" then set S7 "Instructor" else set S7 "1024 x 156" endif}
>  Desktop Folder                        :A.Hs =RevRdist Monkey:Special Items:Desktop Folders:{S7}
<  Desktop Folder                        :A.

>     Appearance                         :A.
>       Desktop Pictures                 :A.
# {if S9 contains "instructor" then set S8 "A." else set S8 "Ad" endif}
|          ACLISDsktopPicInst.jpg        :{S8} =RevRdist Monkey:Special Items:Desktop Pictures:ACLIS Desktop Pic:System Folder:Appearance:Desktop Pictures:ACLISDsktopPicInst.jpg
<       Desktop Pictures                 :A.
<     Appearance                         :A.

# {if S9 contains "instructor" then set S7 "Desktop Pictures Prefs Inst" else set S7 "Desktop Pictures Prefs" endif}
# {if S9 contains "instructor" then set S8 "A." else set S8 "Ad" endif}
|        Desktop Pictures Prefs          :A. =RevRdist Monkey:Special Items:Desktop Pictures:ACLIS Desktop Pic:System Folder:Preferences:{S7}
|        Display Preferences             :{S8} =RevRdist Monkey:Special Items:Display Preferences:System Folder:Preferences:Display Prefs (ML G4 192 9)

Here's a simple example of how the S7, S8, and S9 variables can be used. We customize the appearance of the desktop by putting specific items there, and also by changing the desktop picture. The sections of code that accomplish this are listed above (assuming the Desktop Folder section is within Root, the Appearance section is within System Folder, and the Prefs are within System Folder:Preferences).

Apps with License or ID files (e.g., Lightwave 6.5, Final Cut Pro 2.x)

With Lightwave 6.5 and Final Cut Pro 2.x, there are files that enforce licensing of the software (and with Final Cut Pro 2.x, these files are unique to each particular machine). Luckily, you can copy them to a server and distribute them with RevRdist, without breaking them. I even set the License.key file so it is read-only (you can do this in ResEdit by changing the file type from "TEXT" to "ttro"), since they are SimpleText files. This further prevents tampering.

Doing it this way is a better option than using "Ai" as the action list - it is more robust than trusting users not to delete the file, and more convenient than having to reconfigure the file by hand (typing the lengthy serial number manually on each machine, or using the FCP installer CD again...)

# Applications for Lightwave 6.5
# {if S9 contains "loner" then set S8 "Ad" else set S8 "A." endif}
>    Lightwave 6.5                       :{S8} =RevRdist Monkey:Special Items:Applications:Lightwave 6.5:Applications:Lightwave 6.5
>      Programs                          :A.
|        License.key                     :{S8} =RevRdist Monkey:Special Items:Applications:Lightwave 6.5:License Keys:License.key (all)
<      Programs                          :A.
<    Lightwave 6.5                       :{S8}

Above is our latest Lightwave code. We recently were made aware that you don't have to have a separate License.key file for each machine - you can merely put all of the license numbers into a single file (each with a hard return, one number per line). The if-then code merely says that the one machine ("loner") that has no Lightwave dongle, does not get the software.

As for Final Cut Pro, here below is one example:

# Preferences for Final Cut Pro 2.0.2
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 117 then set S7 "Final Cut Pro User ID - MMac-96" endif}
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 118 then set S7 "Final Cut Pro User ID - MMac-97" endif}
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 119 then set S7 "Final Cut Pro User ID - MMac-98" endif}
>        Final Cut Pro Data              :A. =RevRdist Monkey:Special Items:Applications:Final Cut Pro 2.0.2:System Folder:Preferences:Final Cut Pro Data
|           Final Cut Pro User ID        :A. =RevRdist Monkey:Special Items:Applications:Final Cut Pro 2.0.2:System Folder:Preferences:FCP user ID:{S7}
<        Final Cut Pro Data              :A.

(I know I'm a bad boy and didn't add an else statement above - it's because this code is used on only three machines, so if RevRdist fails to run because a variable is undefined, then I know something is wrong...)

Staggering RevRdist Run Times

Our Marriott Library building has over 170 machines running RevRdist from a single RevRdist server. Obviously, it's smart to stagger their run times so there isn't a singular and excessive load on the server or the network. In general we can simply code different groups' distfiles with different run times, but we currently have over 60 machines of the same type in one part of our lab. So, we had to split the 60 machines into two groups, using code in the distfile to distribute different run times to two groups we designate. In addition, one of the machines in this is also a Scanner, so that is part of the declaration. The code for this appears below:

# ---------------------------------------------------------------------------
# {if (H >= (((128 * 256) + 110) * 256 + 27) * 256 + 22) & (H <= (((128 * 256) + 110) * 256 + 27) * 256 + 54) then set S9 "Group 1" else set S9 "Group 2" endif}
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 28 then set S9 "Scanner Group 1" endif}
# ---------------------------------------------------------------------------

# Preferences for Cron
# {if S9 contains "Group 1" then set S7 "31-39 3" else set S7 "31-39 4" endif}
>        Cron Preferences                :A. =RevRdist Monkey:Special Items:Cron Preferences:{S7} * * *:System Folder:Preferences:Cron Preferences
|           {S7} * * *                   :A. =RevRdist Monkey:Special Items:Scripts:Run RevRdist
|           RevRdist Prefs               :A. =RevRdist Monkey:Special Items:RevRdist Prefs:System Folder:RevRdist Prefs MA G4/466 9.2.1
<        Cron Preferences                :A.
|        Energy Saver Preferences        :A. =RevRdist Monkey:Special Items:Cron Preferences:{S7} * * *:System Folder:Preferences:Energy Saver Preferences
|        Power Mgt Preferences           :A. =RevRdist Monkey:Special Items:Cron Preferences:{S7} * * *:System Folder:Preferences:Power Mgt Preferences

The first section is the IP designations - we have specified a range of IP's that belong to "Group 1", with "Group 2" as the else designation. Note that the Scanner machine also contains "Group 1". The second section has to do with Cron, the app we use to trigger our RevRdist run times. Group 1 runs at 3:31am, Group 2 runs at 4:31am.

Differing Video Cards

# Video Drivers for Rage 128 card
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 87 then set S8 "A." else set S8 "Ad" endif}
|         ATI 3D Accelerator             :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI 3D Accelerator
|         ATI Driver Update              :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI Driver Update
|         ATI Graphics Accelerator       :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI Graphics Accelerator
|         ATI MPP Manager                :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI MPP Manager
|         ATI Radeon 3D Accelerator      :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI Radeon 3D Accelerator
|         ATI Rage 128 3D Accelerator    :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI Rage 128 3D Accelerator
|         ATI Resource Manager           :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI Resource Manager
|         ATI Video Accelerator          :{S8} =RevRdist Monkey:Special Items:OpenGL 1.2.2:System Folder:Extensions:ATI Video Accelerator
# {if H = (((128 * 256) + 110) * 256 + 27) * 256 + 87 then set S8 "Ad" else set S8 "A." endif}
|         NVIDIA 2D Acceleration         :{S8}
|         NVIDIA Driver                  :{S8}
|         NVIDIA DVD Accelerator         :{S8}
|         NVIDIA Engine                  :{S8}
|         NVIDIA OpenGL                  :{S8}
|         NVIDIA Video Accelerator       :{S8}

One machine in our main MMC lab is a G4/466, but an earlier model before they came with nVIDIA cards. So, it uses the same image as the other G4/466's, but the nVIDIA drivers would be inappropriate for a machine with a Rage 128 card (the drivers work but they are slow ;) So, on this machine, it copies the ATI drivers from Special Items, and doesn't copy the nVIDIA drivers.