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