add support for uppercase and lowercase in --restrict-file-names

Mauro Tortonesi <[email protected]> Tue, 13 Jun 2006 15:53:12 +0200
Newsgroups gmane.comp.web.wget.patches
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--------------050306030406090702000101
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit


this patch adds support for character case restrictions by introducing the 
new 'uppercase' and 'lowercase' modes in the --restrict-file-names option.


2006-06-13  Mauro Tortonesi  <[email protected]>

	* options.h (struct options): Introduced member restrict_files_case
         to keep track of preferences on character case restrictions for
	filenames.

	* init.c: Modified defaults and cmd_spec_restrict_file_names to
	support character case restrictions for filenames. Added
	test_cmd_spec_restrict_file_names unit test.

	* url.c: Modified append_uri_pathel to support character case
	restrictions for filenames. Added test_append_uri_pathel unit test.

	* test.c: Added test_cmd_spec_restrict_file_names and
	test_append_uri_pathel to the list of unit tests to run.


-- 
Aequam memento rebus in arduis servare mentem...

Mauro Tortonesi                          http://www.tortonesi.com

University of Ferrara - Dept. of Eng.    http://www.ing.unife.it
GNU Wget - HTTP/FTP file retrieval tool  http://www.gnu.org/software/wget
Deep Space 6 - IPv6 for Linux            http://www.deepspace6.net
Ferrara Linux User Group                 http://www.ferrara.linux.it

--------------050306030406090702000101
Content-Type: text/plain;
 name="restrict-case.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="restrict-case.diff"

Index: options.h
===================================================================
--- options.h	(revisione 2146)
+++ options.h	(copia locale)
@@ -203,6 +203,11 @@
   bool restrict_files_ctrl;	/* non-zero if control chars in URLs
 				   are restricted from appearing in
 				   generated file names. */
+  enum {
+    restrict_no_case_restriction,
+    restrict_lowercase,
+    restrict_uppercase
+  } restrict_files_case;	/* file name case restriction. */
 
   bool strict_comments;		/* whether strict SGML comments are
 				   enforced.  */
Index: init.c
===================================================================
--- init.c	(revisione 2146)
+++ init.c	(copia locale)
@@ -54,6 +54,10 @@
 #include "http.h"		/* for http_cleanup */
 #include "retr.h"		/* for output_stream */
 
+#ifdef TESTING
+#include "test.h"
+#endif
+
 /* We want tilde expansion enabled only when reading `.wgetrc' lines;
    otherwise, it will be performed by the shell.  This variable will
    be set by the wgetrc-reading function.  */
@@ -314,6 +318,7 @@
   opt.restrict_files_os = restrict_windows;
 #endif
   opt.restrict_files_ctrl = true;
+  opt.restrict_files_case = restrict_no_case_restriction;
 
   opt.content_disposition = true;
 }
@@ -1178,40 +1183,47 @@
 {
   int restrict_os = opt.restrict_files_os;
   int restrict_ctrl = opt.restrict_files_ctrl;
+  int restrict_case = opt.restrict_files_case;
 
-  const char *end = strchr (val, ',');
-  if (!end)
-    end = val + strlen (val);
+  const char *end;
 
 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
 
+  do
+    {
+      end = strchr (val, ',');
+      if (!end)
+        end = val + strlen (val);
+      
   if (VAL_IS ("unix"))
     restrict_os = restrict_unix;
   else if (VAL_IS ("windows"))
     restrict_os = restrict_windows;
+      else if (VAL_IS ("lowercase"))
+        restrict_case = restrict_lowercase;
+      else if (VAL_IS ("uppercase"))
+        restrict_case = restrict_uppercase;
   else if (VAL_IS ("nocontrol"))
-    restrict_ctrl = 0;
+        restrict_ctrl = false;
   else
     {
-    err:
       fprintf (stderr,
-	       _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"),
+                   _("%s: %s: Invalid restriction `%s', use [unix|windows],[lowercase|uppercase],[nocontrol].\n"),
 	       exec_name, com, val);
       return false;
     }
 
-#undef VAL_IS
-
   if (*end)
-    {
-      if (!strcmp (end + 1, "nocontrol"))
-	restrict_ctrl = false;
-      else
-	goto err;
+	val = end + 1;
     }
+  while (*val && *end);
+
+#undef VAL_IS
 
   opt.restrict_files_os = restrict_os;
   opt.restrict_files_ctrl = restrict_ctrl;
+  opt.restrict_files_case = restrict_case;
+  
   return true;
 }
 
@@ -1492,3 +1504,50 @@
   xfree_null (opt.passwd);
 #endif /* DEBUG_MALLOC */
 }
