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