[Vigilance on Talos V: Now Shipping!]

the REXX Files- by Dr. Dirk Terrell


Last month we looked at a REXX program that would scan a text file and replace all occurrences of a string with the contents of a file. Such a program is useful as a preprocessor for things like HTML files and programming source code. This month, let's look at another utility I wrote a while back that is somewhat similar and perhaps even more useful: replall, a program to replace all occurrences of one string with another in a list of files.

In the REXX spirit of not recreating something that already does a job perfectly well, my program makes use of a handy REXX program called RxMulch written by Rony G. Flatscher. RxMulch is a REXX program that can count the number of occurrences of a particular string in a file , as well as replace all occurrences of one string with another within a file. RxMulch is an extremely useful tool, and is also very easy to use. You can call it as a stand-alone program or as a function within another REXX program, and can specify parameters either on the command line or in a control file.

To use RxMulch as a standalone program with a control file, the calling form is:

RxMulch input_file output_file control_file

To enter parameters on the command line, use the form:

RxMulch input_file output_file /switch

where /switch is one of several program switches for performing different functions. Rather than describe all possible switches here, I will cover only the switches that will be used for the purposes of the program we are building. The RxMulch documentation covers all the different switches and gives plenty of examples for performing various functions.

As an example of command line switches, let's create a program called lines that simply counts the number of lines in a text file. On an OS/2 system, lines of text files are terminated by carriage return (ASCII 13) and linefeed (ASCII 10) pairs. So, all we have to do is call RxMulch and ask it to count the number of CR-LF pairs. The switch we need is the /F (or Find) switch which finds and, optionally, replaces strings. This switch has the follow format:

/Fsearch_string/replace_string

where the two strings are delimited by a character that you specify right after the /F. Let's use a period (".") as the delimiter. Our call to RxMulch will then be:

RxMulch input_file /F.@c@l

Since we are only counting the occurrences of the CR-LF pairs, we have no replacement string and we don't specify any output file for the same reason. But what is the story behind these @ symbols? RxMulch treats the @ symbol as an indicator for special characters, like those that are normally unprintable, such as carriage returns, linefeeds, and tabs. @c represents the carriage return character and @l represents the linefeed character.

Rather than having to type the above line every time, put it in a command file called lines.cmd with the first (and only) line being;

RxMulch %1 /F.@c@l

(The %1 tells the command file to take the first parameter that the user enters on the command line and replace the %1 with it.) So, if you call the program like this:

lines c:\config.sys

if will count the number of lines in your CONFIG.SYS file.

Now let's create our program that will replace all occurrences of a string within a set of files that we specify on the command line. One common situation where you need this comes about when you need to change an e-mail address or URL in a large number of HTML files. For example, your e-mail address changes and you realize that you have placed it at the bottom of all 5,000 HTML files on your web site. Obviously you don't want to have to update them by hand!

RxMulch already provides what we need to replace a string in one file with another string. But we surely don't want to run RxMulch 5,000 times manually, either. Here we call on some REXX functions in the REXXUTIL library that we looked at not too long ago.

As usual, we need to register the REXXUTIL library:

/* Register REXXUTIL functions */
call rxfuncadd 'SysLoadFuncs','RexxUtil','SysLoadFuncs'
call sysloadfuncs
Next, process the command line. Let's make the calling form:
replall filespec separator target(separator)replacement
where filespec specifies the files we want to process, such as *.html, separator is the character that will separate the target string from the replacement string in the rest of the command line, and target and replacement are the target and replacement strings. The code to parse the input (with a little error checking) is:
/* Parse the command line */
Parse Arg FileSpec Separator Rest
If Length(Separator)<>1 then do
   Say 
   Say "Argument 2 must be the separator character."
   Exit
end  /* Do */
Parse Var Rest Target (Separator) Replace
Notice the last line. Why is the variable Separator enclosed in parentheses? Enclosing a variable in parentheses in a PARSE instruction tells REXX to parse on the value of the variable, which in this case is the separator character. This enables us to split the target and replacement strings where the separator character occurs.

One thing we have to watch out for is the @ character because it has special meaning to RxMulch. So, what we do when we want an actual @ character in one or both of our strings, is to make sure that is it passed as the special character for that symbol. The RxMulch character is @@ (The first indicates that it is a special character, and the second indicating that we want the 'at symbol'. Compare this with the @c and @l characters above.) To accomplish this, we call RxMulch as a function within our REXX program, and replace all @ characters with @@ thusly:

/* Escape the "@" character properly because it is the special character in RxMulch */
Target=RxMulch(Target,"/C.@@.@@@@.")
Replace=RxMulch(Replace,"/C.@@.@@@@.")
Now we are ready to get the list of files to process. Use the SysFileTree function in the REXXUTIL library:
/* Get the list of files */
rc=SysFileTree(FileSpec,"File.","OF")
We're almost done. The final step is to loop over all the files, and call RxMulch for each one. When altering files like this, it is usually a good idea to make backup copies of the files. The loop that does all of this is:
/* Now loop over the files and process them */
Do i=1 to File.0
   Say "Processing file" i "of" File.0 " " File.i
   BackupFile.i=File.i||".bak"
   "@copy" File.i BackupFile.i "1>nul"
   If rc=0 then 
      rc=SysFileDelete(File.i)
   Else Do
      Say "Could not back up" File.i "exiting..."
      Exit
   end  /* Do */
   Call RxMulch BackupFile.i File.i "/C"||Separator||Target||Separator||Replace||Separator
   rc=Stream(File.i,"C","Query Size")
   If rc="" then
      "@copy" BackupFile.i File.i "1>nul"
end /* do */
Exit
And that's it! replall will perform the replacement on all files in the current directory that match the file specification that you give. For example, let's say I have a bunch of HTML files with an old e-mail address, dirk@old.email.net, that I want to change to a new one, terrell@new.email.net. If the HTML files all end in ".HTML", the call to replall would be:
replall *.html $ dirk@old.email.net $ terrell@new.email.net
and all occurrences of the old e-mail address in any file ending in ".HTML" would be replaced by the new e-mail address.

But what if you want to change the files not only in the current directory, but in all subdirectories below the current one? You can make a one byte change in the above program that will do it. Can you see how? Next month I'll give the answer.

The sample code (ZIP, 2k) contains replall.cmd as well as restbak.cmd which will restore the files from the backup copies made by replall -- handy if you find that you typed the wrong replacement or target string. You will, of course, also need RxMulch.


Dr. Dirk Terrell is an astronomer at the University of Florida specializing in interacting binary stars. His hobbies include cave diving, martial arts, painting and writing OS/2 software such as HTML Wizard.

[Index]  [® Previous] - [Feedback] - [Next ¯]

[Our Sponsor: J3 Computer Technologies - Serving the Global OS/2 Community, large & small!]


This page is maintained by Falcon Networking. We welcome your suggestions.

Copyright © 1997 - Falcon Networking