diff options
Diffstat (limited to 'util/sbase/uuencode.c')
-rw-r--r-- | util/sbase/uuencode.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/util/sbase/uuencode.c b/util/sbase/uuencode.c new file mode 100644 index 00000000..b5317205 --- /dev/null +++ b/util/sbase/uuencode.c @@ -0,0 +1,129 @@ +/* See LICENSE file for copyright and license details. */ +#include <sys/stat.h> + +#include <stdio.h> +#include <string.h> + +#include "util.h" + +static unsigned int +b64e(unsigned char *b) +{ + unsigned int o, p = b[2] | (b[1] << 8) | (b[0] << 16); + const char b64et[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + o = b64et[p & 0x3f]; p >>= 6; + o = (o << 8) | b64et[p & 0x3f]; p >>= 6; + o = (o << 8) | b64et[p & 0x3f]; p >>= 6; + o = (o << 8) | b64et[p & 0x3f]; + + return o; +} + +static void +uuencodeb64(FILE *fp, const char *name, const char *s) +{ + struct stat st; + ssize_t n, m = 0; + unsigned char buf[45], *pb; + unsigned int out[sizeof(buf)/3 + 1], *po; + + if (fstat(fileno(fp), &st) < 0) + eprintf("fstat %s:", s); + printf("begin-base64 %o %s\n", st.st_mode & 0777, name); + /* write line by line */ + while ((n = fread(buf, 1, sizeof(buf), fp))) { + /* clear old buffer if converting with non-multiple of 3 */ + if (n != sizeof(buf) && (m = n % 3) != 0) { + buf[n] = '\0'; /* m == 2 */ + if (m == 1) buf[n+1] = '\0'; /* m == 1 */ + } + for (pb = buf, po = out; pb < buf + n; pb += 3) + *po++ = b64e(pb); + if (m != 0) { + unsigned int mask = 0xffffffff, dest = 0x3d3d3d3d; + /* m==2 -> 0x00ffffff; m==1 -> 0x0000ffff */ + mask >>= ((3-m) << 3); + po[-1] = (po[-1] & mask) | (dest & ~mask); + } + *po++ = '\n'; + fwrite(out, 1, (po - out) * sizeof(unsigned int) - 3, stdout); + } + if (ferror(fp)) + eprintf("'%s' read error:", s); + puts("===="); +} + +static void +uuencode(FILE *fp, const char *name, const char *s) +{ + struct stat st; + unsigned char buf[45], *p; + ssize_t n; + int ch; + + if (fstat(fileno(fp), &st) < 0) + eprintf("fstat %s:", s); + printf("begin %o %s\n", st.st_mode & 0777, name); + while ((n = fread(buf, 1, sizeof(buf), fp))) { + ch = ' ' + (n & 0x3f); + putchar(ch == ' ' ? '`' : ch); + for (p = buf; n > 0; n -= 3, p += 3) { + if (n < 3) { + p[2] = '\0'; + if (n < 2) + p[1] = '\0'; + } + ch = ' ' + ((p[0] >> 2) & 0x3f); + putchar(ch == ' ' ? '`' : ch); + ch = ' ' + (((p[0] << 4) | ((p[1] >> 4) & 0xf)) & 0x3f); + putchar(ch == ' ' ? '`' : ch); + ch = ' ' + (((p[1] << 2) | ((p[2] >> 6) & 0x3)) & 0x3f); + putchar(ch == ' ' ? '`' : ch); + ch = ' ' + (p[2] & 0x3f); + putchar(ch == ' ' ? '`' : ch); + } + putchar('\n'); + } + if (ferror(fp)) + eprintf("'%s' read error:", s); + printf("%c\nend\n", '`'); +} + +static void +usage(void) +{ + eprintf("usage: %s [-m] [file] name\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + FILE *fp = NULL; + void (*uuencode_f)(FILE *, const char *, const char *) = uuencode; + int ret = 0; + + ARGBEGIN { + case 'm': + uuencode_f = uuencodeb64; + break; + default: + usage(); + } ARGEND + + if (!argc || argc > 2) + usage(); + + if (argc == 1 || !strcmp(argv[0], "-")) { + uuencode_f(stdin, argv[0], "<stdin>"); + } else { + if (!(fp = fopen(argv[0], "r"))) + eprintf("fopen %s:", argv[0]); + uuencode_f(fp, argv[1], argv[0]); + } + + ret |= fp && fshut(fp, argv[0]); + ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); + + return ret; +} |