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