2632819d3235f7fb4c5d965ab47032de920524bd
[platform/upstream/coreutils.git] / src / split.c
1 /* split.c -- split a file into pieces.
2    Copyright (C) 88, 91, 1995-2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17 \f
18 /* By tege@sics.se, with rms.
19
20    To do:
21    * Implement -t CHAR or -t REGEX to specify break characters other
22      than newline. */
23
24 #include <config.h>
25
26 #include <stdio.h>
27 #include <getopt.h>
28 #include <sys/types.h>
29
30 #include "system.h"
31 #include "closeout.h"
32 #include "error.h"
33 #include "full-write.h"
34 #include "safe-read.h"
35 #include "xstrtol.h"
36
37 /* The official name of this program (e.g., no `g' prefix).  */
38 #define PROGRAM_NAME "split"
39
40 #define AUTHORS N_ ("Torbjorn Granlund and Richard M. Stallman")
41
42 /* The name this program was run with. */
43 char *program_name;
44
45 /* Base name of output files.  */
46 static char *outfile;
47
48 /* Pointer to the end of the prefix in OUTFILE.
49    Suffixes are inserted here.  */
50 static char *outfile_mid;
51
52 /* Pointer to the end of OUTFILE. */
53 static char *outfile_end;
54
55 /* Name of input file.  May be "-".  */
56 static char *infile;
57
58 /* Descriptor on which input file is open.  */
59 static int input_desc;
60
61 /* Descriptor on which output file is open.  */
62 static int output_desc;
63
64 /* If nonzero, print a diagnostic on standard error just before each
65    output file is opened. */
66 static int verbose;
67
68 static struct option const longopts[] =
69 {
70   {"bytes", required_argument, NULL, 'b'},
71   {"lines", required_argument, NULL, 'l'},
72   {"line-bytes", required_argument, NULL, 'C'},
73   {"verbose", no_argument, NULL, 2},
74   {GETOPT_HELP_OPTION_DECL},
75   {GETOPT_VERSION_OPTION_DECL},
76   {NULL, 0, NULL, 0}
77 };
78
79 void
80 usage (int status)
81 {
82   if (status != 0)
83     fprintf (stderr, _("Try `%s --help' for more information.\n"),
84              program_name);
85   else
86     {
87       printf (_("\
88 Usage: %s [OPTION] [INPUT [PREFIX]]\n\
89 "),
90               program_name);
91     printf (_("\
92 Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\
93 PREFIX is `x'.  With no INPUT, or when INPUT is -, read standard input.\n\
94 \n\
95   -b, --bytes=SIZE        put SIZE bytes per output file\n\
96   -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file\n\
97   -l, --lines=NUMBER      put NUMBER lines per output file\n\
98   -NUMBER                 same as -l NUMBER\n\
99       --verbose           print a diagnostic to standard error just\n\
100                             before each output file is opened\n\
101       --help              display this help and exit\n\
102       --version           output version information and exit\n\
103 \n\
104 SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
105 "));
106       puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
107     }
108   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
109 }
110
111 /* Compute the next sequential output file name suffix and store it
112    into the string `outfile' at the position pointed to by `outfile_mid'.  */
113
114 static void
115 next_file_name (void)
116 {
117   static unsigned n_digits = 2;
118   char *p;
119
120   /* Change any suffix of `z's to `a's.  */
121   for (p = outfile_end - 1; *p == 'z'; p--)
122     {
123       *p = 'a';
124     }
125
126   /* Increment the rightmost non-`z' character that was present before the
127      above z/a substitutions.  There is guaranteed to be such a character.  */
128   ++(*p);
129
130   /* If the result of that increment operation yielded a `z' and there
131      are only `z's to the left of it, then append two more `a' characters
132      to the end and add 1 (-1 + 2) to the number of digits (we're taking
133      out this `z' and adding two `a's).  */
134   if (*p == 'z' && p == outfile_mid)
135     {
136       ++n_digits;
137       ++outfile_mid;
138       *outfile_end++ = 'a';
139       *outfile_end++ = 'a';
140     }
141 }
142
143 /* Write BYTES bytes at BP to an output file.
144    If NEW_FILE_FLAG is nonzero, open the next output file.
145    Otherwise add to the same output file already in use.  */
146
147 static void
148 cwrite (int new_file_flag, const char *bp, int bytes)
149 {
150   if (new_file_flag)
151     {
152       if (output_desc >= 0 && close (output_desc) < 0)
153         error (EXIT_FAILURE, errno, "%s", outfile);
154
155       next_file_name ();
156       if (verbose)
157         fprintf (stderr, _("creating file `%s'\n"), outfile);
158       output_desc = open (outfile,
159                           O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
160       if (output_desc < 0)
161         error (EXIT_FAILURE, errno, "%s", outfile);
162     }
163   if (full_write (output_desc, bp, bytes) != bytes)
164     error (EXIT_FAILURE, errno, "%s", outfile);
165 }
166
167 /* Read NCHARS bytes from the input file into BUF.
168    Return the number of bytes successfully read.
169    If this is less than NCHARS, do not call `stdread' again.  */
170
171 static int
172 stdread (char *buf, int nchars)
173 {
174   int n_read;
175   int to_be_read = nchars;
176
177   while (to_be_read)
178     {
179       n_read = safe_read (input_desc, buf, to_be_read);
180       if (n_read < 0)
181         return -1;
182       if (n_read == 0)
183         break;
184       to_be_read -= n_read;
185       buf += n_read;
186     }
187   return nchars - to_be_read;
188 }
189
190 /* Split into pieces of exactly NCHARS bytes.
191    Use buffer BUF, whose size is BUFSIZE.  */
192
193 static void
194 bytes_split (int nchars, char *buf, int bufsize)
195 {
196   int n_read;
197   int new_file_flag = 1;
198   int to_read;
199   int to_write = nchars;
200   char *bp_out;
201
202   do
203     {
204       n_read = stdread (buf, bufsize);
205       if (n_read < 0)
206         error (EXIT_FAILURE, errno, "%s", infile);
207       bp_out = buf;
208       to_read = n_read;
209       for (;;)
210         {
211           if (to_read < to_write)
212             {
213               if (to_read)      /* do not write 0 bytes! */
214                 {
215                   cwrite (new_file_flag, bp_out, to_read);
216                   to_write -= to_read;
217                   new_file_flag = 0;
218                 }
219               break;
220             }
221           else
222             {
223               cwrite (new_file_flag, bp_out, to_write);
224               bp_out += to_write;
225               to_read -= to_write;
226               new_file_flag = 1;
227               to_write = nchars;
228             }
229         }
230     }
231   while (n_read == bufsize);
232 }
233
234 /* Split into pieces of exactly NLINES lines.
235    Use buffer BUF, whose size is BUFSIZE.  */
236
237 static void
238 lines_split (int nlines, char *buf, int bufsize)
239 {
240   int n_read;
241   char *bp, *bp_out, *eob;
242   int new_file_flag = 1;
243   int n = 0;
244
245   do
246     {
247       n_read = stdread (buf, bufsize);
248       if (n_read < 0)
249         error (EXIT_FAILURE, errno, "%s", infile);
250       bp = bp_out = buf;
251       eob = bp + n_read;
252       *eob = '\n';
253       for (;;)
254         {
255           while (*bp++ != '\n')
256             ;                   /* this semicolon takes most of the time */
257           if (bp > eob)
258             {
259               if (eob != bp_out) /* do not write 0 bytes! */
260                 {
261                   cwrite (new_file_flag, bp_out, eob - bp_out);
262                   new_file_flag = 0;
263                 }
264               break;
265             }
266           else
267             if (++n >= nlines)
268               {
269                 cwrite (new_file_flag, bp_out, bp - bp_out);
270                 bp_out = bp;
271                 new_file_flag = 1;
272                 n = 0;
273               }
274         }
275     }
276   while (n_read == bufsize);
277 }
278 \f
279 /* Split into pieces that are as large as possible while still not more
280    than NCHARS bytes, and are split on line boundaries except
281    where lines longer than NCHARS bytes occur. */
282
283 static void
284 line_bytes_split (int nchars)
285 {
286   int n_read;
287   char *bp;
288   int eof = 0;
289   int n_buffered = 0;
290   char *buf = (char *) xmalloc (nchars);
291
292   do
293     {
294       /* Fill up the full buffer size from the input file.  */
295
296       n_read = stdread (buf + n_buffered, nchars - n_buffered);
297       if (n_read < 0)
298         error (EXIT_FAILURE, errno, "%s", infile);
299
300       n_buffered += n_read;
301       if (n_buffered != nchars)
302         eof = 1;
303
304       /* Find where to end this chunk.  */
305       bp = buf + n_buffered;
306       if (n_buffered == nchars)
307         {
308           while (bp > buf && bp[-1] != '\n')
309             bp--;
310         }
311
312       /* If chunk has no newlines, use all the chunk.  */
313       if (bp == buf)
314         bp = buf + n_buffered;
315
316       /* Output the chars as one output file.  */
317       cwrite (1, buf, bp - buf);
318
319       /* Discard the chars we just output; move rest of chunk
320          down to be the start of the next chunk.  Source and
321          destination probably overlap.  */
322       n_buffered -= bp - buf;
323       if (n_buffered > 0)
324         memmove (buf, bp, n_buffered);
325     }
326   while (!eof);
327   free (buf);
328 }
329
330 int
331 main (int argc, char **argv)
332 {
333   struct stat stat_buf;
334   int num;                      /* numeric argument from command line */
335   enum
336     {
337       type_undef, type_bytes, type_byteslines, type_lines, type_digits
338     } split_type = type_undef;
339   int in_blk_size;              /* optimal block size of input file device */
340   char *buf;                    /* file i/o buffer */
341   int accum = 0;
342   char *outbase;
343   int c;
344   int digits_optind = 0;
345
346   program_name = argv[0];
347   setlocale (LC_ALL, "");
348   bindtextdomain (PACKAGE, LOCALEDIR);
349   textdomain (PACKAGE);
350
351   atexit (close_stdout);
352
353   /* Parse command line options.  */
354
355   infile = "-";
356   outbase = "x";
357
358   while (1)
359     {
360       /* This is the argv-index of the option we will read next.  */
361       int this_optind = optind ? optind : 1;
362       long int tmp_long;
363
364       c = getopt_long (argc, argv, "0123456789vb:l:C:", longopts, (int *) 0);
365       if (c == EOF)
366         break;
367
368       switch (c)
369         {
370         case 0:
371           break;
372
373         case 'b':
374           if (split_type != type_undef)
375             {
376               error (0, 0, _("cannot split in more than one way"));
377               usage (EXIT_FAILURE);
378             }
379           split_type = type_bytes;
380           if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
381               || tmp_long < 0 || tmp_long > INT_MAX)
382             {
383               error (0, 0, _("%s: invalid number of bytes"), optarg);
384               usage (EXIT_FAILURE);
385             }
386           accum = (int) tmp_long;
387           break;
388
389         case 'l':
390           if (split_type != type_undef)
391             {
392               error (0, 0, _("cannot split in more than one way"));
393               usage (EXIT_FAILURE);
394             }
395           split_type = type_lines;
396           if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
397               || tmp_long < 0 || tmp_long > INT_MAX)
398             {
399               error (0, 0, _("%s: invalid number of lines"), optarg);
400               usage (EXIT_FAILURE);
401             }
402           accum = (int) tmp_long;
403           break;
404
405         case 'C':
406           if (split_type != type_undef)
407             {
408               error (0, 0, _("cannot split in more than one way"));
409               usage (EXIT_FAILURE);
410             }
411
412           split_type = type_byteslines;
413           if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
414               || tmp_long < 0 ||  tmp_long > INT_MAX)
415             {
416               error (0, 0, _("%s: invalid number of bytes"), optarg);
417               usage (EXIT_FAILURE);
418             }
419           accum = (int) tmp_long;
420           break;
421
422         case '0':
423         case '1':
424         case '2':
425         case '3':
426         case '4':
427         case '5':
428         case '6':
429         case '7':
430         case '8':
431         case '9':
432           if (split_type != type_undef && split_type != type_digits)
433             {
434               error (0, 0, _("cannot split in more than one way"));
435               usage (EXIT_FAILURE);
436             }
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';
442           break;
443
444         case 2:
445           verbose = 1;
446           break;
447
448         case_GETOPT_HELP_CHAR;
449
450         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
451
452         default:
453           usage (EXIT_FAILURE);
454         }
455     }
456
457   /* Handle default case.  */
458   if (split_type == type_undef)
459     {
460       split_type = type_lines;
461       accum = 1000;
462     }
463
464   if (accum < 1)
465     {
466       error (0, 0, _("invalid number"));
467       usage (EXIT_FAILURE);
468     }
469   num = accum;
470
471   /* Get out the filename arguments.  */
472
473   if (optind < argc)
474     infile = argv[optind++];
475
476   if (optind < argc)
477     outbase = argv[optind++];
478
479   if (optind < argc)
480     {
481       error (0, 0, _("too many arguments"));
482       usage (EXIT_FAILURE);
483     }
484
485   /* Open the input file.  */
486   if (STREQ (infile, "-"))
487     input_desc = 0;
488   else
489     {
490       input_desc = open (infile, O_RDONLY);
491       if (input_desc < 0)
492         error (EXIT_FAILURE, errno, "%s", infile);
493     }
494   /* Binary I/O is safer when bytecounts are used.  */
495   SET_BINARY (input_desc);
496
497   /* No output file is open now.  */
498   output_desc = -1;
499
500   /* Copy the output file prefix so we can add suffixes to it.
501      26**29 is certainly enough output files!  */
502
503   outfile = xmalloc (strlen (outbase) + 30);
504   strcpy (outfile, outbase);
505   outfile_mid = outfile + strlen (outfile);
506   outfile_end = outfile_mid + 2;
507   memset (outfile_mid, 0, 30);
508   outfile_mid[0] = 'a';
509   outfile_mid[1] = 'a' - 1;  /* first call to next_file_name makes it an 'a' */
510
511   /* Get the optimal block size of input device and make a buffer.  */
512
513   if (fstat (input_desc, &stat_buf) < 0)
514     error (EXIT_FAILURE, errno, "%s", infile);
515   in_blk_size = ST_BLKSIZE (stat_buf);
516
517   buf = xmalloc (in_blk_size + 1);
518
519   switch (split_type)
520     {
521     case type_digits:
522     case type_lines:
523       lines_split (num, buf, in_blk_size);
524       break;
525
526     case type_bytes:
527       bytes_split (num, buf, in_blk_size);
528       break;
529
530     case type_byteslines:
531       line_bytes_split (num);
532       break;
533
534     default:
535       abort ();
536     }
537
538   if (close (input_desc) < 0)
539     error (EXIT_FAILURE, errno, "%s", infile);
540   if (output_desc >= 0 && close (output_desc) < 0)
541     error (EXIT_FAILURE, errno, "%s", outfile);
542
543   exit (EXIT_SUCCESS);
544 }