diff --git a/usr.bin/bintrans/bintrans.1 b/usr.bin/bintrans/bintrans.1 --- a/usr.bin/bintrans/bintrans.1 +++ b/usr.bin/bintrans/bintrans.1 @@ -56,6 +56,7 @@ .Fl o Ar output_file .Nm b64encode .Op Fl r +.Op Fl w Ar column .Op Fl o Ar output_file .Op Ar file .Ar name @@ -181,6 +182,15 @@ reasons. .El .Pp +Additionally, +.Nm b64encode +accepts the following option: +.Bl -tag -width ident +.It Fl w Ar column +Wrap encoded output after +.Ar column . +.El +.Pp .Nm is a generic utility that can run any of the aforementioned encoders and decoders. diff --git a/usr.bin/bintrans/uuencode.c b/usr.bin/bintrans/uuencode.c --- a/usr.bin/bintrans/uuencode.c +++ b/usr.bin/bintrans/uuencode.c @@ -55,6 +55,7 @@ #include #include +#include #include #include #include @@ -67,12 +68,14 @@ static void encode(void); static void base64_encode(void); +static int arg_to_col(const char *); static void usage(void); static FILE *output; static int mode; static bool raw; static char **av; +static int columns = 76; int main_encode(int argc, char *argv[]) @@ -88,7 +91,7 @@ if (strcmp(basename(argv[0]), "b64encode") == 0) base64 = 1; - while ((ch = getopt(argc, argv, "mo:r")) != -1) { + while ((ch = getopt(argc, argv, "mo:rw:")) != -1) { switch (ch) { case 'm': base64 = true; @@ -99,6 +102,9 @@ case 'r': raw = true; break; + case 'w': + columns = arg_to_col(optarg); + break; case '?': default: usage(); @@ -151,27 +157,37 @@ base64_encode(void) { /* - * Output must fit into 80 columns, chunks come in 4, leave 1. + * This buffer's length should be a multiple of 24 bits to avoid "=" + * padding. Once it reached ~1 KB, further expansion didn't improve + * performance for me. */ -#define GROUPS ((80 / 4) - 1) - unsigned char buf[3]; + unsigned char buf[1023]; char buf2[sizeof(buf) * 2 + 1]; size_t n; - int rv, sequence; - - sequence = 0; + unsigned carry = 0; + int rv, written; if (!raw) fprintf(output, "begin-base64 %o %s\n", mode, *av); while ((n = fread(buf, 1, sizeof(buf), stdin))) { - ++sequence; rv = b64_ntop(buf, n, buf2, nitems(buf2)); if (rv == -1) errx(1, "b64_ntop: error encoding base64"); - fprintf(output, "%s%s", buf2, (sequence % GROUPS) ? "" : "\n"); + if (columns == 0) { + fputs(buf2, output); + continue; + } + for (int i = 0; i < rv; i += written) { + written = fprintf(output, "%.*s", columns - carry, + &buf2[i]); + + carry = (carry + written) % columns; + if (carry == 0) + fputc('\n', output); + } } - if (sequence % GROUPS) - fprintf(output, "\n"); + if (columns == 0 || carry != 0) + fputc('\n', output); if (!raw) fprintf(output, "====\n"); } @@ -225,6 +241,28 @@ (void)fprintf(output, "%c\nend\n", ENC('\0')); } +static int +arg_to_col(const char *w) +{ + char *ep; + long option; + + errno = 0; + option = strtol(w, &ep, 10); + if (option > INT_MAX) + errno = ERANGE; + else if (ep[0] != '\0') + errno = EINVAL; + if (errno != 0) + err(2, NULL); + + if (option < 0) { + errno = EINVAL; + err(2, "columns argument must be non-negative"); + } + return (option); +} + static void usage(void) {