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