xref: /original-bsd/usr.bin/split/split.c (revision 850c0003)
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 are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1987 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)split.c	4.7 (Berkeley) 01/23/89";
26 #endif /* not lint */
27 
28 #include <sys/param.h>
29 #include <sys/file.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 
33 #define DEFLINE	1000			/* default num lines per file */
34 #define ERR	-1			/* general error */
35 #define NO	0			/* no/false */
36 #define OK	0			/* okay exit */
37 #define YES	1			/* yes/true */
38 
39 static long	bytecnt,		/* byte count to split on */
40 		numlines;		/* lines in each file */
41 static int	ifd = ERR,		/* input file descriptor */
42 		ofd = ERR;		/* output file descriptor */
43 static short	file_open;		/* if a file open */
44 static char	bfr[MAXBSIZE],		/* I/O buffer */
45 		fname[MAXPATHLEN];	/* file name */
46 
47 main(argc, argv)
48 	int argc;
49 	char **argv;
50 {
51 	register int cnt;
52 	long atol();
53 	char *strcpy();
54 
55 	for (cnt = 1; cnt < argc; ++cnt) {
56 		if (argv[cnt][0] == '-')
57 			switch(argv[cnt][1]) {
58 			case 0:		/* stdin by request */
59 				if (ifd != ERR)
60 					usage();
61 				ifd = 0;
62 				break;
63 			case 'b':	/* byte count split */
64 				if (numlines)
65 					usage();
66 				if (!argv[cnt][2])
67 					bytecnt = atol(argv[++cnt]);
68 				else
69 					bytecnt = atol(argv[cnt] + 2);
70 				if (bytecnt <= 0) {
71 					fputs("split: byte count must be greater than zero.\n", stderr);
72 					usage();
73 				}
74 				break;
75 			default:
76 				if (!isdigit(argv[cnt][1]) || bytecnt)
77 					usage();
78 				if ((numlines = atol(argv[cnt] + 1)) <= 0) {
79 					fputs("split: line count must be greater than zero.\n", stderr);
80 					usage();
81 				}
82 				break;
83 			}
84 		else if (ifd == ERR) {		/* input file */
85 			if ((ifd = open(argv[cnt], O_RDONLY, 0)) < 0) {
86 				perror(argv[cnt]);
87 				exit(1);
88 			}
89 		}
90 		else if (!*fname)		/* output file prefix */
91 			strcpy(fname, argv[cnt]);
92 		else
93 			usage();
94 	}
95 	if (ifd == ERR)				/* stdin by default */
96 		ifd = 0;
97 	if (bytecnt)
98 		split1();
99 	if (!numlines)
100 		numlines = DEFLINE;
101 	split2();
102 	exit(0);
103 }
104 
105 /*
106  * split1 --
107  *	split by bytes
108  */
109 split1()
110 {
111 	register long bcnt;
112 	register int dist, len;
113 	register char *C;
114 
115 	for (bcnt = 0;;)
116 		switch(len = read(ifd, bfr, MAXBSIZE)) {
117 		case 0:
118 			exit(OK);
119 		case ERR:
120 			perror("read");
121 			exit(1);
122 		default:
123 			if (!file_open) {
124 				newfile();
125 				file_open = YES;
126 			}
127 			if (bcnt + len >= bytecnt) {
128 				dist = bytecnt - bcnt;
129 				if (write(ofd, bfr, dist) != dist)
130 					wrerror();
131 				len -= dist;
132 				for (C = bfr + dist; len >= bytecnt; len -= bytecnt, C += bytecnt) {
133 					newfile();
134 					if (write(ofd, C, (int)bytecnt) != bytecnt)
135 						wrerror();
136 				}
137 				if (len) {
138 					newfile();
139 					if (write(ofd, C, len) != len)
140 						wrerror();
141 				}
142 				else
143 					file_open = NO;
144 				bcnt = len;
145 			}
146 			else {
147 				bcnt += len;
148 				if (write(ofd, bfr, len) != len)
149 					wrerror();
150 			}
151 		}
152 }
153 
154 /*
155  * split2 --
156  *	split by lines
157  */
158 split2()
159 {
160 	register char *Ce, *Cs;
161 	register long lcnt;
162 	register int len, bcnt;
163 
164 	for (lcnt = 0;;)
165 		switch(len = read(ifd, bfr, MAXBSIZE)) {
166 		case 0:
167 			exit(0);
168 		case ERR:
169 			perror("read");
170 			exit(1);
171 		default:
172 			if (!file_open) {
173 				newfile();
174 				file_open = YES;
175 			}
176 			for (Cs = Ce = bfr; len--; Ce++)
177 				if (*Ce == '\n' && ++lcnt == numlines) {
178 					bcnt = Ce - Cs + 1;
179 					if (write(ofd, Cs, bcnt) != bcnt)
180 						wrerror();
181 					lcnt = 0;
182 					Cs = Ce + 1;
183 					if (len)
184 						newfile();
185 					else
186 						file_open = NO;
187 				}
188 			if (Cs < Ce) {
189 				bcnt = Ce - Cs;
190 				if (write(ofd, Cs, bcnt) != bcnt)
191 					wrerror();
192 			}
193 		}
194 }
195 
196 /*
197  * newfile --
198  *	open a new file
199  */
200 newfile()
201 {
202 	static long fnum;
203 	static short defname;
204 	static char *fpnt;
205 
206 	if (ofd == ERR) {
207 		if (fname[0]) {
208 			fpnt = fname + strlen(fname);
209 			defname = NO;
210 		}
211 		else {
212 			fname[0] = 'x';
213 			fpnt = fname + 1;
214 			defname = YES;
215 		}
216 		ofd = fileno(stdout);
217 	}
218 	/*
219 	 * hack to increase max files; original code just wandered through
220 	 * magic characters.  Maximum files is 3 * 26 * 26 == 2028
221 	 */
222 #define MAXFILES	676
223 	if (fnum == MAXFILES) {
224 		if (!defname || fname[0] == 'z') {
225 			fputs("split: too many files.\n", stderr);
226 			exit(1);
227 		}
228 		++fname[0];
229 		fnum = 0;
230 	}
231 	fpnt[0] = fnum / 26 + 'a';
232 	fpnt[1] = fnum % 26 + 'a';
233 	++fnum;
234 	if (!freopen(fname, "w", stdout)) {
235 		fprintf(stderr, "split: unable to write to %s.\n", fname);
236 		exit(ERR);
237 	}
238 }
239 
240 /*
241  * usage --
242  *	print usage message and die
243  */
244 usage()
245 {
246 	fputs("usage: split [-] [-#] [-b byte_count] [file [prefix]]\n", stderr);
247 	exit(1);
248 }
249 
250 /*
251  * wrerror --
252  *	write error
253  */
254 wrerror()
255 {
256 	perror("split: write");
257 	exit(1);
258 }
259