#!/usr/local/bin/kermit + # # REPLACETEXTBLOCK # # Change the top line of this file to reflect the full path of C-Kermit 9.0 # on your computer (followed by a space and a plus sign) or use GETKERMITSCRIPT # to download and install it. See: # # http://www.kermitproject.org/getkermitscript.html # http://www.kermitproject.org/replacetextblock.html # .version = 1.01 .date = 2014/02/28 # # Kermit script to replace a block of text in a file with another block # of text (Kermit's CHANGE command presently can't do this). The text blocks # do not have to be the same size. # # Optional leading arguments (each one must start with '-'): # -nobackup - Don't make backup files # -debug - Print debugging messages # -quiet - Don't print progress messages # -changeall:1 - Change all occurrences, not just the first # -nopatterns - Use search text literally - don't do pattern matching # -except:filespec - Skip the any files that match the filespec (pattern) # NOTE: wildcard characters in filespec must be quoted! # # Required arguments (after any options, must not start with '-'): # 1st arg: name of file containing text to be replaced (may contain patterns) # 2nd arg: name of file containging replacement text # 3rd arg: file in which to make the replacement (can be wildcard) # 4th, 5th...: additional files in which to make the replacement. # # Patterns are similar to regular expressions but not identical. # HELP PATTERNS in Kermit for details. # # Let's refer to the first required argument as "oldtext" (the file that # contains the text block to be replaced). If the oldtext contains # pattern-significant characters like * ? [] {} that are to be taken # literally, these must be quoted with \. Or you can just include the # -nopatterns option to have the text in # # Examples: # replacetextblock -except:main.c oldcopyright newcopyright *.c # replacetextblock -nopatterns oldaddress newaddress *.html # # C-Kermit 9.0 or later required. # # F. da Cruz, 27 February 2014 # --------------------------------------------------------------------------- # Runtime parameters... # .backup = 1 # Make backup files .changeall = 0 # Replace only first occurrence of matched text .matchmode = match # Use patterns in string matching .patterns = 1 # Flag for pattern matching .except = XXXX_X_X # Wildcard to match files to be skipped set quiet off # Print some status messages set debug message off # Don't print debugging messages set case off # Use case-independing string matching # --------------------------------------------------------------------------- # Macro definitions... .myname := \fbasename(\%0) if < \v(version) 900000 exit 1 "\m(myname): C-Kermit 9.0 or later required" def xx if debug echo \%* # Macro to print debugging messages def yy if debug { .zz := \%*, do zz } # Execute command only if debugging def qq if not quiet echo \%* # Print messages only if not quiet def qqx if not quiet xecho \%* # Ditto but with no line terminator def usage { # Macro for missing arguments .\%9 = "is the name of a file" echo "Usage: \m(myname) [ options ] oldtext newtext target [target ...]" echo "where:" echo " oldtext \%9 containing the text to search for;" echo " newtext \%9 containing the text to replace it with;" echo " target is the name of file in which to make the replacement." echo " You can include multiple target files on the command line or" echo " specify multiple files with a wildcard such as *.html." echo echo "Options:" echo " -help - print this message" echo " -nobackup - don't make backup files" echo " -debug - print debugging information" echo " -quiet - run silently" echo " -changeall - change all occurrences of the text not just the first" echo " -case - don't ignore alphabetic case when matching text" echo " -nopatterns - match oldtext literally; don't do pattern matching" echo " -except:pattern - skip files whose names match the pattern" if patterns { echo echo - " If you don't give the -nopatterns option, text in the the oldext file can" echo - " contain pattern-matching symbols such as * ? [] {} - HELP PATTERNS in" echo " C-Kermit for for further information." } echo xecho "If the oldtext file matches text in" echo " the target file, the text is replaced " xecho "with the contents of the newtext file," echo " the target file is replaced with" xecho "an updated copy, and a backup copy is" echo " made of the original. If the oldtext" xecho "is not found in the file, the file is" echo " not changed." echo exit 1 } # --------------------------------------------------------------------------- # Parse any options while equ [\:(\%1[1:1])] [-] { # Options start with '-' .\%1 := \fsubstr(\%1,2) # Get leftmost arg void \fkwval(\%1,:=) # "parse" it switch \v(lastkwval) { # Handle it :nobackup, .backup = 0, yy show macro backup, break :quiet, set quiet on, xx set quiet on, break :debug, set debug message on, xx set debug message on, break :changeall, .changeall = 1, yy show macro changeall, break :case, set case on, xx set case on, break :nopatterns, .matchmode = equal, xx .matchmode = equal .patterns = 0, break :except, yy show macro except, break :help, usage, break :default, exit 1 BAD ARG:\%1 } shift # Shift argument list to the left } if < \v(argc) 4 usage # Check we still have enough args left .oldtext := \%1 # Copy first two arguments .newtext := \%2 # because of shifting if not exist \m(oldtext) exit 1 Oldtext file \m(oldtext) not found if not exist \m(newtext) exit 1 Newtext file \m(newtext) not found qq OLDTEXT=[\m(oldtext)] qq NEWTEXT=[\m(newtext)] # --------------------------------------------------------------------------- # Action... # Read old text to be replaced into an array .maxsize = 999 dcl \&a[maxsize] # Array for lines fopen /read \%c \m(oldtext) # Open the oldtext file if fail exit 1 # Check that we did .n = 0 # Line counter for n 1 maxsize 1 { # Read lines into array fread /line \%c \&a[n] if fail break } if not \f_eof(\%c) exit 1 "OLDTEXT FILE TOO LONG" fclose \%c # Close oldtext file decr n # (because last iteration got EOF) yy show array a # (debugging) dcl \&b[n] # Parallel array for partial matches while def \%3 { # Read the files that we are updating qqx \fpathname(\%3)... # Maybe print current file name if match \%3 \m(except) { # Skip if name matches -except:xxx qq EXCEPTED - SKIPPING shift continue } .perms = 0 if lge \v(version) 900304 { # C-Kermit 9.0.304 or later for this .data := \ffileinfo(\%3,&i) # Get file info of original file if >= \m(data) 7 { # If we have a complete report if not equ "\&i[7]" "regular" { # Check if regular file qq "NOT A REGULAR FILE - SKIPPING" shift continue } if >= \m(data) 9 { # If we have a complete report if not equ "\fword(\&i[9],1)" "text" { # Check if text file qq "NOT A TEXT FILE - SKIPPING" shift continue } } .perms ::= \fright(\&i[5],3) # File is OK - get its permissions } } fopen /read \%c \%3 # Open the source file if fail exit 1 # Check that it's open # Open a temporary file for output .tmpfile := \%3.new # Make name for output file fopen /write \%o \m(tmpfile) # Open it if fail exit 1 # Check .changed = 0 # Flag that text was replaced while 1 { # Loop to process one file fread /line \%c line # Read a line from source file if fail break # This indicates end of file if ( not changeall && changed ) { # Replacement already made? fwrite /line \%o \m(line) # Yes - write line out and keep going continue } if not \m(matchmode) "\m(line)" "\&a[1]" { # Matches 1st oldtext line? fwrite /line \%o \m(line) # No - write it out and keep going continue } .\&b[1] := \m(line) # Yes - start partial-match array xx HAVE FIRST REPLACMENT LINE: xx \m(line) .havematch = 1 # Assume we have a match for i 2 n 1 { # All the subsequent lines must match fread /line \%c line if fail { .havematch = 0, break } .\&b[i] := \m(line) if not equ "\m(line)" "\&a[i]" { .havematch = 0, break } xx OK: \m(i). \m(line) } if not havematch { # Have partial match xx PARTIAL MATCH IGNORED for k 1 i 1 { # write out the partial match lines fwrite /line \%o \&b[k] } continue } # Have a complete match xx HAVE COMPLETE MATCH - REPLACING MATCHED TEXT WITH \m(newtext) fclose \%o # Close output file copy /append \m(newtext) \m(tmpfile) # Append replacement text fopen /append \%o \m(tmpfile) # Reopen output file # fwrite /line \%o \m(line) # Write out the straggling line .changed = 1 # Remember we did this } fclose \%c # Done - close input file fclose \%o # Close output file xx if perms chmod \m(perms) \m(tmpfile) if perms chmod \m(perms) \m(tmpfile) # Set permissions from original if debug { if changed { echo \%3 => \m(tmpfile) OK (text was replaced) } else { echo \%3 (replacement text not found - no change was made) } } else if changed { if backup { # Back up input file if not exist \%3.backup rename \%3 \%3.backup } rename \m(tmpfile) \%3 # Rename temp file to input file if changed qq OK (text was replaced) } else { # File was not changed del \m(tmpfile) # Delete the temporary file qq (replacement text not found - no change was made) } shift # Get next filename } if debug { echo "Remember to delete *.new files" } else if backup { echo "Backup files were created (*.backup)" } exit 0 ; Local Variables: ; comment-column:40 ; comment-start:"# " ; End: