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