xref: /netbsd-src/usr.bin/split/split.c (revision ae1bfcddc410612bc8c58b807e1830becb69a24c)
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