busybox/coreutils/split.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * split - split a file into pieces
   4 * Copyright (c) 2007 Bernhard Reutner-Fischer
   5 *
   6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   7 */
   8/* BB_AUDIT: SUSv3 compliant
   9 * SUSv3 requirements:
  10 * http://www.opengroup.org/onlinepubs/009695399/utilities/split.html
  11 */
  12#include "libbb.h"
  13
  14static const struct suffix_mult split_suffices[] = {
  15#if ENABLE_FEATURE_SPLIT_FANCY
  16        { "b", 512 },
  17#endif
  18        { "k", 1024 },
  19        { "m", 1024*1024 },
  20#if ENABLE_FEATURE_SPLIT_FANCY
  21        { "g", 1024*1024*1024 },
  22#endif
  23        { "", 0 }
  24};
  25
  26/* Increment the suffix part of the filename.
  27 * Returns NULL if we are out of filenames.
  28 */
  29static char *next_file(char *old, unsigned suffix_len)
  30{
  31        size_t end = strlen(old);
  32        unsigned i = 1;
  33        char *curr;
  34
  35        do {
  36                curr = old + end - i;
  37                if (*curr < 'z') {
  38                        *curr += 1;
  39                        break;
  40                }
  41                i++;
  42                if (i > suffix_len) {
  43                        return NULL;
  44                }
  45                *curr = 'a';
  46        } while (1);
  47
  48        return old;
  49}
  50
  51#define read_buffer bb_common_bufsiz1
  52enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 };
  53
  54#define SPLIT_OPT_l (1<<0)
  55#define SPLIT_OPT_b (1<<1)
  56#define SPLIT_OPT_a (1<<2)
  57
  58int split_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  59int split_main(int argc UNUSED_PARAM, char **argv)
  60{
  61        unsigned suffix_len = 2;
  62        char *pfx;
  63        char *count_p;
  64        const char *sfx;
  65        off_t cnt = 1000;
  66        off_t remaining = 0;
  67        unsigned opt;
  68        ssize_t bytes_read, to_write;
  69        char *src;
  70
  71        opt_complementary = "?2:a+"; /* max 2 args; -a N */
  72        opt = getopt32(argv, "l:b:a:", &count_p, &count_p, &suffix_len);
  73
  74        if (opt & SPLIT_OPT_l)
  75                cnt = XATOOFF(count_p);
  76        if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF
  77                cnt = xatoull_sfx(count_p, split_suffices);
  78        sfx = "x";
  79
  80        argv += optind;
  81        if (argv[0]) {
  82                int fd;
  83                if (argv[1])
  84                        sfx = argv[1];
  85                fd = xopen_stdin(argv[0]);
  86                xmove_fd(fd, STDIN_FILENO);
  87        } else {
  88                argv[0] = (char *) bb_msg_standard_input;
  89        }
  90
  91        if (NAME_MAX < strlen(sfx) + suffix_len)
  92                bb_error_msg_and_die("suffix too long");
  93
  94        {
  95                char *char_p = xzalloc(suffix_len + 1);
  96                memset(char_p, 'a', suffix_len);
  97                pfx = xasprintf("%s%s", sfx, char_p);
  98                if (ENABLE_FEATURE_CLEAN_UP)
  99                        free(char_p);
 100        }
 101
 102        while (1) {
 103                bytes_read = safe_read(STDIN_FILENO, read_buffer, READ_BUFFER_SIZE);
 104                if (!bytes_read)
 105                        break;
 106                if (bytes_read < 0)
 107                        bb_simple_perror_msg_and_die(argv[0]);
 108                src = read_buffer;
 109                do {
 110                        if (!remaining) {
 111                                if (!pfx)
 112                                        bb_error_msg_and_die("suffixes exhausted");
 113                                xmove_fd(xopen(pfx, O_WRONLY | O_CREAT | O_TRUNC), 1);
 114                                pfx = next_file(pfx, suffix_len);
 115                                remaining = cnt;
 116                        }
 117
 118                        if (opt & SPLIT_OPT_b) {
 119                                /* split by bytes */
 120                                to_write = (bytes_read < remaining) ? bytes_read : remaining;
 121                                remaining -= to_write;
 122                        } else {
 123                                /* split by lines */
 124                                /* can be sped up by using _memrchr_
 125                                 * and writing many lines at once... */
 126                                char *end = memchr(src, '\n', bytes_read);
 127                                if (end) {
 128                                        --remaining;
 129                                        to_write = end - src + 1;
 130                                } else {
 131                                        to_write = bytes_read;
 132                                }
 133                        }
 134
 135                        xwrite(STDOUT_FILENO, src, to_write);
 136                        bytes_read -= to_write;
 137                        src += to_write;
 138                } while (bytes_read);
 139        }
 140        return EXIT_SUCCESS;
 141}
 142