morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base.git
Log | Files | Refs

split.c (2305B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <ctype.h>
      3 #include <limits.h>
      4 #include <stdint.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 
      9 #include "util.h"
     10 
     11 static int itostr(char *, int, int);
     12 static FILE *nextfile(FILE *, char *, int, int);
     13 
     14 static void
     15 usage(void)
     16 {
     17 	eprintf("usage: split [-d] [-a len] [-b [bytes[k|m|g]]] [-l [lines]] [input [prefix]]\n");
     18 }
     19 
     20 static int base = 26, start = 'a';
     21 
     22 int
     23 main(int argc, char *argv[])
     24 {
     25 	int plen, slen = 2;
     26 	int ch;
     27 	char name[NAME_MAX+1];
     28 	char *prefix = "x";
     29 	char *file = NULL;
     30 	char *tmp, *end;
     31 	uint64_t size = 1000, scale = 1, n;
     32 	int always = 0;
     33 	FILE *in = stdin, *out = NULL;
     34 
     35 	ARGBEGIN {
     36 	case 'b':
     37 		always = 1;
     38 		tmp = ARGF();
     39 		if (!tmp)
     40 			break;
     41 
     42 		size = strtoull(tmp, &end, 10);
     43 		if (!*end)
     44 			break;
     45 		switch (toupper((int)*end)) {
     46 		case 'K':
     47 			scale = 1024;
     48 			break;
     49 		case 'M':
     50 			scale = 1024L * 1024L;
     51 			break;
     52 		case 'G':
     53 			scale = 1024L * 1024L * 1024L;
     54 			break;
     55 		default:
     56 			usage();
     57 		}
     58 		if (size > (UINT64_MAX/scale))
     59 			eprintf("'%s': out of range\n", tmp);
     60 		size *= scale;
     61 		break;
     62 	case 'l':
     63 		always = 0;
     64 		tmp = ARGF();
     65 		if (tmp)
     66 			size = estrtol(tmp, 10);
     67 		break;
     68 	case 'a':
     69 		slen = estrtol(EARGF(usage()), 10);
     70 		break;
     71 	case 'd':
     72 		base = 10;
     73 		start = '0';
     74 		break;
     75 	default:
     76 		usage();
     77 	} ARGEND;
     78 
     79 	if (*argv)
     80 		file = *argv++;
     81 	if (*argv)
     82 		prefix = *argv++;
     83 	if (*argv)
     84 		usage();
     85 
     86 	plen = strlen(prefix);
     87 	if (plen+slen > NAME_MAX)
     88 		eprintf("names cannot exceed %d bytes\n", NAME_MAX);
     89 	strlcpy(name, prefix, sizeof(name));
     90 
     91 	if (file && strcmp(file, "-") != 0) {
     92 		in = fopen(file, "r");
     93 		if (!in)
     94 			eprintf("'%s':", file);
     95 	}
     96 
     97 Nextfile:
     98 	while ((out = nextfile(out, name, plen, slen))) {
     99 		n = 0;
    100 		while ((ch = getc(in)) != EOF) {
    101 			putc(ch, out);
    102 			n += (always || ch == '\n');
    103 			if (n >= size)
    104 				goto Nextfile;
    105 		}
    106 		fclose(out);
    107 		break;
    108 	}
    109 	return 0;
    110 }
    111 
    112 int
    113 itostr(char *str, int x, int n)
    114 {
    115 	str[n] = '\0';
    116 	while (n-- > 0) {
    117 		str[n] = start + (x % base);
    118 		x /= base;
    119 	}
    120 	if (x)
    121 		return -1;
    122 	return 0;
    123 }
    124 
    125 FILE *
    126 nextfile(FILE *f, char *buf, int plen, int slen)
    127 {
    128 	static int n = 0;
    129 	int s;
    130 
    131 	if (f)
    132 		fclose(f);
    133 	s = itostr(buf+plen, n++, slen);
    134 	if (s < 0)
    135 		return NULL;
    136 
    137 	f = fopen(buf, "w");
    138 	if (!f)
    139 		eprintf("'%s':", buf);
    140 	return f;
    141 }