New command line option: unfollowed-links

"Tony Lewis" <[email protected]> Tue, 28 Jun 2005 18:01:20 -0700
Newsgroups gmane.comp.web.wget.patches
Message-ID <[email protected]>
The following patch adds a command line option that allows one to specify a
file to capture all links that wget ignores because of other command line
options. For example:
 
wget http://www.somesite.com --mirror --unfollowed-links=somesite.txt
 
will result in the file somesite.txt containing all external links from
somesite.com. I originally wrote this feature for wget version 1.8.1, but
never submitted it because I wasn't sure what to do with the ChangeLog and
other documentation. I'm submitting it anyway in the hopes that Hrvoje can
fill in the gaps. :-)
 
Hrvoje, I was prompted to send this now by the message from Dan Jacobson
with the subject "add --print-uris or --dry-run". My submission does not
provide the exact functionality that is requested, but I think the concept
may prove useful as you consider that feature.
 
2005-06-28  Tony Lewis <[email protected]>
 
        * main.c: Added --unfollowed-links option.
        * init.c: Added initialization for opt.unfollowed.
        * recur.c: Added code to record links that are not followed and
restored
        recursive_cleanup.
        * gen-md5.c: Added include of <stdio.h> to eliminate compile error.
        * options.h: Defined ufp and unfollowed.
        * recur.h: Defined unfollowed.
 
Index: main.c
===================================================================
--- main.c (version 1.10)
+++ main.c (working copy)
@@ -258,6 +258,7 @@
     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
     { "tries", 't', OPT_VALUE, "tries", -1 },
+    { "unfollowed-links", 0, OPT_VALUE, "unfollowedlinks", -1 },
     { "user", 0, OPT_VALUE, "user", -1 },
     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
@@ -633,6 +634,8 @@
     N_("\
   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
     N_("\
+       --unfollowed-links=FILE     log unfollowed links to FILE.\n"),
+    N_("\
   -np, --no-parent                 don't ascend to the parent
directory.\n"),
     "\n",

@@ -821,6 +824,13 @@
        opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive()
*/
     }

+  if (opt.unfollowed && !opt.recursive)
+    {
+      printf (_("%s: Must be recursive to have unfollowed links\n"),
exec_name);
+      print_usage ();
+      exit (1);
+    }
+
   if (opt.verbose == -1)
     opt.verbose = !opt.quiet;

@@ -906,6 +916,17 @@
            }
          if (fstat (fileno (output_stream), &st) == 0 && S_ISREG
(st.st_mode))
            output_stream_regular = 1;
+       }
+    }
+
+  /* Open the unfollowed links filename if necessary.  */
+  if (opt.unfollowed)
+    {
+      opt.ufp = fopen (opt.unfollowed, "wb");
+      if (opt.ufp == NULL)
+       {
+         perror (opt.unfollowed);
+         exit (1);
        }
     }

Index: init.c
===================================================================
--- init.c (version 1.10)
+++ init.c (working copy)
@@ -238,6 +238,7 @@
   { "timeout",         NULL,                   cmd_spec_timeout },
   { "timestamping",    &opt.timestamping,      cmd_boolean },
   { "tries",           &opt.ntry,              cmd_number_inf },
+  { "unfollowedlinks",  &opt.unfollowed,        cmd_file },
   { "useproxy",                &opt.use_proxy,         cmd_boolean },
   { "user",            &opt.user,              cmd_string },
   { "useragent",       NULL,                   cmd_spec_useragent },
@@ -572,7 +573,7 @@
   p = line;

   cmdstart = p;
-  while (p < end && (ISALPHA (*p) || *p == '_' || *p == '-'))
+  while (p < end && (ISALNUM (*p) || *p == '_' || *p == '-'))
     ++p;
   cmdend = p;

@@ -1471,6 +1472,9 @@
        checks for errors) after any data arrives.  */
   }

+  if (opt.ufp)
+    fclose (opt.ufp);
+
   /* We're exiting anyway so there's no real need to call free()
      hundreds of times.  Skipping the frees will make Wget exit
      faster.
@@ -1480,6 +1484,7 @@
      memory which grows with the size of the program.  */

 #ifdef DEBUG_MALLOC
+  recursive_cleanup ();
   convert_cleanup ();
   res_cleanup ();
   http_cleanup ();
