move debugging to safe place (before vfork)
[oweals/busybox.git] / coreutils / uuencode.c
index 68d6f19a775fb8262aea1cca758ca1bdedcdb6e7..fd3326d808f80559b6cc6ac0c4e6fc0a7c16483f 100644 (file)
@@ -21,6 +21,7 @@
  */
 #include <getopt.h>
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -28,7 +29,7 @@
 #include "busybox.h"
 
 /* Conversion table.  for base 64 */
-static char tbl_base64[64] = {
+static const char tbl_base64[65] = {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -36,10 +37,11 @@ static char tbl_base64[64] = {
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
        'w', 'x', 'y', 'z', '0', '1', '2', '3',
-       '4', '5', '6', '7', '8', '9', '+', '/'
+       '4', '5', '6', '7', '8', '9', '+', '/',
+       '=' /* termination character */
 };
 
-static char tbl_std[64] = {
+static const char tbl_std[65] = {
        '`', '!', '"', '#', '$', '%', '&', '\'',
        '(', ')', '*', '+', ',', '-', '.', '/',
        '0', '1', '2', '3', '4', '5', '6', '7',
@@ -47,7 +49,8 @@ static char tbl_std[64] = {
        '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
        'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
        'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
-       'X', 'Y', 'Z', '[', '\\', ']', '^', '_'
+       'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+       '`' /* termination character */
 };
 
 /*
@@ -56,7 +59,7 @@ static char tbl_std[64] = {
  * buffer of at least 1+BASE64_LENGTH(length) bytes.
  * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
  */
-static void base64_encode (const char *s, const char *store, const int length, const char *tbl)
+static void uuencode (const char *s, const char *store, const int length, const char *tbl)
 {
        int i;
        unsigned char *p = (unsigned char *)store;
@@ -71,118 +74,76 @@ static void base64_encode (const char *s, const char *store, const int length, c
        }
        /* Pad the result if necessary...  */
        if (i == length + 1) {
-               *(p - 1) = '=';
+               *(p - 1) = tbl[64];
        }
        else if (i == length + 2) {
-               *(p - 1) = *(p - 2) = '=';
+               *(p - 1) = *(p - 2) = tbl[64];
        }
        /* ...and zero-terminate it.  */
        *p = '\0';
 }
 
+#define SRC_BUF_SIZE   45  // This *MUST* be a multiple of 3
+#define DST_BUF_SIZE    4 * ((SRC_BUF_SIZE + 2) / 3)
 int uuencode_main(int argc, char **argv)
 {
-       const int src_buf_size = 600;   // This *MUST* be a multiple of 3
-       const int dst_buf_size = 4 * ((src_buf_size + 2) / 3);
-       RESERVE_BB_BUFFER(src_buf, src_buf_size + 1);
-       RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1);
+       const int src_buf_size = SRC_BUF_SIZE;
+       const int dst_buf_size = DST_BUF_SIZE;
+       int write_size = dst_buf_size;
        struct stat stat_buf;
        FILE *src_stream = stdin;
-       char *tbl = tbl_std;
+       const char *tbl;
        size_t size;
        mode_t mode;
-       int opt;
-       int column = 0;
-       int write_size;
-       int remaining;
-       int buffer_offset = 0;
+       RESERVE_CONFIG_BUFFER(src_buf, SRC_BUF_SIZE + 1);
+       RESERVE_CONFIG_BUFFER(dst_buf, DST_BUF_SIZE + 1);
 
-       while ((opt = getopt(argc, argv, "m")) != -1) {
-               switch (opt) {
-               case 'm':
-                       tbl = tbl_base64;
-                       break;
-               default:
-                       show_usage();
-               }
+       tbl = tbl_std;
+       if (bb_getopt_ulflags(argc, argv, "m") & 1) {
+               tbl = tbl_base64;
        }
 
        switch (argc - optind) {
                case 2:
-                       src_stream = xfopen(argv[optind], "r");
-                       stat(argv[optind], &stat_buf);
+                       src_stream = bb_xfopen(argv[optind], "r");
+                       if (stat(argv[optind], &stat_buf) < 0) {
+                               bb_perror_msg_and_die("stat");
+                       }
                        mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
                        if (src_stream == stdout) {
-                               printf("NULL\n");
+                               puts("NULL");
                        }
                        break;
                case 1:
-                       mode = umask(0666);
+                       mode = 0666 & ~umask(0666);
                        break;
                default:
-                       show_usage();
+                       bb_show_usage();
        }
 
-       printf("begin%s %o %s", tbl == tbl_std ? "" : "-base64", mode, argv[argc - 1]);
+       bb_printf("begin%s %o %s", tbl == tbl_std ? "" : "-base64", mode, argv[argc - 1]);
 
        while ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0) {
+               if (size != src_buf_size) {
+                       /* write_size is always 60 until the last line */
+                       write_size=(4 * ((size + 2) / 3));
+                       /* pad with 0s so we can just encode extra bits */
+                       memset(&src_buf[size], 0, src_buf_size - size);
+               }
                /* Encode the buffer we just read in */
-               base64_encode(src_buf, dst_buf, size, tbl);
+               uuencode(src_buf, dst_buf, size, tbl);
 
-               /* Write the buffer to stdout, wrapping at 60 chars.
-                * This looks overly complex, but it gets tricky as
-                * the line has to continue to wrap correctly if we
-                * have to refill the buffer
-                *
-                * Improvments most welcome
-                */
-
-               /* Initialise values for the new buffer */
-               remaining = 4 * ((size + 2) / 3);
-               buffer_offset = 0;
-               if (remaining > (60 - column)) {
-                       write_size = 60 - column;
+               putchar('\n');
+               if (tbl == tbl_std) {
+                       putchar(tbl[size]);
                }
-               else if (remaining < 60) {
-                       write_size = remaining;
-               } else {
-                       write_size = 60;
+               if (fwrite(dst_buf, 1, write_size, stdout) != write_size) {
+                       bb_perror_msg_and_die(bb_msg_write_error);
                }
-
-               /* Write the buffer to stdout, wrapping at 60 chars
-                * starting from the column the last buffer ran out
-                */
-               do {
-                       /* Setup a new row if required */
-                       if (column == 0) {
-                               putchar('\n');
-                               if (tbl == tbl_std) {
-                                       putchar('M');
-                               }
-                       }
-                       /* Write to the 60th column */
-                       if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) {
-                               perror("Couldnt finish writing");
-                       }
-                       /* Update variables based on last write */
-                       buffer_offset += write_size;
-                       remaining -= write_size;
-                       column += write_size;
-                       if (column % 60 == 0) {
-                               column = 0;
-                       }
-
-                       /* working next amount to write */
-                       write_size = (60 - column) % 60;
-                       if (write_size < remaining) {
-                               write_size = remaining;
-                       }
-                       if (write_size == 0) {
-                               write_size = 60;
-                       }
-               } while (remaining > 0);
        }
-       printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n");
+       bb_printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n");
+
+       bb_xferror(src_stream, "source");       /* TODO - Fix this! */
 
-       return(EXIT_SUCCESS);
+       bb_fflush_stdout_and_exit(EXIT_SUCCESS);
 }