1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23 /*
24 * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <sys/statvfs.h>
34 #include <locale.h>
35 #include <malloc.h>
36 #include <string.h>
37 #include <sys/param.h>
38 #include <stdlib.h>
39 #include <wchar.h>
40 #include <widec.h>
41 #include <ctype.h>
42 #include <errno.h>
43
44
45 #define DEFAULT_LINES 1000
46 #define ONE_K 1024
47 #define ONE_M ONE_K*ONE_K
48 #ifndef TRUE
49 #define TRUE 1
50 #define FALSE 0
51 #endif
52
53
54 static void Usage();
55 static void next_file_name();
56
57
58 static char *progname;
59 static int suffix_length = 2;
60
61 int
main(int argc,char ** argv)62 main(int argc, char **argv)
63 {
64 long long line_count = 0;
65 long long byte_count = 0;
66 long long out;
67 char *fname = NULL;
68 char head[MAXPATHLEN];
69 char *output_file_name;
70 char *tail;
71 char *last;
72 FILE *in_file = NULL;
73 FILE *out_file = (FILE *)NULL;
74 int i;
75 int c;
76 wint_t wc;
77 int output_file_open;
78 struct statvfs stbuf;
79 int opt;
80 int non_standard_line_count = FALSE;
81
82
83 (void) setlocale(LC_ALL, "");
84 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
85 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
86 #endif
87 (void) textdomain(TEXT_DOMAIN);
88
89 progname = argv[0];
90
91 /* check for explicit stdin "-" option */
92 for (i = 1; i < argc; i++) {
93 if (strcmp(argv[i], "-") == 0) {
94 in_file = stdin;
95 while (i < argc) {
96 argv[i] = argv[i + 1];
97
98 /* a "-" before "--" is an error */
99 if ((argv[i] != NULL) &&
100 (strcmp(argv[i], "--") == 0)) {
101 Usage();
102 }
103 i++;
104 }
105 argc--;
106 }
107 }
108
109 /* check for non-standard "-line-count" option */
110 for (i = 1; i < argc; i++) {
111 if (strcmp(argv[i], "--") == 0)
112 break;
113
114 if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
115 if (strlen(&argv[i][1]) !=
116 strspn(&argv[i][1], "0123456789")) {
117 (void) fprintf(stderr, gettext(
118 "%s: Badly formed number\n"), progname);
119 Usage();
120 }
121
122 line_count = (long long) strtoll(&argv[i][1],
123 (char **)NULL, 10);
124
125 non_standard_line_count = TRUE;
126 while (i < argc) {
127 argv[i] = argv[i + 1];
128 i++;
129 }
130 argc--;
131 }
132 }
133
134 /* get options */
135 while ((opt = getopt(argc, argv, "a:b:l:")) != EOF) {
136 switch (opt) {
137 case 'a':
138 if (strcmp(optarg, "--") == 0) {
139 Usage();
140 }
141 suffix_length = (long long) strtoll(optarg,
142 (char **)NULL, 10);
143 if (suffix_length <= 0) {
144 (void) fprintf(stderr, gettext(
145 "%s: Invalid \"-a %s\" option\n"),
146 progname, optarg);
147 Usage();
148 }
149 break;
150
151 case 'b':
152 if (strcmp(optarg, "--") == 0) {
153 Usage();
154 }
155 byte_count = (long long) strtoll(optarg,
156 (char **)NULL, 10);
157 if (*(optarg + strspn(optarg, "0123456789")) == 'k')
158 byte_count *= ONE_K;
159 if (*(optarg + strspn(optarg, "0123456789")) == 'm')
160 byte_count *= ONE_M;
161 break;
162
163 case 'l':
164 if (strcmp(optarg, "--") == 0) {
165 Usage();
166 }
167 if (non_standard_line_count == TRUE) {
168 Usage();
169 }
170 line_count = (long long) strtoll(optarg,
171 (char **)NULL, 10);
172 break;
173
174 default:
175 Usage();
176 }
177 }
178
179 /* get input file */
180 if ((in_file == NULL) && (optind < argc)) {
181 if ((in_file = fopen(argv[optind++], "r")) == NULL) {
182 (void) perror("split");
183 return (1);
184 }
185 }
186 if (in_file == NULL) {
187 in_file = stdin;
188 }
189
190 /* get output file name */
191 if (optind < argc) {
192 output_file_name = argv[optind];
193 if ((tail = strrchr(output_file_name, '/')) == NULL) {
194 tail = output_file_name;
195 (void) getcwd(head, sizeof (head));
196 } else {
197 tail++;
198 (void) strcpy(head, output_file_name);
199 last = strrchr(head, '/');
200 *++last = '\0';
201 }
202
203 if (statvfs(head, &stbuf) < 0) {
204 perror(head);
205 return (1);
206 }
207
208 if (strlen(tail) > (stbuf.f_namemax - suffix_length)) {
209 (void) fprintf(stderr, gettext(
210 "%s: More than %d characters in file name\n"),
211 progname, stbuf.f_namemax - suffix_length);
212 Usage();
213 }
214 } else
215 output_file_name = "x";
216
217 /* check options */
218 if (((int)strlen(output_file_name) + suffix_length) > FILENAME_MAX) {
219 (void) fprintf(stderr, gettext(
220 "%s: Output file name too long\n"), progname);
221 return (1);
222 }
223
224 if (line_count && byte_count) {
225 Usage();
226 }
227
228 /* use default line count if none specified */
229 if (line_count == 0) {
230 line_count = DEFAULT_LINES;
231 }
232
233 /*
234 * allocate buffer for the filenames we'll construct; it must be
235 * big enough to hold the name in 'output_file_name' + an n-char
236 * suffix + NULL terminator
237 */
238 if ((fname = (char *)malloc(strlen(output_file_name) +
239 suffix_length + 1)) == NULL) {
240 (void) perror("split");
241 return (1);
242 }
243
244 /* build first output file name */
245 for (i = 0; output_file_name[i]; i++) {
246 fname[i] = output_file_name[i];
247 }
248 while (i < (int)strlen(output_file_name) + suffix_length) {
249 fname[i++] = 'a';
250 }
251 if (suffix_length)
252 fname[i - 1] = 'a' - 1;
253 fname[i] = '\0';
254
255 for (; ; ) {
256 output_file_open = FALSE;
257 if (byte_count) {
258 for (out = 0; out < byte_count; out++) {
259 errno = 0;
260 c = getc(in_file);
261 if (c == EOF) {
262 if (errno != 0) {
263 int lerrno = errno;
264 (void) fprintf(stderr, gettext(
265 "%s: Read error at file offset %lld: %s, "
266 "aborting split\n"),
267 progname, ftello(in_file),
268 strerror(lerrno));
269 if (output_file_open == TRUE)
270 (void) fclose(out_file);
271 free(fname);
272 return (1);
273 }
274 if (output_file_open == TRUE)
275 (void) fclose(out_file);
276 free(fname);
277 return (0);
278 }
279 if (output_file_open == FALSE) {
280 next_file_name(fname);
281 if ((out_file = fopen(fname, "w")) == NULL) {
282 (void) perror("split");
283 free(fname);
284 return (1);
285 }
286 output_file_open = TRUE;
287 }
288 if (putc(c, out_file) == EOF) {
289 perror("split");
290 if (output_file_open == TRUE)
291 (void) fclose(out_file);
292 free(fname);
293 return (1);
294 }
295 }
296 } else {
297 for (out = 0; out < line_count; out++) {
298 do {
299 errno = 0;
300 wc = getwc(in_file);
301 if (wc == WEOF) {
302 if (errno != 0) {
303 if (errno == EILSEQ) {
304 (void) fprintf(stderr, gettext(
305 "%s: Invalid multibyte sequence "
306 "encountered at file offset %lld, "
307 "aborting split\n"),
308 progname, ftello(in_file));
309 } else {
310 (void) perror("split");
311 }
312 if (output_file_open == TRUE)
313 (void) fclose(out_file);
314 free(fname);
315 return (1);
316 }
317 if (output_file_open == TRUE)
318 (void) fclose(out_file);
319 free(fname);
320 return (0);
321 }
322 if (output_file_open == FALSE) {
323 next_file_name(fname);
324 if ((out_file = fopen(fname, "w")) == NULL) {
325 (void) perror("split");
326 free(fname);
327 return (1);
328 }
329 output_file_open = TRUE;
330 }
331 if (putwc(wc, out_file) == WEOF) {
332 (void) perror("split");
333 if (output_file_open == TRUE)
334 (void) fclose(out_file);
335 free(fname);
336 return (1);
337 }
338 } while (wc != '\n');
339 }
340 }
341 if (output_file_open == TRUE)
342 (void) fclose(out_file);
343 }
344
345 /*NOTREACHED*/
346 }
347
348
349 static void
next_file_name(char * name)350 next_file_name(char *name)
351 {
352 int i;
353
354 i = strlen(name) - 1;
355
356 while (i >= (int)(strlen(name) - suffix_length)) {
357 if (++name[i] <= 'z')
358 return;
359 name[i--] = 'a';
360 }
361 (void) fprintf(stderr, gettext(
362 "%s: Exhausted output file names, aborting split\n"),
363 progname);
364 exit(1);
365 }
366
367
368 static void
Usage()369 Usage()
370 {
371 (void) fprintf(stderr, gettext(
372 "Usage: %s [-l #] [-a #] [file [name]]\n"
373 " %s [-b #[k|m]] [-a #] [file [name]]\n"
374 " %s [-#] [-a #] [file [name]]\n"),
375 progname, progname, progname);
376 exit(1);
377 }
378