1 /* split.c -- split a file into pieces.
2 Copyright (C) 88, 91, 1995-1999 Free Software Foundation, Inc.
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)
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* By tege@sics.se, with rms.
21 * Implement -t CHAR or -t REGEX to specify break characters other
28 #include <sys/types.h>
32 #include "long-options.h"
33 #include "safe-read.h"
36 /* The official name of this program (e.g., no `g' prefix). */
37 #define PROGRAM_NAME "split"
39 #define AUTHORS "Torbjorn Granlund and Richard M. Stallman"
43 /* The name this program was run with. */
46 /* Base name of output files. */
49 /* Pointer to the end of the prefix in OUTFILE.
50 Suffixes are inserted here. */
51 static char *outfile_mid;
53 /* Pointer to the end of OUTFILE. */
54 static char *outfile_end;
56 /* Name of input file. May be "-". */
59 /* Descriptor on which input file is open. */
60 static int input_desc;
62 /* Descriptor on which output file is open. */
63 static int output_desc;
65 /* If nonzero, print a diagnostic on standard error just before each
66 output file is opened. */
69 static struct option const longopts[] =
71 {"bytes", required_argument, NULL, 'b'},
72 {"lines", required_argument, NULL, 'l'},
73 {"line-bytes", required_argument, NULL, 'C'},
74 {"verbose", no_argument, NULL, 2},
82 fprintf (stderr, _("Try `%s --help' for more information.\n"),
87 Usage: %s [OPTION] [INPUT [PREFIX]]\n\
91 Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\
92 PREFIX is `x'. With no INPUT, or when INPUT is -, read standard input.\n\
94 -b, --bytes=SIZE put SIZE bytes per output file\n\
95 -C, --line-bytes=SIZE put at most SIZE bytes of lines per output file\n\
96 -l, --lines=NUMBER put NUMBER lines per output file\n\
97 -NUMBER same as -l NUMBER\n\
98 --verbose print a diagnostic to standard error just\n\
99 before each output file is opened\n\
100 --help display this help and exit\n\
101 --version output version information and exit\n\
103 SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
105 puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
107 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
110 /* Compute the next sequential output file name suffix and store it
111 into the string `outfile' at the position pointed to by `outfile_mid'. */
114 next_file_name (void)
116 static unsigned n_digits = 2;
119 /* Change any suffix of `z's to `a's. */
120 for (p = outfile_end - 1; *p == 'z'; p--)
125 /* Increment the rightmost non-`z' character that was present before the
126 above z/a substitutions. There is guaranteed to be such a character. */
129 /* If the result of that increment operation yielded a `z' and there
130 are only `z's to the left of it, then append two more `a' characters
131 to the end and add 1 (-1 + 2) to the number of digits (we're taking
132 out this `z' and adding two `a's). */
133 if (*p == 'z' && p == outfile_mid)
137 *outfile_end++ = 'a';
138 *outfile_end++ = 'a';
142 /* Write BYTES bytes at BP to an output file.
143 If NEW_FILE_FLAG is nonzero, open the next output file.
144 Otherwise add to the same output file already in use. */
147 cwrite (int new_file_flag, const char *bp, int bytes)
151 if (output_desc >= 0 && close (output_desc) < 0)
152 error (EXIT_FAILURE, errno, "%s", outfile);
156 fprintf (stderr, _("creating file `%s'\n"), outfile);
157 output_desc = open (outfile,
158 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
160 error (EXIT_FAILURE, errno, "%s", outfile);
162 if (full_write (output_desc, bp, bytes) < 0)
163 error (EXIT_FAILURE, errno, "%s", outfile);
166 /* Read NCHARS bytes from the input file into BUF.
167 Return the number of bytes successfully read.
168 If this is less than NCHARS, do not call `stdread' again. */
171 stdread (char *buf, int nchars)
174 int to_be_read = nchars;
178 n_read = safe_read (input_desc, buf, to_be_read);
183 to_be_read -= n_read;
186 return nchars - to_be_read;
189 /* Split into pieces of exactly NCHARS bytes.
190 Use buffer BUF, whose size is BUFSIZE. */
193 bytes_split (int nchars, char *buf, int bufsize)
196 int new_file_flag = 1;
198 int to_write = nchars;
203 n_read = stdread (buf, bufsize);
205 error (EXIT_FAILURE, errno, "%s", infile);
210 if (to_read < to_write)
212 if (to_read) /* do not write 0 bytes! */
214 cwrite (new_file_flag, bp_out, to_read);
222 cwrite (new_file_flag, bp_out, to_write);
230 while (n_read == bufsize);
233 /* Split into pieces of exactly NLINES lines.
234 Use buffer BUF, whose size is BUFSIZE. */
237 lines_split (int nlines, char *buf, int bufsize)
240 char *bp, *bp_out, *eob;
241 int new_file_flag = 1;
246 n_read = stdread (buf, bufsize);
248 error (EXIT_FAILURE, errno, "%s", infile);
254 while (*bp++ != '\n')
255 ; /* this semicolon takes most of the time */
258 if (eob != bp_out) /* do not write 0 bytes! */
260 cwrite (new_file_flag, bp_out, eob - bp_out);
268 cwrite (new_file_flag, bp_out, bp - bp_out);
275 while (n_read == bufsize);
278 /* Split into pieces that are as large as possible while still not more
279 than NCHARS bytes, and are split on line boundaries except
280 where lines longer than NCHARS bytes occur. */
283 line_bytes_split (int nchars)
289 char *buf = (char *) xmalloc (nchars);
293 /* Fill up the full buffer size from the input file. */
295 n_read = stdread (buf + n_buffered, nchars - n_buffered);
297 error (EXIT_FAILURE, errno, "%s", infile);
299 n_buffered += n_read;
300 if (n_buffered != nchars)
303 /* Find where to end this chunk. */
304 bp = buf + n_buffered;
305 if (n_buffered == nchars)
307 while (bp > buf && bp[-1] != '\n')
311 /* If chunk has no newlines, use all the chunk. */
313 bp = buf + n_buffered;
315 /* Output the chars as one output file. */
316 cwrite (1, buf, bp - buf);
318 /* Discard the chars we just output; move rest of chunk
319 down to be the start of the next chunk. Source and
320 destination probably overlap. */
321 n_buffered -= bp - buf;
323 memmove (buf, bp, n_buffered);
330 main (int argc, char **argv)
332 struct stat stat_buf;
333 int num; /* numeric argument from command line */
336 type_undef, type_bytes, type_byteslines, type_lines, type_digits
337 } split_type = type_undef;
338 int in_blk_size; /* optimal block size of input file device */
339 char *buf; /* file i/o buffer */
343 int digits_optind = 0;
345 program_name = argv[0];
346 setlocale (LC_ALL, "");
347 bindtextdomain (PACKAGE, LOCALEDIR);
348 textdomain (PACKAGE);
350 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
353 /* Parse command line options. */
360 /* This is the argv-index of the option we will read next. */
361 int this_optind = optind ? optind : 1;
364 c = getopt_long (argc, argv, "0123456789vb:l:C:", longopts, (int *) 0);
374 if (split_type != type_undef)
376 error (0, 0, _("cannot split in more than one way"));
377 usage (EXIT_FAILURE);
379 split_type = type_bytes;
380 if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
381 || tmp_long < 0 || tmp_long > INT_MAX)
383 error (0, 0, _("%s: invalid number of bytes"), optarg);
384 usage (EXIT_FAILURE);
386 accum = (int) tmp_long;
390 if (split_type != type_undef)
392 error (0, 0, _("cannot split in more than one way"));
393 usage (EXIT_FAILURE);
395 split_type = type_lines;
396 if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
397 || tmp_long < 0 || tmp_long > INT_MAX)
399 error (0, 0, _("%s: invalid number of lines"), optarg);
400 usage (EXIT_FAILURE);
402 accum = (int) tmp_long;
406 if (split_type != type_undef)
408 error (0, 0, _("cannot split in more than one way"));
409 usage (EXIT_FAILURE);
412 split_type = type_byteslines;
413 if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
414 || tmp_long < 0 || tmp_long > INT_MAX)
416 error (0, 0, _("%s: invalid number of bytes"), optarg);
417 usage (EXIT_FAILURE);
419 accum = (int) tmp_long;
432 if (split_type != type_undef && split_type != type_digits)
434 error (0, 0, _("cannot split in more than one way"));
435 usage (EXIT_FAILURE);
437 if (digits_optind != 0 && digits_optind != this_optind)
438 accum = 0; /* More than one number given; ignore other. */
439 digits_optind = this_optind;
440 split_type = type_digits;
441 accum = accum * 10 + c - '0';
449 usage (EXIT_FAILURE);
453 /* Handle default case. */
454 if (split_type == type_undef)
456 split_type = type_lines;
462 error (0, 0, _("invalid number"));
463 usage (EXIT_FAILURE);
467 /* Get out the filename arguments. */
470 infile = argv[optind++];
473 outbase = argv[optind++];
477 error (0, 0, _("too many arguments"));
478 usage (EXIT_FAILURE);
481 /* Open the input file. */
482 if (STREQ (infile, "-"))
486 input_desc = open (infile, O_RDONLY);
488 error (EXIT_FAILURE, errno, "%s", infile);
490 /* Binary I/O is safer when bytecounts are used. */
491 SET_BINARY (input_desc);
493 /* No output file is open now. */
496 /* Copy the output file prefix so we can add suffixes to it.
497 26**29 is certainly enough output files! */
499 outfile = xmalloc (strlen (outbase) + 30);
500 strcpy (outfile, outbase);
501 outfile_mid = outfile + strlen (outfile);
502 outfile_end = outfile_mid + 2;
503 memset (outfile_mid, 0, 30);
504 outfile_mid[0] = 'a';
505 outfile_mid[1] = 'a' - 1; /* first call to next_file_name makes it an 'a' */
507 /* Get the optimal block size of input device and make a buffer. */
509 if (fstat (input_desc, &stat_buf) < 0)
510 error (EXIT_FAILURE, errno, "%s", infile);
511 in_blk_size = ST_BLKSIZE (stat_buf);
513 buf = xmalloc (in_blk_size + 1);
519 lines_split (num, buf, in_blk_size);
523 bytes_split (num, buf, in_blk_size);
526 case type_byteslines:
527 line_bytes_split (num);
534 if (close (input_desc) < 0)
535 error (EXIT_FAILURE, errno, "%s", infile);
536 if (output_desc >= 0 && close (output_desc) < 0)
537 error (EXIT_FAILURE, errno, "%s", outfile);