Annotation of src/usr.bin/split/split.c, Revision 1.2
1.2 ! deraadt 1: /* $OpenBSD: split.c,v 1.5 1995/08/31 22:22:05 jtc Exp $ */
1.1 deraadt 2: /* $NetBSD: split.c,v 1.5 1995/08/31 22:22:05 jtc Exp $ */
3:
4: /*
5: * Copyright (c) 1987, 1993, 1994
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
38: static char copyright[] =
39: "@(#) Copyright (c) 1987, 1993, 1994\n\
40: The Regents of the University of California. All rights reserved.\n";
41: #endif /* not lint */
42:
43: #ifndef lint
44: #if 0
45: static char sccsid[] = "@(#)split.c 8.3 (Berkeley) 4/25/94";
46: #endif
1.2 ! deraadt 47: static char rcsid[] = "$OpenBSD: split.c,v 1.5 1995/08/31 22:22:05 jtc Exp $";
1.1 deraadt 48: #endif /* not lint */
49:
50: #include <sys/param.h>
51:
52: #include <ctype.h>
53: #include <err.h>
54: #include <fcntl.h>
55: #include <stdio.h>
56: #include <stdlib.h>
57: #include <string.h>
58: #include <unistd.h>
59:
60: #define DEFLINE 1000 /* Default num lines per file. */
61:
62: long bytecnt; /* Byte count to split on. */
63: long numlines; /* Line count to split on. */
64: int file_open; /* If a file open. */
65: int ifd = -1, ofd = -1; /* Input/output file descriptors. */
66: char bfr[MAXBSIZE]; /* I/O buffer. */
67: char fname[MAXPATHLEN]; /* File name prefix. */
68:
69: void newfile __P((void));
70: void split1 __P((void));
71: void split2 __P((void));
72: void usage __P((void));
73:
74: int
75: main(argc, argv)
76: int argc;
77: char *argv[];
78: {
79: int ch;
80: char *ep, *p;
81:
82: while ((ch = getopt(argc, argv, "-0123456789b:l:")) != EOF)
83: switch (ch) {
84: case '0': case '1': case '2': case '3': case '4':
85: case '5': case '6': case '7': case '8': case '9':
86: /*
87: * Undocumented kludge: split was originally designed
88: * to take a number after a dash.
89: */
90: if (numlines == 0) {
91: p = argv[optind - 1];
92: if (p[0] == '-' && p[1] == ch && !p[2])
93: numlines = strtol(++p, &ep, 10);
94: else
95: numlines =
96: strtol(argv[optind] + 1, &ep, 10);
97: if (numlines <= 0 || *ep)
98: errx(1,
99: "%s: illegal line count.", optarg);
100: }
101: break;
102: case '-': /* Undocumented: historic stdin flag. */
103: if (ifd != -1)
104: usage();
105: ifd = 0;
106: break;
107: case 'b': /* Byte count. */
108: if ((bytecnt = strtol(optarg, &ep, 10)) <= 0 ||
109: *ep != '\0' && *ep != 'k' && *ep != 'm')
110: errx(1, "%s: illegal byte count.", optarg);
111: if (*ep == 'k')
112: bytecnt *= 1024;
113: else if (*ep == 'm')
114: bytecnt *= 1048576;
115: break;
116: case 'l': /* Line count. */
117: if (numlines != 0)
118: usage();
119: if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *ep)
120: errx(1, "%s: illegal line count.", optarg);
121: break;
122: default:
123: usage();
124: }
125: argv += optind;
126: argc -= optind;
127:
128: if (*argv != NULL)
129: if (ifd == -1) { /* Input file. */
130: if ((ifd = open(*argv, O_RDONLY, 0)) < 0)
131: err(1, "%s", *argv);
132: ++argv;
133: }
134: if (*argv != NULL) /* File name prefix. */
135: (void)strcpy(fname, *argv++);
136: if (*argv != NULL)
137: usage();
138:
139: if (numlines == 0)
140: numlines = DEFLINE;
141: else if (bytecnt)
142: usage();
143:
144: if (ifd == -1) /* Stdin by default. */
145: ifd = 0;
146:
147: if (bytecnt) {
148: split1();
149: exit (0);
150: }
151: split2();
152: exit(0);
153: }
154:
155: /*
156: * split1 --
157: * Split the input by bytes.
158: */
159: void
160: split1()
161: {
162: long bcnt;
163: int dist, len;
164: char *C;
165:
166: for (bcnt = 0;;)
167: switch (len = read(ifd, bfr, MAXBSIZE)) {
168: case 0:
169: exit(0);
170: case -1:
171: err(1, "read");
172: /* NOTREACHED */
173: default:
174: if (!file_open) {
175: newfile();
176: file_open = 1;
177: }
178: if (bcnt + len >= bytecnt) {
179: dist = bytecnt - bcnt;
180: if (write(ofd, bfr, dist) != dist)
181: err(1, "write");
182: len -= dist;
183: for (C = bfr + dist; len >= bytecnt;
184: len -= bytecnt, C += bytecnt) {
185: newfile();
186: if (write(ofd,
187: C, (int)bytecnt) != bytecnt)
188: err(1, "write");
189: }
190: if (len) {
191: newfile();
192: if (write(ofd, C, len) != len)
193: err(1, "write");
194: } else
195: file_open = 0;
196: bcnt = len;
197: } else {
198: bcnt += len;
199: if (write(ofd, bfr, len) != len)
200: err(1, "write");
201: }
202: }
203: }
204:
205: /*
206: * split2 --
207: * Split the input by lines.
208: */
209: void
210: split2()
211: {
212: long lcnt;
213: int len, bcnt;
214: char *Ce, *Cs;
215:
216: for (lcnt = 0;;)
217: switch (len = read(ifd, bfr, MAXBSIZE)) {
218: case 0:
219: exit(0);
220: case -1:
221: err(1, "read");
222: /* NOTREACHED */
223: default:
224: if (!file_open) {
225: newfile();
226: file_open = 1;
227: }
228: for (Cs = Ce = bfr; len--; Ce++)
229: if (*Ce == '\n' && ++lcnt == numlines) {
230: bcnt = Ce - Cs + 1;
231: if (write(ofd, Cs, bcnt) != bcnt)
232: err(1, "write");
233: lcnt = 0;
234: Cs = Ce + 1;
235: if (len)
236: newfile();
237: else
238: file_open = 0;
239: }
240: if (Cs < Ce) {
241: bcnt = Ce - Cs;
242: if (write(ofd, Cs, bcnt) != bcnt)
243: err(1, "write");
244: }
245: }
246: }
247:
248: /*
249: * newfile --
250: * Open a new output file.
251: */
252: void
253: newfile()
254: {
255: static long fnum;
256: static int defname;
257: static char *fpnt;
258:
259: if (ofd == -1) {
260: if (fname[0] == '\0') {
261: fname[0] = 'x';
262: fpnt = fname + 1;
263: defname = 1;
264: } else {
265: fpnt = fname + strlen(fname);
266: defname = 0;
267: }
268: ofd = fileno(stdout);
269: }
270: /*
271: * Hack to increase max files; original code wandered through
272: * magic characters. Maximum files is 3 * 26 * 26 == 2028
273: */
274: #define MAXFILES 676
275: if (fnum == MAXFILES) {
276: if (!defname || fname[0] == 'z')
277: errx(1, "too many files.");
278: ++fname[0];
279: fnum = 0;
280: }
281: fpnt[0] = fnum / 26 + 'a';
282: fpnt[1] = fnum % 26 + 'a';
283: ++fnum;
284: if (!freopen(fname, "w", stdout))
285: err(1, "%s", fname);
286: }
287:
288: void
289: usage()
290: {
291: (void)fprintf(stderr,
292: "usage: split [-b byte_count] [-l line_count] [file [prefix]]\n");
293: exit(1);
294: }