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