/* * csplit - character-based split(1) * * Usage: csplit [-n] [file [name [start]]] * * Arguments as split(1), except n is characters instead of lines, and * the default is 65536 instead of 1000. (The third argument has no * analog in split(1).) * * More specifically: the input file (the first filename argument, or * if that's "-" or omitted, the standard input) is read. It is * written in n-byte pieces (where n defaults to 65536) to the output * files. The output filenames are constructed by taking "name" ("x" * if name is not given) and appending numbers in base 26, starting * with aa, then ab, etc, lexicographically. (If there are more than * 676 parts, that is, if the thing to be appended overflows past zz, * the suffix gets longer, going from zz to aaa, from zzz to aaaa, * etc.) The third argument specifies an extension to use for the * first piece; if omitted, aa is assumed. (If the third argument is * only one letter long, one-letter extensions will be used until z is * reached - this is the only way to get one-letter extensions.) * * The last piece may, of course, be shorter than specified. */ #define CHUNKSIZE 65536 /* size of chunk to read */ #include #include #include #include #include #include extern const char *__progname; static const char *infn = "-"; /* stdin by default */ static const char *outprefix = "x"; /* the default */ static unsigned long long int piecesize = 65536; /* the default */ static const char *letters = "abcdefghijklmnopqrstuvwxyz"; static int nletters = 26; static int infd; static char buf[65536]; static int fill; static int outfd; static int outpflen; static char *outfnbuf; static int pieceno; static int pnlen; static int pnbump; static unsigned long long int bytesleft; static unsigned long long int bytesread; static unsigned long long int getsize(const char *s) { unsigned long long int n; char *s2; n = strtouq(s,&s2,0); switch (*s2) { case 'b': case 'B': n *= 512; break; case 'k': case 'K': n <<= 10; break; case 'm': case 'M': n <<= 20; break; case 'g': case 'G': n <<= 30; break; case 't': case 'T': n <<= 40; break; case 'p': case 'P': n <<= 50; break; } return(n); } static void makepiecename(void) { int pn; int i; char *cp; pn = pieceno; cp = outfnbuf + outpflen + pnlen; for (i=0;i= 0) close(outfd); pieceno ++; if (pieceno >= pnbump) { pnlen ++; pieceno = 0; pnbump *= nletters; free(outfnbuf); outfnbuf = malloc(outpflen+pnlen+1); bcopy(outprefix,outfnbuf,outpflen); outfnbuf[outpflen+pnlen] = '\0'; } makepiecename(); outfd = open(outfnbuf,O_WRONLY|O_CREAT|O_TRUNC,0666); if (outfd < 0) { fprintf(stderr,"%s: can't create output file %s: %s\n",__progname,outfnbuf,strerror(errno)); exit(1); } bytesleft = piecesize; } static void setstart(const char *s) { int i; pnlen = strlen(s); pieceno = 0; pnbump = 1; for (i=0;i 1) && (av[1][0] == '-')) { piecesize = getsize(&av[1][1]); ac --; av ++; } if (ac > 1) { infn = av[1]; ac --; av ++; } if (ac > 1) { outprefix = av[1]; ac --; av ++; } pieceno = -1; pnlen = 2; pnbump = nletters * nletters; if (ac > 1) { setstart(av[1]); ac --; av ++; } if ((piecesize < 1) || (ac > 1) || (pnlen < 0)) { fprintf(stderr,"Usage: %s [-n] [file [name [start]]]\n",__progname); exit(1); } infd = strcmp(infn,"-") ? open(infn,O_RDONLY,0) : 0; if (infd < 0) { fprintf(stderr,"%s: can't open %s: %m\n",__progname,infn); exit(1); } outpflen = strlen(outprefix); outfnbuf = malloc(outpflen+pnlen+1); bcopy(outprefix,outfnbuf,outpflen); outfnbuf[outpflen+pnlen] = '\0'; bytesleft = 0; bytesread = 0; outfd = -1; while (1) { char *bp; fill = read(infd,&buf[0],sizeof(buf)); if (fill == 0) break; if (fill < 0) { fprintf(stderr,"%s: input read error after reading %llu bytes: %s\n",__progname,bytesread,strerror(errno)); exit(1); } bytesread += fill; if (bytesleft < 1) { nextpiece(); } bp = &buf[0]; while (fill > bytesleft) { write(outfd,bp,bytesleft); bp += bytesleft; fill -= bytesleft; nextpiece(); } write(outfd,bp,fill); bytesleft -= fill; } exit(0); }