dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / split / split.c
blob4e579c3050470c302e8422372c7eaa9c55c8d75c
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
24 * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <sys/statvfs.h>
36 #include <locale.h>
37 #include <malloc.h>
38 #include <string.h>
39 #include <sys/param.h>
40 #include <stdlib.h>
41 #include <wchar.h>
42 #include <widec.h>
43 #include <ctype.h>
44 #include <errno.h>
47 #define DEFAULT_LINES 1000
48 #define ONE_K 1024
49 #define ONE_M ONE_K*ONE_K
50 #ifndef TRUE
51 #define TRUE 1
52 #define FALSE 0
53 #endif
56 static void Usage();
57 static void next_file_name();
60 static char *progname;
61 static int suffix_length = 2;
63 int
64 main(int argc, char **argv)
66 long long line_count = 0;
67 long long byte_count = 0;
68 long long out;
69 char *fname = NULL;
70 char head[MAXPATHLEN];
71 char *output_file_name;
72 char *tail;
73 char *last;
74 FILE *in_file = NULL;
75 FILE *out_file = NULL;
76 int i;
77 int c;
78 wint_t wc;
79 int output_file_open;
80 struct statvfs stbuf;
81 int opt;
82 int non_standard_line_count = FALSE;
85 (void) setlocale(LC_ALL, "");
86 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
87 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
88 #endif
89 (void) textdomain(TEXT_DOMAIN);
91 progname = argv[0];
93 /* check for explicit stdin "-" option */
94 for (i = 1; i < argc; i++) {
95 if (strcmp(argv[i], "-") == 0) {
96 in_file = stdin;
97 while (i < argc) {
98 argv[i] = argv[i + 1];
100 /* a "-" before "--" is an error */
101 if ((argv[i] != NULL) &&
102 (strcmp(argv[i], "--") == 0)) {
103 Usage();
105 i++;
107 argc--;
111 /* check for non-standard "-line-count" option */
112 for (i = 1; i < argc; i++) {
113 if (strcmp(argv[i], "--") == 0)
114 break;
116 if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
117 if (strlen(&argv[i][1]) !=
118 strspn(&argv[i][1], "0123456789")) {
119 (void) fprintf(stderr, gettext(
120 "%s: Badly formed number\n"), progname);
121 Usage();
124 line_count = (long long) strtoll(&argv[i][1],
125 (char **)NULL, 10);
127 non_standard_line_count = TRUE;
128 while (i < argc) {
129 argv[i] = argv[i + 1];
130 i++;
132 argc--;
136 /* get options */
137 while ((opt = getopt(argc, argv, "a:b:l:")) != EOF) {
138 switch (opt) {
139 case 'a':
140 if (strcmp(optarg, "--") == 0) {
141 Usage();
143 suffix_length = (long long) strtoll(optarg,
144 (char **)NULL, 10);
145 if (suffix_length <= 0) {
146 (void) fprintf(stderr, gettext(
147 "%s: Invalid \"-a %s\" option\n"),
148 progname, optarg);
149 Usage();
151 break;
153 case 'b':
154 if (strcmp(optarg, "--") == 0) {
155 Usage();
157 byte_count = (long long) strtoll(optarg,
158 (char **)NULL, 10);
159 if (*(optarg + strspn(optarg, "0123456789")) == 'k')
160 byte_count *= ONE_K;
161 if (*(optarg + strspn(optarg, "0123456789")) == 'm')
162 byte_count *= ONE_M;
163 break;
165 case 'l':
166 if (strcmp(optarg, "--") == 0) {
167 Usage();
169 if (non_standard_line_count == TRUE) {
170 Usage();
172 line_count = (long long) strtoll(optarg,
173 (char **)NULL, 10);
174 break;
176 default:
177 Usage();
181 /* get input file */
182 if ((in_file == NULL) && (optind < argc)) {
183 if ((in_file = fopen(argv[optind++], "r")) == NULL) {
184 (void) perror("split");
185 return (1);
188 if (in_file == NULL) {
189 in_file = stdin;
192 /* get output file name */
193 if (optind < argc) {
194 output_file_name = argv[optind];
195 if ((tail = strrchr(output_file_name, '/')) == NULL) {
196 tail = output_file_name;
197 (void) getcwd(head, sizeof (head));
198 } else {
199 tail++;
200 (void) strcpy(head, output_file_name);
201 last = strrchr(head, '/');
202 *++last = '\0';
205 if (statvfs(head, &stbuf) < 0) {
206 perror(head);
207 return (1);
210 if (strlen(tail) > (stbuf.f_namemax - suffix_length)) {
211 (void) fprintf(stderr, gettext(
212 "%s: More than %d characters in file name\n"),
213 progname, stbuf.f_namemax - suffix_length);
214 Usage();
216 } else
217 output_file_name = "x";
219 /* check options */
220 if (((int)strlen(output_file_name) + suffix_length) > FILENAME_MAX) {
221 (void) fprintf(stderr, gettext(
222 "%s: Output file name too long\n"), progname);
223 return (1);
226 if (line_count && byte_count) {
227 Usage();
230 /* use default line count if none specified */
231 if (line_count == 0) {
232 line_count = DEFAULT_LINES;
236 * allocate buffer for the filenames we'll construct; it must be
237 * big enough to hold the name in 'output_file_name' + an n-char
238 * suffix + NULL terminator
240 if ((fname = (char *)malloc(strlen(output_file_name) +
241 suffix_length + 1)) == NULL) {
242 (void) perror("split");
243 return (1);
246 /* build first output file name */
247 for (i = 0; output_file_name[i]; i++) {
248 fname[i] = output_file_name[i];
250 while (i < (int)strlen(output_file_name) + suffix_length) {
251 fname[i++] = 'a';
253 if (suffix_length)
254 fname[i - 1] = 'a' - 1;
255 fname[i] = '\0';
257 for (; ; ) {
258 output_file_open = FALSE;
259 if (byte_count) {
260 for (out = 0; out < byte_count; out++) {
261 errno = 0;
262 c = getc(in_file);
263 if (c == EOF) {
264 if (errno != 0) {
265 int lerrno = errno;
266 (void) fprintf(stderr, gettext(
267 "%s: Read error at file offset %lld: %s, "
268 "aborting split\n"),
269 progname, ftello(in_file),
270 strerror(lerrno));
271 if (output_file_open == TRUE)
272 (void) fclose(out_file);
273 free(fname);
274 return (1);
276 if (output_file_open == TRUE)
277 (void) fclose(out_file);
278 free(fname);
279 return (0);
281 if (output_file_open == FALSE) {
282 next_file_name(fname);
283 if ((out_file = fopen(fname, "w")) == NULL) {
284 (void) perror("split");
285 free(fname);
286 return (1);
288 output_file_open = TRUE;
290 if (putc(c, out_file) == EOF) {
291 perror("split");
292 if (output_file_open == TRUE)
293 (void) fclose(out_file);
294 free(fname);
295 return (1);
298 } else {
299 for (out = 0; out < line_count; out++) {
300 do {
301 errno = 0;
302 wc = getwc(in_file);
303 if (wc == WEOF) {
304 if (errno != 0) {
305 if (errno == EILSEQ) {
306 (void) fprintf(stderr, gettext(
307 "%s: Invalid multibyte sequence "
308 "encountered at file offset %lld, "
309 "aborting split\n"),
310 progname, ftello(in_file));
311 } else {
312 (void) perror("split");
314 if (output_file_open == TRUE)
315 (void) fclose(out_file);
316 free(fname);
317 return (1);
319 if (output_file_open == TRUE)
320 (void) fclose(out_file);
321 free(fname);
322 return (0);
324 if (output_file_open == FALSE) {
325 next_file_name(fname);
326 if ((out_file = fopen(fname, "w")) == NULL) {
327 (void) perror("split");
328 free(fname);
329 return (1);
331 output_file_open = TRUE;
333 if (putwc(wc, out_file) == WEOF) {
334 (void) perror("split");
335 if (output_file_open == TRUE)
336 (void) fclose(out_file);
337 free(fname);
338 return (1);
340 } while (wc != '\n');
343 if (output_file_open == TRUE)
344 (void) fclose(out_file);
347 /*NOTREACHED*/
351 static void
352 next_file_name(char *name)
354 int i;
356 i = strlen(name) - 1;
358 while (i >= (int)(strlen(name) - suffix_length)) {
359 if (++name[i] <= 'z')
360 return;
361 name[i--] = 'a';
363 (void) fprintf(stderr, gettext(
364 "%s: Exhausted output file names, aborting split\n"),
365 progname);
366 exit(1);
370 static void
371 Usage()
373 (void) fprintf(stderr, gettext(
374 "Usage: %s [-l #] [-a #] [file [name]]\n"
375 " %s [-b #[k|m]] [-a #] [file [name]]\n"
376 " %s [-#] [-a #] [file [name]]\n"),
377 progname, progname, progname);
378 exit(1);