master xplshn/aruu / cmd / posix / uuencode.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <sys/stat.h>
  5
  6#include <stdio.h>
  7#include <string.h>
  8
  9#include "util.h"
 10
 11static unsigned int
 12b64e(unsigned char *b)
 13{
 14	unsigned int o, p = b[2] | (b[1] << 8) | (b[0] << 16);
 15	const char b64et[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 16
 17	o = b64et[p & 0x3f]; p >>= 6;
 18	o = (o << 8) | b64et[p & 0x3f]; p >>= 6;
 19	o = (o << 8) | b64et[p & 0x3f]; p >>= 6;
 20	o = (o << 8) | b64et[p & 0x3f];
 21
 22	return o;
 23}
 24
 25static void
 26uuencodeb64(FILE *fp, const char *name, const char *s)
 27{
 28	struct stat st;
 29	ssize_t n, m = 0;
 30	unsigned char buf[45], *pb;
 31	unsigned int out[sizeof(buf)/3 + 1], *po;
 32
 33	if (fstat(fileno(fp), &st) < 0)
 34		eprintf("fstat %s:", s);
 35	printf("begin-base64 %o %s\n", st.st_mode & 0777, name);
 36	/* write line by line */
 37	while ((n = fread(buf, 1, sizeof(buf), fp))) {
 38		/* clear old buffer if converting with non-multiple of 3 */
 39		if (n != sizeof(buf) && (m = n % 3) != 0) {
 40			buf[n] = '\0'; /* m == 2 */
 41			if (m == 1) buf[n+1] = '\0'; /* m == 1 */
 42		}
 43		for (pb = buf, po = out; pb < buf + n; pb += 3)
 44			*po++ = b64e(pb);
 45		if (m != 0) {
 46			unsigned int mask = 0xffffffff, dest = 0x3d3d3d3d;
 47			/* m==2 -> 0x00ffffff; m==1 -> 0x0000ffff */
 48			mask >>= ((3-m) << 3);
 49			po[-1] = (po[-1] & mask) | (dest & ~mask);
 50		}
 51		*po++ = '\n';
 52		fwrite(out, 1, (po - out) * sizeof(unsigned int) - 3, stdout);
 53	}
 54	if (ferror(fp))
 55		eprintf("'%s' read error:", s);
 56	puts("====");
 57}
 58
 59static void
 60uuencode(FILE *fp, const char *name, const char *s)
 61{
 62	struct stat st;
 63	unsigned char buf[45], *p;
 64	ssize_t n;
 65	int ch;
 66
 67	if (fstat(fileno(fp), &st) < 0)
 68		eprintf("fstat %s:", s);
 69	printf("begin %o %s\n", st.st_mode & 0777, name);
 70	while ((n = fread(buf, 1, sizeof(buf), fp))) {
 71		ch = ' ' + (n & 0x3f);
 72		putchar(ch == ' ' ? '`' : ch);
 73		for (p = buf; n > 0; n -= 3, p += 3) {
 74			if (n < 3) {
 75				p[2] = '\0';
 76				if (n < 2)
 77					p[1] = '\0';
 78			}
 79			ch = ' ' + ((p[0] >> 2) & 0x3f);
 80			putchar(ch == ' ' ? '`' : ch);
 81			ch = ' ' + (((p[0] << 4) | ((p[1] >> 4) & 0xf)) & 0x3f);
 82			putchar(ch == ' ' ? '`' : ch);
 83			ch = ' ' + (((p[1] << 2) | ((p[2] >> 6) & 0x3)) & 0x3f);
 84			putchar(ch == ' ' ? '`' : ch);
 85			ch = ' ' + (p[2] & 0x3f);
 86			putchar(ch == ' ' ? '`' : ch);
 87		}
 88		putchar('\n');
 89	}
 90	if (ferror(fp))
 91		eprintf("'%s' read error:", s);
 92	printf("%c\nend\n", '`');
 93}
 94
 95static void
 96usage(void)
 97{
 98	eprintf("usage: %s [-m] [file] name\n", argv0);
 99}
100
101// ?man uuencode: encode binary file
102// ?man arguments: file] name
103// ?man encode a binary file into ascii text
104int
105main(int argc, char *argv[])
106{
107	FILE *fp = NULL;
108	void (*uuencode_f)(FILE *, const char *, const char *) = uuencode;
109	int ret = 0;
110
111	ARGBEGIN {
112	// ?man -m: specify mode or limit
113	case 'm':
114		uuencode_f = uuencodeb64;
115		break;
116	default:
117		usage();
118	} ARGEND
119
120	if (!argc || argc > 2)
121		usage();
122
123	if (argc == 1 || !strcmp(argv[0], "-")) {
124		uuencode_f(stdin, argv[0], "<stdin>");
125	} else {
126		if (!(fp = fopen(argv[0], "r")))
127			eprintf("fopen %s:", argv[0]);
128		uuencode_f(fp, argv[1], argv[0]);
129	}
130
131	ret |= fp && fshut(fp, argv[0]);
132	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
133
134	return ret;
135}