1 /* split.c -- split a file into pieces.
2 Copyright (C) 1988, 1991, 1995 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
16 Foundation, 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>
37 /* The name this program was run with. */
40 /* Base name of output files. */
43 /* Pointer to the end of the prefix in OUTFILE.
44 Suffixes are inserted here. */
45 static char *outfile_mid;
47 /* Pointer to the end of OUTFILE. */
48 static char *outfile_end;
50 /* Name of input file. May be "-". */
53 /* Descriptor on which input file is open. */
54 static int input_desc;
56 /* Descriptor on which output file is open. */
57 static int output_desc;
59 /* If non-zero, display usage information and exit. */
62 /* If non-zero, print the version on standard output then exit. */
63 static int show_version;
65 static struct option const longopts[] =
67 {"bytes", required_argument, NULL, 'b'},
68 {"lines", required_argument, NULL, 'l'},
69 {"line-bytes", required_argument, NULL, 'C'},
70 {"help", no_argument, &show_help, 1},
71 {"version", no_argument, &show_version, 1},
76 usage (status, reason)
81 fprintf (stderr, "%s: %s\n", program_name, reason);
84 fprintf (stderr, _("Try `%s --help' for more information.\n"),
89 Usage: %s [OPTION] [INPUT [PREFIX]]\n\
93 Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\
94 PREFIX is `x'. With no INPUT, or when INPUT is -, read standard input.\n\
96 -C, --line-bytes=SIZE put at most SIZE bytes of lines per output file\n\
97 -b, --bytes=SIZE put SIZE bytes per output file\n\
98 -l, --lines=NUMBER put NUMBER lines per output file\n\
99 -NUMBER same as -l NUMBER\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\
109 /* Return nonzero if the string STR is composed entirely of decimal digits. */
125 /* Put the value of the number in STR into *VAL.
126 STR can specify a positive integer, optionally ending in `k'
127 to mean kilo or `m' to mean mega.
128 Return 0 if STR is valid, -1 if not. */
136 int arglen = strlen (str);
140 switch (str[arglen - 1])
144 str[arglen - 1] = '\0';
148 str[arglen - 1] = '\0';
151 multiplier = 1048576;
152 str[arglen - 1] = '\0';
158 *val = atoi (str) * multiplier;
162 /* Compute the next sequential output file name suffix and store it
163 into the string `outfile' at the position pointed to by `outfile_mid'. */
172 static int first_call = 1;
174 /* Status for outfile name generation. */
175 static unsigned outfile_count = 0;
176 static unsigned outfile_name_limit = 25 * 26;
177 static unsigned outfile_name_generation = 1;
182 if (outfile_count < outfile_name_limit)
184 for (ne = outfile_end - 1; ; ne--)
196 outfile_name_limit *= 26;
197 outfile_name_generation++;
198 *outfile_mid++ = 'z';
199 for (i = 0; i <= outfile_name_generation; i++)
200 outfile_mid[i] = 'a';
204 /* Write BYTES bytes at BP to an output file.
205 If NEW_FILE_FLAG is nonzero, open the next output file.
206 Otherwise add to the same output file already in use. */
209 cwrite (new_file_flag, bp, bytes)
216 if (output_desc >= 0 && close (output_desc) < 0)
217 error (1, errno, "%s", outfile);
220 output_desc = open (outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
222 error (1, errno, "%s", outfile);
224 if (full_write (output_desc, bp, bytes) < 0)
225 error (1, errno, "%s", outfile);
228 /* Read NCHARS bytes from the input file into BUF.
229 Return the number of bytes successfully read.
230 If this is less than NCHARS, do not call `stdread' again. */
233 stdread (buf, nchars)
238 int to_be_read = nchars;
242 n_read = safe_read (input_desc, buf, to_be_read);
247 to_be_read -= n_read;
250 return nchars - to_be_read;
253 /* Split into pieces of exactly NCHARS bytes.
254 Use buffer BUF, whose size is BUFSIZE. */
257 bytes_split (nchars, buf, bufsize)
263 int new_file_flag = 1;
265 int to_write = nchars;
270 n_read = stdread (buf, bufsize);
272 error (1, errno, "%s", infile);
277 if (to_read < to_write)
279 if (to_read) /* do not write 0 bytes! */
281 cwrite (new_file_flag, bp_out, to_read);
289 cwrite (new_file_flag, bp_out, to_write);
297 while (n_read == bufsize);
300 /* Split into pieces of exactly NLINES lines.
301 Use buffer BUF, whose size is BUFSIZE. */
304 lines_split (nlines, buf, bufsize)
310 char *bp, *bp_out, *eob;
311 int new_file_flag = 1;
316 n_read = stdread (buf, bufsize);
318 error (1, errno, "%s", infile);
324 while (*bp++ != '\n')
325 ; /* this semicolon takes most of the time */
328 if (eob != bp_out) /* do not write 0 bytes! */
330 cwrite (new_file_flag, bp_out, eob - bp_out);
338 cwrite (new_file_flag, bp_out, bp - bp_out);
345 while (n_read == bufsize);
348 /* Split into pieces that are as large as possible while still not more
349 than NCHARS bytes, and are split on line boundaries except
350 where lines longer than NCHARS bytes occur. */
353 line_bytes_split (nchars)
360 char *buf = (char *) xmalloc (nchars);
364 /* Fill up the full buffer size from the input file. */
366 n_read = stdread (buf + n_buffered, nchars - n_buffered);
368 error (1, errno, "%s", infile);
370 n_buffered += n_read;
371 if (n_buffered != nchars)
374 /* Find where to end this chunk. */
375 bp = buf + n_buffered;
376 if (n_buffered == nchars)
378 while (bp > buf && bp[-1] != '\n')
382 /* If chunk has no newlines, use all the chunk. */
384 bp = buf + n_buffered;
386 /* Output the chars as one output file. */
387 cwrite (1, buf, bp - buf);
389 /* Discard the chars we just output; move rest of chunk
390 down to be the start of the next chunk. Source and
391 destination probably overlap. */
392 n_buffered -= bp - buf;
394 memmove (buf, bp, n_buffered);
405 struct stat stat_buf;
406 int num; /* numeric argument from command line */
409 type_undef, type_bytes, type_byteslines, type_lines, type_digits
410 } split_type = type_undef;
411 int in_blk_size; /* optimal block size of input file device */
412 char *buf; /* file i/o buffer */
416 int digits_optind = 0;
418 program_name = argv[0];
420 /* Parse command line options. */
427 /* This is the argv-index of the option we will read next. */
428 int this_optind = optind ? optind : 1;
430 c = getopt_long (argc, argv, "0123456789b:l:C:", longopts, (int *) 0);
440 if (split_type != type_undef)
441 usage (2, _("cannot split in more than one way"));
442 split_type = type_bytes;
443 /* FIXME: use xstrtoul */
444 if (convint (optarg, &accum) == -1)
445 usage (2, _("invalid number of bytes"));
449 if (split_type != type_undef)
450 usage (2, _("cannot split in more than one way"));
451 split_type = type_lines;
452 if (!isdigits (optarg))
453 usage (2, _("invalid number of lines"));
454 /* FIXME: use xstrtoul */
455 accum = atoi (optarg);
459 if (split_type != type_undef)
460 usage (2, _("cannot split in more than one way"));
461 split_type = type_byteslines;
462 /* FIXME: use xstrtoul */
463 if (convint (optarg, &accum) == -1)
464 usage (2, _("invalid number of bytes"));
477 if (split_type != type_undef && split_type != type_digits)
478 usage (2, _("cannot split in more than one way"));
479 if (digits_optind != 0 && digits_optind != this_optind)
480 accum = 0; /* More than one number given; ignore other. */
481 digits_optind = this_optind;
482 split_type = type_digits;
483 accum = accum * 10 + c - '0';
487 usage (2, (char *)0);
493 printf ("split - %s\n", version_string);
498 usage (0, (char *)0);
500 /* Handle default case. */
501 if (split_type == type_undef)
503 split_type = type_lines;
508 usage (2, _("invalid number"));
511 /* Get out the filename arguments. */
514 infile = argv[optind++];
517 outbase = argv[optind++];
520 usage (2, _("too many arguments"));
522 /* Open the input file. */
523 if (!strcmp (infile, "-"))
527 input_desc = open (infile, O_RDONLY);
529 error (1, errno, "%s", infile);
532 /* No output file is open now. */
535 /* Copy the output file prefix so we can add suffixes to it.
536 26**29 is certainly enough output files! */
538 outfile = xmalloc (strlen (outbase) + 30);
539 strcpy (outfile, outbase);
540 outfile_mid = outfile + strlen (outfile);
541 outfile_end = outfile_mid + 2;
542 memset (outfile_mid, 0, 30);
543 outfile_mid[0] = 'a';
544 outfile_mid[1] = 'a' - 1; /* first call to next_file_name makes it an 'a' */
546 /* Get the optimal block size of input device and make a buffer. */
548 if (fstat (input_desc, &stat_buf) < 0)
549 error (1, errno, "%s", infile);
550 in_blk_size = ST_BLKSIZE (stat_buf);
552 buf = xmalloc (in_blk_size + 1);
558 lines_split (num, buf, in_blk_size);
562 bytes_split (num, buf, in_blk_size);
565 case type_byteslines:
566 line_bytes_split (num);
573 if (close (input_desc) < 0)
574 error (1, errno, "%s", infile);
575 if (output_desc >= 0 && close (output_desc) < 0)
576 error (1, errno, "%s", outfile);