uuencode.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) 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 }