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 }