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 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 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 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