+
+/* Unit testing routines.  */
+
+#ifdef TESTING
+
+const char *
+test_cmd_spec_restrict_file_names()
+{
+  int i;
+  struct {
+    char *val;
+    int expected_restrict_files_os;
+    int expected_restrict_files_ctrl;
+    int expected_restrict_files_case;
+    bool result;
+  } test_array[] = {
+    { "windows", restrict_windows, true, restrict_no_case_restriction, true },
+    { "windows,", restrict_windows, true, restrict_no_case_restriction, true },
+    { "windows,lowercase", restrict_windows, true, restrict_lowercase, true },
+    { "unix,nocontrol,lowercase,", restrict_unix, false, restrict_lowercase, true },
+  };
+  
+  for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i) 
+    {
+      bool res;
+      
+      defaults();
+      res = cmd_spec_restrict_file_names ("dummy", test_array[i].val, NULL);
+
+      /*
+      fprintf (stderr, "test_cmd_spec_restrict_file_names: TEST %d\n", i); fflush (stderr);
+      fprintf (stderr, "opt.restrict_files_os: %d\n",   opt.restrict_files_os); fflush (stderr);
+      fprintf (stderr, "opt.restrict_files_ctrl: %d\n", opt.restrict_files_ctrl); fflush (stderr);
+      fprintf (stderr, "opt.restrict_files_case: %d\n", opt.restrict_files_case); fflush (stderr);
+      */
+      mu_assert ("test_cmd_spec_restrict_file_names: wrong result", 
+                 res == test_array[i].result
+                 && opt.restrict_files_os   == test_array[i].expected_restrict_files_os 
+                 && opt.restrict_files_ctrl == test_array[i].expected_restrict_files_ctrl 
+                 && opt.restrict_files_case == test_array[i].expected_restrict_files_case);
+    }
+
+  return NULL;
+}
+
+#endif /* TESTING */
+
Index: ChangeLog
===================================================================
--- ChangeLog	(revisione 2150)
+++ ChangeLog	(copia locale)
@@ -1,3 +1,19 @@
+2006-06-13  Mauro Tortonesi  <[email protected]>
+
+	* options.h (struct options): Introduced member restrict_files_case to
+	keep track of preferences on character case restrictions for
+	filenames.
+
+	* init.c: Modified defaults and cmd_spec_restrict_file_names to
+	support character case restrictions for filenames. Added
+	test_cmd_spec_restrict_file_names unit test.
+
+	* url.c: Modified append_uri_pathel to support character case
+	restrictions for filenames. Added test_append_uri_pathel unit test.
+
+	* test.c: Added test_cmd_spec_restrict_file_names and
+	test_append_uri_pathel to the list of unit tests to run.
+
 2006-06-12  Mauro Tortonesi  <[email protected]>
 
 	* retr.c (retrieve_from_file): Use retrieve_tree and automatically
Index: test.c
===================================================================
--- test.c	(revisione 2146)
+++ test.c	(copia locale)
@@ -38,6 +38,8 @@
 const char *test_parse_content_disposition();
 const char *test_subdir_p();
 const char *test_dir_matches_p();
+const char *test_cmd_spec_restrict_file_names();
+const char *test_append_uri_pathel();
 
 int tests_run;
 
@@ -47,6 +49,8 @@
   mu_run_test (test_parse_content_disposition);
   mu_run_test (test_subdir_p);
   mu_run_test (test_dir_matches_p);
+  mu_run_test (test_cmd_spec_restrict_file_names);
+  mu_run_test (test_append_uri_pathel);
   
   return NULL;
 }
Index: url.c
===================================================================
--- url.c	(revisione 2146)
+++ url.c	(copia locale)
@@ -43,6 +43,10 @@
 #include "url.h"
 #include "host.h"  /* for is_valid_ipv6_address */
 
+#ifdef TESTING
+#include "test.h"
+#endif
+
 enum {
   scm_disabled = 1,		/* for https when OpenSSL fails to init. */
   scm_has_params = 2,		/* whether scheme has ;params */
@@ -1360,6 +1364,21 @@
 	}
       assert (q - TAIL (dest) == outlen);
     }
+  
+  /* Perform inline case transformation if required.  */
+  if (opt.restrict_files_case == restrict_lowercase
+      || opt.restrict_files_case == restrict_uppercase)
+    {
+      char *q;
+      for (q = TAIL (dest); *q; ++q)
+        {
+          if (opt.restrict_files_case == restrict_lowercase)
+            *q = TOLOWER (*q);
+          else
+            *q = TOUPPER (*q);
+        }
+    }
+	  
   TAIL_INCR (dest, outlen);
 }
 
@@ -1984,3 +2003,38 @@
     }
 }
 #endif
+
+#ifdef TESTING
+
+const char *
+test_append_uri_pathel()
+{
+  int i;
+  struct {
+    char *original_url;
+    char *input;
+    bool escaped;
+    char *expected_result;
+  } test_array[] = {
+    { "http://www.yoyodyne.com/path/", "somepage.html", false, "http://www.yoyodyne.com/path/somepage.html" },
+  };
+  
+  for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i) 
+    {
+      struct growable dest;
+      const char *p = test_array[i].input;
+      
+      memset (&dest, 0, sizeof (dest));
+      
+      append_string (test_array[i].original_url, &dest);
+      append_uri_pathel (p, p + strlen(p), test_array[i].escaped, &dest);
+
+      mu_assert ("test_append_uri_pathel: wrong result", 
+                 strcmp (dest.base, test_array[i].expected_result) == 0);
+    }
+
+  return NULL;
+}
+
+#endif /* TESTING */
+

--------------050306030406090702000101--