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}