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