[comp.os.vms] YAUU

CHRIS@ENGVAX.SCG.HAC.COM (Chris Yoder) (07/07/87)

Hi all,

     I thought that I'd forward a late 4th of July present to the net.  It's a
procedure that will allow you to replace strings in a set of files with new
strings.  I have often wanted to be able to globally replace one string for
another for a given set of files, and now I have the ability.  (You TECO and
Un*x hackers can bite your toungues.)  This utility consists of a TPU command
file and a DCL command file.  It requires VMS 4.4 or better because the DCL
command file uses a GOSUB and I'm not 100 percent certain that the TPU command
file is backward compatible to 4.3 or 4.2.

     To install:  Extract everything below the line that says "Cut below this
line" into a file.  @ the extracted file.  The files REPLACE.COM, REPLACE.RNH
and REPLACE.TPU should appear.  Edit REPLACE.COM so that the
EDIT/TPU/NOSECTION/NODISPLAY/COMMAND=PUB:REPLACE.TPU points at the directory
where REPLACE.TPU will live.  We have a directory where all public utilities
live called PUB:, so that's what we use.

     If you want to provide help for all of your users use the command: RUNOFF
REPLACE.RNH to get REPLACE.HLP.  Insert this into whatever help library you
keep documentation for public domain software.

                                Enjoy!

-- Chris Yoder          UUCP -- {allegra or ihnp4}!scgvaxd!engvax!chris
   Hughes Aircraft  Internet -- chris%engvax.scg.hac.com@ymir.claremont.edu
        Company         ARPA -- chris%engvax.scg.hac.com@oberon.usc.edu

------------------------------ Cut below this line. ----------------------------
$ show default
$ write sys$output "Creating REPLACE.COM"
$ create REPLACE.COM
$ DECK/DOLLARS="$*$*EOD*$*$"
$       veri = 0
$       veri = f$verify (veri)
$ !     REPLACE.COM
$ !
$ !          This command file will allow the user to replace one string for
$ !     another in any given file.  If the user specifies an old string and a
$ !     new string on the call to this procedure, no prompting will be done.  If
$ !     the user does not specify an old string on the command line, the
$ !     procedure will prompt for old and new string pairs until the user enters
$ !     a return for an old string.  An empty string will be accepted for a new
$ !     string.  The actual editing is done by a TPU program, this command
$ !     procedure was designed as a friendly interface to the TPU program.
$ !
$ !             P1      Name of the (wildcarded) file(s) to be modified.
$ !             P2      (Optional) Old string
$ !             P3      (Optional) New string
$ !
$ !                     Written by:     Chris Yoder
$ !                             for:    Hughes Aircraft Company
$ !                                     Space and Communications Group
$ !                                     Computing Technology Center
$ !                             on:     July 2, 1987
$ !
$       on error then goto End_Processing
$       on warning then goto End_Processing
$       if P1 .nes. "" then goto Check_P2
$ !
$ Get_Filename:
$ !
$       if P1 .eqs. "" then read sys$command P1/prompt="File(s) to modify: "
$       if P1 .eqs. "" then goto Get_Filenames
$ !
$ Check_P2:
$ !
$       type sys$input

     Replace.Com is a command procedure that globally replaces one string
for a new string.  Any VMS file specifications that the DIRECTORY command
understands may used to specify the files to be modified.  If the user does
not specify a pair of old and new strings on the command line, Replace.Com
will ask the user for old and new string pairs until the user enters a
<RETURN> as an old string.

$ !
$       open/write subs_file sys$scratch:subs_string.tmp
$       if P2 .nes. "" then gosub Write_Record
$       if P2 .nes. "" then goto Close_and_Process
$       type sys$input

     This command procedure will now build a list of old string and new string
pairs.  When you wish to stop adding pairs to the list, enter a <RETURN> in
response to the prompt for an old string.

