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