sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

uuencode.c (3015B)


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