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