X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsplit.c;h=a02e64aa634c924dd91e2740c35a6b0a229a50be;hb=ff4121e50e68db095b7248ec6160ff3a660be55a;hp=a2aee897bc627120d51b421d93b5de68fc01f293;hpb=eb3a2516dba78740843793f755af412f24ac5330;p=platform%2Fupstream%2Fcoreutils.git diff --git a/src/split.c b/src/split.c index a2aee89..a02e64a 100644 --- a/src/split.c +++ b/src/split.c @@ -1,5 +1,5 @@ /* split.c -- split a file into pieces. - Copyright (C) 1988, 1991 Free Software Foundation, Inc. + Copyright (C) 88, 91, 1995-2001 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,8 +12,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* By tege@sics.se, with rms. @@ -21,25 +21,25 @@ * Implement -t CHAR or -t REGEX to specify break characters other than newline. */ +#include + #include #include -#include #include + #include "system.h" +#include "closeout.h" +#include "error.h" +#include "full-write.h" +#include "safe-read.h" +#include "xstrtol.h" -char *xmalloc (); -void error (); +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "split" -static int convint (); -static int isdigits (); -static int stdread (); -static void line_bytes_split (); -static void bytes_split (); -static void cwrite (); -static void lines_split (); -static void next_file_name (); +#define AUTHORS N_ ("Torbjorn Granlund and Richard M. Stallman") -/* Name under which this program was invoked. */ +/* The name this program was run with. */ char *program_name; /* Base name of output files. */ @@ -52,11 +52,6 @@ static char *outfile_mid; /* Pointer to the end of OUTFILE. */ static char *outfile_end; -/* Status for outfile name generation. */ -static unsigned outfile_count = -1; -static unsigned outfile_name_limit = 25 * 26; -static unsigned outfile_name_generation = 1; - /* Name of input file. May be "-". */ static char *infile; @@ -65,256 +60,139 @@ static int input_desc; /* Descriptor on which output file is open. */ static int output_desc; - -static void -usage (reason) - char *reason; -{ - if (reason != NULL) - fprintf (stderr, "%s: %s\n", program_name, reason); - fprintf (stderr, "\ -Usage: %s [-lines] [-l lines] [-b bytes[bkm]] [-C bytes[bkm]]\n\ - [--lines=lines] [--bytes=bytes[bkm]] [--line-bytes=bytes[bkm]]\n\ - [infile [outfile-prefix]]\n", - program_name); - exit (2); -} - + +/* If nonzero, print a diagnostic on standard error just before each + output file is opened. */ +static int verbose; + static struct option const longopts[] = { {"bytes", required_argument, NULL, 'b'}, {"lines", required_argument, NULL, 'l'}, {"line-bytes", required_argument, NULL, 'C'}, + {"verbose", no_argument, NULL, 2}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} }; void -main (argc, argv) - int argc; - char *argv[]; +usage (int status) { - struct stat stat_buf; - int num; /* numeric argument from command line */ - enum - { - type_undef, type_bytes, type_byteslines, type_lines, type_digits - } split_type = type_undef; - int in_blk_size; /* optimal block size of input file device */ - char *buf; /* file i/o buffer */ - int accum = 0; - char *outbase; - int c; - int digits_optind = 0; - - program_name = argv[0]; - - /* Parse command line options. */ - - infile = "-"; - outbase = "x"; - - while (1) - { - /* This is the argv-index of the option we will read next. */ - int this_optind = optind ? optind : 1; - - c = getopt_long (argc, argv, "0123456789b:l:C:", longopts, (int *) 0); - if (c == EOF) - break; - - switch (c) - { - case 'b': - if (split_type != type_undef) - usage ("cannot split in more than one way"); - split_type = type_bytes; - if (convint (optarg, &accum) == -1) - usage ("invalid number of bytes"); - break; - - case 'l': - if (split_type != type_undef) - usage ("cannot split in more than one way"); - split_type = type_lines; - if (!isdigits (optarg)) - usage ("invalid number of lines"); - accum = atoi (optarg); - break; - - case 'C': - if (split_type != type_undef) - usage ("cannot split in more than one way"); - split_type = type_byteslines; - if (convint (optarg, &accum) == -1) - usage ("invalid number of bytes"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (split_type != type_undef && split_type != type_digits) - usage ("cannot split in more than one way"); - if (digits_optind != 0 && digits_optind != this_optind) - accum = 0; /* More than one number given; ignore other. */ - digits_optind = this_optind; - split_type = type_digits; - accum = accum * 10 + c - '0'; - break; - - default: - usage ((char *)0); - } - } - - /* Handle default case. */ - if (split_type == type_undef) + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else { - split_type = type_lines; - accum = 1000; + printf (_("\ +Usage: %s [OPTION] [INPUT [PREFIX]]\n\ +"), + program_name); + printf (_("\ +Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\ +PREFIX is `x'. With no INPUT, or when INPUT is -, read standard input.\n\ +\n\ +Mandatory arguments to long options are mandatory for short options too.\n\ + -b, --bytes=SIZE put SIZE bytes per output file\n\ + -C, --line-bytes=SIZE put at most SIZE bytes of lines per output file\n\ + -l, --lines=NUMBER put NUMBER lines per output file\n\ + -NUMBER same as -l NUMBER\n\ + --verbose print a diagnostic to standard error just\n\ + before each output file is opened\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\ +")); + puts (_("\nReport bugs to .")); } + exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} - if (accum < 1) - usage ("invalid number"); - num = accum; - - /* Get out the filename arguments. */ - - if (optind < argc) - infile = argv[optind++]; - - if (optind < argc) - outbase = argv[optind++]; +/* Compute the next sequential output file name suffix and store it + into the string `outfile' at the position pointed to by `outfile_mid'. */ - if (optind < argc) - usage ("too many arguments"); +static void +next_file_name (void) +{ + static unsigned n_digits = 2; + char *p; - /* Open the input file. */ - if (!strcmp (infile, "-")) - input_desc = 0; - else + /* Change any suffix of `z's to `a's. */ + for (p = outfile_end - 1; *p == 'z'; p--) { - input_desc = open (infile, O_RDONLY); - if (input_desc < 0) - error (1, errno, "%s", infile); + *p = 'a'; } - /* No output file is open now. */ - output_desc = -1; - - /* Copy the output file prefix so we can add suffixes to it. - 26**29 is certainly enough output files! */ + /* Increment the rightmost non-`z' character that was present before the + above z/a substitutions. There is guaranteed to be such a character. */ + ++(*p); - outfile = xmalloc (strlen (outbase) + 30); - strcpy (outfile, outbase); - outfile_mid = outfile + strlen (outfile); - outfile_end = outfile_mid + 2; - bzero (outfile_mid, 30); - outfile_mid[0] = 'a'; - outfile_mid[1] = 'a' - 1; /* first call to next_file_name makes it an 'a' */ - - /* Get the optimal block size of input device and make a buffer. */ - - if (fstat (input_desc, &stat_buf) < 0) - error (1, errno, "%s", infile); - in_blk_size = ST_BLKSIZE (stat_buf); - - buf = xmalloc (in_blk_size + 1); - - switch (split_type) + /* If the result of that increment operation yielded a `z' and there + are only `z's to the left of it, then append two more `a' characters + to the end and add 1 (-1 + 2) to the number of digits (we're taking + out this `z' and adding two `a's). */ + if (*p == 'z' && p == outfile_mid) { - case type_digits: - case type_lines: - lines_split (num, buf, in_blk_size); - break; - - case type_bytes: - bytes_split (num, buf, in_blk_size); - break; - - case type_byteslines: - line_bytes_split (num); - break; - - default: - abort (); + ++n_digits; + ++outfile_mid; + *outfile_end++ = 'a'; + *outfile_end++ = 'a'; } - - if (close (input_desc) < 0) - error (1, errno, "%s", infile); - if (output_desc >= 0 && close (output_desc) < 0) - error (1, errno, "%s", outfile); - - exit (0); } -/* Return nonzero if the string STR is composed entirely of decimal digits. */ +/* Write BYTES bytes at BP to an output file. + If NEW_FILE_FLAG is nonzero, open the next output file. + Otherwise add to the same output file already in use. */ -static int -isdigits (str) - char *str; +static void +cwrite (int new_file_flag, const char *bp, int bytes) { - do + if (new_file_flag) { - if (!isdigit (*str)) - return 0; - str++; + if (output_desc >= 0 && close (output_desc) < 0) + error (EXIT_FAILURE, errno, "%s", outfile); + + next_file_name (); + if (verbose) + fprintf (stderr, _("creating file `%s'\n"), outfile); + output_desc = open (outfile, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (output_desc < 0) + error (EXIT_FAILURE, errno, "%s", outfile); } - while (*str); - return 1; + if (full_write (output_desc, bp, bytes) != bytes) + error (EXIT_FAILURE, errno, "%s", outfile); } -/* Put the value of the number in STR into *VAL. - STR can specify a positive integer, optionally ending in `k' - to mean kilo or `m' to mean mega. - Return 0 if STR is valid, -1 if not. */ +/* Read NCHARS bytes from the input file into BUF. + Return the number of bytes successfully read. + If this is less than NCHARS, do not call `stdread' again. */ static int -convint (str, val) - char *str; - int *val; +stdread (char *buf, int nchars) { - int multiplier = 1; - int arglen = strlen (str); + int n_read; + int to_be_read = nchars; - if (arglen > 1) + while (to_be_read) { - switch (str[arglen - 1]) - { - case 'b': - multiplier = 512; - str[arglen - 1] = '\0'; - break; - case 'k': - multiplier = 1024; - str[arglen - 1] = '\0'; - break; - case 'm': - multiplier = 1048576; - str[arglen - 1] = '\0'; - break; - } + n_read = safe_read (input_desc, buf, to_be_read); + if (n_read < 0) + return -1; + if (n_read == 0) + break; + to_be_read -= n_read; + buf += n_read; } - if (!isdigits (str)) - return -1; - *val = atoi (str) * multiplier; - return 0; + return nchars - to_be_read; } - + /* Split into pieces of exactly NCHARS bytes. Use buffer BUF, whose size is BUFSIZE. */ static void -bytes_split (nchars, buf, bufsize) - int nchars; - char *buf; - int bufsize; +bytes_split (int nchars, char *buf, int bufsize) { int n_read; int new_file_flag = 1; @@ -326,7 +204,7 @@ bytes_split (nchars, buf, bufsize) { n_read = stdread (buf, bufsize); if (n_read < 0) - error (1, errno, "%s", infile); + error (EXIT_FAILURE, errno, "%s", infile); bp_out = buf; to_read = n_read; for (;;) @@ -353,15 +231,12 @@ bytes_split (nchars, buf, bufsize) } while (n_read == bufsize); } - + /* Split into pieces of exactly NLINES lines. Use buffer BUF, whose size is BUFSIZE. */ static void -lines_split (nlines, buf, bufsize) - int nlines; - char *buf; - int bufsize; +lines_split (int nlines, char *buf, int bufsize) { int n_read; char *bp, *bp_out, *eob; @@ -372,7 +247,7 @@ lines_split (nlines, buf, bufsize) { n_read = stdread (buf, bufsize); if (n_read < 0) - error (1, errno, "%s", infile); + error (EXIT_FAILURE, errno, "%s", infile); bp = bp_out = buf; eob = bp + n_read; *eob = '\n'; @@ -407,8 +282,7 @@ lines_split (nlines, buf, bufsize) where lines longer than NCHARS bytes occur. */ static void -line_bytes_split (nchars) - int nchars; +line_bytes_split (int nchars) { int n_read; char *bp; @@ -422,7 +296,7 @@ line_bytes_split (nchars) n_read = stdread (buf + n_buffered, nchars - n_buffered); if (n_read < 0) - error (1, errno, "%s", infile); + error (EXIT_FAILURE, errno, "%s", infile); n_buffered += n_read; if (n_buffered != nchars) @@ -444,92 +318,228 @@ line_bytes_split (nchars) cwrite (1, buf, bp - buf); /* Discard the chars we just output; move rest of chunk - down to be the start of the next chunk. */ + down to be the start of the next chunk. Source and + destination probably overlap. */ n_buffered -= bp - buf; if (n_buffered > 0) - bcopy (bp, buf, n_buffered); + memmove (buf, bp, n_buffered); } while (!eof); free (buf); } - -/* Write BYTES bytes at BP to an output file. - If NEW_FILE_FLAG is nonzero, open the next output file. - Otherwise add to the same output file already in use. */ -static void -cwrite (new_file_flag, bp, bytes) - int new_file_flag; - char *bp; - int bytes; +int +main (int argc, char **argv) { - if (new_file_flag) + struct stat stat_buf; + int num; /* numeric argument from command line */ + enum { - if (output_desc >= 0 && close (output_desc) < 0) - error (1, errno, "%s", outfile); + type_undef, type_bytes, type_byteslines, type_lines, type_digits + } split_type = type_undef; + int in_blk_size; /* optimal block size of input file device */ + char *buf; /* file i/o buffer */ + int accum = 0; + char *outbase; + int c; + int digits_optind = 0; - next_file_name (); - output_desc = open (outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (output_desc < 0) - error (1, errno, "%s", outfile); - } - if (write (output_desc, bp, bytes) < 0) - error (1, errno, "%s", outfile); -} + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); -/* Read NCHARS bytes from the input file into BUF. - Return the number of bytes successfully read. - If this is less than NCHARS, do not call `stdread' again. */ + atexit (close_stdout); -static int -stdread (buf, nchars) - char *buf; - int nchars; -{ - int n_read; - int to_be_read = nchars; + /* Parse command line options. */ - while (to_be_read) + infile = "-"; + outbase = "x"; + + while (1) { - n_read = read (input_desc, buf, to_be_read); - if (n_read < 0) - return -1; - if (n_read == 0) + /* This is the argv-index of the option we will read next. */ + int this_optind = optind ? optind : 1; + long int tmp_long; + + c = getopt_long (argc, argv, "0123456789vb:l:C:", longopts, (int *) 0); + if (c == EOF) break; - to_be_read -= n_read; - buf += n_read; + + switch (c) + { + case 0: + break; + + case 'b': + if (split_type != type_undef) + { + error (0, 0, _("cannot split in more than one way")); + usage (EXIT_FAILURE); + } + split_type = type_bytes; + if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + { + error (0, 0, _("%s: invalid number of bytes"), optarg); + usage (EXIT_FAILURE); + } + accum = (int) tmp_long; + break; + + case 'l': + if (split_type != type_undef) + { + error (0, 0, _("cannot split in more than one way")); + usage (EXIT_FAILURE); + } + split_type = type_lines; + if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + { + error (0, 0, _("%s: invalid number of lines"), optarg); + usage (EXIT_FAILURE); + } + accum = (int) tmp_long; + break; + + case 'C': + if (split_type != type_undef) + { + error (0, 0, _("cannot split in more than one way")); + usage (EXIT_FAILURE); + } + + split_type = type_byteslines; + if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + { + error (0, 0, _("%s: invalid number of bytes"), optarg); + usage (EXIT_FAILURE); + } + accum = (int) tmp_long; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (split_type != type_undef && split_type != type_digits) + { + error (0, 0, _("cannot split in more than one way")); + usage (EXIT_FAILURE); + } + if (digits_optind != 0 && digits_optind != this_optind) + accum = 0; /* More than one number given; ignore other. */ + digits_optind = this_optind; + split_type = type_digits; + accum = accum * 10 + c - '0'; + break; + + case 2: + verbose = 1; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } } - return nchars - to_be_read; -} -/* Compute the next sequential output file name suffix and store it - into the string `outfile' at the position pointed to by `outfile_mid'. */ + /* Handle default case. */ + if (split_type == type_undef) + { + split_type = type_lines; + accum = 1000; + } -static void -next_file_name () -{ - int x; - char *ne; + if (accum < 1) + { + error (0, 0, _("invalid number")); + usage (EXIT_FAILURE); + } + num = accum; + + /* Get out the filename arguments. */ + + if (optind < argc) + infile = argv[optind++]; + + if (optind < argc) + outbase = argv[optind++]; - outfile_count++; - if (outfile_count < outfile_name_limit) + if (optind < argc) { - for (ne = outfile_end - 1; ; ne--) - { - x = *ne; - if (x != 'z') - break; - *ne = 'a'; - } - *ne = x + 1; - return; + error (0, 0, _("too many arguments")); + usage (EXIT_FAILURE); } - outfile_count = 0; - outfile_name_limit *= 26; - outfile_name_generation++; - *outfile_mid++ = 'z'; - for (x = 0; x <= outfile_name_generation; x++) - outfile_mid[x] = 'a'; - outfile_end += 2; + /* Open the input file. */ + if (STREQ (infile, "-")) + input_desc = 0; + else + { + input_desc = open (infile, O_RDONLY); + if (input_desc < 0) + error (EXIT_FAILURE, errno, "%s", infile); + } + /* Binary I/O is safer when bytecounts are used. */ + SET_BINARY (input_desc); + + /* No output file is open now. */ + output_desc = -1; + + /* Copy the output file prefix so we can add suffixes to it. + 26**29 is certainly enough output files! */ + + outfile = xmalloc (strlen (outbase) + 30); + strcpy (outfile, outbase); + outfile_mid = outfile + strlen (outfile); + outfile_end = outfile_mid + 2; + memset (outfile_mid, 0, 30); + outfile_mid[0] = 'a'; + outfile_mid[1] = 'a' - 1; /* first call to next_file_name makes it an 'a' */ + + /* Get the optimal block size of input device and make a buffer. */ + + if (fstat (input_desc, &stat_buf) < 0) + error (EXIT_FAILURE, errno, "%s", infile); + in_blk_size = ST_BLKSIZE (stat_buf); + + buf = xmalloc (in_blk_size + 1); + + switch (split_type) + { + case type_digits: + case type_lines: + lines_split (num, buf, in_blk_size); + break; + + case type_bytes: + bytes_split (num, buf, in_blk_size); + break; + + case type_byteslines: + line_bytes_split (num); + break; + + default: + abort (); + } + + if (close (input_desc) < 0) + error (EXIT_FAILURE, errno, "%s", infile); + if (output_desc >= 0 && close (output_desc) < 0) + error (EXIT_FAILURE, errno, "%s", outfile); + + exit (EXIT_SUCCESS); }