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