]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
base32: A new program similar to base64
authorPádraig Brady <P@draigBrady.com>
Wed, 5 Aug 2015 08:28:36 +0000 (10:28 +0200)
committerPádraig Brady <P@draigBrady.com>
Wed, 2 Sep 2015 23:33:19 +0000 (00:33 +0100)
Suggested in https://bugzilla.redhat.com/1250113

* AUTHORS: Add base32.
* THANKS.in: Add suggester.
* README: Reference the new program.
* NEWS: Mention the new program.
* src/.gitignore: Ignore the new binary.
* bootstrap.conf: Reference the gnulib base32 module.
* build-aux/gen-lists-of-programs.sh: Add base32.
* man/base32.x: A new template.
* man/.gitignore: Ignore the new man page.
* man/local.mk: Reference the new man page.
* doc/coreutils.texi (base32 invocation): Document the new command.
* src/local.mk: Adjust to build base32 based on base64.c.
* src/base64.c: Parameterize to use the correct headers,
functions and buffer sizes, depending on which binary
is being built.
* tests/misc/base64.pl: Adjust to test both base32 and base64.
* tests/misc/tty-eof.pl: Add base32 as a program that
accepts input on stdin without any options specified.
* scripts/git-hooks/commit-msg: Add base32 to the template.

16 files changed:
AUTHORS
NEWS
README
THANKS.in
bootstrap.conf
build-aux/gen-lists-of-programs.sh
doc/coreutils.texi
man/.gitignore
man/base32.x [new file with mode: 0644]
man/local.mk
scripts/git-hooks/commit-msg
src/.gitignore
src/base64.c
src/local.mk
tests/misc/base64.pl
tests/misc/tty-eof.pl

diff --git a/AUTHORS b/AUTHORS
index 64c11d75940fc638fd0e55500a9540c9999d8981..572ad59a80a6fc089954dbc187aa67ec65afdd22 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,6 +2,7 @@ Here are the names of the programs in this package,
 each followed by the name(s) of its author(s).
 
 arch: David MacKenzie, Karel Zak
+base32: Simon Josefsson
 base64: Simon Josefsson
 basename: David MacKenzie
 cat: Torbjörn Granlund, Richard M. Stallman
diff --git a/NEWS b/NEWS
index 54a0ab6305a27e757d0b75c0b1909d70cf40e437..d247e9d3c8af646390910ed6d73295aa51895957 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,11 @@ GNU coreutils NEWS                                    -*- outline -*-
   shred again uses defined patterns for all iteration counts.
   [bug introduced in coreutils-5.93]
 
+** New commands
+
+  base32 is added to complement the existing base64 command,
+  and encodes and decodes printable text as per RFC 4648.
+
 
 * Noteworthy changes in release 8.24 (2015-07-03) [stable]
 
diff --git a/README b/README
index 7473aebbfb3168435bf0ebfe439638362ec5d93c..cb24e13f8bae6a7222588d75b7dfe9530c01be77 100644 (file)
--- a/README
+++ b/README
@@ -7,7 +7,7 @@ arbitrary limits.
 
 The programs that can be built with this package are:
 
