1 /* uud - bulletproof version of uudecode */
4 * Uud -- decode a uuencoded file back to binary form.
6 * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
7 * The Atari GEMDOS version compiled with MWC 2.x.
8 * The MSDOS version with TurboC.
9 * The Unix version with cc.
10 * this version is made: 25 Nov 1988.
11 * Jan 2 1990: Change system definition and change MSDOS to open the output
12 * file for write binary do cr/lf replacement.
15 #define UNIX 1 /* define one of: UNIX (Minix too!), MSDOS, or GEMDOS */
18 #define SYSNAME "gemdos"
22 #define SYSNAME "msdos"
26 #define SYSNAME "unix"
29 #include <sys/types.h>
39 #define Error(n) { Bconin(2); exit(n); }
41 #define Error(n) exit(n)
46 #define WRITE "wb" /* for both MSDOS and GEMDOS! */
49 #define loop while (1)
54 #define NORMLEN 60 /* allows for 80 encoded chars per line */
59 int first
, secnd
, check
, numl
;
63 char ifname
[FILELEN
], ofname
[FILELEN
];
64 char *source
= NULL
, *target
= NULL
;
65 char blank
, part
= '\0';
67 int debug
= 0, nochk
= 0, onedone
= 0;
68 int chtbl
[NCHARS
], cdlen
[NORMLEN
+ 3];
70 int main(int argc
, char **argv
);
71 char *getnword(char *str
, int n
);
74 void getfile(char *buf
);
75 void format(char *fp
, ...);
76 void doprnt(char *fp
, char *ap
);
77 void puti(unsigned int i
, unsigned int r
);
80 int main(argc
, argv
) int argc
; char *argv
[];
85 char dest
[FILELEN
], buf
[LINELEN
];
87 while ((curarg
= argv
[1]) != NULL
&& curarg
[0] == '-') {
88 if (((curarg
[1] == 'd') || (curarg
[1] == 'D')) &&
89 (curarg
[2] == '\0')) {
91 } else if (((curarg
[1] == 'n') || (curarg
[1] == 'N')) &&
92 (curarg
[2] == '\0')) {
94 } else if (((curarg
[1] == 't') || (curarg
[1] == 'T')) &&
95 (curarg
[2] == '\0')) {
99 format("uud: Missing target directory.\n");
104 format("Target dir = %s\n",target
);
105 } else if (((curarg
[1] == 's') || (curarg
[1] == 'S')) &&
106 (curarg
[2] == '\0')) {
110 format("uud: Missing source directory.\n");
115 format("Source dir = %s\n",source
);
116 } else if (curarg
[1] != '\0') {
117 format("Usage: uud [-n] [-d] [-s dir] [-t dir] [input-file]\n");
125 if (curarg
== NULL
|| ((curarg
[0] == '-') && (curarg
[1] == '\0'))) {
127 strcpy(ifname
, "<stdin>");
129 if (source
!= NULL
) {
130 strcpy(ifname
, source
);
131 strcat(ifname
, curarg
);
133 strcpy(ifname
, curarg
);
134 if ((in
= fopen(ifname
, "r")) == NULL
) {
135 format("uud: Can't open %s\n", ifname
);
142 * Set up the default translation table.
144 for (i
= 0; i
< ' '; i
++) chtbl
[i
] = -1;
145 for (i
= ' ', j
= 0; i
< ' ' + 64; i
++, j
++) chtbl
[i
] = j
;
146 for (i
= ' ' + 64; i
< NCHARS
; i
++) chtbl
[i
] = -1;
147 chtbl
['`'] = chtbl
[' ']; /* common mutation */
148 chtbl
['~'] = chtbl
['^']; /* an other common mutation */
151 * set up the line length table, to avoid computing lotsa * and / ...
154 for (i
= 1, j
= 5; i
<= NORMLEN
; i
+= 3, j
+= 4)
155 cdlen
[i
] = (cdlen
[i
+ 1] = (cdlen
[i
+ 2] = j
));
157 * search for header or translation table line.
159 loop
{ /* master loop for multiple decodes in one file */
162 if (fgets(buf
, sizeof buf
, in
) == NULL
) {
164 if (debug
) format("End of file.\n");
167 format("uud: No begin line.\n");
172 if (strncmp(buf
, "table", (size_t)5) == 0) {
176 if (strncmp(buf
, "begin", (size_t)5) == 0) {
181 if (lens
) buf
[--lens
] = '\0';
183 if ((pos
= getnword(buf
, 3))) {
187 if(sscanf(buf
,"begin%o%s", &mode
, dest
) != 2)
190 format("uud: Missing filename in begin line.\n");
194 if (target
!= NULL
) {
195 strcpy(ofname
, target
);
196 strcat(ofname
, dest
);
198 strcpy(ofname
, dest
);
200 if((out
= fopen(ofname
, WRITE
)) == NULL
) {
201 format("uud: Cannot open output file: %s\n", ofname
);
204 if (debug
) format("Begin uudecoding: %s\n", ofname
);
206 check
= nochk
? 0 : 1;
215 if (debug
) format("End uudecoding: %s\n", ofname
);
216 } /* master loop for multiple decodes in one file */
220 * Bring back a pointer to the start of the nth word.
222 char *getnword(str
, n
) register char *str
; register int n
;
224 while((*str
== '\t') || (*str
== ' ')) str
++;
225 if (! *str
) return NULL
;
227 while ((*str
!= '\t') && (*str
!= ' ') && (*str
)) str
++;
228 if (! *str
) return NULL
;
229 while((*str
== '\t') || (*str
== ' ')) str
++;
230 if (! *str
) return NULL
;
236 * Install the table in memory for later use.
241 register int c
, n
= 0;
244 for (c
= 0; c
< NCHARS
; c
++) chtbl
[c
] = -1;
246 again
: if (fgets(buf
, sizeof buf
, in
) == NULL
) {
247 format("uud: EOF while in translation table.\n");
251 if (strncmp(buf
, "begin", (size_t)5) == 0) {
252 format("uud: Incomplete translation table.\n");
255 cpt
= buf
+ strlen(buf
) - 1;
257 while (*(cpt
) == ' ') {
263 if (chtbl
[c
] != -1) {
264 format("uud: Duplicate char in translation table.\n");
267 if (n
== 0) blank
= c
;
276 * copy from in to out, decoding as you go along.
281 char buf
[LINELEN
], outl
[LINELEN
];
282 register char *bp
, *ut
;
283 register int *trtbl
= chtbl
;
284 register int n
, c
, rlen
;
285 register unsigned int len
;
288 if (fgets(buf
, sizeof buf
, in
) == NULL
) {
289 format("uud: EOF before end.\n");
295 if (len
) buf
[--len
] = '\0';
297 * Is it an unprotected empty line before the end line ?
299 if (len
== 0) continue;
301 * Get the binary line length.
304 if (n
>= 0) goto decod
;
306 * end of uuencoded file ?
308 if (strncmp(buf
, "end", (size_t)3) == 0) return;
310 * end of current file ? : get next one.
312 if (strncmp(buf
, "include", (size_t)7) == 0) {
316 format("uud: Bad prefix line %d in file: %s\n",numl
, ifname
);
317 if (debug
) format("Bad line =%s\n",buf
);
320 * Sequence checking ?
322 decod
: rlen
= cdlen
[n
];
324 * Is it the empty line before the end line ?
326 if (n
== 0) continue;
330 for (bp
= &buf
[c
= len
];
331 c
< rlen
; c
++, bp
++) *bp
= blank
;
333 * Verify if asked for.
336 for (len
= 0, bp
= buf
; len
< rlen
; len
++) {
337 if (trtbl
[*bp
] < 0) {
339 "Non uuencoded char <%c>, line %d in file: %s\n", *bp
, numl
, ifname
);
340 format("Bad line =%s\n",buf
);
347 * All this just to check for uuencodes that append a 'z' to each line....
349 if (secnd
&& check
) {
351 if (buf
[rlen
] == SEQMAX
) {
353 if (debug
) format("Sequence check turned off (2).\n");
355 if (debug
) format("Sequence check on (2).\n");
356 } else if (first
&& check
) {
359 if (buf
[rlen
] != SEQMAX
) {
361 if (debug
) format("No sequence check (1).\n");
363 if (debug
) format("Sequence check on (1).\n");
369 if (buf
[rlen
] != seqc
) {
370 format("uud: Wrong sequence line %d in %s\n",
374 "Sequence char is <%c> instead of <%c>.\n", buf
[rlen
], seqc
);
378 if (seqc
< SEQMIN
) seqc
= SEQMAX
;
381 * output a group of 3 bytes (4 input characters).
382 * the input chars are pointed to by p, they are to
383 * be output to file f.n is used to tell us not to
384 * output all of them at the end of the file.
390 *(ut
++) = trtbl
[*bp
] << 2 | trtbl
[bp
[1]] >> 4;
393 *(ut
++) = (trtbl
[bp
[1]] << 4) |
398 *(ut
++) = trtbl
[bp
[2]] << 6 | trtbl
[bp
[3]];
403 if ((n
= fwrite(outl
, (size_t)1, (size_t)len
, out
)) <= 0) {
404 format("uud: Error on writing decoded file.\n");
411 * Find the next needed file, if existing, otherwise try further
414 void getfile(buf
) register char *buf
;
416 if ((pos
= getnword(buf
, 2)) == NULL
) {
417 format("uud: Missing include file name.\n");
420 if (source
!= NULL
) {
421 strcpy(ifname
, source
);
426 if (Fattrib(ifname
, 0, 0) < 0)
428 if (access(ifname
, 04))
432 format("Cant find: %s\n", ifname
);
433 format("Continuing to read same file.\n");
437 if (freopen(ifname
, "r", in
) == in
) {
440 format("Reading next section from: %s\n", ifname
);
442 format("uud: Freopen abort: %s\n", ifname
);
447 if (fgets(buf
, LINELEN
, in
) == NULL
) {
448 format("uud: No begin line after include: %s\n", ifname
);
452 if (strncmp(buf
, "table", (size_t)5) == 0) {
456 if (strncmp(buf
, "begin", (size_t)5) == 0) break;
459 if (lens
) buf
[--lens
] = '\0';
461 * Check the part suffix.
463 if ((pos
= getnword(buf
, 3)) == NULL
) {
464 format("uud: Missing part name, in included file: %s\n", ifname
);
469 if (partn
> 'z') partn
= 'a';
471 format("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
475 if (debug
) format("Reading part %c\n", *pos
);
480 * Printf style formatting. (Borrowed from MicroEmacs by Dave Conroy.)
481 * A lot smaller than the full fledged printf.
484 void format(char *fp
, ...)
489 doprnt(fp
, (char *)&args
);
494 void format(fp
, args
) char *fp
;
496 doprnt(fp
, (char *)&args
);
507 while ((c
= *fp
++) != '\0') {
514 puti(*(int *)ap
, 10);
520 while ((k
= *s
++) != '\0')
522 ap
+= sizeof(char *);
538 * Put integer, in radix "r".
541 register unsigned int i
;
542 register unsigned int r
;
544 register unsigned int q
, s
;
546 if ((q
= i
/ r
) != 0)
554 void outc(c
) register char c
;
557 if (c
== '\n') Bconout(2, '\r');