xref: /csrg-svn/usr.bin/split/split.c (revision 34912)
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.6 (Berkeley) 06/29/88";
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 ERREXIT	0			/* error exit */
36 #define NO	0			/* no/false */
37 #define OK	0			/* okay exit */
38 #define YES	1			/* yes/true */
39 
40 static long	bytecnt,		/* byte count to split on */
41 		numlines;		/* lines in each file */
42 static int	ifd = ERR,		/* input file descriptor */
43 		ofd = ERR;		/* output file descriptor */
44 static short	file_open;		/* if a file open */
45 static char	bfr[MAXBSIZE],		/* I/O buffer */
46 		fname[MAXPATHLEN];	/* file name */
47 
48 main(argc, argv)
49 	int	argc;
50 	char	**argv;
51 {
52 	register int	cnt;		/* general counter */
53 	long	atol();
54 	char	*strcpy();
55 
56 	for (cnt = 1; cnt < argc; ++cnt) {
57 		if (argv[cnt][0] == '-')
58 			switch(argv[cnt][1]) {
59 			case 0:		/* stdin by request */
60 				if (ifd != ERR)
61 					usage();
62 				ifd = 0;
63 				break;
64 			case 'b':	/* byte count split */
65 				if (numlines)
66 					usage();
67 				if (!argv[cnt][2])
68 					bytecnt = atol(argv[++cnt]);
69 				else
70 					bytecnt = atol(argv[cnt] + 2);
71 				if (bytecnt <= 0) {
72 					fputs("split: byte count must be greater than zero.\n", stderr);
73 					usage();
74 				}
75 				break;
76 			default:
77 				if (!isdigit(argv[cnt][1]) || bytecnt)
78 					usage();
79 				if ((numlines = atol(argv[cnt] + 1)) <= 0) {
80 					fputs("split: line count must be greater than zero.\n", stderr);
81 					usage();
82 				}
83 				break;
84 			}
85 		else if (ifd == ERR) {		/* input file */
86 			if ((ifd = open(argv[cnt], O_RDONLY, 0)) < 0) {
87 				perror(argv[cnt]);
88 				exit(ERREXIT);
89 			}
90 		}
91 		else if (!*fname)		/* output file prefix */
92 			strcpy(fname, argv[cnt]);
93 		else
94 			usage();
95 	}
96 	if (ifd == ERR)				/* stdin by default */
97 		ifd = 0;
98 	if (bytecnt)
99 		split1();
100 	if (!numlines)
101 		numlines = DEFLINE;
102 	split2();
103 }
104 
105 /*
106  * split1 --
107  *	split by bytes
108  */
109 static
110 split1()
111 {
112 	register long	bcnt;		/* byte counter */
113 	register int	dist,		/* buffer offset */
114 			len;		/* read length */
115 	register char	*C;		/* tmp pointer into buffer */
116 
117 	for (bcnt = 0;;)
118 		switch(len = read(ifd, bfr, MAXBSIZE)) {
119 		case 0:
120 			exit(OK);
121 		case ERR:
122 			perror("read");
123 			exit(ERREXIT);
124 		default:
125 			if (!file_open) {
126 				newfile();
127 				file_open = YES;
128 			}
129 			if (bcnt + len >= bytecnt) {
130 				dist = bytecnt - bcnt;
131 				write(ofd, bfr, dist);
132 				len -= dist;
133 				for (C = bfr + dist; len >= bytecnt; len -= bytecnt, C += bytecnt) {
134 					newfile();
135 					write(ofd, C, (int)bytecnt);
136 				}
137 				if (len) {
138 					newfile();
139 					write(ofd, C, len);
140 				}
141 				else
142 					file_open = NO;
143 				bcnt = len;
144 			}
145 			else {
146 				bcnt += len;
147 				write(ofd, bfr, len);
148 			}
149 		}
150 }
151 
152 /*
153  * split2 --
154  *	split by lines
155  */
156 static
157 split2()
158 {
159 	register char	*Ce,			/* start/end pointers */
160 			*Cs;
161 	register long	lcnt;			/* line counter */
162 	register int	len;			/* read length */
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 			break;
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 					write(ofd, Cs, (int)(Ce - Cs) + 1);
179 					lcnt = 0;
180 					Cs = Ce + 1;
181 					if (len)
182 						newfile();
183 					else
184 						file_open = NO;
185 				}
186 			if (Cs < Ce)
187 				write(ofd, Cs, (int)(Ce - Cs));
188 		}
189 }
190 
191 /*
192  * newfile --
193  *	open a new file
194  */
195 static
196 newfile()
197 {
198 	static long	fnum;		/* file name counter */
199 	static short	defname;	/* using default name, "x" */
200 	static char	*fpnt;		/* output file name pointer */
201 
202 	if (ofd == ERR) {
203 		if (fname[0]) {
204 			fpnt = fname + strlen(fname);
205 			defname = NO;
206 		}
207 		else {
208 			fname[0] = 'x';
209 			fpnt = fname + 1;
210 			defname = YES;
211 		}
212 		ofd = fileno(stdout);
213 	}
214 	/*
215 	 * hack to increase max files; original code just wandered through
216 	 * magic characters.  Maximum files is 3 * 26 * 26 == 2028
217 	 */
218 #define MAXFILES	676
219 	if (fnum == MAXFILES) {
220 		if (!defname || fname[0] == 'z') {
221 			fputs("split: too many files.\n", stderr);
222 			exit(ERREXIT);
223 		}
224 		++fname[0];
225 		fnum = 0;
226 	}
227 	fpnt[0] = fnum / 26 + 'a';
228 	fpnt[1] = fnum % 26 + 'a';
229 	++fnum;
230 	if (!freopen(fname, "w", stdout)) {
231 		fprintf(stderr, "split: unable to write to %s.\n", fname);
232 		exit(ERR);
233 	}
234 }
235 
236 /*
237  * usage --
238  *	print usage message and die
239  */
240 static
241 usage()
242 {
243 	fputs("usage: split [-] [-#] [-b byte_count] [file [prefix]]\n", stderr);
244 	exit(ERREXIT);
245 }
246