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