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