xref: /original-bsd/usr.bin/split/split.c (revision f4a18198)
1 /*
2  * Copyright (c) 1987, 1993, 1994
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, 1994\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.3 (Berkeley) 04/25/94";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 
20 #include <ctype.h>
21 #include <err.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #define DEFLINE	1000			/* Default num lines per file. */
29 
30 long	 bytecnt;			/* Byte count to split on. */
31 long	 numlines;			/* Line count to split on. */
32 int	 file_open;			/* If a file open. */
33 int	 ifd = -1, ofd = -1;		/* Input/output file descriptors. */
34 char	 bfr[MAXBSIZE];			/* I/O buffer. */
35 char	 fname[MAXPATHLEN];		/* File name prefix. */
36 
37 void newfile __P((void));
38 void split1 __P((void));
39 void split2 __P((void));
40 void usage __P((void));
41 
42 int
43 main(argc, argv)
44 	int argc;
45 	char *argv[];
46 {
47 	int ch;
48 	char *ep, *p;
49 
50 	while ((ch = getopt(argc, argv, "-0123456789b:l:")) != EOF)
51 		switch (ch) {
52 		case '0': case '1': case '2': case '3': case '4':
53 		case '5': case '6': case '7': case '8': case '9':
54 			/*
55 			 * Undocumented kludge: split was originally designed
56 			 * to take a number after a dash.
57 			 */
58 			if (numlines == 0) {
59 				p = argv[optind - 1];
60 				if (p[0] == '-' && p[1] == ch && !p[2])
61 					numlines = strtol(++p, &ep, 10);
62 				else
63 					numlines =
64 					    strtol(argv[optind] + 1, &ep, 10);
65 				if (numlines <= 0 || *ep)
66 					errx(1,
67 					    "%s: illegal line count.", optarg);
68 			}
69 			break;
70 		case '-':		/* Undocumented: historic stdin flag. */
71 			if (ifd != -1)
72 				usage();
73 			ifd = 0;
74 			break;
75 		case 'b':		/* Byte count. */
76 			if ((bytecnt = strtol(optarg, &ep, 10)) <= 0 ||
77 			    *ep != '\0' && *ep != 'k' && *ep != 'm')
78 				errx(1, "%s: illegal byte count.", optarg);
79 			if (*ep == 'k')
80 				bytecnt *= 1024;
81 			else if (*ep == 'm')
82 				bytecnt *= 1048576;
83 			break;
84 		case 'l':		/* Line count. */
85 			if (numlines != 0)
86 				usage();
87 			if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *ep)
88 				errx(1, "%s: illegal line count.", optarg);
89 			break;
90 		default:
91 			usage();
92 		}
93 	argv += optind;
94 	argc -= optind;
95 
96 	if (*argv != NULL)
97 		if (ifd == -1) {		/* Input file. */
98 			if ((ifd = open(*argv, O_RDONLY, 0)) < 0)
99 				err(1, "%s", *argv);
100 			++argv;
101 		}
102 	if (*argv != NULL)			/* File name prefix. */
103 		(void)strcpy(fname, *argv++);
104 	if (*argv != NULL)
105 		usage();
106 
107 	if (numlines == 0)
108 		numlines = DEFLINE;
109 	else if (bytecnt)
110 		usage();
111 
112 	if (ifd == -1)				/* Stdin by default. */
113 		ifd = 0;
114 
115 	if (bytecnt) {
116 		split1();
117 		exit (0);
118 	}
119 	split2();
120 	exit(0);
121 }
122 
123 /*
124  * split1 --
125  *	Split the input by bytes.
126  */
127 void
128 split1()
129 {
130 	long bcnt;
131 	int dist, len;
132 	char *C;
133 
134 	for (bcnt = 0;;)
135 		switch (len = read(ifd, bfr, MAXBSIZE)) {
136 		case 0:
137 			exit(0);
138 		case -1:
139 			err(1, "read");
140 			/* NOTREACHED */
141 		default:
142 			if (!file_open) {
143 				newfile();
144 				file_open = 1;
145 			}
146 			if (bcnt + len >= bytecnt) {
147 				dist = bytecnt - bcnt;
148 				if (write(ofd, bfr, dist) != dist)
149 					err(1, "write");
150 				len -= dist;
151 				for (C = bfr + dist; len >= bytecnt;
152 				    len -= bytecnt, C += bytecnt) {
153 					newfile();
154 					if (write(ofd,
155 					    C, (int)bytecnt) != bytecnt)
156 						err(1, "write");
157 				}
158 				if (len) {
159 					newfile();
160 					if (write(ofd, C, len) != len)
161 						err(1, "write");
162 				} else
163 					file_open = 0;
164 				bcnt = len;
165 			} else {
166 				bcnt += len;
167 				if (write(ofd, bfr, len) != len)
168 					err(1, "write");
169 			}
170 		}
171 }
172 
173 /*
174  * split2 --
175  *	Split the input by lines.
176  */
177 void
178 split2()
179 {
180 	long lcnt;
181 	int len, bcnt;
182 	char *Ce, *Cs;
183 
184 	for (lcnt = 0;;)
185 		switch (len = read(ifd, bfr, MAXBSIZE)) {
186 		case 0:
187 			exit(0);
188 		case -1:
189 			err(1, "read");
190 			/* NOTREACHED */
191 		default:
192 			if (!file_open) {
193 				newfile();
194 				file_open = 1;
195 			}
196 			for (Cs = Ce = bfr; len--; Ce++)
197 				if (*Ce == '\n' && ++lcnt == numlines) {
198 					bcnt = Ce - Cs + 1;
199 					if (write(ofd, Cs, bcnt) != bcnt)
200 						err(1, "write");
201 					lcnt = 0;
202 					Cs = Ce + 1;
203 					if (len)
204 						newfile();
205 					else
206 						file_open = 0;
207 				}
208 			if (Cs < Ce) {
209 				bcnt = Ce - Cs;
210 				if (write(ofd, Cs, bcnt) != bcnt)
211 					err(1, "write");
212 			}
213 		}
214 }
215 
216 /*
217  * newfile --
218  *	Open a new output file.
219  */
220 void
221 newfile()
222 {
223 	static long fnum;
224 	static int defname;
225 	static char *fpnt;
226 
227 	if (ofd == -1) {
228 		if (fname[0] == '\0') {
229 			fname[0] = 'x';
230 			fpnt = fname + 1;
231 			defname = 1;
232 		} else {
233 			fpnt = fname + strlen(fname);
234 			defname = 0;
235 		}
236 		ofd = fileno(stdout);
237 	}
238 	/*
239 	 * Hack to increase max files; original code wandered through
240 	 * magic characters.  Maximum files is 3 * 26 * 26 == 2028
241 	 */
242 #define MAXFILES	676
243 	if (fnum == MAXFILES) {
244 		if (!defname || fname[0] == 'z')
245 			errx(1, "too many files.");
246 		++fname[0];
247 		fnum = 0;
248 	}
249 	fpnt[0] = fnum / 26 + 'a';
250 	fpnt[1] = fnum % 26 + 'a';
251 	++fnum;
252 	if (!freopen(fname, "w", stdout))
253 		err(1, "%s", fname);
254 }
255 
256 void
257 usage()
258 {
259 	(void)fprintf(stderr,
260 "usage: split [-b byte_count] [-l line_count] [file [prefix]]\n");
261 	exit(1);
262 }
263