$ !
$ Write_Subs_File_Top:
$ !
$       read sys$command P2 /prompt="Old string: "
$       IF P2 .eqs. "" then goto Close_and_Process
$       read sys$command P3 /prompt="Replacement string: "
$       gosub Write_Record
$       goto Write_Subs_File_Top
$ !
$ Close_and_Process:
$ !
$       close subs_file
$ !
$ ! Figure out a list of files to replace strings in.
$ !
$       directory/noheading/notrailing/versions=1 -
                /output=sys$scratch:subs_files.tmp 'P1'
$       write sys$output "Please ignore any ""String Not Found"" errors."
$       open file_list sys$scratch:subs_files.tmp
$ Processing_Loop_Top:
$       read/end_of_file=End_Processing file_list file
$ !
$       edit/tpu/nosection/nodisplay/command=pub:replace 'file'
$       goto Processing_Loop_Top
$ !
$ End_Processing:
$ !
$       set noon
$       close file_list
$       delete sys$scratch:subs_files.tmp;*
$       delete sys$scratch:subs_string.tmp;*
$       veri = f$verify (veri)
$       exit
$ !
$ Write_Record:
$ !
$       write subs_file "''P2'"
$       write subs_file "''P3'"
$       return
$*$*EOD*$*$
$ write sys$output "Creating REPLACE.RNH"
$ create REPLACE.RNH
$ DECK/DOLLARS="$*$*EOD*$*$"
.RM 64
.NO NUMBER
.NO PAGING
.STHL 5,1,1
.lm 0
1 REPLACE
.lm 1
.lm +5
REPLACE [filespec [old__string [new__string]]]
.lm -5
.s
REPLACE is a utility that allows a user to replace strings in a set of files
with new strings.  The user may choose to modify one file or several as well as
replace one string or several.
.s
Allowing one or several files is accomplished by having the user specify as a
filespec any file specification that the DIRECTORY command would accept. The
only restriction is only the latest version of each file will be modified
unless a specific version number is provided.
.s
If the user does not specify an old string on the command line, REPLACE will
ask the user for old and new string pairs until the user enters a <RETURN> as
the old string.
.lm 0
2 Filespec
.lm 1
Any valid file specification that the DIRECTORY command would be able to
accept.  All file selection flags are allowed, including date, size, and
exclusion selectors.
.lm 0
2 Old__String
.lm 1
Any old string in the text.  This string is searched for in a case insensitive
manner.  No provision has been made for case sensitive searches of the old
string.
.s
If entered on the command line, remember standard DCL parsing rules apply so
any old string that has spaces in it must be enclosed with double quotes.
(NOTE: This only applies when REPLACE is NOT prompting for the old and new
string pairs.  REPLACE uses the READ statement internally so no DCL parsing is
invoked to process the string.)
.lm 0
2 New__String
.lm 1
A new string to replace the old string.  This string is entered exactly as
typed, no attempt to modify it will be made by REPLACE.  However, if entered on
the command line the new string must be enclosed in double quotes if the user
is entering a string with spaces in it or if the user wishes to preserve case.
(NOTE: This only applies when REPLACE is NOT prompting for the old and new
string pairs.  REPLACE uses the READ statement internally so no DCL parsing is
invoked to process the string.)
.s
One other caveat about new strings is that they may be empty!  An old string
but no new string on the command line will cause the old string to be extracted
and nothing to take it's place.  The same applies if the user is entering old
and new string pairs and hits a return for the new string.
.lm 0
2 Examples
.lm 1
Example 1:
.s
.lm +5
.nj
$ REPLACE NEWDISK:[USER42.COMFILES]*.COM OLDDISK NEWDISK
.j
.lm -5
.s
This example shows replacing all occurrences of the string OLDDISK with the
string NEWDISK in all of the command files in USER42's COMFILES subdirectory.
This case might come up if USER42's files are moved from OLDDISK to NEWDISK.
.s
Example 2:
.s
.lm +5
.nj
.nf
$ REPLACE<CR>
File(s) to modify: EARTH:[ARTHUR...]*.*/EXCLUDE=*.SEP<CR>
Old string: Advanced Tea Substitute<CR>
Replacement string: Tea<CR>
Old string: Dolphin<CR>
Replacement string: <CR>
Old string: <CR>
.f
.j
.lm -5
.s
This example shows Arthur returning to the disk EARTH and finally being able to
replace all occurrences of Advanced Tea Substitute with Tea.  At the same time
all occurrences of dolphin disappear.  Notice that all files that have the SEP
file type were excluded from the replacement operation.
.s
The <CR> strings indicate that the <RETURN> key was pressed.
.lm 0
2 Author
.lm 1
REPLACE was written by Chris Yoder of Hughes Aircraft Company.
$*$*EOD*$*$
$ write sys$output "Creating REPLACE.TPU"
$ create REPLACE.TPU
$ DECK/DOLLARS="$*$*EOD*$*$"
!  Replace.tpu
!
!            This fragment of TPU code will allow the user to replace one
!       string for another.  It is driven by a table in SYS$SCRATCH: called
!       SUBS_STRING.TMP.  This file contains old and new string pairs, one
!       string on a line.
!
!            Sample SYS$SCRATCH:SUBS_STRING.TMP
! +
! old first string
! new first string
! old second string
! new second string
! -
!
!                       Written by:     Chris Yoder
!                               for:    Hughes Aircraft Company
!                                       Space and Communications Group
!                                       Computing Technology Center
!                               on:     July 2, 1987
!
!  Batch mode TPU fragment.  Please note that this code does not require any
!  user interaction or any TPU Section files to run.  In order to use this
!  code, use the command:
!
!  $ EDIT/TPU/NOSECTION/NODISPLAY/COMMAND=<this-file-name>.TPU <file-to-edit>
!
input_file := get_info (command_line, "file_name");
input_file := file_parse (input_file);
main_buffer := create_buffer ('MAIN',input_file);
set (output_file, main_buffer, input_file);
position (beginning_of(main_buffer));
!
!  Code above this point is generic
!  Code below this point is specific
!
subs_buffer := create_buffer ('SUBS','SYS$SCRATCH:SUBS_STRING.TMP');
position (beginning_of(subs_buffer));

