Potpourri of REXX items

From EDM2
Jump to: navigation, search

By Richard K. Goran

This month I searched back through my E-mail for topics that people have asked me to provide information about. Therefore, this column covers many topics.

Finding files

There are a couple of methods that you can use in REXX to locate files. The simplest, and most common, is the STREAM() function. The STREAM() function with a second parameter of 'C' and a third parameter of 'QUERY EXISTS' will return the full file system name of the file named in the first parameter. Using a third parameter of 'QUERY SIZE' will return the file size of the named file. In both cases a null string is returned in the file does not exist in the current directory.

However, if the file you are looking for files that have their hidden or system attribute set, STREAM() will not see them. The SysFileTree() function in REXXUTIL must be used. SysFileTree() will build a stem, or compound, variable containing all of the files in the current directory, and optionally any subdirectories. Tail .0 of the stem will contain the number of entries that the function assigned to the stem variable including 0 if no file information was returned. SysFileTree() is quite flexible in the information it puts into the stem variable for each file. By default, five fields are returned for each file:

  1. the file's date in the format: mm/dd/yy;
  2. the file's time in the format: hh:mm followed by a lowercase a or p for AM or PM;
  3. the file's size in bytes;
  4. a five-character field containing a list of the file's attributes; and
  5. the full file system name.

Since the year is returned as a 2-digit value, you should begin giving consideration to the year 2,000. The technique I use when using the date returned by the function is if the 2-digit year is less than 80, I prefix the 2-digit year with 20 otherwise I prefix the 2-digit year with 19. The field containing the file's attributes is a positional string with each position respectively representing the attributes: archive, directory, hidden, read-only, and system. An example of simple technique to check for a specific file with SysFileTree() rather than STREAM() would be:

call SysFileTree file_name, 'stem'
if stem.0 = 1 then say file_name 'exists'
else say file_name 'does not exist'

Next you probably want to parse, or separate, the fields return in the stem element. The safest way to handle this, so that you don't have to concern yourself with FAT vs. HPFS file names, is the following:

parse value stem.1 with,
  file_date,
  file_time,
  file_size,
  file_attributes,
  file_path_and_name
  file_path_and_name = STRIP( file_path_and_name )

Any of the attributes that are set for the file are represented by the first letter of the attribute appearing in its defined position in the string in uppercase. There are numerous ways that you can test the attribute list for a specific value or values, so typical of REXX. The SUBSTR() built-in function allows you to explicitly reference a specific position or positions within the field. The POS() built-in function allows you to test for a specific character in the attribute list. The often overlooked VERIFY() built-in function allows you to test for one or more attributes being present. The following example will test for the presence of the system and/or read-only attributes being present:

if VERIFY( file_attribute, 'RS' ) > 0 then ...

Numeric vs. Character Strings

REXX treats all data as character strings unless that data is used in an arithmetic operation. For example a = 0001 followed by say a will display the original string of 0001. However, say a + 0 will show a string of 1 without the leading zeroes. If you have to pass a fixed length string containing numeric characters to a subroutine or a function, the RIGHT() built-in function will serve your purpose. By adding a third parameter of '0' to the RIGHT() function, the resulting value will be padded on the left with leading zeroes. If you want to be sure that a string containing numeric characters is passed to the subroutine intact, enclose the string in quotes and pass the string as a non-numeric literal ('0001').

In a related area, comparison of numeric strings must sometimes be given special consideration. Given the following two assignments:

a = 0001
b = 01

a comparison of if a = b will yield a 1 (true) whereas if a == b will yield a 0 (false).

Disk Volume Labels

Most of us have never given much thought to the volume labels on our disk drives. However, with the popularity of Warp Connect and more systems becoming connected drive, volume labels can reduce the confusion of what drive is where. To see the label assigned to a drive, you can issue the VOL command from an OS/2 or DOS command line. The volume label is also available following the third word of the string returned by the SysDriveInfo() function in REXXUTIL. Since the volume label can contain imbedded spaces, the Parse instruction should be used to extract the volume label and the built-in STRIP() function should be used to remove leading spaces. For example:

string = SysDriveInfo( 'C:' )
parse value string with,
   drive_letter_colon,
   free_bytes,
   total_bytes,
   volume_label
volume_label = STRIP( volume_label )

By assigning a new label that is indicative of the machine and the drive letter as it is known on the local machine, you can save some confusion when multiple machines are referencing the drive.

First, each machine should be identified with a name. Each of my config.sys files contains a statement

SET MACHINE_NAME=name

My notebook is named AST01 and my REXX programs can interrogate what machine they are running on with:

machine_name = VALUE( 'MACHINE_NAME',, 'OS2ENVIRONMENT' )

[#Listing 1 Listing 1], which is available via anonymous FTP, contains a program that can be used to assign a meaningful volume label to each drive on my system. The volume label will be of the form: machine_name drive_letter. Since a volume label is restricted to 11 characters, your machine name must be kept to eight or fewer characters since the intervening space and the drive letter and colon will occupy 11 bytes. The three drives on the notebook have the volume labels:

AST01 - C:
AST01 - D:
AST01 - E:

Listing 1

/* 9608LS01.CMD - assign meaningful volume labels */
/*
   This program will assign a volume composed from the
   machine name and drive letter to all local drives on
   your system.

   It requires an environment variable be set as follows:

      SET MACHINE_NAME=name

   where name should be 8 or fewer characters.
*/

/*-------------------*\
|  Register REXXUTIL  |
\*-------------------*/
call RxFuncAdd 'SysLoadFuncs', 'REXXUTIL', 'SysLoadFuncs'
call SysLoadFuncs

machine_name = VALUE( 'HOSTNAME',, 'OS2ENVIRONMENT' )
if machine_name = ,
      |,
   LENGTH( machine_name ) > 8 then
   do
      say '    1 to 8 character machine name required'
      exit
   end

local_drive_list = SysDriveMap( 'C:', 'LOCAL' )

do while local_drive_list \= 
   parse value local_drive_list with,
      drive_letter_colon,
      local_drive_list

   parse value SysDriveInfo( drive_letter_colon ) with,
      drive_letter_colon,
      free_bytes,
      total_bytes,
      old_volume_label
   old_volume_label = STRIP( old_volume_label )

   new_volume_label =,
      machine_name        ||,
      ' '                 ||,
      drive_letter_colon

   '@echo' new_volume_label,
          '| label' drive_letter_colon ||,
           ' 1>nul 2>&1'
end
exit