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