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.2 (Berkeley) 04/16/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 || *p) 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