1/* vi: set sw=4 ts=4: */
2/*
3 * split - split a file into pieces
4 * Copyright (c) 2007 Bernhard Fischer
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 */
8/* BB_AUDIT: SUSv3 compliant
9 * SUSv3 requirements:
10 * http://www.opengroup.org/onlinepubs/009695399/utilities/split.html
11 */
12#include "libbb.h"
13
14static const struct suffix_mult split_suffices[] = {
15#if ENABLE_FEATURE_SPLIT_FANCY
16	{ "b", 512 },
17#endif
18	{ "k", 1024 },
19	{ "m", 1024*1024 },
20#if ENABLE_FEATURE_SPLIT_FANCY
21	{ "g", 1024*1024*1024 },
22#endif
23	{ }
24};
25
26/* Increment the suffix part of the filename.
27 * Returns NULL if we are out of filenames.
28 */
29static char *next_file(char *old, unsigned suffix_len)
30{
31	size_t end = strlen(old);
32	unsigned i = 1;
33	char *curr;
34
35	do {
36		curr = old + end - i;
37		if (*curr < 'z') {
38			*curr += 1;
39			break;
40		}
41		i++;
42		if (i > suffix_len) {
43			return NULL;
44		}
45		*curr = 'a';
46	} while (1);
47
48	return old;
49}
50
51#define read_buffer bb_common_bufsiz1
52enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 };
53
54#define SPLIT_OPT_l (1<<0)
55#define SPLIT_OPT_b (1<<1)
56#define SPLIT_OPT_a (1<<2)
57
58int split_main(int argc, char **argv);
59int split_main(int argc, char **argv)
60{
61	unsigned suffix_len = 2;
62	char *pfx;
63	char *count_p;
64	const char *sfx;
65	off_t cnt = 1000;
66	off_t remaining = 0;
67	unsigned opt;
68	ssize_t bytes_read, to_write;
69	char *src;
70
71	opt_complementary = "?2";
72	opt = getopt32(argv, "l:b:a:", &count_p, &count_p, &sfx);
73
74	if (opt & SPLIT_OPT_l)
75		cnt = xatoul(count_p);
76	if (opt & SPLIT_OPT_b)
77		cnt = xatoul_sfx(count_p, split_suffices);
78	if (opt & SPLIT_OPT_a)
79		suffix_len = xatou(sfx);
80	sfx = "x";
81
82	argv += optind;
83	if (argv[0]) {
84		if (argv[1])
85			sfx = argv[1];
86		xmove_fd(xopen(argv[0], O_RDONLY), 0);
87	} else {
88		argv[0] = (char *) bb_msg_standard_input;
89	}
90
91	if (NAME_MAX < strlen(sfx) + suffix_len)
92		bb_error_msg_and_die("suffix too long");
93
94	{
95		char *char_p = xzalloc(suffix_len + 1);
96		memset(char_p, 'a', suffix_len);
97		pfx = xasprintf("%s%s", sfx, char_p);
98		if (ENABLE_FEATURE_CLEAN_UP)
99			free(char_p);
100	}
101
102	while (1) {
103		bytes_read = safe_read(0, read_buffer, READ_BUFFER_SIZE);
104		if (!bytes_read)
105			break;
106		if (bytes_read < 0)
107			bb_perror_msg_and_die("%s", argv[0]);
108		src = read_buffer;
109		do {
110			if (!remaining) {
111				if (!pfx)
112					bb_error_msg_and_die("suffixes exhausted");
113				xmove_fd(xopen(pfx, O_WRONLY | O_CREAT | O_TRUNC), 1);
114				pfx = next_file(pfx, suffix_len);
115				remaining = cnt;
116			}
117
118			if (opt & SPLIT_OPT_b) {
119				/* split by bytes */
120				to_write = (bytes_read < remaining) ? bytes_read : remaining;
121				remaining -= to_write;
122			} else {
123				/* split by lines */
124				/* can be sped up by using _memrchr_
125				 * and writing many lines at once... */
126				char *end = memchr(src, '\n', bytes_read);
127				if (end) {
128					--remaining;
129					to_write = end - src + 1;
130				} else {
131					to_write = bytes_read;
132				}
133			}
134
135			xwrite(1, src, to_write);
136			bytes_read -= to_write;
137			src += to_write;
138		} while (bytes_read);
139	}
140	return 0;
141}
142