Index: usr.bin/uuencode/uuencode.1 =================================================================== --- usr.bin/uuencode/uuencode.1 +++ usr.bin/uuencode/uuencode.1 @@ -52,6 +52,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 @@ -176,6 +177,15 @@ deletes any prefix ending with the last slash '/' for security 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 .Sh EXAMPLES The following example packages up a source tree, compresses it, uuencodes it and mails it to a user on another system. Index: usr.bin/uuencode/uuencode.c =================================================================== --- usr.bin/uuencode/uuencode.c +++ usr.bin/uuencode/uuencode.c @@ -55,6 +55,7 @@ #include #include +#include #include #include #include @@ -66,12 +67,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 char raw = 0; static char **av; +static int columns = 76; int main_encode(int argc, char *argv[]) @@ -87,7 +90,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 = 1; @@ -98,6 +101,9 @@ case 'r': raw = 1; break; + case 'w': + columns = arg_to_col(optarg); + break; case '?': default: usage(); @@ -150,27 +156,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"); } @@ -224,6 +240,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) {