[comp.os.minix] ptch, fndx and runcrc - perl scripts to apply patches and check dirs

amoss@SHUM.HUJI.AC.IL (Amos Shapira) (04/14/91)

Hello,

I attach at the end of this article three perl scripts as follows:

1. ptch - a front end to patch. It checks the files ending in "*cdif"
   and finds the names of the files on which the the patches in the "*cdif"
   files should be applayed. Gives an interactive line oriented user interface.

2. runcrc - read the file who's name matches the pattern "*.crc" (if not given
   a file name on the command line) checks crc and size of the files who's
   names are mentioned in the .crc file and report about any bad files.

3. fndx - find extra files in the current directory (according to the local
   .crc file). Will *not* report the .crc file itself (so you can do "rm
   `fndx`" after finishing the upgrade).

There are meny ways these scripts could be impruved (like better handling in
failed patches, multy directory patches and multi file operations in ptch),
but I finished upgrading my copy of Minix so I didn't bother with them any
more. If you want features to be added and/or bug fixes then feel free to mail
me.

I suspect there is no perl on Minix, so maybe I'll translate these to C one day
(when I get Minix 1.5.10 running).

Hope these help,

Amos Shapira
C.S. System Group
Hebrew University
Jerusalem, Israel
amoss@cs.huji.ac.il

"Superusers do it without asking for permission." - me

P.S.	The crc program of 1.5 seems to compile on our Solbourne (a Sparc
	compatible with a variant of SunOS) without any change, so there
	shouldn't be a problem to check crc's.

----------------------------------------------------------------------
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  ptch
#	  runcrc
#	  fndx
#
sed 's/^X//' << 'SHAR_EOF' > ptch &&
X#!/usr/local/bin/perl
X
X$[ = 1;		# so it looks nicer on output
X$| = 1;		# so the prompt is printed at the right time
X
X@statusnames = ('Original', 'Patched', 'Failed');
X
X# open a channel directly to the tty if possible, otherwise read STDIN
Xopen(IN,"</dev/tty") || open(IN, "<&STDIN");
X
X# get the names of all the *.cdif files and find what files exist which could
X# be used as the base version for them
Xwhile (<*.cdif>) {
X	($f = $_) =~ s/\.cdif$//;
X	if (! -e $f && ! -e ($f .= ".c")) {
X		print "Error: ", ($f . "dif"), " without a base\n";
X		next;
X	}
X
X	# save base filenames by diff file names
X	push(@basefiles, $f);
X	push(@patchfiles, $_);
X	push(@status, $[);
X}
X
Xdie "No files to process\n" if scalar(@basefiles) == 0;
X
X$current = $[;
X$verbose = 1;
X
X&listfiles;
X
X# Main loop
XCMD:
Xwhile ((print "Ptch> "), $cmd = <IN>) {
X	$cmd eq '' && exit 0;			# quit on EOF
X	chop($cmd);
X	$cmd =~ /^$/ && next;			# ignore empty lines
X	$cmd eq 'c' && do {
X		$x = $basefiles[$current];
X		unlink($patchfiles[$current], $x . ".orig", $x . ".new",
X		    $x . ".rej");
X		print("Done.\n") if $verbose;
X		next CMD;
X	};
X	$cmd eq 'C' && do {
X		for ($i = 1; $i <= @basefiles; ++$i) {
X			$x = $basefiles[$i];
X			print "$x..." if $verbose;
X			unlink($patchfiles[$i], $x . ".orig", $x . ".new",
X			    $x . ".rej");
X			print "done.\n" if $verbose;
X		}
X		next CMD;
X	};
X	$cmd eq 'e' && do {
X		system($ENV{'EDITOR'}, $basefiles[$current]);
X		next CMD;
X	};
X	$cmd eq 'h' && do {
X		print "
Xc		Cleanup for current file.
XC		Cleanup all (i.e. remove .cdif .orig .rej and .new files)
Xe		Run editor on base and patch file.
Xh		Print this help.
Xl		List the files and status.
Xn		Move to the next file.
Xp		Move to the previous file.
Xq or ^D		Quit.
Xr		Restore original.
XR		Save patched file in .new and restore original.
Xs		Copy the original file to .old.
Xv		Toggle verbosity flag.
Xx		Execute patch on current file and move to the next.
XX		Execute patch on current file and stay.
X#		Move to the file who's number is given.
X.		List current file.
X
X";
X		next CMD;
X	};
X	$cmd eq 'l' && do {			# list files on 'l'
X		&listfiles;
X		next CMD;
X	};
X	$cmd eq 'n' && do {			# move to next file on 'n'
X		++$current if $current < @basefiles;
X		&list_current_file if $verbose;
X		next CMD;
X	};
X	$cmd =~ /^n\s*(\d+)/ && do {
X		$current += $1 if (($current + $1) <= @basefiles);
X		&list_current_file if $verbose;
X		next CMD;
X	};
X	$cmd eq 'p' && do {			# move to previous file on 'p'
X		$current-- if $current > $[;
X		&list_current_file if $verbose;
X		next CMD;
X	};
X	$cmd =~ /^p\s*(\d+)/ && do {
X		$current -= $1 if (($current - $1) >= $[);
X		&list_current_file if $verbose;
X		next CMD;
X	};
X	$cmd eq 'q' && exit 0;			# quit on q
X	$cmd eq 'R' && do {			# mv $file $file.new;
X						# mv $file.orig $file
X		next CMD if $status[$current] == 1;
X		$x = $basefiles[$current];
X		rename($x, $x . ".new");
X		rename($x . ".orig", $x);
X		$status[$current] = 1;
X		&list_current_file if $verbose;
X		next CMD;
X	};
X	$cmd eq 'v' && do {			# toggle verbosity on 'v'
X		$verbose = !$verbose;
X		print "Verbosity ", ($verbose ? "on\n" : "off\n");
X		next CMD;
X	};
X	($cmd eq 'x' || $cmd eq 'X') && do {
X		system("patch", $basefiles[$current], $patchfiles[$current]);
X		$status[$current] = (($? == 0) ? 2 : 3);
X		&list_current_file if $verbose;
X		if ($cmd eq 'x') {
X			++$current if ($current < @basefiles);
X			print '>' x 30, " Last file!\a ", '<' x 30, "\n"
X			    if ($current == @basefiles);
X		}
X		next CMD;
X	};
X	$cmd =~ /^(\d+)$/ && do {		# jump to a file on #
X		$current = $1 if ($1 >= $[) && ($1 <= @basefiles);
X		&list_current_file if $verbose;
X		next CMD;
X	};
X	$cmd eq '.' && do {			# print current file on '.'
X		&list_current_file;
X		next CMD;
X	};
X	print "Unknown command \"$cmd\". Type 'h' for help\n" if $verbose;
X}
X
X# list the @files array
Xsub listfiles {
X	local ($f);
X	print "   ---BASE FILE--- ---PATCH FILE--  STATUS\n";
X	for $i ($[..$#basefiles) {
X		printf("%2d %-15.15s %-15.15s %s%s\n", $i, $basefiles[$i],
X		    $patchfiles[$i], $i == $current ? '*' : ' ',
X		    $statusnames[$status[$i]]);
X	}
X}
X
X# list current file in list format
Xsub list_current_file {
X	printf("%2d %-15.15s %-15.15s *%s\n", $current, $basefiles[$current],
X	    $patchfiles[$current], $statusnames[$status[$current]]);
X}
SHAR_EOF
chmod 0755 ptch || echo "restore of ptch fails"
sed 's/^X//' << 'SHAR_EOF' > runcrc &&
X#!/usr/local/bin/perl
Xunshift(@ARGV,`echo *.crc`) if $#ARGV < $[;
Xwhile (<>) {
X	($crc, $size, $file) = split;
X	# strip path components from file name, leave only the file name
X	$file =~ s,.*/([^/]*),\1, if ($file =~ m,.*/.*,);
X	if (! -e $file) {
X		print "$file: doesn't exist!\n";
X		next;
X	}
X
X	if (-d _ && $crc == 0 && $size == 0) {
X		print "$file: a directory, seems OK.\n";
X		next;
X	}
X
X	if (! -f _) {
X		print "$file: not a plain file!\n";
X		next;
X	}
X
X	if (! -r _ && ! -R _) {
X		print "$file: not readable!\n";
X		next;
X	}
X
X	($mycrc, $mysize) = split(' ',`mcrc $file`);
X
X	if ($mysize != $size) {
X		print "$file: different sizes " .
X		    "(expected: $size; really is: $mysize)\n";
X	} elsif ($mycrc != $crc) {
X		print "$file: different crc's " .
X		    "(expected: $crc; really is: $mycrc)\n";
X	} else {
X		print "$file: OK.\n";
X	}
X}
SHAR_EOF
chmod 0755 runcrc || echo "restore of runcrc fails"
sed 's/^X//' << 'SHAR_EOF' > fndx &&
X#!/usr/local/bin/perl
Xunshift(@ARGV, `echo *.crc`) if $#ARGV < $[;
Xwhile(<>) {
X	($crc, $size, $file) = split;
X	$file =~ s,.*/([^/]*),\1, if ($file =~ m,.*/.*,);
X	$list{$file}++;
X}
X
Xwhile (<*>) {
X	print "$_\n" if $_ !~ '.*\.crc$' && $list{$_} == 0;
X}
SHAR_EOF
chmod 0755 fndx || echo "restore of fndx fails"
exit 0
----------------------------------------------------------------------