Rename local variables: nchars -> n_bytes.
[platform/upstream/coreutils.git] / src / split.c
1 /* split.c -- split a file into pieces.
2    Copyright (C) 88, 91, 1995-2003 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 "dirname.h"
33 #include "error.h"
34 #include "full-read.h"
35 #include "full-write.h"
36 #include "posixver.h"
37 #include "safe-read.h"
38 #include "xstrtol.h"
39
40 /* The official name of this program (e.g., no `g' prefix).  */
41 #define PROGRAM_NAME "split"
42
43 #define AUTHORS N_ ("Torbjorn Granlund and Richard M. Stallman")
44
45 #define DEFAULT_SUFFIX_LENGTH 2
46
47 /* The name this program was run with. */
48 char *program_name;
49
50 /* Base name of output files.  */
51 static char const *outbase;
52
53 /* 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 /* Length of OUTFILE's suffix.  */
61 static size_t suffix_length = DEFAULT_SUFFIX_LENGTH;
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, print a diagnostic on standard error just before each
73    output file is opened. */
74 static int verbose;
75
76 static struct option const longopts[] =
77 {
78   {"bytes", required_argument, NULL, 'b'},
79   {"lines", required_argument, NULL, 'l'},
80   {"line-bytes", required_argument, NULL, 'C'},
81   {"suffix-length", required_argument, NULL, 'a'},
82   {"verbose", no_argument, &verbose, 0},
83   {GETOPT_HELP_OPTION_DECL},
84   {GETOPT_VERSION_OPTION_DECL},
85   {NULL, 0, NULL, 0}
86 };
87
88 void
89 usage (int status)
90 {
91   if (status != 0)
92     fprintf (stderr, _("Try `%s --help' for more information.\n"),
93              program_name);
94   else
95     {
96       printf (_("\
97 Usage: %s [OPTION] [INPUT [PREFIX]]\n\
98 "),
99               program_name);
100     fputs (_("\
101 Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\
102 PREFIX is `x'.  With no INPUT, or when INPUT is -, read standard input.\n\
103 \n\
104 "), stdout);
105       fputs (_("\
106 Mandatory arguments to long options are mandatory for short options too.\n\
107 "), stdout);
108       fprintf (stdout, _("\
109   -a, --suffix-length=N   use suffixes of length N (default %d)\n\
110   -b, --bytes=SIZE        put SIZE bytes per output file\n\
111   -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file\n\
112   -l, --lines=NUMBER      put NUMBER lines per output file\n\
113 "), DEFAULT_SUFFIX_LENGTH);
114       fputs (_("\
115       --verbose           print a diagnostic to standard error just\n\
116                             before each output file is opened\n\
117 "), stdout);
118       fputs (HELP_OPTION_DESCRIPTION, stdout);
119       fputs (VERSION_OPTION_DESCRIPTION, stdout);
120       fputs (_("\
121 \n\
122 SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
123 "), stdout);
124       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
125     }
126   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
127 }
128
129 /* Compute the next sequential output file name and store it into the
130    string `outfile'.  */
131
132 static void
133 next_file_name (void)
134 {
135   if (! outfile)
136     {
137       /* Allocate and initialize the first file name.  */
138
139       size_t outbase_length = strlen (outbase);
140       size_t outfile_length = outbase_length + suffix_length;
141       if (outfile_length + 1 < outbase_length)
142         xalloc_die ();
143       outfile = xmalloc (outfile_length + 1);
144       outfile_mid = outfile + outbase_length;
145       memcpy (outfile, outbase, outbase_length);
146       memset (outfile_mid, 'a', suffix_length);
147       outfile[outfile_length] = 0;
148
149 #if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
150       /* POSIX requires that if the output file name is too long for
151          its directory, `split' must fail without creating any files.
152          This must be checked for explicitly on operating systems that
153          silently truncate file names.  */
154       {
155         char *dir = dir_name (outfile);
156         long name_max = pathconf (dir, _PC_NAME_MAX);
157         if (0 <= name_max && name_max < base_len (base_name (outfile)))
158           error (EXIT_FAILURE, ENAMETOOLONG, "%s", outfile);
159         free (dir);
160       }
161 #endif
162     }
163   else
164     {
165       /* Increment the suffix in place, if possible.  */
166
167       char *p;
168       for (p = outfile_mid + suffix_length; outfile_mid < p; *--p = 'a')
169         if (p[-1]++ != 'z')
170           return;
171       error (EXIT_FAILURE, 0, _("Output file suffixes exhausted"));
172     }
173 }
174
175 /* Write BYTES bytes at BP to an output file.
176    If NEW_FILE_FLAG is nonzero, open the next output file.
177    Otherwise add to the same output file already in use.  */
178
179 static void
180 cwrite (int new_file_flag, const char *bp, size_t bytes)
181 {
182   if (new_file_flag)
183     {
184       if (output_desc >= 0 && close (output_desc) < 0)
185         error (EXIT_FAILURE, errno, "%s", outfile);
186
187       next_file_name ();
188       if (verbose)
189         fprintf (stderr, _("creating file `%s'\n"), outfile);
190       output_desc = open (outfile,
191                           O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
192       if (output_desc < 0)
193         error (EXIT_FAILURE, errno, "%s", outfile);
194     }
195   if (full_write (output_desc, bp, bytes) != bytes)
196     error (EXIT_FAILURE, errno, "%s", outfile);
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 (size_t n_bytes, char *buf, size_t bufsize)
204 {
205   size_t n_read;
206   int new_file_flag = 1;
207   size_t to_read;
208   size_t to_write = n_bytes;
209   char *bp_out;
210
211   do
212     {
213       n_read = full_read (input_desc, buf, bufsize);
214       if (n_read == SAFE_READ_ERROR)
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
231           cwrite (new_file_flag, bp_out, to_write);
232           bp_out += to_write;
233           to_read -= to_write;
234           new_file_flag = 1;
235           to_write = n_bytes;
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 (size_t nlines, char *buf, size_t bufsize)
246 {
247   size_t n_read;
248   char *bp, *bp_out, *eob;
249   int new_file_flag = 1;
250   size_t n = 0;
251
252   do
253     {
254       n_read = full_read (input_desc, buf, bufsize);
255       if (n_read == SAFE_READ_ERROR)
256         error (EXIT_FAILURE, errno, "%s", infile);
257       bp = bp_out = buf;
258       eob = bp + n_read;
259       *eob = '\n';
260       for (;;)
261         {
262           bp = memchr (bp, '\n', eob - bp + 1);
263           if (bp == eob)
264             {
265               if (eob != bp_out) /* do not write 0 bytes! */
266                 {
267                   size_t len = eob - bp_out;
268                   cwrite (new_file_flag, bp_out, len);
269                   new_file_flag = 0;
270                 }
271               break;
272             }
273
274           ++bp;
275           if (++n >= nlines)
276             {
277               cwrite (new_file_flag, bp_out, bp - bp_out);
278               bp_out = bp;
279               new_file_flag = 1;
280               n = 0;
281             }
282         }
283     }
284   while (n_read == bufsize);
285 }
286 \f
287 /* Split into pieces that are as large as possible while still not more
288    than NCHARS bytes, and are split on line boundaries except
289    where lines longer than NCHARS bytes occur. */
290
291 static void
292 line_bytes_split (size_t n_bytes)
293 {
294   size_t n_read;
295   char *bp;
296   int eof = 0;
297   size_t n_buffered = 0;
298   char *buf = (char *) xmalloc (n_bytes);
299
300   do
301     {
302       /* Fill up the full buffer size from the input file.  */
303
304       n_read = full_read (input_desc, buf + n_buffered, n_bytes - n_buffered);
305       if (n_read == SAFE_READ_ERROR)
306         error (EXIT_FAILURE, errno, "%s", infile);
307
308       n_buffered += n_read;
309       if (n_buffered != n_bytes)
310         eof = 1;
311
312       /* Find where to end this chunk.  */
313       bp = buf + n_buffered;
314       if (n_buffered == n_bytes)
315         {
316           while (bp > buf && bp[-1] != '\n')
317             bp--;
318         }
319
320       /* If chunk has no newlines, use all the chunk.  */
321       if (bp == buf)
322         bp = buf + n_buffered;
323
324       /* Output the chars as one output file.  */
325       cwrite (1, buf, bp - buf);
326
327       /* Discard the chars we just output; move rest of chunk
328          down to be the start of the next chunk.  Source and
329          destination probably overlap.  */
330       n_buffered -= bp - buf;
331       if (n_buffered > 0)
332         memmove (buf, bp, n_buffered);
333     }
334   while (!eof);
335   free (buf);
336 }
337
338 #define FAIL_ONLY_ONE_WAY()                                     \
339   do                                                            \
340     {                                                           \
341       error (0, 0, _("cannot split in more than one way"));     \
342       usage (EXIT_FAILURE);                                     \
343     }                                                           \
344   while (0)
345
346 int
347 main (int argc, char **argv)
348 {
349   struct stat stat_buf;
350   size_t num;                   /* numeric argument from command line */
351   enum
352     {
353       type_undef, type_bytes, type_byteslines, type_lines, type_digits
354     } split_type = type_undef;
355   size_t in_blk_size;           /* optimal block size of input file device */
356   char *buf;                    /* file i/o buffer */
357   size_t accum = 0;
358   int c;
359   int digits_optind = 0;
360
361   program_name = argv[0];
362   setlocale (LC_ALL, "");
363   bindtextdomain (PACKAGE, LOCALEDIR);
364   textdomain (PACKAGE);
365
366   atexit (close_stdout);
367
368   /* Parse command line options.  */
369
370   infile = "-";
371   outbase = "x";
372
373   while (1)
374     {
375       /* This is the argv-index of the option we will read next.  */
376       int this_optind = optind ? optind : 1;
377       long int tmp_long;
378
379       c = getopt_long (argc, argv, "0123456789C:a:b:l:", longopts, NULL);
380       if (c == -1)
381         break;
382
383       switch (c)
384         {
385         case 0:
386           break;
387
388         case 'a':
389           {
390             unsigned long tmp;
391             if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK
392                 || SIZE_MAX < tmp)
393               {
394                 error (0, 0, _("%s: invalid suffix length"), optarg);
395                 usage (EXIT_FAILURE);
396               }
397             suffix_length = tmp;
398           }
399           break;
400
401         case 'b':
402           if (split_type != type_undef)
403             FAIL_ONLY_ONE_WAY ();
404           split_type = type_bytes;
405           if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
406               || tmp_long < 0 || tmp_long > INT_MAX)
407             {
408               error (0, 0, _("%s: invalid number of bytes"), optarg);
409               usage (EXIT_FAILURE);
410             }
411           accum = /* FIXME: */ (int) tmp_long;
412           break;
413
414         case 'l':
415           if (split_type != type_undef)
416             FAIL_ONLY_ONE_WAY ();
417           split_type = type_lines;
418           if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
419               || tmp_long < 0 || tmp_long > INT_MAX)
420             {
421               error (0, 0, _("%s: invalid number of lines"), optarg);
422               usage (EXIT_FAILURE);
423             }
424           accum = /* FIXME */ (int) tmp_long;
425           break;
426
427         case 'C':
428           if (split_type != type_undef)
429             FAIL_ONLY_ONE_WAY ();
430           split_type = type_byteslines;
431           if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
432               || tmp_long < 0 ||  tmp_long > INT_MAX)
433             {
434               error (0, 0, _("%s: invalid number of bytes"), optarg);
435               usage (EXIT_FAILURE);
436             }
437           accum = /* FIXME */ (int) tmp_long;
438           break;
439
440         case '0':
441         case '1':
442         case '2':
443         case '3':
444         case '4':
445         case '5':
446         case '6':
447         case '7':
448         case '8':
449         case '9':
450           if (split_type != type_undef && split_type != type_digits)
451             FAIL_ONLY_ONE_WAY ();
452           if (digits_optind != 0 && digits_optind != this_optind)
453             accum = 0;          /* More than one number given; ignore other. */
454           digits_optind = this_optind;
455           split_type = type_digits;
456           accum = accum * 10 + c - '0';
457           break;
458
459         case_GETOPT_HELP_CHAR;
460
461         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
462
463         default:
464           usage (EXIT_FAILURE);
465         }
466     }
467
468   if (digits_optind && 200112 <= posix2_version ())
469     {
470       error (0, 0, _("`-%d' option is obsolete; use `-l %d'"), accum, accum);
471       usage (EXIT_FAILURE);
472     }
473
474   /* Handle default case.  */
475   if (split_type == type_undef)
476     {
477       split_type = type_lines;
478       accum = 1000;
479     }
480
481   if (accum < 1)
482     {
483       error (0, 0, _("invalid number"));
484       usage (EXIT_FAILURE);
485     }
486   num = accum;
487
488   /* Get out the filename arguments.  */
489
490   if (optind < argc)
491     infile = argv[optind++];
492
493   if (optind < argc)
494     outbase = argv[optind++];
495
496   if (optind < argc)
497     {
498       error (0, 0, _("too many arguments"));
499       usage (EXIT_FAILURE);
500     }
501
502   /* Open the input file.  */
503   if (STREQ (infile, "-"))
504     input_desc = 0;
505   else
506     {
507       input_desc = open (infile, O_RDONLY);
508       if (input_desc < 0)
509         error (EXIT_FAILURE, errno, "%s", infile);
510     }
511   /* Binary I/O is safer when bytecounts are used.  */
512   SET_BINARY (input_desc);
513
514   /* No output file is open now.  */
515   output_desc = -1;
516
517   /* Get the optimal block size of input device and make a buffer.  */
518
519   if (fstat (input_desc, &stat_buf) < 0)
520     error (EXIT_FAILURE, errno, "%s", infile);
521   in_blk_size = ST_BLKSIZE (stat_buf);
522
523   buf = xmalloc (in_blk_size + 1);
524
525   switch (split_type)
526     {
527     case type_digits:
528     case type_lines:
529       lines_split (num, buf, in_blk_size);
530       break;
531
532     case type_bytes:
533       bytes_split (num, buf, in_blk_size);
534       break;
535
536     case type_byteslines:
537       line_bytes_split (num);
538       break;
539
540     default:
541       abort ();
542     }
543
544   if (close (input_desc) < 0)
545     error (EXIT_FAILURE, errno, "%s", infile);
546   if (output_desc >= 0 && close (output_desc) < 0)
547     error (EXIT_FAILURE, errno, "%s", outfile);
548
549   exit (EXIT_SUCCESS);
550 }