split.c (2086B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <ctype.h> 3 #include <stdint.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #include "util.h" 9 10 static int base = 26, start = 'a'; 11 12 static int 13 itostr(char *str, int x, int n) 14 { 15 str[n] = '\0'; 16 while (n-- > 0) { 17 str[n] = start + (x % base); 18 x /= base; 19 } 20 21 return x ? -1 : 0; 22 } 23 24 static FILE * 25 nextfile(FILE *f, char *buf, int plen, int slen) 26 { 27 static int filecount = 0; 28 29 if (f) 30 fshut(f, "<file>"); 31 if (itostr(buf + plen, filecount++, slen) < 0) 32 return NULL; 33 34 if (!(f = fopen(buf, "w"))) 35 eprintf("'%s':", buf); 36 37 return f; 38 } 39 40 static void 41 usage(void) 42 { 43 eprintf("usage: %s [-a num] [-b num[k|m|g] | -l num] [-d] " 44 "[file [prefix]]\n", argv0); 45 } 46 47 int 48 main(int argc, char *argv[]) 49 { 50 FILE *in = stdin, *out = NULL; 51 off_t size = 1000, n; 52 int ret = 0, ch, plen, slen = 2, always = 0; 53 char name[NAME_MAX + 1], *prefix = "x", *file = NULL; 54 55 ARGBEGIN { 56 case 'a': 57 slen = estrtonum(EARGF(usage()), 0, INT_MAX); 58 break; 59 case 'b': 60 always = 1; 61 if ((size = parseoffset(EARGF(usage()))) < 0) 62 return 1; 63 if (!size) 64 eprintf("size needs to be positive\n"); 65 break; 66 case 'd': 67 base = 10; 68 start = '0'; 69 break; 70 case 'l': 71 always = 0; 72 size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SSIZE_MAX)); 73 break; 74 default: 75 usage(); 76 } ARGEND 77 78 if (*argv) 79 file = *argv++; 80 if (*argv) 81 prefix = *argv++; 82 if (*argv) 83 usage(); 84 85 plen = strlen(prefix); 86 if (plen + slen > NAME_MAX) 87 eprintf("names cannot exceed %d bytes\n", NAME_MAX); 88 estrlcpy(name, prefix, sizeof(name)); 89 90 if (file && strcmp(file, "-")) { 91 if (!(in = fopen(file, "r"))) 92 eprintf("fopen %s:", file); 93 } 94 95 n = 0; 96 while ((ch = getc(in)) != EOF) { 97 if (!out || n >= size) { 98 if (!(out = nextfile(out, name, plen, slen))) 99 eprintf("fopen: %s:", name); 100 n = 0; 101 } 102 n += (always || ch == '\n'); 103 putc(ch, out); 104 } 105 106 ret |= (in != stdin) && fshut(in, "<infile>"); 107 ret |= out && (out != stdout) && fshut(out, "<outfile>"); 108 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); 109 110 return ret; 111 }