#!/usr/bin/perl -wpi.bak # html-update-link-dates # Michael Ernst # Time-stamp: <2016-10-04 10:35:20 mernst> # usage: # html-update-link-dates file [...] # For any text of the form # text (14 Mar 1967), # text (14 Mar 1967, 19 Mbytes) # text (PDF, 14 Mar 1967), # text (PDF, 14 Mar 1967, 19 Mbytes) # update the date and file size text, but don't update the HTML file's # modification date. # For examples, see http://homes.cs.washington.edu/~mernst/software/ and # http://pag.csail.mit.edu/daikon/download/. # Warning: if the filename is the HTML file being edited, the date/size may # be incorrect. # To do: # Need to operate by paragraphs, not by lines. use FindBin (); use lib "$FindBin::Bin"; use checkargs; require POSIX; require Time::Local; # Forward declaration for Perl 5.6. sub file_date_replacement ( $$$$$ ); BEGIN { for my $file (@ARGV) { $file =~ s/\/$/\/index.html/; if (!(-f $file && -r $file)) { die "$file isn't a readable normal file"; } my ($atime, $mtime, $gid); ( undef, undef, undef, undef, undef, $gid, undef, undef, $atime, $mtime, undef, undef, undef ) = stat($file); $file_gid{$file} = $gid; $file_atime{$file} = $atime; $file_mtime{$file} = $mtime; } # What should I do about May?? $longmonthre = '(?:January|February|March|April|May|June|July|August|September|October|November|December)'; $datere = '(?:[0123]?[0-9] (?:[A-Z][a-z][a-z]|' . $longmonthre . ') [0-9]{4})'; $sizere = '(?:[0-9.]+ [kMG]?bytes)'; $datesizere = '(' . $datere . '(?:, ' . $sizere . ')?)'; } s/( ]+)(\">.*?<\/a>(?:,? (?:by|from) [A-Za-z]+(?: [A-Za-z]+)?)?(?: \((?:PDF, )?|, ))$datesizere([\)]?)/file_date_replacement($1,$2,$3,$4,$5)/eg; END { for my $file (keys %file_atime) { utime($file_atime{$file}, $file_mtime{$file}, $file) or warn "html-update-link-dates: can't restore timestamps of $file: $!\n"; # $< is the real userid for whoever is running this program. chown($<, $file_gid{$file}, $file) or warn "html-update-link-dates: can't restore ownership of $file: $!\n"; } # Ordinary, non-erroneous termination exit(0); } ########################################################################### sub file_date_replacement ( $$$$$ ) { my ($pre, $file, $mid, $old_date, $post) = check_args(5, @_); # print "\#$pre\#$file\#$mid\#$old_date\#$post\#\n"; my $dir = $ARGV; $dir =~ s/(^|\/)[^\/]*$/$1/; my $old_size; if ($old_date =~ /^($datere), ($sizere)/) { $old_date = $1; $old_size = $2; } my $longmonth = ($old_date =~ m/$longmonthre/); my $full_file = $file; if ($full_file !~ s:^/:/www/:) { $full_file = $dir . $file; } $full_file = simplify_path_name($full_file); $full_file =~ s/\/$/\/index.html/; if (!-f $full_file) { my $date = "00 Mth 0000"; if (defined($old_size)) { $date .= ", 00 Mbytes"; } # Warn about the missing file, unless the link is commented out. # ($pre is only the " $date\n"; return $date; } # Return human-readable file size in form NN [kM]bytes sub file_size ( $ ) { my ($file) = check_args(1, @_); my $size; ( undef, undef, undef, undef, undef, undef, undef, $size, undef, undef, undef, undef, undef ) = stat($file); if ($size < 1000) { return "$size bytes"; } my ($divisor, $metric_letter); if ($size < 950000) { $divisor = 1000; $metric_letter = "k"; } elsif ($size < 950000000) { $divisor = 1000000; $metric_letter = "M"; } else { $divisor = 1000000000; $metric_letter = "G"; } # This truncates, but it really ought to round instead. Do so by adding # 5 to the third most significant digit (since we truncate to two # significant digits). my $to_add = "5" . ("0" x (length($size) - 3)); my $trunc_size = sprintf("%f", ($size + $to_add) / $divisor); if ($trunc_size =~ m/^([0-9][0-9])([0-9]*)(\.[0-9]*)?$/) { $trunc_size = $1 . "0" x length($2); } elsif ($trunc_size !~ s/^([0-9]\.?[0-9])([0-9]*)$/$1/) { die "What trunc_size? " . $trunc_size; } return $trunc_size . " " . $metric_letter . "bytes"; } ## Lifted from em_util.pm, 9/8/97 # Simplify a directory path by canonicalizing to not contain # any ".." or "." components # e.g. simplify_path_name("./bink/baz/foo/../foo2/../../bar") is # "./bink/bar" sub simplify_path_name ( $ ) { my ($path) = check_args(1, @_); my $result = $path; 1 while $result =~ s%/[^/\n]*/\.\./%/%; 1 while $result =~ s%//%/%g; return $result; }