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