@@ -1525,6 +1530,8 @@
   xfree_null (opt.bind_address);
   xfree_null (opt.cookies_input);
   xfree_null (opt.cookies_output);
+  xfree_null (opt.unfollowed);
+  xfree_null (opt.ufp);
   xfree_null (opt.user);
   xfree_null (opt.passwd);
 #endif /* DEBUG_MALLOC */

Index: recur.c
===================================================================
--- recur.c (version 1.10)
+++ recur.c (working copy)
@@ -63,6 +63,8 @@

 extern struct hash_table *dl_url_file_map;
 extern struct hash_table *downloaded_html_set;
+struct hash_table *unfollowed_logged;
+


 /* Functions for maintaining the URL queue.  */

@@ -118,7 +120,7 @@
   if (queue->count > queue->maxcount)
     queue->maxcount = queue->count;

-  DEBUGP (("Enqueuing %s at depth %d\n", url, depth));
+  DEBUGP (("Enqueuing %s at depth %d (from %s)\n", url, depth, referer));
   DEBUGP (("Queue count %d, maxcount %d.\n", queue->count,
queue->maxcount));

   if (queue->tail)
@@ -328,6 +330,14 @@

          if (opt.use_robots && meta_disallow_follow)
            {
+              if (opt.ufp)
+                {
+                 struct urlpos *child = children;
+
+                 for (; child; child = child->next)
+                     unfollowed(child->url->url);
+                }
+
              free_urlpos (children);
              children = NULL;
            }
@@ -341,9 +351,15 @@
              for (; child; child = child->next)
                {
                  if (child->ignore_when_downloading)
-                   continue;
+                    {
+                     unfollowed(child->url->url);
+                     continue;
+                    }
                  if (dash_p_leaf_HTML && !child->link_inline_p)
-                   continue;
+                    {
+                     unfollowed(child->url->url);
+                     continue;
+                    }
                  if (download_child_p (child, url_parsed, depth,
start_url_parsed,
                                        blacklist))
                    {
@@ -433,7 +449,7 @@
   if (string_set_contains (blacklist, url))
     {
       DEBUGP (("Already on the black list.\n"));
-      goto out;
+      goto out_blacklist;
     }

   /* Several things to check for:
@@ -588,6 +604,8 @@
   return 1;

  out:
+  unfollowed(u->url);
+ out_blacklist:
   DEBUGP (("Decided NOT to load it.\n"));

   return 0;
@@ -626,4 +644,31 @@
     DEBUGP (("Redirection \"%s\" failed the test.\n", redirected));

   return success;
+}
+
+/* Cleanup the data structures associated with recursive retrieving
+   (the variables above).  */
+void
+recursive_cleanup (void)
+{
+  if (unfollowed_logged)
+    string_set_free (unfollowed_logged);
+  unfollowed_logged = NULL;
+}
+
+/* Record unfollowed links */
+void
+unfollowed (const char *url)
+{
+  if (!opt.ufp)
+    return;
+
+  if (unfollowed_logged == NULL)
+    unfollowed_logged = make_string_hash_table (0);
+
+  if (string_set_contains (unfollowed_logged, url))
+    return;
+
+  string_set_add (unfollowed_logged, url);
+  fprintf(opt.ufp, "%s\n", url);
 }

Index: gen-md5.c
===================================================================
--- gen-md5.c (version 1.10)
+++ get-md5.c (working copy)
@@ -28,6 +28,7 @@
 so, delete this exception statement from your version.  */

 #include <config.h>
+#include <stdio.h>
 #include "wget.h"

 #include "gen-md5.h"

Index: options.h
===================================================================
--- options.h (version 1.10)
+++ options.h (working copy)
@@ -219,6 +219,11 @@
     prefer_none
   } prefer_family;             /* preferred address family when more
                                   than one type is available */
+
+  FILE *ufp;                   /* The file pointer to the unfollowed links
+                                  file. */
+  char *unfollowed;             /* The file to which unfollowed links will
+                                   be recorded. */
 };

 extern struct options opt;

Index: recur.h
===================================================================
--- recur.h (version 1.10)
+++ recur.h (working copy)
 struct urlpos *get_urls_html PARAMS ((const char *, const char *, int *));
 void free_urlpos PARAMS ((struct urlpos *));

+void unfollowed PARAMS ((const char *));
+
 #endif /* RECUR_H */