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