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