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