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