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