split.c revision 1.2 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.2 1993/08/01 18:08:21 mycroft 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 bytecnt = atol(argv[++cnt]);
85 else
86 bytecnt = atol(argv[cnt] + 2);
87 if (bytecnt <= 0) {
88 fputs("split: byte count must be greater than zero.\n", stderr);
89 usage();
90 }
91 break;
92 default:
93 if (!isdigit(argv[cnt][1]) || bytecnt)
94 usage();
95 if ((numlines = atol(argv[cnt] + 1)) <= 0) {
96 fputs("split: line count must be greater than zero.\n", stderr);
97 usage();
98 }
99 break;
100 }
101 else if (ifd == ERR) { /* input file */
102 if ((ifd = open(argv[cnt], O_RDONLY, 0)) < 0) {
103 perror(argv[cnt]);
104 exit(1);
105 }
106 }
107 else if (!*fname) /* output file prefix */
108 strcpy(fname, argv[cnt]);
109 else
110 usage();
111 }
112 if (ifd == ERR) /* stdin by default */
113 ifd = 0;
114 if (bytecnt)
115 split1();
116 if (!numlines)
117 numlines = DEFLINE;
118 split2();
119 exit(0);
120 }
121
122 /*
123 * split1 --
124 * split by bytes
125 */
126 split1()
127 {
128 register long bcnt;
129 register int dist, len;
130 register char *C;
131
132 for (bcnt = 0;;)
133 switch(len = read(ifd, bfr, MAXBSIZE)) {
134 case 0:
135 exit(OK);
136 case ERR:
137 perror("read");
138 exit(1);
139 default:
140 if (!file_open) {
141 newfile();
142 file_open = YES;
143 }
144 if (bcnt + len >= bytecnt) {
145 dist = bytecnt - bcnt;
146 if (write(ofd, bfr, dist) != dist)
147 wrerror();
148 len -= dist;
149 for (C = bfr + dist; len >= bytecnt; len -= bytecnt, C += bytecnt) {
150 newfile();
151 if (write(ofd, C, (int)bytecnt) != bytecnt)
152 wrerror();
153 }
154 if (len) {
155 newfile();
156 if (write(ofd, C, len) != len)
157 wrerror();
158 }
159 else
160 file_open = NO;
161 bcnt = len;
162 }
163 else {
164 bcnt += len;
165 if (write(ofd, bfr, len) != len)
166 wrerror();
167 }
168 }
169 }
170
171 /*
172 * split2 --
173 * split by lines
174 */
175 split2()
176 {
177 register char *Ce, *Cs;
178 register long lcnt;
179 register int len, bcnt;
180
181 for (lcnt = 0;;)
182 switch(len = read(ifd, bfr, MAXBSIZE)) {
183 case 0:
184 exit(0);
185 case ERR:
186 perror("read");
187 exit(1);
188 default:
189 if (!file_open) {
190 newfile();
191 file_open = YES;
192 }
193 for (Cs = Ce = bfr; len--; Ce++)
194 if (*Ce == '\n' && ++lcnt == numlines) {
195 bcnt = Ce - Cs + 1;
196 if (write(ofd, Cs, bcnt) != bcnt)
197 wrerror();
198 lcnt = 0;
199 Cs = Ce + 1;
200 if (len)
201 newfile();
202 else
203 file_open = NO;
204 }
205 if (Cs < Ce) {
206 bcnt = Ce - Cs;
207 if (write(ofd, Cs, bcnt) != bcnt)
208 wrerror();
209 }
210 }
211 }
212
213 /*
214 * newfile --
215 * open a new file
216 */
217 newfile()
218 {
219 static long fnum;
220 static short defname;
221 static char *fpnt;
222
223 if (ofd == ERR) {
224 if (fname[0]) {
225 fpnt = fname + strlen(fname);
226 defname = NO;
227 }
228 else {
229 fname[0] = 'x';
230 fpnt = fname + 1;
231 defname = YES;
232 }
233 ofd = fileno(stdout);
234 }
235 /*
236 * hack to increase max files; original code just wandered through
237 * magic characters. Maximum files is 3 * 26 * 26 == 2028
238 */
239 #define MAXFILES 676
240 if (fnum == MAXFILES) {
241 if (!defname || fname[0] == 'z') {
242 fputs("split: too many files.\n", stderr);
243 exit(1);
244 }
245 ++fname[0];
246 fnum = 0;
247 }
248 fpnt[0] = fnum / 26 + 'a';
249 fpnt[1] = fnum % 26 + 'a';
250 ++fnum;
251 if (!freopen(fname, "w", stdout)) {
252 fprintf(stderr, "split: unable to write to %s.\n", fname);
253 exit(ERR);
254 }
255 }
256
257 /*
258 * usage --
259 * print usage message and die
260 */
261 usage()
262 {
263 fputs("usage: split [-] [-#] [-b byte_count] [file [prefix]]\n", stderr);
264 exit(1);
265 }
266
267 /*
268 * wrerror --
269 * write error
270 */
271 wrerror()
272 {
273 perror("split: write");
274 exit(1);
275 }
276