| 1 | /* split.c -- split a file into pieces.
|
|---|
| 2 | Copyright (C) 88, 91, 1995-2005 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This program is free software; you can redistribute it and/or modify
|
|---|
| 5 | it under the terms of the GNU General Public License as published by
|
|---|
| 6 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 7 | any later version.
|
|---|
| 8 |
|
|---|
| 9 | This program is distributed in the hope that it will be useful,
|
|---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 12 | GNU General Public License for more details.
|
|---|
| 13 |
|
|---|
| 14 | You should have received a copy of the GNU General Public License
|
|---|
| 15 | along with this program; if not, write to the Free Software Foundation,
|
|---|
| 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
|---|
| 17 | |
|---|
| 18 |
|
|---|
| 19 | /* By [email protected], with rms.
|
|---|
| 20 |
|
|---|
| 21 | To do:
|
|---|
| 22 | * Implement -t CHAR or -t REGEX to specify break characters other
|
|---|
| 23 | than newline. */
|
|---|
| 24 |
|
|---|
| 25 | #include <config.h>
|
|---|
| 26 |
|
|---|
| 27 | #include <stdio.h>
|
|---|
| 28 | #include <getopt.h>
|
|---|
| 29 | #include <sys/types.h>
|
|---|
| 30 |
|
|---|
| 31 | #include "system.h"
|
|---|
| 32 | #include "dirname.h"
|
|---|
| 33 | #include "error.h"
|
|---|
| 34 | #include "fd-reopen.h"
|
|---|
| 35 | #include "fcntl--.h"
|
|---|
| 36 | #include "getpagesize.h"
|
|---|
| 37 | #include "full-read.h"
|
|---|
| 38 | #include "full-write.h"
|
|---|
| 39 | #include "inttostr.h"
|
|---|
| 40 | #include "quote.h"
|
|---|
| 41 | #include "safe-read.h"
|
|---|
| 42 | #include "xstrtol.h"
|
|---|
| 43 |
|
|---|
| 44 | /* The official name of this program (e.g., no `g' prefix). */
|
|---|
| 45 | #define PROGRAM_NAME "split"
|
|---|
| 46 |
|
|---|
| 47 | #define AUTHORS "Torbjorn Granlund", "Richard M. Stallman"
|
|---|
| 48 |
|
|---|
| 49 | #define DEFAULT_SUFFIX_LENGTH 2
|
|---|
| 50 |
|
|---|
| 51 | /* The name this program was run with. */
|
|---|
| 52 | char *program_name;
|
|---|
| 53 |
|
|---|
| 54 | /* Base name of output files. */
|
|---|
| 55 | static char const *outbase;
|
|---|
| 56 |
|
|---|
| 57 | /* Name of output files. */
|
|---|
| 58 | static char *outfile;
|
|---|
| 59 |
|
|---|
| 60 | /* Pointer to the end of the prefix in OUTFILE.
|
|---|
| 61 | Suffixes are inserted here. */
|
|---|
| 62 | static char *outfile_mid;
|
|---|
| 63 |
|
|---|
| 64 | /* Length of OUTFILE's suffix. */
|
|---|
| 65 | static size_t suffix_length = DEFAULT_SUFFIX_LENGTH;
|
|---|
| 66 |
|
|---|
| 67 | /* Alphabet of characters to use in suffix. */
|
|---|
| 68 | static char const *suffix_alphabet = "abcdefghijklmnopqrstuvwxyz";
|
|---|
| 69 |
|
|---|
| 70 | /* Name of input file. May be "-". */
|
|---|
| 71 | static char *infile;
|
|---|
| 72 |
|
|---|
| 73 | /* Descriptor on which output file is open. */
|
|---|
| 74 | static int output_desc;
|
|---|
| 75 |
|
|---|
| 76 | /* If true, print a diagnostic on standard error just before each
|
|---|
| 77 | output file is opened. */
|
|---|
| 78 | static bool verbose;
|
|---|
| 79 |
|
|---|
| 80 | /* For long options that have no equivalent short option, use a
|
|---|
| 81 | non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
|---|
| 82 | enum
|
|---|
| 83 | {
|
|---|
| 84 | VERBOSE_OPTION = CHAR_MAX + 1
|
|---|
| 85 | };
|
|---|
| 86 |
|
|---|
| 87 | static struct option const longopts[] =
|
|---|
| 88 | {
|
|---|
| 89 | {"bytes", required_argument, NULL, 'b'},
|
|---|
| 90 | {"lines", required_argument, NULL, 'l'},
|
|---|
| 91 | {"line-bytes", required_argument, NULL, 'C'},
|
|---|
| 92 | {"suffix-length", required_argument, NULL, 'a'},
|
|---|
| 93 | {"numeric-suffixes", no_argument, NULL, 'd'},
|
|---|
| 94 | {"verbose", no_argument, NULL, VERBOSE_OPTION},
|
|---|
| 95 | {GETOPT_HELP_OPTION_DECL},
|
|---|
| 96 | {GETOPT_VERSION_OPTION_DECL},
|
|---|
| 97 | {NULL, 0, NULL, 0}
|
|---|
| 98 | };
|
|---|
| 99 |
|
|---|
| 100 | void
|
|---|
| 101 | usage (int status)
|
|---|
| 102 | {
|
|---|
| 103 | if (status != EXIT_SUCCESS)
|
|---|
| 104 | fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
|---|
| 105 | program_name);
|
|---|
| 106 | else
|
|---|
| 107 | {
|
|---|
| 108 | printf (_("\
|
|---|
| 109 | Usage: %s [OPTION] [INPUT [PREFIX]]\n\
|
|---|
| 110 | "),
|
|---|
| 111 | program_name);
|
|---|
| 112 | fputs (_("\
|
|---|
| 113 | Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\
|
|---|
| 114 | size is 1000 lines, and default PREFIX is `x'. With no INPUT, or when INPUT\n\
|
|---|
| 115 | is -, read standard input.\n\
|
|---|
| 116 | \n\
|
|---|
| 117 | "), stdout);
|
|---|
| 118 | fputs (_("\
|
|---|
| 119 | Mandatory arguments to long options are mandatory for short options too.\n\
|
|---|
| 120 | "), stdout);
|
|---|
| 121 | fprintf (stdout, _("\
|
|---|
| 122 | -a, --suffix-length=N use suffixes of length N (default %d)\n\
|
|---|
| 123 | -b, --bytes=SIZE put SIZE bytes per output file\n\
|
|---|
| 124 | -C, --line-bytes=SIZE put at most SIZE bytes of lines per output file\n\
|
|---|
| 125 | -d, --numeric-suffixes use numeric suffixes instead of alphabetic\n\
|
|---|
| 126 | -l, --lines=NUMBER put NUMBER lines per output file\n\
|
|---|
| 127 | "), DEFAULT_SUFFIX_LENGTH);
|
|---|
| 128 | fputs (_("\
|
|---|
| 129 | --verbose print a diagnostic to standard error just\n\
|
|---|
| 130 | before each output file is opened\n\
|
|---|
| 131 | "), stdout);
|
|---|
| 132 | fputs (HELP_OPTION_DESCRIPTION, stdout);
|
|---|
| 133 | fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
|---|
| 134 | fputs (_("\
|
|---|
| 135 | \n\
|
|---|
| 136 | SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
|
|---|
| 137 | "), stdout);
|
|---|
| 138 | printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
|---|
| 139 | }
|
|---|
| 140 | exit (status);
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | /* Compute the next sequential output file name and store it into the
|
|---|
| 144 | string `outfile'. */
|
|---|
| 145 |
|
|---|
| 146 | static void
|
|---|
| 147 | next_file_name (void)
|
|---|
| 148 | {
|
|---|
| 149 | /* Index in suffix_alphabet of each character in the suffix. */
|
|---|
| 150 | static size_t *sufindex;
|
|---|
| 151 |
|
|---|
| 152 | if (! outfile)
|
|---|
| 153 | {
|
|---|
| 154 | /* Allocate and initialize the first file name. */
|
|---|
| 155 |
|
|---|
| 156 | size_t outbase_length = strlen (outbase);
|
|---|
| 157 | size_t outfile_length = outbase_length + suffix_length;
|
|---|
| 158 | if (outfile_length + 1 < outbase_length)
|
|---|
| 159 | xalloc_die ();
|
|---|
| 160 | outfile = xmalloc (outfile_length + 1);
|
|---|
| 161 | outfile_mid = outfile + outbase_length;
|
|---|
| 162 | memcpy (outfile, outbase, outbase_length);
|
|---|
| 163 | memset (outfile_mid, suffix_alphabet[0], suffix_length);
|
|---|
| 164 | outfile[outfile_length] = 0;
|
|---|
| 165 | sufindex = xcalloc (suffix_length, sizeof *sufindex);
|
|---|
| 166 |
|
|---|
| 167 | #if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
|
|---|
| 168 | /* POSIX requires that if the output file name is too long for
|
|---|
| 169 | its directory, `split' must fail without creating any files.
|
|---|
| 170 | This must be checked for explicitly on operating systems that
|
|---|
| 171 | silently truncate file names. */
|
|---|
| 172 | {
|
|---|
| 173 | char *dir = dir_name (outfile);
|
|---|
| 174 | long name_max = pathconf (dir, _PC_NAME_MAX);
|
|---|
| 175 | if (0 <= name_max && name_max < base_len (base_name (outfile)))
|
|---|
| 176 | error (EXIT_FAILURE, ENAMETOOLONG, "%s", outfile);
|
|---|
| 177 | free (dir);
|
|---|
| 178 | }
|
|---|
| 179 | #endif
|
|---|
| 180 | }
|
|---|
| 181 | else
|
|---|
| 182 | {
|
|---|
| 183 | /* Increment the suffix in place, if possible. */
|
|---|
| 184 |
|
|---|
| 185 | size_t i = suffix_length;
|
|---|
| 186 | while (i-- != 0)
|
|---|
| 187 | {
|
|---|
| 188 | sufindex[i]++;
|
|---|
| 189 | outfile_mid[i] = suffix_alphabet[sufindex[i]];
|
|---|
| 190 | if (outfile_mid[i])
|
|---|
| 191 | return;
|
|---|
| 192 | sufindex[i] = 0;
|
|---|
| 193 | outfile_mid[i] = suffix_alphabet[sufindex[i]];
|
|---|
| 194 | }
|
|---|
| 195 | error (EXIT_FAILURE, 0, _("Output file suffixes exhausted"));
|
|---|
| 196 | }
|
|---|
| 197 | }
|
|---|
| 198 |
|
|---|
| 199 | /* Write BYTES bytes at BP to an output file.
|
|---|
| 200 | If NEW_FILE_FLAG is true, open the next output file.
|
|---|
| 201 | Otherwise add to the same output file already in use. */
|
|---|
| 202 |
|
|---|
| 203 | static void
|
|---|
| 204 | cwrite (bool new_file_flag, const char *bp, size_t bytes)
|
|---|
| 205 | {
|
|---|
| 206 | if (new_file_flag)
|
|---|
| 207 | {
|
|---|
| 208 | if (output_desc >= 0 && close (output_desc) < 0)
|
|---|
| 209 | error (EXIT_FAILURE, errno, "%s", outfile);
|
|---|
| 210 |
|
|---|
| 211 | next_file_name ();
|
|---|
| 212 | if (verbose)
|
|---|
| 213 | fprintf (stderr, _("creating file %s\n"), quote (outfile));
|
|---|
| 214 | output_desc = open (outfile,
|
|---|
| 215 | O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
|---|
| 216 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
|
|---|
| 217 | | S_IROTH | S_IWOTH));
|
|---|
| 218 | if (output_desc < 0)
|
|---|
| 219 | error (EXIT_FAILURE, errno, "%s", outfile);
|
|---|
| 220 | }
|
|---|
| 221 | if (full_write (output_desc, bp, bytes) != bytes)
|
|---|
| 222 | error (EXIT_FAILURE, errno, "%s", outfile);
|
|---|
| 223 | }
|
|---|
| 224 |
|
|---|
| 225 | /* Split into pieces of exactly N_BYTES bytes.
|
|---|
| 226 | Use buffer BUF, whose size is BUFSIZE. */
|
|---|
| 227 |
|
|---|
| 228 | static void
|
|---|
| 229 | bytes_split (uintmax_t n_bytes, char *buf, size_t bufsize)
|
|---|
| 230 | {
|
|---|
| 231 | size_t n_read;
|
|---|
| 232 | bool new_file_flag = true;
|
|---|
| 233 | size_t to_read;
|
|---|
| 234 | uintmax_t to_write = n_bytes;
|
|---|
| 235 | char *bp_out;
|
|---|
| 236 |
|
|---|
| 237 | do
|
|---|
| 238 | {
|
|---|
| 239 | n_read = full_read (STDIN_FILENO, buf, bufsize);
|
|---|
| 240 | if (n_read == SAFE_READ_ERROR)
|
|---|
| 241 | error (EXIT_FAILURE, errno, "%s", infile);
|
|---|
| 242 | bp_out = buf;
|
|---|
| 243 | to_read = n_read;
|
|---|
| 244 | for (;;)
|
|---|
| 245 | {
|
|---|
| 246 | if (to_read < to_write)
|
|---|
| 247 | {
|
|---|
| 248 | if (to_read) /* do not write 0 bytes! */
|
|---|
| 249 | {
|
|---|
| 250 | cwrite (new_file_flag, bp_out, to_read);
|
|---|
| 251 | to_write -= to_read;
|
|---|
| 252 | new_file_flag = false;
|
|---|
| 253 | }
|
|---|
| 254 | break;
|
|---|
| 255 | }
|
|---|
| 256 | else
|
|---|
| 257 | {
|
|---|
| 258 | size_t w = to_write;
|
|---|
| 259 | cwrite (new_file_flag, bp_out, w);
|
|---|
| 260 | bp_out += w;
|
|---|
| 261 | to_read -= w;
|
|---|
| 262 | new_file_flag = true;
|
|---|
| 263 | to_write = n_bytes;
|
|---|
| 264 | }
|
|---|
| 265 | }
|
|---|
| 266 | }
|
|---|
| 267 | while (n_read == bufsize);
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | /* Split into pieces of exactly N_LINES lines.
|
|---|
| 271 | Use buffer BUF, whose size is BUFSIZE. */
|
|---|
| 272 |
|
|---|
| 273 | static void
|
|---|
| 274 | lines_split (uintmax_t n_lines, char *buf, size_t bufsize)
|
|---|
| 275 | {
|
|---|
| 276 | size_t n_read;
|
|---|
| 277 | char *bp, *bp_out, *eob;
|
|---|
| 278 | bool new_file_flag = true;
|
|---|
| 279 | uintmax_t n = 0;
|
|---|
| 280 |
|
|---|
| 281 | do
|
|---|
| 282 | {
|
|---|
| 283 | n_read = full_read (STDIN_FILENO, buf, bufsize);
|
|---|
| 284 | if (n_read == SAFE_READ_ERROR)
|
|---|
| 285 | error (EXIT_FAILURE, errno, "%s", infile);
|
|---|
| 286 | bp = bp_out = buf;
|
|---|
| 287 | eob = bp + n_read;
|
|---|
| 288 | *eob = '\n';
|
|---|
| 289 | for (;;)
|
|---|
| 290 | {
|
|---|
| 291 | bp = memchr (bp, '\n', eob - bp + 1);
|
|---|
| 292 | if (bp == eob)
|
|---|
| 293 | {
|
|---|
| 294 | if (eob != bp_out) /* do not write 0 bytes! */
|
|---|
| 295 | {
|
|---|
| 296 | size_t len = eob - bp_out;
|
|---|
| 297 | cwrite (new_file_flag, bp_out, len);
|
|---|
| 298 | new_file_flag = false;
|
|---|
| 299 | }
|
|---|
| 300 | break;
|
|---|
| 301 | }
|
|---|
| 302 |
|
|---|
| 303 | ++bp;
|
|---|
| 304 | if (++n >= n_lines)
|
|---|
| 305 | {
|
|---|
| 306 | cwrite (new_file_flag, bp_out, bp - bp_out);
|
|---|
| 307 | bp_out = bp;
|
|---|
| 308 | new_file_flag = true;
|
|---|
| 309 | n = 0;
|
|---|
| 310 | }
|
|---|
| 311 | }
|
|---|
| 312 | }
|
|---|
| 313 | while (n_read == bufsize);
|
|---|
| 314 | }
|
|---|
| 315 | |
|---|
| 316 |
|
|---|
| 317 | /* Split into pieces that are as large as possible while still not more
|
|---|
| 318 | than N_BYTES bytes, and are split on line boundaries except
|
|---|
| 319 | where lines longer than N_BYTES bytes occur.
|
|---|
| 320 | FIXME: Allow N_BYTES to be any uintmax_t value, and don't require a
|
|---|
| 321 | buffer of size N_BYTES, in case N_BYTES is very large. */
|
|---|
| 322 |
|
|---|
| 323 | static void
|
|---|
| 324 | line_bytes_split (size_t n_bytes)
|
|---|
| 325 | {
|
|---|
| 326 | size_t n_read;
|
|---|
| 327 | char *bp;
|
|---|
| 328 | bool eof = false;
|
|---|
| 329 | size_t n_buffered = 0;
|
|---|
| 330 | char *buf = xmalloc (n_bytes);
|
|---|
| 331 |
|
|---|
| 332 | do
|
|---|
| 333 | {
|
|---|
| 334 | /* Fill up the full buffer size from the input file. */
|
|---|
| 335 |
|
|---|
| 336 | n_read = full_read (STDIN_FILENO, buf + n_buffered, n_bytes - n_buffered);
|
|---|
| 337 | if (n_read == SAFE_READ_ERROR)
|
|---|
| 338 | error (EXIT_FAILURE, errno, "%s", infile);
|
|---|
| 339 |
|
|---|
| 340 | n_buffered += n_read;
|
|---|
| 341 | if (n_buffered != n_bytes)
|
|---|
| 342 | eof = true;
|
|---|
| 343 |
|
|---|
| 344 | /* Find where to end this chunk. */
|
|---|
| 345 | bp = buf + n_buffered;
|
|---|
| 346 | if (n_buffered == n_bytes)
|
|---|
| 347 | {
|
|---|
| 348 | while (bp > buf && bp[-1] != '\n')
|
|---|
| 349 | bp--;
|
|---|
| 350 | }
|
|---|
| 351 |
|
|---|
| 352 | /* If chunk has no newlines, use all the chunk. */
|
|---|
| 353 | if (bp == buf)
|
|---|
| 354 | bp = buf + n_buffered;
|
|---|
| 355 |
|
|---|
| 356 | /* Output the chars as one output file. */
|
|---|
| 357 | cwrite (true, buf, bp - buf);
|
|---|
| 358 |
|
|---|
| 359 | /* Discard the chars we just output; move rest of chunk
|
|---|
| 360 | down to be the start of the next chunk. Source and
|
|---|
| 361 | destination probably overlap. */
|
|---|
| 362 | n_buffered -= bp - buf;
|
|---|
| 363 | if (n_buffered > 0)
|
|---|
| 364 | memmove (buf, bp, n_buffered);
|
|---|
| 365 | }
|
|---|
| 366 | while (!eof);
|
|---|
| 367 | free (buf);
|
|---|
| 368 | }
|
|---|
| 369 |
|
|---|
| 370 | #define FAIL_ONLY_ONE_WAY() \
|
|---|
| 371 | do \
|
|---|
| 372 | { \
|
|---|
| 373 | error (0, 0, _("cannot split in more than one way")); \
|
|---|
| 374 | usage (EXIT_FAILURE); \
|
|---|
| 375 | } \
|
|---|
| 376 | while (0)
|
|---|
| 377 |
|
|---|
| 378 | int
|
|---|
| 379 | main (int argc, char **argv)
|
|---|
| 380 | {
|
|---|
| 381 | struct stat stat_buf;
|
|---|
| 382 | enum
|
|---|
| 383 | {
|
|---|
| 384 | type_undef, type_bytes, type_byteslines, type_lines, type_digits
|
|---|
| 385 | } split_type = type_undef;
|
|---|
| 386 | size_t in_blk_size; /* optimal block size of input file device */
|
|---|
| 387 | char *buf; /* file i/o buffer */
|
|---|
| 388 | size_t page_size = getpagesize ();
|
|---|
| 389 | uintmax_t n_units;
|
|---|
| 390 | int c;
|
|---|
| 391 | int digits_optind = 0;
|
|---|
| 392 |
|
|---|
| 393 | initialize_main (&argc, &argv);
|
|---|
| 394 | program_name = argv[0];
|
|---|
| 395 | setlocale (LC_ALL, "");
|
|---|
| 396 | bindtextdomain (PACKAGE, LOCALEDIR);
|
|---|
| 397 | textdomain (PACKAGE);
|
|---|
| 398 |
|
|---|
| 399 | atexit (close_stdout);
|
|---|
| 400 |
|
|---|
| 401 | /* Parse command line options. */
|
|---|
| 402 |
|
|---|
| 403 | infile = "-";
|
|---|
| 404 | outbase = "x";
|
|---|
| 405 |
|
|---|
| 406 | while (1)
|
|---|
| 407 | {
|
|---|
| 408 | /* This is the argv-index of the option we will read next. */
|
|---|
| 409 | int this_optind = optind ? optind : 1;
|
|---|
| 410 |
|
|---|
| 411 | c = getopt_long (argc, argv, "0123456789C:a:b:dl:", longopts, NULL);
|
|---|
| 412 | if (c == -1)
|
|---|
| 413 | break;
|
|---|
| 414 |
|
|---|
| 415 | switch (c)
|
|---|
| 416 | {
|
|---|
| 417 | case 'a':
|
|---|
| 418 | {
|
|---|
| 419 | unsigned long tmp;
|
|---|
| 420 | if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK
|
|---|
| 421 | || SIZE_MAX / sizeof (size_t) < tmp)
|
|---|
| 422 | {
|
|---|
| 423 | error (0, 0, _("%s: invalid suffix length"), optarg);
|
|---|
| 424 | usage (EXIT_FAILURE);
|
|---|
| 425 | }
|
|---|
| 426 | suffix_length = tmp;
|
|---|
| 427 | }
|
|---|
| 428 | break;
|
|---|
| 429 |
|
|---|
| 430 | case 'b':
|
|---|
| 431 | if (split_type != type_undef)
|
|---|
| 432 | FAIL_ONLY_ONE_WAY ();
|
|---|
| 433 | split_type = type_bytes;
|
|---|
| 434 | if (xstrtoumax (optarg, NULL, 10, &n_units, "bkm") != LONGINT_OK
|
|---|
| 435 | || n_units == 0)
|
|---|
| 436 | {
|
|---|
| 437 | error (0, 0, _("%s: invalid number of bytes"), optarg);
|
|---|
| 438 | usage (EXIT_FAILURE);
|
|---|
| 439 | }
|
|---|
| 440 | break;
|
|---|
| 441 |
|
|---|
| 442 | case 'l':
|
|---|
| 443 | if (split_type != type_undef)
|
|---|
| 444 | FAIL_ONLY_ONE_WAY ();
|
|---|
| 445 | split_type = type_lines;
|
|---|
| 446 | if (xstrtoumax (optarg, NULL, 10, &n_units, "") != LONGINT_OK
|
|---|
| 447 | || n_units == 0)
|
|---|
| 448 | {
|
|---|
| 449 | error (0, 0, _("%s: invalid number of lines"), optarg);
|
|---|
| 450 | usage (EXIT_FAILURE);
|
|---|
| 451 | }
|
|---|
| 452 | break;
|
|---|
| 453 |
|
|---|
| 454 | case 'C':
|
|---|
| 455 | if (split_type != type_undef)
|
|---|
| 456 | FAIL_ONLY_ONE_WAY ();
|
|---|
| 457 | split_type = type_byteslines;
|
|---|
| 458 | if (xstrtoumax (optarg, NULL, 10, &n_units, "bkm") != LONGINT_OK
|
|---|
| 459 | || n_units == 0 || SIZE_MAX < n_units)
|
|---|
| 460 | {
|
|---|
| 461 | error (0, 0, _("%s: invalid number of bytes"), optarg);
|
|---|
| 462 | usage (EXIT_FAILURE);
|
|---|
| 463 | }
|
|---|
| 464 | break;
|
|---|
| 465 |
|
|---|
| 466 | case '0':
|
|---|
| 467 | case '1':
|
|---|
| 468 | case '2':
|
|---|
| 469 | case '3':
|
|---|
| 470 | case '4':
|
|---|
| 471 | case '5':
|
|---|
| 472 | case '6':
|
|---|
| 473 | case '7':
|
|---|
| 474 | case '8':
|
|---|
| 475 | case '9':
|
|---|
| 476 | if (split_type == type_undef)
|
|---|
| 477 | {
|
|---|
| 478 | split_type = type_digits;
|
|---|
| 479 | n_units = 0;
|
|---|
| 480 | }
|
|---|
| 481 | if (split_type != type_undef && split_type != type_digits)
|
|---|
| 482 | FAIL_ONLY_ONE_WAY ();
|
|---|
| 483 | if (digits_optind != 0 && digits_optind != this_optind)
|
|---|
| 484 | n_units = 0; /* More than one number given; ignore other. */
|
|---|
| 485 | digits_optind = this_optind;
|
|---|
| 486 | if (!DECIMAL_DIGIT_ACCUMULATE (n_units, c - '0', uintmax_t))
|
|---|
| 487 | {
|
|---|
| 488 | char buffer[INT_BUFSIZE_BOUND (uintmax_t)];
|
|---|
| 489 | error (EXIT_FAILURE, 0,
|
|---|
| 490 | _("line count option -%s%c... is too large"),
|
|---|
| 491 | umaxtostr (n_units, buffer), c);
|
|---|
| 492 | }
|
|---|
| 493 | break;
|
|---|
| 494 |
|
|---|
| 495 | case 'd':
|
|---|
| 496 | suffix_alphabet = "0123456789";
|
|---|
| 497 | break;
|
|---|
| 498 |
|
|---|
| 499 | case VERBOSE_OPTION:
|
|---|
| 500 | verbose = true;
|
|---|
| 501 | break;
|
|---|
| 502 |
|
|---|
| 503 | case_GETOPT_HELP_CHAR;
|
|---|
| 504 |
|
|---|
| 505 | case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
|---|
| 506 |
|
|---|
| 507 | default:
|
|---|
| 508 | usage (EXIT_FAILURE);
|
|---|
| 509 | }
|
|---|
| 510 | }
|
|---|
| 511 |
|
|---|
| 512 | /* Handle default case. */
|
|---|
| 513 | if (split_type == type_undef)
|
|---|
| 514 | {
|
|---|
| 515 | split_type = type_lines;
|
|---|
| 516 | n_units = 1000;
|
|---|
| 517 | }
|
|---|
| 518 |
|
|---|
| 519 | if (n_units == 0)
|
|---|
| 520 | {
|
|---|
| 521 | error (0, 0, _("invalid number of lines: 0"));
|
|---|
| 522 | usage (EXIT_FAILURE);
|
|---|
| 523 | }
|
|---|
| 524 |
|
|---|
| 525 | /* Get out the filename arguments. */
|
|---|
| 526 |
|
|---|
| 527 | if (optind < argc)
|
|---|
| 528 | infile = argv[optind++];
|
|---|
| 529 |
|
|---|
| 530 | if (optind < argc)
|
|---|
| 531 | outbase = argv[optind++];
|
|---|
| 532 |
|
|---|
| 533 | if (optind < argc)
|
|---|
| 534 | {
|
|---|
| 535 | error (0, 0, _("extra operand %s"), quote (argv[optind]));
|
|---|
| 536 | usage (EXIT_FAILURE);
|
|---|
| 537 | }
|
|---|
| 538 |
|
|---|
| 539 | /* Open the input file. */
|
|---|
| 540 | if (! STREQ (infile, "-")
|
|---|
| 541 | && fd_reopen (STDIN_FILENO, infile, O_RDONLY, 0) < 0)
|
|---|
| 542 | error (EXIT_FAILURE, errno, _("cannot open %s for reading"),
|
|---|
| 543 | quote (infile));
|
|---|
| 544 |
|
|---|
| 545 | /* Binary I/O is safer when bytecounts are used. */
|
|---|
| 546 | if (O_BINARY && ! isatty (STDIN_FILENO))
|
|---|
| 547 | freopen (NULL, "rb", stdin);
|
|---|
| 548 |
|
|---|
| 549 | /* No output file is open now. */
|
|---|
| 550 | output_desc = -1;
|
|---|
| 551 |
|
|---|
| 552 | /* Get the optimal block size of input device and make a buffer. */
|
|---|
| 553 |
|
|---|
| 554 | if (fstat (STDIN_FILENO, &stat_buf) != 0)
|
|---|
| 555 | error (EXIT_FAILURE, errno, "%s", infile);
|
|---|
| 556 | in_blk_size = ST_BLKSIZE (stat_buf);
|
|---|
| 557 |
|
|---|
| 558 | buf = ptr_align (xmalloc (in_blk_size + 1 + page_size - 1), page_size);
|
|---|
| 559 |
|
|---|
| 560 | switch (split_type)
|
|---|
| 561 | {
|
|---|
| 562 | case type_digits:
|
|---|
| 563 | case type_lines:
|
|---|
| 564 | lines_split (n_units, buf, in_blk_size);
|
|---|
| 565 | break;
|
|---|
| 566 |
|
|---|
| 567 | case type_bytes:
|
|---|
| 568 | bytes_split (n_units, buf, in_blk_size);
|
|---|
| 569 | break;
|
|---|
| 570 |
|
|---|
| 571 | case type_byteslines:
|
|---|
| 572 | line_bytes_split (n_units);
|
|---|
| 573 | break;
|
|---|
| 574 |
|
|---|
| 575 | default:
|
|---|
| 576 | abort ();
|
|---|
| 577 | }
|
|---|
| 578 |
|
|---|
| 579 | if (close (STDIN_FILENO) != 0)
|
|---|
| 580 | error (EXIT_FAILURE, errno, "%s", infile);
|
|---|
| 581 | if (output_desc >= 0 && close (output_desc) < 0)
|
|---|
| 582 | error (EXIT_FAILURE, errno, "%s", outfile);
|
|---|
| 583 |
|
|---|
| 584 | exit (EXIT_SUCCESS);
|
|---|
| 585 | }
|
|---|