Standardize --help and --version processing.
[platform/upstream/coreutils.git] / src / split.c
1 /* split.c -- split a file into pieces.
2    Copyright (C) 88, 91, 1995-1999 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 "error.h"
32 #include "safe-read.h"
33 #include "xstrtol.h"
34
35 /* The official name of this program (e.g., no `g' prefix).  */
36 #define PROGRAM_NAME "split"
37
38 #define AUTHORS "Torbjorn Granlund and Richard M. Stallman"
39
40 int full_write ();
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) < 0)
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   /* Parse command line options.  */
352
353   infile = "-";
354   outbase = "x";
355
356   while (1)
357     {
358       /* This is the argv-index of the option we will read next.  */
359       int this_optind = optind ? optind : 1;
360       long int tmp_long;
361
362       c = getopt_long (argc, argv, "0123456789vb:l:C:", longopts, (int *) 0);
363       if (c == EOF)
364         break;
365
366       switch (c)
367         {
368         case 0:
369           break;
370
371         case 'b':
372           if (split_type != type_undef)
373             {
374               error (0, 0, _("cannot split in more than one way"));
375               usage (EXIT_FAILURE);
376             }
377           split_type = type_bytes;
378           if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
379               || tmp_long < 0 || tmp_long > INT_MAX)
380             {
381               error (0, 0, _("%s: invalid number of bytes"), optarg);
382               usage (EXIT_FAILURE);
383             }
384           accum = (int) tmp_long;
385           break;
386
387         case 'l':
388           if (split_type != type_undef)
389             {
390               error (0, 0, _("cannot split in more than one way"));
391               usage (EXIT_FAILURE);
392             }
393           split_type = type_lines;
394           if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
395               || tmp_long < 0 || tmp_long > INT_MAX)
396             {
397               error (0, 0, _("%s: invalid number of lines"), optarg);
398               usage (EXIT_FAILURE);
399             }
400           accum = (int) tmp_long;
401           break;
402
403         case 'C':
404           if (split_type != type_undef)
405             {
406               error (0, 0, _("cannot split in more than one way"));
407               usage (EXIT_FAILURE);
408             }
409
410           split_type = type_byteslines;
411           if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
412               || tmp_long < 0 ||  tmp_long > INT_MAX)
413             {
414               error (0, 0, _("%s: invalid number of bytes"), optarg);
415               usage (EXIT_FAILURE);
416             }
417           accum = (int) tmp_long;
418           break;
419
420         case '0':
421         case '1':
422         case '2':
423         case '3':
424         case '4':
425         case '5':
426         case '6':
427         case '7':
428         case '8':
429         case '9':
430           if (split_type != type_undef && split_type != type_digits)
431             {
432               error (0, 0, _("cannot split in more than one way"));
433               usage (EXIT_FAILURE);
434             }
435           if (digits_optind != 0 && digits_optind != this_optind)
436             accum = 0;          /* More than one number given; ignore other. */
437           digits_optind = this_optind;
438           split_type = type_digits;
439           accum = accum * 10 + c - '0';
440           break;
441
442         case 2:
443           verbose = 1;
444           break;
445
446         case_GETOPT_HELP_CHAR;
447
448         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
449
450         default:
451           usage (EXIT_FAILURE);
452         }
453     }
454
455   /* Handle default case.  */
456   if (split_type == type_undef)
457     {
458       split_type = type_lines;
459       accum = 1000;
460     }
461
462   if (accum < 1)
463     {
464       error (0, 0, _("invalid number"));
465       usage (EXIT_FAILURE);
466     }
467   num = accum;
468
469   /* Get out the filename arguments.  */
470
471   if (optind < argc)
472     infile = argv[optind++];
473
474   if (optind < argc)
475     outbase = argv[optind++];
476
477   if (optind < argc)
478     {
479       error (0, 0, _("too many arguments"));
480       usage (EXIT_FAILURE);
481     }
482
483   /* Open the input file.  */
484   if (STREQ (infile, "-"))
485     input_desc = 0;
486   else
487     {
488       input_desc = open (infile, O_RDONLY);
489       if (input_desc < 0)
490         error (EXIT_FAILURE, errno, "%s", infile);
491     }
492   /* Binary I/O is safer when bytecounts are used.  */
493   SET_BINARY (input_desc);
494
495   /* No output file is open now.  */
496   output_desc = -1;
497
498   /* Copy the output file prefix so we can add suffixes to it.
499      26**29 is certainly enough output files!  */
500
501   outfile = xmalloc (strlen (outbase) + 30);
502   strcpy (outfile, outbase);
503   outfile_mid = outfile + strlen (outfile);
504   outfile_end = outfile_mid + 2;
505   memset (outfile_mid, 0, 30);
506   outfile_mid[0] = 'a';
507   outfile_mid[1] = 'a' - 1;  /* first call to next_file_name makes it an 'a' */
508
509   /* Get the optimal block size of input device and make a buffer.  */
510
511   if (fstat (input_desc, &stat_buf) < 0)
512     error (EXIT_FAILURE, errno, "%s", infile);
513   in_blk_size = ST_BLKSIZE (stat_buf);
514
515   buf = xmalloc (in_blk_size + 1);
516
517   switch (split_type)
518     {
519     case type_digits:
520     case type_lines:
521       lines_split (num, buf, in_blk_size);
522       break;
523
524     case type_bytes:
525       bytes_split (num, buf, in_blk_size);
526       break;
527
528     case type_byteslines:
529       line_bytes_split (num);
530       break;
531
532     default:
533       abort ();
534     }
535
536   if (close (input_desc) < 0)
537     error (EXIT_FAILURE, errno, "%s", infile);
538   if (output_desc >= 0 && close (output_desc) < 0)
539     error (EXIT_FAILURE, errno, "%s", outfile);
540
541   exit (EXIT_SUCCESS);
542 }