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