http://www.jwz.org/xscreensaver/xscreensaver-5.12.tar.gz
[xscreensaver] / driver / xscreensaver-text
index 8eeaf8968e8002f547f50d66d58e5546bb16e95a..24149408bb05b4faa9e7ae385d2fc2e210f2f6a5 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-# Copyright © 2005-2008 Jamie Zawinski <jwz@jwz.org>
+# Copyright © 2005-2010 Jamie Zawinski <jwz@jwz.org>
 #
 # Permission to use, copy, modify, distribute, and sell this software and its
 # documentation for any purpose is hereby granted without fee, provided that
@@ -30,7 +30,7 @@ use Text::Wrap qw(wrap);
 use bytes;
 
 my $progname = $0; $progname =~ s@.*/@@g;
-my $version = q{ $Revision: 1.17 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
+my $version = q{ $Revision: 1.22 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
 
 my $verbose = 0;
 my $http_proxy = undef;
@@ -132,15 +132,19 @@ sub de_entify($) {
   my ($text) = @_;
   $text =~ s/(&(\#)?([[:alpha:]\d]+);?)/
     {
-     my $c;
-     if ($2) {
-       $c = chr($3);  # the &#number is always decimal, right?
+     my $c = $3;
+     if (! defined($2)) {
+       $c = $entity_table{$c};         # for &Aacute;
      } else {
-       $c = $entity_table{$3};
+       if ($c =~ m@^x([\dA-F]+)$@si) { # for &#x41;
+         $c = chr(hex($1));
+       } elsif ($c =~ m@^\d+$@si) {    # for &#65;
+         $c = chr($c);
+       } else {
+         $c = undef;
+       }
      }
-#    print STDERR "$progname: warning: unknown HTML character entity \"$1\"\n"
-#     unless $c;
-     ($c ? $c : "[$3]");
+     ($c || "[$3]");                   # for &unknown; => "[unknown]"
     }
    /gexi;
   return $text;
@@ -424,7 +428,8 @@ sub output() {
 sub get_url_1($;$) {
   my ($url, $referer) = @_;
   
-  if (! ($url =~ m@^(http|feed)://@i)) {
+  $url =~ s@^feed:@http:@si;
+  if (! ($url =~ m@^http://@i)) {
     error ("not an HTTP URL: $url");
   }
 
@@ -610,8 +615,18 @@ sub reformat_html($$) {
   my ($body, $rss_p) = @_;
   $_ = $body;
 
+  # In HTML, try to preserve newlines inside of PRE.
+  #
+  if (! $rss_p) {
+    s@(<PRE\b[^<>]*>\s*)(.*?)(</PRE)@{
+      my ($a, $b, $c) = ($1, $2, $3);
+      $b =~ s/[\r\n]/<BR>/gs;
+      $a . $b . $c;
+     }@gsexi;
+  }
+
   if (! $rss_p) {
-    # In HTML, unfold lines (this breaks PRE.  Sue me.)
+    # In HTML, unfold lines.
     # In RSS, assume \n means literal line break.
     s@[\r\n]@ @gsi;
   }
@@ -751,17 +766,42 @@ sub reformat_text($) {
 }
 
 
-sub get_url_text($) {
-  my ($url) = @_;
+# Figure out what the proxy server should be, either from environment
+# variables or by parsing the output of the (MacOS) program "scutil",
+# which tells us what the system-wide proxy settings are.
+#
+sub set_proxy() {
 
   # historical suckage: the environment variable name is lower case.
   $http_proxy = $ENV{http_proxy} || $ENV{HTTP_PROXY};
 
-  if ($http_proxy && $http_proxy =~ m@^http://([^/]*)/?$@ ) {
-    # historical suckage: allow "http://host:port" as well as "host:port".
-    $http_proxy = $1;
+  if (defined ($http_proxy)) {
+    if ($http_proxy && $http_proxy =~ m@^http://([^/]*)/?$@ ) {
+      # historical suckage: allow "http://host:port" as well as "host:port".
+      $http_proxy = $1;
+    }
+
+  } else {
+    my $proxy_data = `scutil --proxy 2>/dev/null`;
+    my ($server) = ($proxy_data =~ m/\bHTTPProxy\s*:\s*([^\s]+)/s);
+    my ($port)   = ($proxy_data =~ m/\bHTTPPort\s*:\s*([^\s]+)/s);
+    # Note: this ignores the "ExceptionsList".
+    if ($server) {
+      $http_proxy = $server;
+      $http_proxy .= ":$port" if $port;
+    }
   }
 
+  print STDERR "$progname: proxy server: $http_proxy\n" 
+    if ($verbose > 2 && $http_proxy);
+}
+
+
+sub get_url_text($) {
+  my ($url) = @_;
+
+  set_proxy();
+
   my ($ct, $body) = get_url ($url);
 
   $ct = guess_content_type ($ct, $body);
@@ -827,16 +867,16 @@ sub main() {
     elsif (m/^--?date$/)    { $text_mode = 'date';
                               $load_p = 0; }
     elsif (m/^--?text$/)    { $text_mode = 'literal';
-                              $text_literal = shift @ARGV;
+                              $text_literal = shift @ARGV || '';
                               $load_p = 0; }
     elsif (m/^--?file$/)    { $text_mode = 'file';
-                              $text_file = shift @ARGV;
+                              $text_file = shift @ARGV || '';
                               $load_p = 0; }
     elsif (m/^--?program$/) { $text_mode = 'program';
-                              $text_program = shift @ARGV;
+                              $text_program = shift @ARGV || '';
                               $load_p = 0; }
     elsif (m/^--?url$/)     { $text_mode = 'url';
-                              $text_url = shift @ARGV;
+                              $text_url = shift @ARGV || '';
                               $load_p = 0; }
     elsif (m/^--?col(umn)?s?$/) { $wrap_columns = 0 + shift @ARGV; }
     elsif (m/^--?cocoa$/)   { $cocoa_id = shift @ARGV; }
@@ -860,6 +900,42 @@ sub main() {
   }
 
   output();
+
+
+  if (defined ($cocoa_id)) {
+    #
+    # On MacOS, sleep for 10 seconds between when the last output is
+    # printed, and when this process exits.  This is because MacOS
+    # 10.5.0 and later broke ptys in a new and exciting way: basically,
+    # once the process at the end of the pty exits, you have exactly
+    # 1 second to read all the queued data off the pipe before it is
+    # summarily flushed.
+    #
+    # Many of the screen savers were written to depend on being able
+    # to read a small number of bytes, and continue reading until they
+    # reached EOF.  This is no longer possible.
+    #
+    # Note that the current MacOS behavior has all three of these
+    # awesome properties: 1) Inconvenient; 2) Has no sane workaround;
+    # 3) Different behavior than MacOS 10.1 through 10.4; and 4)
+    # Different behavior than every other Unix in the world.
+    #
+    # See http://jwz.livejournal.com/817438.html, and for those of
+    # you inside Apple, "Problem ID 5606018".
+    #
+    # One workaround would be to rewrite the savers to have an
+    # internal buffer, and always read as much data as possible as
+    # soon as a pipe has input available.  However, that's a lot more
+    # work, so instead, let's just not exit right away, and hope that
+    # 10 seconds is enough.
+    #
+    # This will solve the problem for invocations of xscreensaver-text
+    # that produce little output (e.g., date-mode); and won't solve it
+    # in cases where a large amount of text is generated in a short
+    # amount of time (e.g., url-mode.)
+    #
+    sleep (10);
+  }
 }
 
 main();