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//config:config SPLIT
   9//config:       bool "split (5 kb)"
  10//config:       default y
  11//config:       help
  12//config:       Split a file into pieces.
  13//config:
  14//config:config FEATURE_SPLIT_FANCY
  15//config:       bool "Fancy extensions"
  16//config:       default y
  17//config:       depends on SPLIT
  18//config:       help
  19//config:       Add support for features not required by SUSv3.
  20//config:       Supports additional suffixes 'b' for 512 bytes,
  21//config:       'g' for 1GiB for the -b option.
  22
  23//applet:IF_SPLIT(APPLET(split, BB_DIR_USR_BIN, BB_SUID_DROP))
  24
  25//kbuild:lib-$(CONFIG_SPLIT) += split.o
  26
  27/* BB_AUDIT: SUSv3 compliant
  28 * SUSv3 requirements:
  29 * http://www.opengroup.org/onlinepubs/009695399/utilities/split.html
  30 */
  31
  32//usage:#define split_trivial_usage
  33//usage:       "[OPTIONS] [INPUT [PREFIX]]"
  34//usage:#define split_full_usage "\n\n"
  35//usage:       "        -b N[k|m]       Split by N (kilo|mega)bytes"
  36//usage:     "\n        -l N            Split by N lines"
  37//usage:     "\n        -a N            Use N letters as suffix"
  38//usage:
  39//usage:#define split_example_usage
  40//usage:       "$ split TODO foo\n"
  41//usage:       "$ cat TODO | split -a 2 -l 2 TODO_\n"
  42
  43#include "libbb.h"
  44#include "common_bufsiz.h"
  45
  46#if ENABLE_FEATURE_SPLIT_FANCY
  47static const struct suffix_mult split_suffixes[] ALIGN_SUFFIX = {
  48        { "b", 512 },
  49        { "k", 1024 },
  50        { "m", 1024*1024 },
  51        { "g", 1024*1024*1024 },
  52        { "", 0 }
  53};
  54#endif
  55
  56/* Increment the suffix part of the filename.
  57 * Returns NULL if we are out of filenames.
  58 */
  59static char *next_file(char *old, unsigned suffix_len)
  60{
  61        size_t end = strlen(old);
  62        unsigned i = 1;
  63        char *curr;
  64
  65        while (1) {
  66                curr = old + end - i;
  67                if (*curr < 'z') {
  68                        *curr += 1;
  69                        break;
  70                }
  71                i++;
  72                if (i > suffix_len) {
  73                        return NULL;
  74                }
  75                *curr = 'a';
  76        }
  77
  78        return old;
  79}
  80
  81#define read_buffer bb_common_bufsiz1
  82enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 };
  83
  84#define SPLIT_OPT_l (1<<0)
  85#define SPLIT_OPT_b (1<<1)
  86#define SPLIT_OPT_a (1<<2)
  87
  88int split_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  89int split_main(int argc UNUSED_PARAM, char **argv)
  90{
  91        unsigned suffix_len = 2;
  92        char *pfx;
  93        char *count_p;
  94        const char *sfx;
  95        off_t cnt = 1000;
  96        off_t remaining = 0;
  97        unsigned opt;
  98        ssize_t bytes_read, to_write;
  99        char *src;
 100
 101        setup_common_bufsiz();
 102
 103        opt = getopt32(argv, "^"
 104                        "l:b:a:+" /* -a N */
 105                        "\0" "?2"/*max 2 args*/,
 106                        &count_p, &count_p, &suffix_len
 107        );
 108
 109        if (opt & SPLIT_OPT_l)
 110                cnt = XATOOFF(count_p);
 111        if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF
 112                cnt = xatoull_sfx(count_p,
 113                                IF_FEATURE_SPLIT_FANCY(split_suffixes)
 114                                IF_NOT_FEATURE_SPLIT_FANCY(km_suffixes)
 115                );
 116        sfx = "x";
 117
 118        argv += optind;
 119        if (argv[0]) {
 120                int fd;
 121                if (argv[1])
 122                        sfx = argv[1];
 123                fd = xopen_stdin(argv[0]);
 124                xmove_fd(fd, STDIN_FILENO);
 125        } else {
 126                argv[0] = (char *) bb_msg_standard_input;
 127        }
 128
 129        if (NAME_MAX < strlen(sfx) + suffix_len)
 130                bb_simple_error_msg_and_die("suffix too long");
 131
 132        {
 133                char *char_p = xzalloc(suffix_len + 1);
 134                memset(char_p, 'a', suffix_len);
 135                pfx = xasprintf("%s%s", sfx, char_p);
 136                if (ENABLE_FEATURE_CLEAN_UP)
 137                        free(char_p);
 138        }
 139
 140        while (1) {
 141                bytes_read = safe_read(STDIN_FILENO, read_buffer, READ_BUFFER_SIZE);
 142                if (!bytes_read)
 143                        break;
 144                if (bytes_read < 0)
 145                        bb_simple_perror_msg_and_die(argv[0]);
 146                src = read_buffer;
 147                do {
 148                        if (!remaining) {
 149                                if (!pfx)
 150                                        bb_simple_error_msg_and_die("suffixes exhausted");
 151                                xmove_fd(xopen(pfx, O_WRONLY | O_CREAT | O_TRUNC), 1);
 152                                pfx = next_file(pfx, suffix_len);
 153                                remaining = cnt;
 154                        }
 155
 156                        if (opt & SPLIT_OPT_b) {
 157                                /* split by bytes */
 158                                to_write = (bytes_read < remaining) ? bytes_read : remaining;
 159                                remaining -= to_write;
 160                        } else {
 161                                /* split by lines */
 162                                /* can be sped up by using _memrchr_
 163                                 * and writing many lines at once... */
 164                                char *end = memchr(src, '\n', bytes_read);
 165                                if (end) {
 166                                        --remaining;
 167                                        to_write = end - src + 1;
 168                                } else {
 169                                        to_write = bytes_read;
 170                                }
 171                        }
 172
 173                        xwrite(STDOUT_FILENO, src, to_write);
 174                        bytes_read -= to_write;
 175                        src += to_write;
 176                } while (bytes_read);
 177        }
 178        return EXIT_SUCCESS;
 179}
 180