📄 ch21.htm
字号:
</CENTER>
<P>
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Turn on the warning option.<BR>
Turn on the strict pragma.<BR>
Declare some variables.<BR>
Call the </I><TT><I>checkFiles()</I></TT><I>
fuNCtion to find modified files.<BR>
Call the </I><TT><I>setLastTime()</I></TT><I>
fuNCtion to update the log file.<BR>
Call the </I><TT><I>createHTML()</I></TT><I>
fuNCtion to create the web page.<BR>
<BR>
Define the </I><TT><I>getLastTime()</I></TT><I>
fuNCtion.<BR>
Declare local variables to hold the parameters.<BR>
If the data file can't be opened, use the current time as the
default.<BR>
Read in the time of the last running of the program.<BR>
Close the data file.<BR>
Return the time.<BR>
Define the </I><TT><I>setLastTime()</I></TT><I>
fuNCtion.<BR>
Declare local variables to hold the parameters.<BR>
Open the data file for writing.<BR>
Output </I><TT><I>$time</I></TT><I>
which is the current time this program is running. <BR>
Close the data file.<BR>
Define the </I><TT><I>checkFiles()</I></TT><I>
fuNCtion.<BR>
Declare local variables to hold the parameters.<BR>
Declare more local variables.<BR>
Create an array containing the files in the </I><TT><I>$path</I></TT><I>
directory.<BR>
Iterate over the list of files.<BR>
If current file is current dir or parent dir, move on to next
file.<BR>
Create full filename by joining dir (</I><TT><I>$path</I></TT><I>)
with filename (</I><TT><I>$_</I></TT><I>).
<BR>
If current file is a directory, then recurse and move to next
file.<BR>
Get last modification time of current file.<BR>
Provide a default value for the file's title.<BR>
If the file has been changed siNCe the last running of this program,open
the file, look for a title HTML tag, and close the file.<BR>
Create an anonymous array and assign it to a hash entry.<BR>
Define the </I><TT><I>createHTML()</I></TT><I>
fuNCtion.<BR>
Declare local variables to hold the parameters.<BR>
Declare more local variables.<BR>
Open the HTML file for output.<BR>
Output the HTML header and title tags.<BR>
Output an H1 header tag.<BR>
If no files have changed, output a message.<BR>
Otherwise output the HTML tags to begin a table.<BR>
Iterate the list of modified files.<BR>
Output info about modified file as an HTML table row.<BR>
Output the HTML tags to end a table.<BR>
Output the HTML tags to end the document.<BR>
Close the HTML file.</I>
</BLOCKQUOTE>
<HR>
<P>
<B>Listing 21.7 21LST07.PL-Generating a Primitive What's
New Page<BR>
</B>
<BLOCKQUOTE>
<PRE>#!/usr/bin/perl -w
use strict;
my($root) = "/website/root"; # root of server
my($newLog) = "new.log"; # file w/time of last run.
my($htmlFile) = "$root/whatnew.htm"; # output file.
my($lastTime) = getLastTime($newLog); # time of last run.
my(%modList); # hash of modified files.
checkFiles($root, $root, $lastTime, \%modList);
setLastTime($newLog, time());
createHTML($htmlFile, $lastTime, \%modList);
sub getLastTime {
my($newLog) = shift; # filename of log file.
my($time) = time(); # the current time is the default.
if (open(NEWLOG, "<$newLog")) {
chomp($time = <NEWLOG>);
close(NEWLOG);
}
return($time);
}
sub setLastTime {
my($newLog) = shift; # filename of log file.
my($time) = shift; # the time of this run.
open(NEWLOG, ">$newLog") or die("Can't write What's New log file.");
print NEWLOG ("$time\n");
close(NEWLOG);
}
sub checkFiles {
my($base) = shift; # the root of the dir tree to search
my($path) = shift; # the current dir as we recurse
my($time) = shift; # the time of the last run of this script
my($hashRef) = shift; # the hash where modified files are listed.
my($fullFilename); # a combo of $path and the current filename.
my(@files); # holds a list of files in current dir.
my($title); # the HTML title of a modified doc.
my($modTime); # the modification time of a modfied doc.
opendir(ROOT, $path);
@files = readdir(ROOT);
closedir(ROOT);
foreach (@files) {
next if /^\.|\.\.$/;
$fullFilename = "$path/$_";
if (-d $fullFilename) {
checkFiles($base, $fullFilename, $time, $hashRef);
next;
}
$modTime = (stat($fullFilename))[9]; # only need the mod time.
$title = 'Untitled'; # provide a default value
if ($modTime > $time) {
open(FILE, $fullFilename);
while (<FILE>) {
if (m!<title>(.+)</title>!i) {
$title = $1;
last;
}
}
close(FILE);
%{$hashRef}->{substr($fullFilename, length($base))} =
[ $modTime, $title ];
}
}
}
sub createHTML {
my($htmlFile) = shift;
my($lastTime) = shift;
my($hashRef) = shift;
my($htmlTitle) = "What's New SiNCe " . scalar(localtime($lastTime)). "!";
my(@sortedList) = sort(keys(%{$hashRef}));
open(HTML, ">$htmlFile");
print HTML ("<TITLE>$htmlTitle</TITLE>\n");
print HTML ("<HTML>\n");
print HTML ("<HEAD><TITLE>$htmlTitle</TITLE></HEAD>\n");
print HTML ("<BODY>\n");
print HTML ("<H1>$htmlTitle</H1><P>\n");
if (scalar(@sortedList) == 0) {
print HTML ("There are no new files.\n");
}
else {
print HTML ("<TABLE BORDER=1 CELLPADDING=10>\n");
print HTML ("<TR>\n");
print HTML (" <TH>Filename</TH>\n");
print HTML (" <TH>Modification<BR>Date</TH>\n");
print HTML (" <TH>Title</TH>\n");
print HTML ("</TR>\n");
foreach (sort(keys(%{$hashRef}))) {
my($modTime, $title) = @{%{$hashRef}->{$_}};
$modTime = scalar(localtime($modTime));
print HTML ("<TR>\n");
print HTML (" <TD><FONT SIZE=2><A HREF=\"$_\">$_</A></FONT></TD>\n");
print HTML (" <TD><FONT SIZE=2>$modTime</FONT></TD>\n");
print HTML (" <TD><FONT SIZE=2>$title</FONT></TD>\n");
print HTML ("</TR>\n");
}
print HTML ("</TABLE>\n");
}
print HTML ("</BODY>\n");
print HTML ("</HTML>\n");
close(HTML);
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
The program from Listing 21.7 will generate an HTML file that
can be displayed in any browser capable of handling HTML tables.
Figure 21.2 shows how the page looks in Netscape Navigator.
<P>
<A HREF="f21-2.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/f21-2.gif"><B>Figure 21.2 : </B><I>A What's New page</I>.</A>
<P>
You might wonder why I end the HTML lines with newline characters
when newlines are ignored by Web browsers. The newline characters
will help you to edit the resulting HTML file with a standard
text editor if you need to make an emergeNCy change. For example,
a document might change status from <TT>visible</TT>
to <TT>for internal use only</TT>
and you'd like to remove it from the What's New page. It is much
easier to fire up a text editor and remove the refereNCe then
to rerun the What's New script.
<P>
I think the only tricky code in Listing 22.7 is where it creates
an anonymous array that is stored into the hash that holds the
changed files. Look at that line of code closely.
<BLOCKQUOTE>
<PRE>%{$hashRef}->{substr($fullFilename, length($base))} = [ $modTime, $title
</PRE>
</BLOCKQUOTE>
<P>
The <TT>$hashRef</TT> variable holds
a refereNCe to <TT>%modList</TT> that
was passed from the main program. The key part of the key-value
pair for this hash is the relative path and file name. The value
part is an anonymous array that holds the modification time and
the document title.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Tip</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
An array was used to store the information about the modified file so that you can easily change the program to display additional information. You might also want to display the file size or perhaps some category information.</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
Using the relative path in the key becomes important when the
HTML file is created. In order to create hypertext links to the
changed documents, the links need to have the document's directory
relative to the server's root directory. For example, my WebSite
server has a base directory of <TT>/website/root</TT>.
If a document changes in <TT>/website/root/apache</TT>,
then the hypertext link must use <TT>/apache</TT>
as the relative path in order for the user's Web browser to find
the file. To arrive at the relative path, the program simply takes
the full path and filename and removes the beginning of the string
value using the <TT>substr()</TT>
fuNCtion.
<P>
You might also want to know a bit about the recursive nature of
the <TT>checkFiles()</TT> fuNCtion.
This book really hasn't mentioned recursive fuNCtions in any detail
yet. So, I'll take this opportunity to explain them.
<P>
A <I>recursive fuNCtion</I> calls itself in order to get work
done. One classic example of recursiveness is the <TT>factorial()</TT>
fuNCtion from the math world. 3! (five factorial) is the same
as 1*2*3 or 6. The <TT>factorial()</TT>
fuNCtion looks like this:
<BLOCKQUOTE>
<PRE>sub factorial {
my($n) = shift;
return(1) if $n == 1;
return($n * factorial($n-1));
}
</PRE>
</BLOCKQUOTE>
<P>
Now track the value of the return statements when factorial(3)
is called:
<OL>
<LI><B>factorial(3)</B>-return(3 * factorial(2));
<LI><B>factorial(2)</B>-return(2 * factorial(1));
<LI><B>factorial(1)</B>-return(1);
<LI><B>factorial(2)</B>-return(2 * 1);
<LI><B>factorial(3)</B>-return(3 * 2);
<LI>A value of 6 is returned.
</OL>
<P>
First, the fuNCtion repeated calls itself (recurses) until an
end condition is reached. When the end condition is reached ($n
== 1) then the stack of fuNCtion calls is followed backwards to
read the final value of 6.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Caution</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
It is very important for a recursive fuNCtion to have an end condition. If not, the fuNCtion recurses until your system runs out of memory.</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
If you look back at the <TT>checkFiles()</TT>
fuNCtion, you see that the end condition is not explicitly stated.
When a directory has no subdirectories, the fuNCtion will stop
recursing. And instead of returning a value that is used in a
mathematical expression, a hash refereNCe is continually passed
where the information about changed files is stored.
<P>
While the topic is the information about the changed files, let
me mention the two directories that are used as parameters for
<TT>checkFiles()</TT>. The first directory
is the path to the Web server root-it will not change as the recursion
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -