b64encode: implement -w to wrap lines

This functionality is present in GNU base64 and I find it useful when
I want to generate random, ASCII-clean data of specific width.

Reviewed by:	delphij
Differential Revision:	https://reviews.freebsd.org/D32944
This commit is contained in:
Piotr Pawel Stefaniak 2022-04-06 20:03:02 +02:00
parent f331cf9b04
commit 2ad786c63a
2 changed files with 59 additions and 11 deletions

View File

@ -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 @@ 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
.Pp
.Nm
is a generic utility that can run
any of the aforementioned encoders and decoders.

View File

@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <err.h>
#include <errno.h>
#include <libgen.h>
#include <resolv.h>
#include <stdio.h>
@ -67,12 +68,14 @@ extern int main_encode(int, char *[]);
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 @@ main_encode(int argc, char *argv[])
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 @@ main_encode(int argc, char *argv[])
case 'r':
raw = true;
break;
case 'w':
columns = arg_to_col(optarg);
break;
case '?':
default:
usage();
@ -151,27 +157,37 @@ static void
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 @@ encode(void)
(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)
{