Article 1340 of comp.infosystems.wais: Xref: feenix.metronet.com comp.infosystems.gopher:7848 comp.infosystems.wais:1340 comp.infosystems.www:5541 Newsgroups: comp.infosystems.gopher,comp.infosystems.wais,comp.infosystems.www Path: feenix.metronet.com!news.utdallas.edu!corpgate!bnrgate!bnr.co.uk!uknet!pipex!howland.reston.ans.net!cs.utexas.edu!newsfeed.rice.edu!rice!riddle From: riddle@is.rice.edu (Prentiss Riddle) Subject: Re: Single program to summarize logs of several kinds of server? Message-ID: Sender: news@rice.edu (News) Organization: Ministry of Information, William's Marsh References: Date: Thu, 6 Jan 1994 20:29:40 GMT Lines: 930 A couple of hours ago I wrote: > I could swear that I had seen and saved an announcement of a single log > summary program which could handle gopher, ftp, WAIS and (I think) a > couple of other flavors of log files. Several people responded with clues, but Bob Bagwill (bagwill@sst.ncsl.nist.gov) sent me a copy of the program. It's called "fwgstat 0.35" and the author is Jonathan Magid (jem@sunsite.unc.edu). Since neither archie, veronica nor I can find it archived anywhere, I am appending it below. Let's hope the author puts it on boombox or some other well-know site soon. Thanks to everyone who responded. -- Prentiss Riddle ("aprendiz de todo, maestro de nada") riddle@rice.edu -- Systems Programmer, Office of Networking Services -- Rice University, POB 1892, Houston, TX 77251 / Mudd 208 / 713-285-5327 -- Opinions expressed are not necessarily those of my employer. ------------------------------------------------------------------------- # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # README # country-codes # fwgstat # mygetopts.pl # echo x - README sed 's/^X//' >README << 'END-of-README' XThis is fwgstat v 0.35. It is heavily based on the much better Xwritten xferstats, which is packaged with the Wuarchive FTP daemon. X XThis version is capable of parsing the usage files for most Xof the public access protocols in use today: FTP, Gopher, WAIS, and the NCSA Xand the Plexus implementations of HTTP, and writing a nice usage report. X XAs of this version, fwgstat can summarize the usage of any number of these Xprotocols in a single report. X XTo install the program, edit the perl script to specify the locations Xof the log files for each daemon and the location of the accompanying Xcountry-codes file. You must also add the library file 'mygetopts.pl' to Xyour Perl library directory. X X XThese are the options which fwgstat supports: X X -f Use for the log file X -r include real users (for FTP) X -a include anonymous users (for FTP) X -h include report on hourly traffic X -d include report on domain traffic X -t report on total traffic by section X -D report only on traffic from X -l Depth of path detail for sections X -s
Section to report on, For example: -s /pub will report X only on paths under /pub X (left in for backward compatibility) X -g
Process a Gopher file, followed by an optional section X -w
Process a WAIS file, followed by an optional section X -p
Process a Plexus HTTPD file, followed by an optional X section X -n
Process a NCSA HTTPD file, followed by an optional X section X -F
Process a FTP file, followed by an optional section X -m Process multiple file types into one report X X XIf you have any suggestions, bug reports, fixes, or enhancements, Xsend them to jem@sunsite.unc.edu. END-of-README echo x - country-codes sed 's/^X//' >country-codes << 'END-of-country-codes' XAD Andorra XAE United Arab Emirates XAF Afghanistan XAG Antigua and Barbuda XAI Anguilla XAL Albania XAM Armenia XAN Netherland Antilles XAO Angola XAQ Antarctica XAR Argentina XAS American Samoa XAT Austria XAU Australia XAW Aruba XAZ Azerbaidjan XBA Bosnia-Herzegovina XBB Barbados XBD Banglades XBE Belgium XBF Burkina Faso XBG Bulgaria XBH Bahrain XBI Burundi XBJ Benin XBM Bermuda XBN Brunei Darussalam XBO Bolivia XBR Brazil XBS Bahamas XBT Buthan XBV Bouvet Island XBW Botswana XBY Belarus XBZ Belize XCA Canada XCC Cocos (Keeling) Isl. XCF Central African Rep. XCG Congo XCH Switzerland XCI Ivory Coast XCK Cook Islands XCL Chile XCM Cameroon XCN China XCO Colombia XCR Costa Rica XCS Czechoslovakia XCU Cuba XCV Cape Verde XCX Christmas Island XCY Cyprus XCZ Czech Republic XDE Germany XDJ Djibouti XDK Denmark XDM Dominica XDO Dominican Republic XDZ Algeria XEC Ecuador XEE Estonia XEG Egypt XEH Western Sahara XES Spain XET Ethiopia XFI Finland XFJ Fiji XFK Falkland Isl.(Malvinas) XFM Micronesia XFO Faroe Islands XFR France XFX France (European Ter.) XGA Gabon XGB Great Britain (UK) XGD Grenada XGE Georgia XGH Ghana XGI Gibraltar XGL Greenland XGP Guadeloupe (Fr.) XGQ Equatorial Guinea XGF Guyana (Fr.) XGM Gambia XGN Guinea XGR Greece XGT Guatemala XGU Guam (US) XGW Guinea Bissau XGY Guyana XHK Hong Kong XHM Heard & McDonald Isl. XHN Honduras XHR Croatia XHT Haiti XHU Hungary XID Indonesia XIE Ireland XIL Israel XIN India XIO British Indian O. Terr. XIQ Iraq XIR Iran XIS Iceland XIT Italy XJM Jamaica XJO Jordan XJP Japan XKE Kenya XKG Kirgistan XKH Cambodia XKI Kiribati XKM Comoros XKN St.Kitts Nevis Anguilla XKP Korea (North) XKR Korea (South) XKW Kuwait XKY Cayman Islands XKZ Kazachstan XLA Laos XLB Lebanon XLC Saint Lucia XLI Liechtenstein XLK Sri Lanka XLR Liberia XLS Lesotho XLT Lithuania XLU Luxembourg XLV Latvia XLY Libya XMA Morocco XMC Monaco XMD Moldavia XMG Madagascar XMH Marshall Islands XML Mali XMM Myanmar XMN Mongolia XMO Macau XMP Northern Mariana Isl. XMQ Martinique (Fr.) XMR Mauritania XMS Montserrat XMT Malta XMU Mauritius XMV Maldives XMW Malawi XMX Mexico XMY Malaysia XMZ Mozambique XNA Namibia XNC New Caledonia (Fr.) XNE Niger XNF Norfolk Island XNG Nigeria XNI Nicaragua XNL Netherlands XNO Norway XNP Nepal XNR Nauru XNT Neutral Zone XNU Niue XNZ New Zealand XOM Oman XPA Panama XPE Peru XPF Polynesia (Fr.) XPG Papua New XPH Philippines XPK Pakistan XPL Poland XPM St. Pierre & Miquelon XPN Pitcairn XPT Portugal XPR Puerto Rico (US) XPW Palau XPY Paraguay XQA Qatar XRE Reunion (Fr.) XRO Romania XRU Russian Federation XRW Rwanda XSA Saudi Arabia XSB Solomon Islands XSC Seychelles XSD Sudan XSE Sweden XSG Singapore XSH St. Helena XSI Slovenia XSJ Svalbard & Jan Mayen Is XSK Slovak Republic XSL Sierra Leone XSM San Marino XSN Senegal XSO Somalia XSR Suriname XST St. Tome and Principe XSU Soviet Union XSV El Salvador XSY Syria XSZ Swaziland XTC Turks & Caicos Islands XTD Chad XTF French Southern Terr. XTG Togo XTH Thailand XTJ Tadjikistan XTK Tokelau XTM Turkmenistan XTN Tunisia XTO Tonga XTP East Timor XTR Turkey XTT Trinidad & Tobago XTV Tuvalu XTW Taiwan XTZ Tanzania XUA Ukraine XUG Uganda XUK United Kingdom XUM US Minor outlying Isl. XUS United States XUY Uruguay XUZ Uzbekistan XVA Vatican City State XVC St.Vincent & Grenadines XVE Venezuela XVG Virgin Islands (British) XVI Virgin Islands (US) XVN Vietnam XVU Vanuatu XWF Wallis & Futuna Islands XWS Samoa XYE Yemen XYU Yugoslavia XZA South Africa XZM Zambia XZR Zaire XZW Zimbabwe XARPA Old style Arpanet XCOM US Commercial XEDU US Educational XGOV US Government XINT International XMIL US Military XNATO Nato field XNET Network XORG Non-Profit X X END-of-country-codes echo x - fwgstat sed 's/^X//' >fwgstat << 'END-of-fwgstat' X#!/usr/local/bin/perl X# --------------------------------------------------------------------------- X# X# USAGE: fwgstat X# X# OPTIONS: X# -f Use for the log file X# -r include real users X# -a include anonymous users X# -h include report on hourly traffic X# -d include report on domain traffic X# -t report on total traffic by section X# -D report only on traffic from X# -l Depth of path detail for sections X# -s
Section to report on, For example: -s /pub will report X# only on paths under /pub X# (left in for backward compatibility) X# -g
Process a Gopher file, followed by an optional section X# -w
Process a WAIS file, followed by an optional section X# -p
Process an Plexus HTTPD file, followed by an optional X# section X# -n
Process an NCSA HTTPD file, followed by an optional X# section X# -F
Process a FTP file, followed by an optional section X# (the default) X# -m Process multiple file types X# X# --------------------------------------------------------------------------- X X X# added support for the Plexus HTTPD. (which is now the -p switch). changed X# switch for NCSA httpd to -n. 04-Oct-1993 jem@sunsite.unc.edu v.035 X# X# changed format for government data report including support for summarizing X# multiple protocol logs into one report and added optional arguements to X# getopts 30-Sep-1993 jem@sunsite.unc.edu. v.03 X# X# added WWW (NCSA httpd) logging 9-Sep-1993 jem@sunsite.unc.edu X# X# added file-size, proper DocID request, and host counting for WAIS X# jem@sunsite.unc.edu 24-Aug-1993 v.02 (first public release) X# X# initial take at WAIS logfile parsing- datta@cs.uwp.edu 18-Aug-1993 X# X# bug fixes in gopher routines, added full country names- by Jonathan Magid X# jem@sunsite.unc.edu 18-Aug-1993 X# X# changes by David Datta (datta@cs.uwp.edu) to write stats for gopher logfiles X# 14-Aug-1993 v.01 X# X# original version- from the Wuarchive enhanced FTPD distribution X X# edit the next two lines to customize for your domain. X# This will allow your domain to be seperated in the domain listing. X X$mydom1 = "unc"; X$mydom2 = "edu"; X X# edit the next line to identify the top of your Gopher data tree X$gopherroot= "/etc/gopher-data"; X X# edit the next line to identify the top of your HTTPD (WWW) data tree X$httpdroot = "/usr/local/etc/http/data"; X X# edit the next line to locate the country-codes file. This is a file X# of the format: X# domain text X# which will allow expansion from domain to country name. X$countrycodefile="/usr/local/etc/country-codes"; X X# edit the next line to customize for your default log file X%usagefiles = ( X 'opt_F', '/usr/adm/xferlog', #for FTP X 'opt_g', '/usr/adm/gopher.log', #for gopher X 'opt_w', '/usr/adm/server.log', #for wais X 'opt_p', 'plexus_log', #for plexus httpd X 'opt_n', '/usr/adm/access_log' #for NCSA httpd X); X X#options for all the types of files which we can parse X%filetypes=( X 'opt_F', 'FTP', X 'opt_g', 'GOPHER', X 'opt_p', 'WWW', X 'opt_n', 'WWW', X 'opt_w', 'WAIS', X); X X# Edit the following lines for default report settings. X# Entries defined here will be over-ridden by the command line. X X$opt_h = 1; X$opt_d = 1; X$opt_t = 1; X$opt_l = 2; X Xrequire 'mygetopts.pl'; X&MyGetopts('f:ramhdp?F?D:l:s:g?w?n?'); X Xif ($opt_r) { $real = 1;} Xif ($opt_a) { $anon = 1;} Xif ($real == 0 && $anon == 0) { $anon = 1; } Xif ($opt_f) {$usage_file = $opt_f;} Xif (!($opt_g || $opt_w || $opt_p || $opt_n)) {$opt_F = 1;} X X X Xtype: Xforeach $_ (keys %filetypes) { X if (eval "defined(\$$_);") { X if ($foundone) { X print STDERR "More than one report type specified\n"; X print STDERR "You must use the -m switch to summarize multiple types\n"; X exit; X } X $filestogrind{$_}=$usagefiles{$_}; X $foundone=1 unless $opt_m; X next type; X } X} X Xgrep ($reporttype="$filetypes{$_} $reporttype",keys(%filestogrind)); Xprint "This report is for $reporttype transfers.\n\n"; X Xforeach $filetype (keys(%filestogrind)) { X X $usage_file = $filestogrind{$filetype} unless $opt_f; X $optarg = eval "\$$filetype"; X $opt_s = $optarg unless $optarg==1; X X X if ($opt_D) { X print "$filetypes{$filetype} Transfer Totals include the '$opt_D' domain only.\n"; X print "All other domains are filtered out for this report.\n\n"; X } X X if ($opt_s) { X print "$filetypes{$filetype} Transfer Totals include the '$opt_s' section only.\n"; X print "All other sections are filtered out for this report.\n\n"; X } X X open (LOG,$usage_file) || die "Error opening usage log file: $usage_file\n"; X X X X line: while () { X X @line = split; X $finished=0; X if ($filetype eq 'opt_F') { X next line if ($#line != 16); X next line if (!$anon && $line[12] eq "a"); X next line if (!$real && $line[12] eq "r"); X } X if ($filetype eq 'opt_p') { X next line if /^----/; #informational message X next line if $line[7] ne 'GET'; #does this happen? X } X if ($filetype eq 'opt_w') { X if ($line[7] eq "Accepted") { X $hostpid{$line[0]}=$line[10]; X next line; X } X if ($line[7] eq "Done") { X $afield=$hostpid{$line[0]}; X $hostpid{$line[0]} =~ /^\[(\d+\.\d+\.\d+\.\d+)\],$/; X $afield = $1 if $1; X $fsize=$sizepid{$line[0]}; X $numfiles=$numpid{$line[0]}; X ($daytime,$time,$fname)=split('/',$infopid{$line[0]}); X delete $hostpid{$line[0]}; X delete $numpid{$line[0]}; X delete $docidpid{$line[0]}; X delete $sizepid{$line[0]}; X delete $infopid{$line[0]}; X if ($daytime eq '' || $afield eq '' || $fsize == 0) { X #no retrievals for this search X next line; X } X $finished=1; X } X next line if ($line[8] ne "DocID:"); X } X X if (!$finished) { X X #fill in these fields for each logtype (daytime,time,fsize,fname) X LOGTYPE: { X if ($filetype eq 'opt_F' || $filetype eq 'opt_g') { X $afield=$line[6]; X $daytime = substr($_, 4, 6) . substr($_, 19, 5); X $time = substr($_,11,2); X } X if ($filetype eq 'opt_F') { X $fname=$line[8]; X $fsize = $line[7]; X $xfsecs = $line[5]; X if ($fname eq "\.") { $fname = "/unreadable/filename";} X $numfiles=1; X last LOGTYPE; X } X if ($filetype eq 'opt_n') { X $fname=$line[7]; X $fsize=(-s "$httpdroot/$fname"); X /\[(.*)\]/; X $daytime = substr($1, 4, 6) . substr($1, 19, 5); X $time = substr($1,11,2); X $numfiles=1; X $afield=$line[0]; X last LOGTYPE; X } X if ($filetype eq 'opt_p') { X $fname=$line[8]; X $fsize=(-s "$httpdroot/$fname"); X /^\S+\s+(.*)/; X $daytime = substr($1, 4, 6) . substr($1, 23, 5); X $time = substr($1,11,2); X $numfiles=1; X $afield=$line[0]; X last LOGTYPE; X } X if ($filetype eq 'opt_w') { X /^\d+: \d+: (.*)/; #get rid of stupid variable length stuff X $daytime = substr($1, 0, 7) . substr($1, 16, 4); X $time = substr($line[4],0,2); X @path=split('/',$line[17]); X $infopid{$line[0]} = "$daytime/$time/$path[$#path]"; X $line[13] =~ s/,$//; X $sizepid{$line[0]} += ($line[14]-$line[13]); X $numpid{$line[0]}++ if $docidpid{$line[0]} != "$line[10] $line[11]"; X $docidpid{$line[0]} = "$line[10] $line[11]"; X $xfsecs = 0; X $avgrate = '0.0 KB/s'; X last LOGTYPE; X next line; X } X if ($filetype eq 'opt_g') { X if ( $line[9] eq "range") { X $fsize=$line[12]-$line[10]; X $fname=$line[15]; X $fname=~s:^(/../)+:/:; X } X else { X next line if ( $line[9] ne "file"); X $fname=$line[10]; X $fname=~s:^(/../)+:/:; X $fname=~s://:/:; X $fsize = (-s "$gopherroot/$fname"); X } X $numfiles=1; X last LOGTYPE; X } X } X next if (substr($fname,0,length("$opt_s")) ne "$opt_s"); X $fname = substr($fname,length("$opt_s")); X @path = split(/\//, $fname); X } X X # Uncomment this line to show records being processed. X # print $daytime," ",$time," ",$fsize," ",$fname,"\n"; X X # Things in the top-level directory are assumed to be informational files X X LOGTYPE: { X if ($filetype eq 'opt_F' || $filetype eq 'opt_g' || $filetype eq 'opt_p') { X if ($#path == 1) { $pathkey = "Index/Informational Files"; } X else { X $pathkey = ""; X for ($i=1; $i <= $#path-1 && $i <= $opt_l;$i++) { X $pathkey = "$pathkey/$path[$i]"; X } X } X last LOGTYPE; X } X if ($filetype eq 'opt_w') { X $pathkey=$fname; X last LOGTYPE; X } X X } X X next line if $pathkey eq ''; X X $afield =~ tr/A-Z/a-z/; X X @address = split(/\./, $afield); X X $domain = $address[$#address]; X if ($domain eq "$mydom2" && $address[$#address-1] eq "$mydom1") X { $domain = "$mydom1.$mydom2"; } X if ( $address[0] =~ /^[0-9]+$/ ) { $domain = "unresolved"; } X if ( $#address < 2 ) { $domain = "localhost"; } X X $count = 1; X if ($opt_D) { X if (substr($domain,0,length("$opt_D")) eq "$opt_D" ) { $count = 1;} X else {$count = 0;} X } X X if ($count) { X X $xferfiles +=$numfiles; # total files sent X $xferfiles{$daytime} +=$numfiles; # files per day X $groupfiles{$pathkey}++; # per-group accesses X $domainfiles{$domain}++; X X $xfersecs{$daytime} += $xfsecs; # xmit seconds per day X $domainsecs{$domain} += $xfsecs; # xmit seconds for domain X $xferbytes{$daytime} += $fsize; # bytes per day X $domainbytes{$domain} += $fsize; # xmit bytes to domain X $xferbytes += $fsize; # total bytes sent X $groupbytes{$pathkey} += $fsize; # per-group bytes sent X X $xfertfiles{$time}++; # files per hour X $xfertsecs{$time} += $xfsecs; # xmit seconds per hour X $xfertbytes{$time} += $fsize; # bytes per hour X $xfertbytes += $fsize; # total bytes sent X } X } X close LOG; X} X X X@dates = sort datecompare keys(xferbytes); X Xif ($xferfiles == 0) {die "There was no data to process.\n";} X X Xprint "TOTALS FOR SUMMARY PERIOD ", $dates[0], " TO ", $dates[$#dates], "\n\n"; Xprintf ("Files Transmitted During Summary Period %12.0f\n", $xferfiles); Xprintf ("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes); X Xprintf ("Average Files Transmitted Daily %12.0f\n", X $xferfiles / ($#dates + 1)); Xprintf ("Average Bytes Transmitted Daily %12.0f\n", X $xferbytes / ($#dates + 1)); X Xformat top1 = X XDaily Transmission Statistics X X Number Of Number of Average Percent Of Percent Of X Date Files Sent Bytes Sent Xmit Rate Files Sent Bytes Sent X--------------- ---------- ----------- ---------- ---------- ---------- X. X Xformat line1 = X@<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>>>> @>>>>>>> @>>>>>>> X$date, $nfiles, $nbytes, $avgrate, $pctfiles, $pctbytes X. X X$^ = top1; X$~ = line1; X Xforeach $date ( sort datecompare keys(xferbytes) ) { X X $nfiles = $xferfiles{$date}; X $nbytes = $xferbytes{$date}; X $avgrate = sprintf("%5.1f KB/s", $xferbytes{$date}/$xfersecs{$date}/1000) if$xfersecs{$date}; X $pctfiles = sprintf("%8.2f", 100*$xferfiles{$date} / $xferfiles); X $pctbytes = sprintf("%8.2f", 100*$xferbytes{$date} / $xferbytes); X write; X} X Xif ($opt_t) { X format top2 = X XTotal Transfers from each Archive Section (By bytes) X X ---- Percent Of ---- X Archive Section Files Sent Bytes Sent Files Sent Bytes Sent X------------------------- ---------- ----------- ---------- ---------- X. X X format line2 = X@<<<<<<<<<<<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>> @>>>>>>> X$section, $files, $bytes, $pctfiles, $pctbytes X. X X $| = 1; X $- = 0; X $^ = top2; X $~ = line2; X X foreach $section ( sort bytecompare keys(groupfiles) ) { X X $files = $groupfiles{$section}; X $bytes = $groupbytes{$section}; X $pctbytes = sprintf("%8.2f", 100 * $groupbytes{$section} / $xferbytes); X $pctfiles = sprintf("%8.2f", 100 * $groupfiles{$section} / $xferfiles); X write; X X } X X if ( $xferfiles < 1 ) { $xferfiles = 1; } X if ( $xferbytes < 1 ) { $xferbytes = 1; } X} X Xif ($opt_d) { X format top3 = X XTotal Transfer Amount By Domain X#changes listing by domain to listing by country X X Number Of Number of Average Percent Of Percent Of XDomain Name Files Sent Bytes Sent Xmit Rate Files Sent Bytes Sent X----------- ---------- ------------ ---------- ---------- ---------- X. X X format line3 = X@<<<<<<<<<<<<<<< @>>>>> @>>>>>>>>>>> @>>>>>>>>> @>>>>>>> @>>>>>>> X$country, $files, $bytes, $avgrate, $pctfiles, $pctbytes X. X X $- = 0; X $^ = top3; X $~ = line3; X X %codetable=&initcountryname(); X foreach $domain ( sort domnamcompare keys(domainfiles) ) { X X if ( $domainsecs{$domain} < 1 ) { $domainsecs{$domain} = 1; } X X $country = $domain; #added by jem X $country = &countryname($domain,%codetable); X $country = $domain if $country eq ''; X $files = $domainfiles{$domain}; X $bytes = $domainbytes{$domain}; X if ($domainsec{$domain}) { X $avgrate = sprintf("%5.1f KB/s", X $domainbytes{$domain}/$domainsecs{$domain}/1000); X } X $pctfiles = sprintf("%8.2f", 100 * $domainfiles{$domain} / $xferfiles); X $pctbytes = sprintf("%8.2f", 100 * $domainbytes{$domain} / $xferbytes); X write; X X } X X X} X Xif ($opt_h) { X X format top8 = X XHourly Transmission Statistics X X Number Of Number of Average Percent Of Percent Of X Time Files Sent Bytes Sent Xmit Rate Files Sent Bytes Sent X--------------- ---------- ----------- ---------- ---------- ---------- X. X X format line8 = X@<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>>>> @>>>>>>> @>>>>>>> X$time, $nfiles, $nbytes, $avgrate, $pctfiles, $pctbytes X. X X X $| = 1; X $- = 0; X $^ = top8; X $~ = line8; X X foreach $time ( sort keys(xfertbytes) ) { X X $nfiles = $xfertfiles{$time}; X $nbytes = $xfertbytes{$time}; X $avgrate = sprintf("%5.1f KB/s", $xfertbytes{$time}/$xfertsecs{$time}/1000) if $xfertsecs{$time}; X $pctfiles = sprintf("%8.2f", 100*$xfertfiles{$time} / $xferfiles); X $pctbytes = sprintf("%8.2f", 100*$xfertbytes{$time} / $xferbytes); X write; X } X} Xexit(0); X Xsub initcountryname { X #read in table of ISO codes and country names -added by jem X open (blah, "<$countrycodefile") || die "Can't open $countrycodefile"; X while () { X chop; X local($iso,$name)=split(' '); X $iso =~ y/A-Z/a-z/; X $code{$iso}=$name; X } X close blah; X return %code; X} X Xsub countryname { X #returns country name for an iso code X local($iso, %codetable) = @_; X return $codetable{$iso}; X} X Xsub datecompare { X X $date1 = substr($a, 7, 4) * 4800; X $date2 = substr($b, 7, 4) * 4800; X $date1 += index("JanFebMarAprMayJunJulAugSepOctNovDec",substr($a, 0, 3))*400; X $date2 += index("JanFebMarAprMayJunJulAugSepOctNovDec",substr($b, 0, 3))*400; X $date1 += substr($a, 4, 2); X $date2 += substr($b, 4, 2); X $date1 - $date2; X X} X Xsub domnamcompare { X X $sdiff = length($a) - length($b); X ($sdiff < 0) ? -1 : ($sdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0; X X} X Xsub bytecompare { X X $bdiff = $groupbytes{$b} - $groupbytes{$a}; X ($bdiff < 0) ? -1 : ($bdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0; X X} X Xsub faccompare { X X $fdiff = $fac{$b} - $fac{$a}; X ($fdiff < 0) ? -1 : ($fdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0; X X} X END-of-fwgstat echo x - mygetopts.pl sed 's/^X//' >mygetopts.pl << 'END-of-mygetopts.pl' X;# mygetopts.pl - getopts.pl with optional args added (a kludge) X X;# Usage: X;# do MyGetopts('a:b?c'); # -a takes arg. -b takes optional arg. X;# & -c takes no arg. Sets opt_* as a side effect. X Xsub MyGetopts { X local($argumentative) = @_; X local(@args,$_,$first,$rest); X local($errs) = 0; X local($[) = 0; X X @args = split( / */, $argumentative ); X while(@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) { X ($first,$rest) = ($1,$2); X $pos = index($argumentative,$first); X if($pos >= $[) { X if($args[$pos+1] eq ':' || $args[$pos+1] eq '?') { X shift(@ARGV); X if($rest eq '') { X ++$errs unless @ARGV || $args[$pos+1] eq '?'; X $rest = shift(@ARGV); X } X if ($args[$pos+1] eq ':') { X eval "\$opt_$first = \$rest;" ; X } X else { X if ($rest ne '') { X if ($rest !~ /^-/) { X eval "\$opt_$first = \$rest;" X } X else { X unshift(@ARGV,$rest); X eval "\$opt_$first = 1"; X } X } X else { X eval "\$opt_$first = 1"; X } X X } X } X else { X eval "\$opt_$first = 1"; X if($rest eq '') { X shift(@ARGV); X } X else { X $ARGV[0] = "-$rest"; X } X } X } X else { X print STDERR "Unknown option: $first\n"; X ++$errs; X if($rest ne '') { X $ARGV[0] = "-$rest"; X } X else { X shift(@ARGV); X } X } X } X $errs == 0; X} X X1; END-of-mygetopts.pl exit