loop
  ! get the old string
  ! move to the start of the next line.
  EXITIF mark (none) = end_of(current_buffer);
  old_string := current_line;
  move_vertical(1);

  ! get the new string
  ! move to the start of the next line.
  EXITIF mark (none) = end_of(current_buffer);
  new_string := current_line;
  move_vertical(1);

  subs_position := mark (NONE);

  ! go through the source file and replace the old_string with the new_string
  position (beginning_of(main_buffer));
  loop
    replace_range := search (old_string,forward);
    EXITIF replace_range = 0;
    position (beginning_of(replace_range));
    throw_away := erase_character (length (replace_range));
    copy_text (new_string);
  endloop; ! this pass of substituting one "word" for another

  position (subs_position);
endloop; ! substituting one "word" for another
!
!  Code above this point is specific
!  Code below this point is generic
!
write_file (main_buffer);
exit;
$*$*EOD*$*$
$ exit

ADLER1@BRANDEIS.BITNET (07/09/87)

I just ran my favorite string replacement benchmark on Yoder's belated
4th of July gift to the network and got an error message to the effect
that I must immediately submit an SPR form explaining what I could
possibly have done to bring about this error condition.

I am rather new at VMS and have been largely unsuccessful at getting
it to work the way I would like. One problem is that I don't know
how to control the formatting of files and to guarantee that
records don't get too large. I can't read the documentation
most of the time and sometimes when I have, it has contained
errors that no one here, at least, knows how to get around.

Here's what I did to break Yoder's program: I created a file
called test. which contained the following, more or less:
.......................................................
I then told it to replace every occurrence of a period by
an occurrence of
.........................................................
and that is what produced the error condition.
I'm sure the literati will at once reply, "Of course you
get an error if you do that" and even I can imagine why
I get the error. But I am quite helpless to do anything
about it. How could one modify the program so that it
would automatically create new records when necessary to
handle the overflow caused by string replacement?

I should mention that I got interested in this problem earlier
when I wrote a simple C program to replace every occurrence of
a given character by a given string. It's performance on
VMS has been marred by precisely the same type of problems.
Any suggestions on how to deal with them in case of C will
be especially welcome.

Sincerely,

Allan Adler
ADLER1@BRANDEIS.BITNET