Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
6.3 KiB

  1. @rem = '--*-Perl-*--
  2. @echo off
  3. if "%OS%" == "Windows_NT" goto WinNT
  4. perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
  5. goto endofperl
  6. :WinNT
  7. perl -x -S "%0" %*
  8. if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl
  9. if %errorlevel% == 9009 echo You do not have Perl in your PATH.
  10. goto endofperl
  11. @rem ';
  12. #!perl -w
  13. #line 14
  14. # $Id: lwp-download.PL,v 1.10 1999/03/19 14:06:30 gisle Exp $
  15. =head1 NAME
  16. lwp-download - fetch large files from the net
  17. =head1 SYNOPSIS
  18. lwp-download [-a] <url> [<local file>]
  19. =head1 DESCRIPTION
  20. The I<lwp-download> program will down load the document specified by the URL
  21. given as the first command line argument to a local file. The local
  22. filename used to save the document is guessed from the URL unless
  23. specified as the second command line argument.
  24. The I<lwp-download> program is implemented using the I<libwww-perl>
  25. library. It is better suited to down load big files than the
  26. I<lwp-request> program because it does not store the file in memory.
  27. Another benefit is that it will keep you updated about its progress
  28. and that you don't have much options to worry about.
  29. Use the C<-a> option to save the file in text (ascii) mode. Might make a
  30. difference on dosish systems.
  31. =head1 EXAMPLE
  32. Fetch the newest and greatest perl version:
  33. $ lwp-download http://www.perl.com/CPAN/src/latest.tar.gz
  34. Saving to 'latest.tar.gz'...
  35. 1.47 MB received in 22 seconds (68.7 KB/sec)
  36. =head1 AUTHOR
  37. Gisle Aas <[email protected]>
  38. =cut
  39. use strict;
  40. use LWP::UserAgent ();
  41. use LWP::MediaTypes qw(guess_media_type media_suffix);
  42. use URI ();
  43. use HTTP::Date ();
  44. my $progname = $0;
  45. $progname =~ s,.*/,,; # only basename left in progname
  46. $progname =~ s/\.\w*$//; # strip extension if any
  47. #parse option
  48. use Getopt::Std;
  49. my %opt;
  50. unless (getopts('a', \%opt)) {
  51. usage();
  52. }
  53. my $url = URI->new(shift || usage());
  54. my $argfile = shift;
  55. my $version = q$Revision: 1.10 $;
  56. my $ua = new LWP::UserAgent;
  57. $ua->agent("lwp-download/$version " . $ua->agent);
  58. $ua->env_proxy;
  59. my $req = new HTTP::Request GET => $url;
  60. my $file; # name of file we download into
  61. my $length; # total number of bytes to download
  62. my $flength; # formatted length
  63. my $size = 0; # number of bytes received
  64. my $start_t; # start time of download
  65. my $last_dur; # time of last callback
  66. my $shown = 0; # have we called the show() function yet
  67. $SIG{INT} = sub { die "Interrupted\n"; };
  68. $| = 1; # autoflush
  69. my $res = $ua->request($req,
  70. sub {
  71. unless($file) {
  72. my $res = $_[1];
  73. unless ($argfile) {
  74. # must find a suitable name to use. First thing
  75. # to do is to look for the "Content-Disposition"
  76. # header defined by RFC1806. This is also supported
  77. # by Netscape
  78. my $cd = $res->header("Content-Disposition");
  79. if ($cd && $cd =~ /\bfilename\s*=\s*(\S+)/) {
  80. $file = $1;
  81. $file =~ s/;$//;
  82. $file =~ s/^([\"\'])(.*)\1$/$2/;
  83. }
  84. # if this fails we try to make something from the URL
  85. unless ($file) {
  86. my $req = $res->request; # now always there
  87. my $rurl = $req ? $req->url : $url;
  88. $file = ($rurl->path_segments)[-1];
  89. unless (length $file) {
  90. $file = "index";
  91. my $suffix = media_suffix($res->content_type);
  92. $file .= ".$suffix" if $suffix;
  93. } elsif ($rurl->scheme eq 'ftp' ||
  94. $file =~ /\.tgz$/ ||
  95. $file =~ /\.tar(\.(Z|gz))?$/
  96. ) {
  97. # leave the filename as it was
  98. } else {
  99. my $ct = guess_media_type($file);
  100. unless ($ct eq $res->content_type) {
  101. # need a better suffix for this type
  102. my $suffix = media_suffix($res->content_type);
  103. $file .= ".$suffix" if $suffix;
  104. }
  105. }
  106. }
  107. # Check if the file is already present
  108. if (-f $file && -t) {
  109. print "Overwrite $file? [y] ";
  110. my $ans = <STDIN>;
  111. exit if !defined($ans) || !($ans =~ /^y?\n/);
  112. } else {
  113. print "Saving to '$file'...\n";
  114. }
  115. } else {
  116. $file = $argfile;
  117. }
  118. open(FILE, ">$file") || die "Can't open $file: $!";
  119. binmode FILE unless $opt{a};
  120. $length = $res->content_length;
  121. $flength = fbytes($length) if defined $length;
  122. $start_t = time;
  123. $last_dur = 0;
  124. }
  125. $size += length($_[0]);
  126. print FILE $_[0];
  127. if (defined $length) {
  128. my $dur = time - $start_t;
  129. if ($dur != $last_dur) { # don't update too often
  130. $last_dur = $dur;
  131. my $perc = $size / $length;
  132. my $speed;
  133. $speed = fbytes($size/$dur) . "/sec" if $dur > 3;
  134. my $secs_left = fduration($dur/$perc - $dur);
  135. $perc = int($perc*100);
  136. my $show = "$perc% of $flength";
  137. $show .= " (at $speed, $secs_left remaining)" if $speed;
  138. show($show, 1);
  139. }
  140. } else {
  141. show( fbytes($size) . " received");
  142. }
  143. }
  144. );
  145. if ($res->is_success || $res->message =~ /^Interrupted/) {
  146. show(""); # clear text
  147. print "\r";
  148. print fbytes($size);
  149. print " of ", fbytes($length) if defined($length) && $length != $size;
  150. print " received";
  151. my $dur = time - $start_t;
  152. if ($dur) {
  153. my $speed = fbytes($size/$dur) . "/sec";
  154. print " in ", fduration($dur), " ($speed)";
  155. }
  156. print "\n";
  157. my $died = $res->header("X-Died");
  158. if ($died || !$res->is_success) {
  159. if (-t) {
  160. print "Transfer aborted. Delete $file? [n] ";
  161. my $ans = <STDIN>;
  162. unlink($file) if defined($ans) && $ans =~ /^y\n/;
  163. } else {
  164. print "Transfer aborted, $file kept\n";
  165. }
  166. }
  167. } else {
  168. print "\n" if $shown;
  169. print "$progname: ", $res->status_line, "\n";
  170. exit 1;
  171. }
  172. sub fbytes
  173. {
  174. my $n = int(shift);
  175. if ($n >= 1024 * 1024) {
  176. return sprintf "%.3g MB", $n / (1024.0 * 1024);
  177. } elsif ($n >= 1024) {
  178. return sprintf "%.3g KB", $n / 1024.0;
  179. } else {
  180. return "$n bytes";
  181. }
  182. }
  183. sub fduration
  184. {
  185. use integer;
  186. my $secs = int(shift);
  187. my $hours = $secs / (60*60);
  188. $secs -= $hours * 60*60;
  189. my $mins = $secs / 60;
  190. $secs %= 60;
  191. if ($hours) {
  192. return "$hours hours $mins minutes";
  193. } elsif ($mins >= 2) {
  194. return "$mins minutes";
  195. } else {
  196. $secs += $mins * 60;
  197. return "$secs seconds";
  198. }
  199. }
  200. BEGIN {
  201. my @ani = qw(- \ | /);
  202. my $ani = 0;
  203. sub show
  204. {
  205. my($mess, $show_ani) = @_;
  206. print "\r$mess" . (" " x (75 - length $mess));
  207. print $show_ani ? "$ani[$ani++]\b" : " ";
  208. $ani %= @ani;
  209. $shown++;
  210. }
  211. }
  212. sub usage
  213. {
  214. die "Usage: $progname [-a] <url> [<lpath>]\n";
  215. }
  216. __END__
  217. :endofperl