-  [ arch base64 basename cat chcon chgrp chmod chown chroot cksum comm
+  [ arch base32 base64 basename cat chcon chgrp chmod chown chroot cksum comm
   coreutils cp csplit cut date dd df dir dircolors dirname du echo env
   expand expr factor false fmt fold groups head hostid hostname id install
   join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl
index ba8e264b767094dca2a7cba94163ca1c23ecdf9a..51c77ef741c229443bcd3bee2c21e9add5a0857c 100644 (file)
--- a/THANKS.in
+++ b/THANKS.in
@@ -469,6 +469,7 @@ Nicolas François                    nicolas.francois@centraliens.net
 Niklas Edmundsson                   nikke@acc.umu.se
 Nikola Milutinovic                  Nikola.Milutinovic@ev.co.yu
 Nikolaus Rath                       Nikolaus@rath.org
+Nikos Mavrogiannopoulos             nmav@redhat.com
 Nima Nikzad                         nnikzad@ucla.edu
 Noah Friedman                       friedman@splode.com
 Noel Cragg                          noel@red-bean.com
index 5c6d2bf8eea683034165bc1a5df69e5428bd01ff..d0017f995c2f8b716b6e96ad03c6141ca0e3f885 100644 (file)
@@ -37,6 +37,7 @@ gnulib_modules="
   linked-list
   backupfile
   base64
+  base32
   buffer-lcm
   c-strcase
   c-strtod
index c95e598154eb901587bc542a93aeefb9869ff0f5..40c3a3236ccbaa547c736605b322beb77e8fa9ba 100755 (executable)
@@ -42,6 +42,7 @@ build_if_possible_progs='
 normal_progs='
     [
     base64
+    base32
     basename
     cat
     chcon
index c35401f993eadc625580a7b95cfa159048ce6212..5589162e57139a5744c81c7ad6eceac3837ec6d8 100644 (file)
@@ -37,6 +37,7 @@
 @dircategory Individual utilities
 @direntry
 * arch: (coreutils)arch invocation.             Print machine hardware name.
+* base32: (coreutils)base32 invocation.         Base32 encode/decode data.
 * base64: (coreutils)base64 invocation.         Base64 encode/decode data.
 * basename: (coreutils)basename invocation.     Strip directory and suffix.
 * cat: (coreutils)cat invocation.               Concatenate and write files.
@@ -183,7 +184,7 @@ Free Documentation License''.
 @menu
 * Introduction::                 Caveats, overview, and authors
 * Common options::               Common options
-* Output of entire files::       cat tac nl od base64
+* Output of entire files::       cat tac nl od base32 base64
 * Formatting file contents::     fmt pr fold
 * Output of parts of files::     head tail split csplit
 * Summarizing files::            wc sum cksum md5sum sha1sum sha2
@@ -238,6 +239,7 @@ Output of entire files
 * tac invocation::               Concatenate and write files in reverse
 * nl invocation::                Number lines and write files
 * od invocation::                Write files in octal or other formats
+* base32 invocation::            Transform data into printable data
 * base64 invocation::            Transform data into printable data
 
 Formatting file contents
@@ -1551,6 +1553,7 @@ in some way.
 * tac invocation::              Concatenate and write files in reverse.
 * nl invocation::               Number lines and write files.
 * od invocation::               Write files in octal or other formats.
+* base32 invocation::           Transform data into printable data.
 * base64 invocation::           Transform data into printable data.
 @end menu
 
@@ -2138,6 +2141,20 @@ address.
 
 @exitstatus
 
+
+@node base32 invocation
+@section @command{base32}: Transform data into printable data
+
+@pindex base32
+@cindex base32 encoding
+
+@command{base32} transforms data read from a file, or standard input,
+into (or from) base32 encoded form.  The base32 encoded form uses
+printable ASCII characters to represent binary data.
+The usage and options of this command are precisely the
+same as for @command{base64}.  @xref{base64 invocation}.
+
+
 @node base64 invocation
 @section @command{base64}: Transform data into printable data
 
@@ -2155,6 +2172,7 @@ base64 --decode [@var{option}]@dots{} [@var{file}]
 @end smallexample
 
 The base64 encoding expands data to roughly 133% of the original.
+The base32 encoding expands data to roughly 160% of the original.
 The format conforms to
 @uref{ftp://ftp.rfc-editor.org/in-notes/rfc4648.txt, RFC 4648}.
 
index aef40029292503aff1eb5819517a839c3e17b36a..37bc6c426b996d40dcb8335f1ba6798e959c5a3c 100644 (file)
@@ -1,5 +1,6 @@
 Makefile
 Makefile.in
+base32.1
 base64.1
 basename.1
 cat.1
diff --git a/man/base32.x b/man/base32.x
new file mode 100644 (file)
index 0000000..f73de65
--- /dev/null
@@ -0,0 +1,4 @@
+[NAME]
+base32 \- base32 encode/decode data and print to standard output
+[DESCRIPTION]
+.\" Add any additional description here
index 45bda93e1bd7490455a4e84ba0e91c237031bf61..d1117606f1a27c75f0048c60acfc45884be605a1 100644 (file)
@@ -60,6 +60,7 @@ man/arch.1:      src/uname$(EXEEXT)
 man/install.1:   src/ginstall$(EXEEXT)
 man/test.1:      src/[$(EXEEXT)
 
+man/base32.1:    src/base32$(EXEEXT)
 man/base64.1:    src/base64$(EXEEXT)
 man/basename.1:  src/basename$(EXEEXT)
 man/cat.1:       src/cat$(EXEEXT)
index 559a0ea8f5277a5d8ff92bfacf91c6a744006240..0e4dad6a89da8edddb71fd03a2f9d735ddf485bc 100755 (executable)
@@ -14,7 +14,7 @@ $editor = "vi" if $? != 0 or $editor =~ /^\s*\z/;
 # Keywords allowed before the colon on the first line of a commit message:
 # program names and a few general category names.
 my @valid = qw(
-    arch base64 basename cat chcon chgrp chmod chown chroot cksum comm
+    arch base32 base64 basename cat chcon chgrp chmod chown chroot cksum comm
     cp csplit cut date dd df dir dircolors dirname du echo env expand
     expr factor false fmt fold groups head hostid hostname id install
     join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp
index e8bccbae5cfff318b5a07e0f88732c0f9e4e800b..c1f3b0d1365185066f76be4d54e4abf3494f5a8e 100644 (file)
@@ -2,6 +2,7 @@
 /.dirstamp
 \[
 arch
+base32
 base64
 basename
 cat
index ec3fe0720e9404c3ad864c92896640eb1ff1074d..679044e4099c5e97b93ec239e52fcfae314bc774 100644 (file)
 #include "quotearg.h"
 #include "xfreopen.h"
 
-#include "base64.h"
+#define AUTHORS proper_name ("Simon Josefsson")
 
-/* The official name of this program (e.g., no 'g' prefix).  */
-#define PROGRAM_NAME "base64"
+#if BASE_TYPE == 32
+# include "base32.h"
+# define PROGRAM_NAME "base32"
+#else
+# include "base64.h"
+# define PROGRAM_NAME "base64"
+#endif
 
-#define AUTHORS proper_name ("Simon Josefsson")
 
 static struct option const long_options[] =
 {
@@ -59,8 +63,8 @@ usage (int status)
     {
       printf (_("\
 Usage: %s [OPTION]... [FILE]\n\
-Base64 encode or decode FILE, or standard input, to standard output.\n\
-"), program_name);
+Base%d encode or decode FILE, or standard input, to standard output.\n\
+"), program_name, BASE_TYPE);
 
       emit_stdin_note ();
       emit_mandatory_arg_note ();
@@ -74,13 +78,13 @@ Base64 encode or decode FILE, or standard input, to standard output.\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
-      fputs (_("\
+      printf (_("\
 \n\
-The data are encoded as described for the base64 alphabet in RFC 3548.\n\
+The data are encoded as described for the %s alphabet in RFC 4648.\n\
 When decoding, the input may contain newlines in addition to the bytes of\n\
-the formal base64 alphabet.  Use --ignore-garbage to attempt to recover\n\
+the formal %s alphabet.  Use --ignore-garbage to attempt to recover\n\
 from any other non-alphabet bytes in the encoded stream.\n"),
-             stdout);
+              PROGRAM_NAME, PROGRAM_NAME);
       emit_ancillary_info (PROGRAM_NAME);
     }
 
@@ -88,15 +92,38 @@ from any other non-alphabet bytes in the encoded stream.\n"),
 }
 
 #define ENC_BLOCKSIZE (1024*3*10)
-#define ENC_B64BLOCKSIZE BASE64_LENGTH (ENC_BLOCKSIZE)
+
+#if BASE_TYPE == 32
+# define BASE_LENGTH BASE32_LENGTH
+/* Note that increasing this may decrease performance if --ignore-garbage
+   is used, because of the memmove operation below.  */
+# define DEC_BLOCKSIZE (1024*5)
+
+/* Ensure that BLOCKSIZE is a multiple of 5 and 8.  */
+verify (ENC_BLOCKSIZE % 40 == 0);  /* So padding chars only on last block.  */
+verify (DEC_BLOCKSIZE % 40 == 0);  /* So complete encoded blocks are used.  */
+
+# define base_encode base32_encode
+# define base_decode_context base32_decode_context
+# define base_decode_ctx_init base32_decode_ctx_init
+# define base_decode_ctx base32_decode_ctx
+# define isbase isbase32
+#else
+# define BASE_LENGTH BASE64_LENGTH
 /* Note that increasing this may decrease performance if --ignore-garbage
    is used, because of the memmove operation below.  */
-#define DEC_BLOCKSIZE (1024*3)
-#define DEC_B64BLOCKSIZE BASE64_LENGTH (DEC_BLOCKSIZE)
+# define DEC_BLOCKSIZE (1024*3)
 
 /* Ensure that BLOCKSIZE is a multiple of 3 and 4.  */
-verify (ENC_BLOCKSIZE % 12 == 0);
-verify (DEC_BLOCKSIZE % 12 == 0);
+verify (ENC_BLOCKSIZE % 12 == 0);  /* So padding chars only on last block.  */
+verify (DEC_BLOCKSIZE % 12 == 0);  /* So complete encoded blocks are used.  */
+
+# define base_encode base64_encode
+# define base_decode_context base64_decode_context
+# define base_decode_ctx_init base64_decode_ctx_init
+# define base_decode_ctx base64_decode_ctx
+# define isbase isbase64
+#endif
 
 static void
 wrap_write (const char *buffer, size_t len,
@@ -138,7 +165,7 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
 {
   size_t current_column = 0;
   char inbuf[ENC_BLOCKSIZE];
-  char outbuf[ENC_B64BLOCKSIZE];
+  char outbuf[BASE_LENGTH (ENC_BLOCKSIZE)];
   size_t sum;
 
   do
@@ -155,11 +182,11 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
 
       if (sum > 0)
         {
-          /* Process input one block at a time.  Note that ENC_BLOCKSIZE %
-             3 == 0, so that no base64 pads will appear in output. */
-          base64_encode (inbuf, sum, outbuf, BASE64_LENGTH (sum));
+          /* Process input one block at a time.  Note that ENC_BLOCKSIZE
+             is sized so that no pad chars will appear in output. */
+          base_encode (inbuf, sum, outbuf, BASE_LENGTH (sum));
 
-          wrap_write (outbuf, BASE64_LENGTH (sum), wrap_column,
+          wrap_write (outbuf, BASE_LENGTH (sum), wrap_column,
                       &current_column, out);
         }
     }
@@ -176,12 +203,12 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
 static void
 do_decode (FILE *in, FILE *out, bool ignore_garbage)
 {
-  char inbuf[DEC_B64BLOCKSIZE];
+  char inbuf[BASE_LENGTH (DEC_BLOCKSIZE)];
   char outbuf[DEC_BLOCKSIZE];
   size_t sum;
-  struct base64_decode_context ctx;
+  struct base_decode_context ctx;
 
-  base64_decode_ctx_init (&ctx);
+  base_decode_ctx_init (&ctx);
 
   do
     {
@@ -192,13 +219,13 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage)
       sum = 0;
       do
         {
-          n = fread (inbuf + sum, 1, DEC_B64BLOCKSIZE - sum, in);
+          n = fread (inbuf + sum, 1, BASE_LENGTH (DEC_BLOCKSIZE) - sum, in);
 
           if (ignore_garbage)
             {
               size_t i;
               for (i = 0; n > 0 && i < n;)
-                if (isbase64 (inbuf[sum + i]) || inbuf[sum + i] == '=')
+                if (isbase (inbuf[sum + i]) || inbuf[sum + i] == '=')
                   i++;
                 else
                   memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i);
@@ -209,7 +236,7 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage)
           if (ferror (in))
             error (EXIT_FAILURE, errno, _("read error"));
         }
-      while (sum < DEC_B64BLOCKSIZE && !feof (in));
+      while (sum < BASE_LENGTH (DEC_BLOCKSIZE) && !feof (in));
 
       /* The following "loop" is usually iterated just once.
          However, when it processes the final input buffer, we want
@@ -220,7 +247,7 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage)
           if (k == 1 && ctx.i == 0)
             break;
           n = DEC_BLOCKSIZE;
-          ok = base64_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
+          ok = base_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
 
           if (fwrite (outbuf, 1, n, out) < n)
             error (EXIT_FAILURE, errno, _("write error"));
@@ -241,9 +268,9 @@ main (int argc, char **argv)
 
   /* True if --decode has been given and we should decode data. */
   bool decode = false;
-  /* True if we should ignore non-base64-alphabetic characters. */
+  /* True if we should ignore non-base-alphabetic characters. */
   bool ignore_garbage = false;
-  /* Wrap encoded base64 data around the 76:th column, by default. */
+  /* Wrap encoded data around the 76:th column, by default. */
   uintmax_t wrap_column = 76;
 
   initialize_main (&argc, &argv);
index 3fb167692214cb6eaf621ff2da31ab3ef95e752e..d0ceae4bde5a6f1636413687781e1d3ade1b00a8 100644 (file)
@@ -94,6 +94,7 @@ LDADD = src/libver.a lib/libcoreutils.a $(LIBINTL) lib/libcoreutils.a
 # See [ below.
 src_arch_LDADD = $(LDADD)
 src_base64_LDADD = $(LDADD)
+src_base32_LDADD = $(LDADD)
 src_basename_LDADD = $(LDADD)
 src_cat_LDADD = $(LDADD)
 src_chcon_LDADD = $(LDADD)
@@ -398,6 +399,10 @@ src_sha384sum_CPPFLAGS = -DHASH_ALGO_SHA384=1 $(AM_CPPFLAGS)
 src_sha512sum_SOURCES = src/md5sum.c
 src_sha512sum_CPPFLAGS = -DHASH_ALGO_SHA512=1 $(AM_CPPFLAGS)
 
+src_base64_CPPFLAGS = -DBASE_TYPE=64 $(AM_CPPFLAGS)
+src_base32_SOURCES = src/base64.c
+src_base32_CPPFLAGS = -DBASE_TYPE=32 $(AM_CPPFLAGS)
+
 src_ginstall_CPPFLAGS = -DENABLE_MATCHPATHCON=1 $(AM_CPPFLAGS)
 
 # Ensure we don't link against libcoreutils.a as that lib is
index fd75c624ff8ec49b148447d8651f5baccdf50041..872535afb26aaedd6172cdd90c26894f7762eefe 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl
-# Exercise base64.
+# Exercise base{32,64}.
 
 # Copyright (C) 2006-2015 Free Software Foundation, Inc.
 
@@ -24,22 +24,27 @@ use strict;
 @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
 
 # Return the encoding of a string of N 'a's.
-sub enc($)
+sub enc64($)
 {
   my ($n) = @_;
   my %remainder = ( 0 => '', 1 => 'YQ==', 2 => 'YWE=' );
   return 'YWFh' x ($n / 3) . $remainder{$n % 3};
 }
 
-# Construct an encoded string of length 4KB, using 3K "a"s.
-my $a3k = enc 3072;
+sub enc32($)
+{
+  my ($n) = @_;
+  my %remainder = ( 0 => '', 1 => 'ME======', 2 => 'MFQQ====',
+                    3 => 'MFQWC===', 4 => 'MFQWCYI=');
+  return 'MFQWCYLB' x ($n / 5) . $remainder{$n % 5};
+}
+
+# Function reference to appropriate encoder
+my $enc;
+
+# An encoded string of length 4KB, using 3K "a"s.
+my $a3k;
 my @a3k_nl;
-# A few copies, each with different number of newlines at the start.
-for my $k (0..3)
-  {
-    (my $t = $a3k) =~ s/^/"\n"x $k/e;
-    push @a3k_nl, $t;
-  }
 
 # Return a copy of S, with newlines inserted every WIDTH bytes.
 # Ensure that the result (if not the empty string) is newline-terminated.
@@ -52,103 +57,140 @@ sub wrap($$)
   return $s;
 }
 
-my @Tests =
+my @Tests;
+
+sub gen_tests($)
+{
+  my ($prog) = @_;
+  @Tests=
     (
      ['empty', {IN=>''}, {OUT=>""}],
-     ['inout', {IN=>'a'}, {OUT=>"YQ==\n"}],
-     ['wrap', '--wrap 0', {IN=>'foo'}, {OUT=>'Zm9v'}],
-     ['wrap5-39', '--wrap=5', {IN=>'a' x 39}, {OUT=>wrap enc(39),5}],
-     ['wrap5-40', '--wrap=5', {IN=>'a' x 40}, {OUT=>wrap enc(40),5}],
-     ['wrap5-41', '--wrap=5', {IN=>'a' x 41}, {OUT=>wrap enc(41),5}],
-     ['wrap5-42', '--wrap=5', {IN=>'a' x 42}, {OUT=>wrap enc(42),5}],
-     ['wrap5-43', '--wrap=5', {IN=>'a' x 43}, {OUT=>wrap enc(43),5}],
-     ['wrap5-44', '--wrap=5', {IN=>'a' x 44}, {OUT=>wrap enc(44),5}],
-     ['wrap5-45', '--wrap=5', {IN=>'a' x 45}, {OUT=>wrap enc(45),5}],
-     ['wrap5-46', '--wrap=5', {IN=>'a' x 46}, {OUT=>wrap enc(46),5}],
-
-     ['buf-1',   '--decode', {IN=>enc 1}, {OUT=>'a' x 1}],
-     ['buf-2',   '--decode', {IN=>enc 2}, {OUT=>'a' x 2}],
-     ['buf-3',   '--decode', {IN=>enc 3}, {OUT=>'a' x 3}],
-     ['buf-4',   '--decode', {IN=>enc 4}, {OUT=>'a' x 4}],
+     ['inout1', {IN=>'a'x1}, {OUT=>&$enc(1)."\n"}],
+     ['inout2', {IN=>'a'x2}, {OUT=>&$enc(2)."\n"}],
+     ['inout3', {IN=>'a'x3}, {OUT=>&$enc(3)."\n"}],
+     ['inout4', {IN=>'a'x4}, {OUT=>&$enc(4)."\n"}],
+     ['inout5', {IN=>'a'x5}, {OUT=>&$enc(5)."\n"}],
+     ['wrap', '--wrap 0', {IN=>'a'}, {OUT=>&$enc(1)}],
+     ['wrap5-39', '--wrap=5', {IN=>'a' x 39}, {OUT=>wrap &$enc(39),5}],
+     ['wrap5-40', '--wrap=5', {IN=>'a' x 40}, {OUT=>wrap &$enc(40),5}],
+     ['wrap5-41', '--wrap=5', {IN=>'a' x 41}, {OUT=>wrap &$enc(41),5}],
+     ['wrap5-42', '--wrap=5', {IN=>'a' x 42}, {OUT=>wrap &$enc(42),5}],
+     ['wrap5-43', '--wrap=5', {IN=>'a' x 43}, {OUT=>wrap &$enc(43),5}],
+     ['wrap5-44', '--wrap=5', {IN=>'a' x 44}, {OUT=>wrap &$enc(44),5}],
+     ['wrap5-45', '--wrap=5', {IN=>'a' x 45}, {OUT=>wrap &$enc(45),5}],
+     ['wrap5-46', '--wrap=5', {IN=>'a' x 46}, {OUT=>wrap &$enc(46),5}],
+
+     ['buf-1',   '--decode', {IN=>&$enc(1)}, {OUT=>'a' x 1}],
+     ['buf-2',   '--decode', {IN=>&$enc(2)}, {OUT=>'a' x 2}],
+     ['buf-3',   '--decode', {IN=>&$enc(3)}, {OUT=>'a' x 3}],
+     ['buf-4',   '--decode', {IN=>&$enc(4)}, {OUT=>'a' x 4}],
      # 4KB worth of input.
-     ['buf-4k0', '--decode', {IN=>enc 3072+0}, {OUT=>'a' x (3072+0)}],
-     ['buf-4k1', '--decode', {IN=>enc 3072+1}, {OUT=>'a' x (3072+1)}],
-     ['buf-4k2', '--decode', {IN=>enc 3072+2}, {OUT=>'a' x (3072+2)}],
-     ['buf-4k3', '--decode', {IN=>enc 3072+3}, {OUT=>'a' x (3072+3)}],
-     ['buf-4km1','--decode', {IN=>enc 3072-1}, {OUT=>'a' x (3072-1)}],
-     ['buf-4km2','--decode', {IN=>enc 3072-2}, {OUT=>'a' x (3072-2)}],
-     ['buf-4km3','--decode', {IN=>enc 3072-3}, {OUT=>'a' x (3072-3)}],
-     ['buf-4km4','--decode', {IN=>enc 3072-4}, {OUT=>'a' x (3072-4)}],
+     ['buf-4k0', '--decode', {IN=>&$enc(3072+0)}, {OUT=>'a' x (3072+0)}],
+     ['buf-4k1', '--decode', {IN=>&$enc(3072+1)}, {OUT=>'a' x (3072+1)}],
+     ['buf-4k2', '--decode', {IN=>&$enc(3072+2)}, {OUT=>'a' x (3072+2)}],
+     ['buf-4k3', '--decode', {IN=>&$enc(3072+3)}, {OUT=>'a' x (3072+3)}],
+     ['buf-4km1','--decode', {IN=>&$enc(3072-1)}, {OUT=>'a' x (3072-1)}],
+     ['buf-4km2','--decode', {IN=>&$enc(3072-2)}, {OUT=>'a' x (3072-2)}],
+     ['buf-4km3','--decode', {IN=>&$enc(3072-3)}, {OUT=>'a' x (3072-3)}],
+     ['buf-4km4','--decode', {IN=>&$enc(3072-4)}, {OUT=>'a' x (3072-4)}],
 
      # Exercise the case in which the final base-64 byte is
      # in a buffer all by itself.
      ['b4k-1',   '--decode', {IN=>$a3k_nl[1]}, {OUT=>'a' x (3072+0)}],
      ['b4k-2',   '--decode', {IN=>$a3k_nl[2]}, {OUT=>'a' x (3072+0)}],
      ['b4k-3',   '--decode', {IN=>$a3k_nl[3]}, {OUT=>'a' x (3072+0)}],
-
-     ['baddecode', '--decode', {IN=>'a'}, {OUT=>""},
-      {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
-     ['baddecode2', '--decode', {IN=>'ab'}, {OUT=>"i"},
-      {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
-     ['baddecode3', '--decode', {IN=>'Zzz'}, {OUT=>"g<"},
-      {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
-     ['baddecode4', '--decode', {IN=>'Zz='}, {OUT=>"g"},
-      {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
-     ['baddecode5', '--decode', {IN=>'Z==='}, {OUT=>""},
-      {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}]
     );
 
-# For each non-failing test, create a --decode test using the
-# expected output as input.  Also, add tests inserting newlines.
-my @new;
-foreach my $t (@Tests)
+  if ($prog eq "base64")
+    {
+        push @Tests, (
+          ['baddecode', '--decode', {IN=>'a'}, {OUT=>""},
+          {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+          ['baddecode2', '--decode', {IN=>'ab'}, {OUT=>"i"},
+          {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+          ['baddecode3', '--decode', {IN=>'Zzz'}, {OUT=>"g<"},
+          {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+          ['baddecode4', '--decode', {IN=>'Zz='}, {OUT=>"g"},
+          {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}],
+          ['baddecode5', '--decode', {IN=>'Z==='}, {OUT=>""},
+          {ERR_SUBST => 's/.*: invalid input//'}, {ERR => "\n"}, {EXIT => 1}]
+        );
+    }
+
+  # For each non-failing test, create a --decode test using the
+  # expected output as input.  Also, add tests inserting newlines.
+  my @new;
+  foreach my $t (@Tests)
   {
-    my $exit_val;
-    my $in;
-    my @out;
+      my $exit_val;
+      my $in;
+      my @out;
 
-    # If the test has a single option of "--decode", then skip it.
-    !ref $t->[1] && $t->[1] eq '--decode'
+      # If the test has a single option of "--decode", then skip it.
+      !ref $t->[1] && $t->[1] eq '--decode'
       and next;
 
-    foreach my $e (@$t)
+      foreach my $e (@$t)
       {
-        ref $e && ref $e eq 'HASH'
+          ref $e && ref $e eq 'HASH'
           or next;
-        defined $e->{EXIT}
+          defined $e->{EXIT}
           and $exit_val = $e->{EXIT};
-        defined $e->{IN}
+          defined $e->{IN}
           and $in = $e->{IN};
-        if (defined $e->{OUT})
+          if (defined $e->{OUT})
           {
-            my $t = $e->{OUT};
-            push @out, $t;
-            my $len = length $t;
-            foreach my $i (0..$len)
+              my $t = $e->{OUT};
+              push @out, $t;
+              my $len = length $t;
+              foreach my $i (0..$len)
               {
-                my $u = $t;
-                substr ($u, $i, 0) = "\n";
-                push @out, $u;
-                10 <= $i
+                  my $u = $t;
+                  substr ($u, $i, 0) = "\n";
+                  push @out, $u;
+                  10 <= $i
                   and last;
               }
           }
       }
-    $exit_val
+      $exit_val
       and next;
 
-    my $i = 0;
-    foreach my $o (@out)
+      my $i = 0;
+      foreach my $o (@out)
       {
-        push @new, ["d$i-$t->[0]", '--decode', {IN => $o}, {OUT => $in}];
-        ++$i;
+          push @new, ["d$i-$t->[0]", '--decode', {IN => $o}, {OUT => $in}];
+          ++$i;
       }
   }
-push @Tests, @new;
+  push @Tests, @new;
+}
 
 my $save_temps = $ENV{DEBUG};
 my $verbose = $ENV{VERBOSE};
 
-my $prog = 'base64';
-my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+my $fail = 0;
+foreach my $prog (qw(base32 base64))
+  {
+    $enc = $prog eq "base32" ? \&enc32 : \&enc64;
+
+    # Construct an encoded string of length 4KB, using 3K "a"s.
+    $a3k = &$enc(3072);
+    @a3k_nl = ();
+    # A few copies, each with different number of newlines at the start.
+    for my $k (0..3)
+      {
+        (my $t = $a3k) =~ s/^/"\n"x $k/e;
+        push @a3k_nl, $t;
+      }
+
+    gen_tests($prog);
+
+    $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+    if ($fail != 0)
+      {
+        last;
+      }
+  }
+
 exit $fail;
index c49efc24f9012aa9afdc43fa004cdb36ea58eb1a..1bd9124606e24d074355d3fd945814a4f54eef01 100755 (executable)
@@ -31,6 +31,7 @@ $@
 {
   my $fail = 0;
   my @stdin_reading_commands = qw(
+    base32
     base64
     cat
     cksum