aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPiotr Pawel Stefaniak <pstef@FreeBSD.org>2022-04-06 18:03:02 +0000
committerPiotr Pawel Stefaniak <pstef@FreeBSD.org>2022-04-18 11:53:58 +0000
commit2ad786c63ae2f8018f67414076c9aa023e062028 (patch)
treea77464b2e809e101fe02e805389fcf4648f8ed63
parentf331cf9b043a7e5ad4fd22ed9908c5f59da744d4 (diff)
downloadsrc-2ad786c63ae2f8018f67414076c9aa023e062028.tar.gz
src-2ad786c63ae2f8018f67414076c9aa023e062028.zip
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
-rw-r--r--usr.bin/bintrans/bintrans.110
-rw-r--r--usr.bin/bintrans/uuencode.c60
2 files changed, 59 insertions, 11 deletions
diff --git a/usr.bin/bintrans/bintrans.1 b/usr.bin/bintrans/bintrans.1
index e3ad5813f4cd..cdc819aa7a18 100644
--- 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 @@ 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.
diff --git a/usr.bin/bintrans/uuencode.c b/usr.bin/bintrans/uuencode.c
index f2d4b5b2b498..4837d3310578 100644
--- a/usr.bin/bintrans/uuencode.c
+++ b/usr.bin/bintrans/uuencode.c
@@ -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)
{