17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*23a1cceaSRoger A. Faulkner * Common Development and Distribution License (the "License"). 6*23a1cceaSRoger A. Faulkner * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate 227c478bd9Sstevel@tonic-gate /* 23*23a1cceaSRoger A. Faulkner * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 26*23a1cceaSRoger A. Faulkner /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27*23a1cceaSRoger A. Faulkner /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * csplit - Context or line file splitter 317c478bd9Sstevel@tonic-gate * Compile: cc -O -s -o csplit csplit.c 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <stdlib.h> 367c478bd9Sstevel@tonic-gate #include <unistd.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <ctype.h> 397c478bd9Sstevel@tonic-gate #include <errno.h> 407c478bd9Sstevel@tonic-gate #include <limits.h> 417c478bd9Sstevel@tonic-gate #include <regexpr.h> 427c478bd9Sstevel@tonic-gate #include <signal.h> 437c478bd9Sstevel@tonic-gate #include <locale.h> 447c478bd9Sstevel@tonic-gate #include <libintl.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #define LAST 0LL 477c478bd9Sstevel@tonic-gate #define ERR -1 487c478bd9Sstevel@tonic-gate #define FALSE 0 497c478bd9Sstevel@tonic-gate #define TRUE 1 507c478bd9Sstevel@tonic-gate #define EXPMODE 2 517c478bd9Sstevel@tonic-gate #define LINMODE 3 527c478bd9Sstevel@tonic-gate #define LINSIZ LINE_MAX /* POSIX.2 - read lines LINE_MAX long */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* Globals */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate char linbuf[LINSIZ]; /* Input line buffer */ 577c478bd9Sstevel@tonic-gate char *expbuf; 587c478bd9Sstevel@tonic-gate char tmpbuf[BUFSIZ]; /* Temporary buffer for stdin */ 597c478bd9Sstevel@tonic-gate char file[8192] = "xx"; /* File name buffer */ 607c478bd9Sstevel@tonic-gate char *targ; /* Arg ptr for error messages */ 617c478bd9Sstevel@tonic-gate char *sptr; 627c478bd9Sstevel@tonic-gate FILE *infile, *outfile; /* I/O file streams */ 637c478bd9Sstevel@tonic-gate int silent, keep, create; /* Flags: -s(ilent), -k(eep), (create) */ 647c478bd9Sstevel@tonic-gate int errflg; 657c478bd9Sstevel@tonic-gate int fiwidth = 2; /* file index width (output file names) */ 667c478bd9Sstevel@tonic-gate extern int optind; 677c478bd9Sstevel@tonic-gate extern char *optarg; 687c478bd9Sstevel@tonic-gate offset_t offset; /* Regular expression offset value */ 697c478bd9Sstevel@tonic-gate offset_t curline; /* Current line in input file */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * These defines are needed for regexp handling(see regexp(7)) 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate #define PERROR(x) fatal("%s: Illegal Regular Expression\n", targ); 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static int asc_to_ll(char *, long long *); 777c478bd9Sstevel@tonic-gate static void closefile(void); 787c478bd9Sstevel@tonic-gate static void fatal(char *, char *); 797c478bd9Sstevel@tonic-gate static offset_t findline(char *, offset_t); 807c478bd9Sstevel@tonic-gate static void flush(void); 817c478bd9Sstevel@tonic-gate static FILE *getfile(void); 82*23a1cceaSRoger A. Faulkner static char *getaline(int); 837c478bd9Sstevel@tonic-gate static void line_arg(char *); 847c478bd9Sstevel@tonic-gate static void num_arg(char *, int); 857c478bd9Sstevel@tonic-gate static void re_arg(char *); 867c478bd9Sstevel@tonic-gate static void sig(int); 877c478bd9Sstevel@tonic-gate static void to_line(offset_t); 887c478bd9Sstevel@tonic-gate static void usage(void); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate int 917c478bd9Sstevel@tonic-gate main(int argc, char **argv) 927c478bd9Sstevel@tonic-gate { 937c478bd9Sstevel@tonic-gate int ch, mode; 947c478bd9Sstevel@tonic-gate char *ptr; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 977c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 987c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 997c478bd9Sstevel@tonic-gate #endif 1007c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, "skf:n:")) != EOF) { 1037c478bd9Sstevel@tonic-gate switch (ch) { 1047c478bd9Sstevel@tonic-gate case 'f': 1057c478bd9Sstevel@tonic-gate (void) strcpy(file, optarg); 1067c478bd9Sstevel@tonic-gate if ((ptr = strrchr(optarg, '/')) == NULL) 1077c478bd9Sstevel@tonic-gate ptr = optarg; 1087c478bd9Sstevel@tonic-gate else 1097c478bd9Sstevel@tonic-gate ptr++; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate break; 1127c478bd9Sstevel@tonic-gate case 'n': /* POSIX.2 */ 1137c478bd9Sstevel@tonic-gate for (ptr = optarg; *ptr != NULL; ptr++) 1147c478bd9Sstevel@tonic-gate if (!isdigit((int)*ptr)) 1157c478bd9Sstevel@tonic-gate fatal("-n num\n", NULL); 1167c478bd9Sstevel@tonic-gate fiwidth = atoi(optarg); 1177c478bd9Sstevel@tonic-gate break; 1187c478bd9Sstevel@tonic-gate case 'k': 1197c478bd9Sstevel@tonic-gate keep++; 1207c478bd9Sstevel@tonic-gate break; 1217c478bd9Sstevel@tonic-gate case 's': 1227c478bd9Sstevel@tonic-gate silent++; 1237c478bd9Sstevel@tonic-gate break; 1247c478bd9Sstevel@tonic-gate case '?': 1257c478bd9Sstevel@tonic-gate errflg++; 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate argv = &argv[optind]; 1307c478bd9Sstevel@tonic-gate argc -= optind; 1317c478bd9Sstevel@tonic-gate if (argc <= 1 || errflg) 1327c478bd9Sstevel@tonic-gate usage(); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate if (strcmp(*argv, "-") == 0) { 1357c478bd9Sstevel@tonic-gate infile = tmpfile(); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate while (fread(tmpbuf, 1, BUFSIZ, stdin) != 0) { 1387c478bd9Sstevel@tonic-gate if (fwrite(tmpbuf, 1, BUFSIZ, infile) == 0) 1397c478bd9Sstevel@tonic-gate if (errno == ENOSPC) { 1407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "csplit: "); 1417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1427c478bd9Sstevel@tonic-gate "No space left on device\n")); 1437c478bd9Sstevel@tonic-gate exit(1); 1447c478bd9Sstevel@tonic-gate } else { 1457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "csplit: "); 1467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1477c478bd9Sstevel@tonic-gate "Bad write to temporary " 1487c478bd9Sstevel@tonic-gate "file\n")); 1497c478bd9Sstevel@tonic-gate exit(1); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* clear the buffer to get correct size when writing buffer */ 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate (void) memset(tmpbuf, '\0', sizeof (tmpbuf)); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate rewind(infile); 1577c478bd9Sstevel@tonic-gate } else if ((infile = fopen(*argv, "r")) == NULL) 1587c478bd9Sstevel@tonic-gate fatal("Cannot open %s\n", *argv); 1597c478bd9Sstevel@tonic-gate ++argv; 1607c478bd9Sstevel@tonic-gate curline = (offset_t)1; 1617c478bd9Sstevel@tonic-gate (void) signal(SIGINT, sig); 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* 1647c478bd9Sstevel@tonic-gate * The following for loop handles the different argument types. 1657c478bd9Sstevel@tonic-gate * A switch is performed on the first character of the argument 1667c478bd9Sstevel@tonic-gate * and each case calls the appropriate argument handling routine. 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate for (; *argv; ++argv) { 1707c478bd9Sstevel@tonic-gate targ = *argv; 1717c478bd9Sstevel@tonic-gate switch (**argv) { 1727c478bd9Sstevel@tonic-gate case '/': 1737c478bd9Sstevel@tonic-gate mode = EXPMODE; 1747c478bd9Sstevel@tonic-gate create = TRUE; 1757c478bd9Sstevel@tonic-gate re_arg(*argv); 1767c478bd9Sstevel@tonic-gate break; 1777c478bd9Sstevel@tonic-gate case '%': 1787c478bd9Sstevel@tonic-gate mode = EXPMODE; 1797c478bd9Sstevel@tonic-gate create = FALSE; 1807c478bd9Sstevel@tonic-gate re_arg(*argv); 1817c478bd9Sstevel@tonic-gate break; 1827c478bd9Sstevel@tonic-gate case '{': 1837c478bd9Sstevel@tonic-gate num_arg(*argv, mode); 1847c478bd9Sstevel@tonic-gate mode = FALSE; 1857c478bd9Sstevel@tonic-gate break; 1867c478bd9Sstevel@tonic-gate default: 1877c478bd9Sstevel@tonic-gate mode = LINMODE; 1887c478bd9Sstevel@tonic-gate create = TRUE; 1897c478bd9Sstevel@tonic-gate line_arg(*argv); 1907c478bd9Sstevel@tonic-gate break; 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate create = TRUE; 1947c478bd9Sstevel@tonic-gate to_line(LAST); 1957c478bd9Sstevel@tonic-gate return (0); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * asc_to_ll takes an ascii argument(str) and converts it to a long long(plc) 2007c478bd9Sstevel@tonic-gate * It returns ERR if an illegal character. The reason that asc_to_ll 2017c478bd9Sstevel@tonic-gate * does not return an answer(long long) is that any value for the long 2027c478bd9Sstevel@tonic-gate * long is legal, and this version of asc_to_ll detects error strings. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate static int 2067c478bd9Sstevel@tonic-gate asc_to_ll(char *str, long long *plc) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate int f; 2097c478bd9Sstevel@tonic-gate *plc = 0; 2107c478bd9Sstevel@tonic-gate f = 0; 2117c478bd9Sstevel@tonic-gate for (; ; str++) { 2127c478bd9Sstevel@tonic-gate switch (*str) { 2137c478bd9Sstevel@tonic-gate case ' ': 2147c478bd9Sstevel@tonic-gate case '\t': 2157c478bd9Sstevel@tonic-gate continue; 2167c478bd9Sstevel@tonic-gate case '-': 2177c478bd9Sstevel@tonic-gate f++; 2187c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2197c478bd9Sstevel@tonic-gate case '+': 2207c478bd9Sstevel@tonic-gate str++; 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate break; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate for (; *str != NULL; str++) 2257c478bd9Sstevel@tonic-gate if (*str >= '0' && *str <= '9') 2267c478bd9Sstevel@tonic-gate *plc = *plc * 10 + *str - '0'; 2277c478bd9Sstevel@tonic-gate else 2287c478bd9Sstevel@tonic-gate return (ERR); 2297c478bd9Sstevel@tonic-gate if (f) 2307c478bd9Sstevel@tonic-gate *plc = -(*plc); 2317c478bd9Sstevel@tonic-gate return (TRUE); /* not error */ 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * Closefile prints the byte count of the file created,(via fseeko 2367c478bd9Sstevel@tonic-gate * and ftello), if the create flag is on and the silent flag is not on. 2377c478bd9Sstevel@tonic-gate * If the create flag is on closefile then closes the file(fclose). 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate static void 2417c478bd9Sstevel@tonic-gate closefile() 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate if (!silent && create) { 2447c478bd9Sstevel@tonic-gate (void) fseeko(outfile, (offset_t)0, SEEK_END); 2457c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%lld\n", (offset_t)ftello(outfile)); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate if (create) 2487c478bd9Sstevel@tonic-gate (void) fclose(outfile); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * Fatal handles error messages and cleanup. 2537c478bd9Sstevel@tonic-gate * Because "arg" can be the global file, and the cleanup processing 2547c478bd9Sstevel@tonic-gate * uses the global file, the error message is printed first. If the 2557c478bd9Sstevel@tonic-gate * "keep" flag is not set, fatal unlinks all created files. If the 2567c478bd9Sstevel@tonic-gate * "keep" flag is set, fatal closes the current file(if there is one). 2577c478bd9Sstevel@tonic-gate * Fatal exits with a value of 1. 2587c478bd9Sstevel@tonic-gate */ 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate static void 2617c478bd9Sstevel@tonic-gate fatal(char *string, char *arg) 2627c478bd9Sstevel@tonic-gate { 2637c478bd9Sstevel@tonic-gate char *fls; 2647c478bd9Sstevel@tonic-gate int num; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "csplit: "); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* gettext dynamically replaces string */ 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(string), arg); 2717c478bd9Sstevel@tonic-gate if (!keep) { 2727c478bd9Sstevel@tonic-gate if (outfile) { 2737c478bd9Sstevel@tonic-gate (void) fclose(outfile); 2747c478bd9Sstevel@tonic-gate for (fls = file; *fls != '\0'; fls++) 2757c478bd9Sstevel@tonic-gate continue; 2767c478bd9Sstevel@tonic-gate fls -= fiwidth; 2777c478bd9Sstevel@tonic-gate for (num = atoi(fls); num >= 0; num--) { 2787c478bd9Sstevel@tonic-gate (void) sprintf(fls, "%.*d", fiwidth, num); 2797c478bd9Sstevel@tonic-gate (void) unlink(file); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate } else 2837c478bd9Sstevel@tonic-gate if (outfile) 2847c478bd9Sstevel@tonic-gate closefile(); 2857c478bd9Sstevel@tonic-gate exit(1); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * Findline returns the line number referenced by the current argument. 2907c478bd9Sstevel@tonic-gate * Its arguments are a pointer to the compiled regular expression(expr), 2917c478bd9Sstevel@tonic-gate * and an offset(oset). The variable lncnt is used to count the number 2927c478bd9Sstevel@tonic-gate * of lines searched. First the current stream location is saved via 293*23a1cceaSRoger A. Faulkner * ftello(), and getaline is called so that R.E. searching starts at the 2947c478bd9Sstevel@tonic-gate * line after the previously referenced line. The while loop checks 2957c478bd9Sstevel@tonic-gate * that there are more lines(error if none), bumps the line count, and 2967c478bd9Sstevel@tonic-gate * checks for the R.E. on each line. If the R.E. matches on one of the 2977c478bd9Sstevel@tonic-gate * lines the old stream location is restored, and the line number 2987c478bd9Sstevel@tonic-gate * referenced by the R.E. and the offset is returned. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate static offset_t 3027c478bd9Sstevel@tonic-gate findline(char *expr, offset_t oset) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate static int benhere = 0; 3057c478bd9Sstevel@tonic-gate offset_t lncnt = 0, saveloc; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate saveloc = ftello(infile); 3087c478bd9Sstevel@tonic-gate if (curline != (offset_t)1 || benhere) /* If first line, first time, */ 309*23a1cceaSRoger A. Faulkner (void) getaline(FALSE); /* then don't skip */ 3107c478bd9Sstevel@tonic-gate else 3117c478bd9Sstevel@tonic-gate lncnt--; 3127c478bd9Sstevel@tonic-gate benhere = 1; 313*23a1cceaSRoger A. Faulkner while (getaline(FALSE) != NULL) { 3147c478bd9Sstevel@tonic-gate lncnt++; 3157c478bd9Sstevel@tonic-gate if ((sptr = strrchr(linbuf, '\n')) != NULL) 3167c478bd9Sstevel@tonic-gate *sptr = '\0'; 3177c478bd9Sstevel@tonic-gate if (step(linbuf, expr)) { 3187c478bd9Sstevel@tonic-gate (void) fseeko(infile, (offset_t)saveloc, SEEK_SET); 3197c478bd9Sstevel@tonic-gate return (curline+lncnt+oset); 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate (void) fseeko(infile, (offset_t)saveloc, SEEK_SET); 3237c478bd9Sstevel@tonic-gate return (curline+lncnt+oset+2); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * Flush uses fputs to put lines on the output file stream(outfile) 3287c478bd9Sstevel@tonic-gate * Since fputs does its own buffering, flush doesn't need to. 3297c478bd9Sstevel@tonic-gate * Flush does nothing if the create flag is not set. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate static void 3337c478bd9Sstevel@tonic-gate flush() 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate if (create) 3367c478bd9Sstevel@tonic-gate (void) fputs(linbuf, outfile); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * Getfile does nothing if the create flag is not set. If the create 3417c478bd9Sstevel@tonic-gate * flag is set, getfile positions the file pointer(fptr) at the end of 3427c478bd9Sstevel@tonic-gate * the file name prefix on the first call(fptr=0). The file counter is 3437c478bd9Sstevel@tonic-gate * stored in the file name and incremented. If the subsequent fopen 3447c478bd9Sstevel@tonic-gate * fails, the file name is copied to tfile for the error message, the 3457c478bd9Sstevel@tonic-gate * previous file name is restored for cleanup, and fatal is called. If 3467c478bd9Sstevel@tonic-gate * the fopen succeeds, the stream(opfil) is returned. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate FILE * 3507c478bd9Sstevel@tonic-gate getfile() 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate static char *fptr; 3537c478bd9Sstevel@tonic-gate static int ctr; 3547c478bd9Sstevel@tonic-gate FILE *opfil; 3557c478bd9Sstevel@tonic-gate char tfile[15]; 3567c478bd9Sstevel@tonic-gate char *delim; 3577c478bd9Sstevel@tonic-gate char savedelim; 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if (create) { 3607c478bd9Sstevel@tonic-gate if (fptr == 0) 361*23a1cceaSRoger A. Faulkner for (fptr = file; *fptr != NULL; fptr++) 362*23a1cceaSRoger A. Faulkner continue; 3637c478bd9Sstevel@tonic-gate (void) sprintf(fptr, "%.*d", fiwidth, ctr++); 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* check for suffix length overflow */ 3667c478bd9Sstevel@tonic-gate if (strlen(fptr) > fiwidth) { 3677c478bd9Sstevel@tonic-gate fatal("Suffix longer than %ld chars; increase -n\n", 3687c478bd9Sstevel@tonic-gate (char *)fiwidth); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* check for filename length overflow */ 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate delim = strrchr(file, '/'); 3747c478bd9Sstevel@tonic-gate if (delim == (char *)NULL) { 3757c478bd9Sstevel@tonic-gate if (strlen(file) > pathconf(".", _PC_NAME_MAX)) { 3767c478bd9Sstevel@tonic-gate fatal("Name too long: %s\n", file); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate } else { 3797c478bd9Sstevel@tonic-gate /* truncate file at pathname delim to do pathconf */ 3807c478bd9Sstevel@tonic-gate savedelim = *delim; 3817c478bd9Sstevel@tonic-gate *delim = '\0'; 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * file: pppppppp\0fffff\0 3847c478bd9Sstevel@tonic-gate * ..... ^ file 3857c478bd9Sstevel@tonic-gate * ............. ^ delim 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate if (strlen(delim + 1) > pathconf(file, _PC_NAME_MAX)) { 3887c478bd9Sstevel@tonic-gate fatal("Name too long: %s\n", delim + 1); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate *delim = savedelim; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate if ((opfil = fopen(file, "w")) == NULL) { 3947c478bd9Sstevel@tonic-gate (void) strcpy(tfile, file); 3957c478bd9Sstevel@tonic-gate (void) sprintf(fptr, "%.*d", fiwidth, (ctr-2)); 3967c478bd9Sstevel@tonic-gate fatal("Cannot create %s\n", tfile); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate return (opfil); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate return (NULL); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * Getline gets a line via fgets from the input stream "infile". 4057c478bd9Sstevel@tonic-gate * The line is put into linbuf and may not be larger than LINSIZ. 406*23a1cceaSRoger A. Faulkner * If getaline is called with a non-zero value, the current line 4077c478bd9Sstevel@tonic-gate * is bumped, otherwise it is not(for R.E. searching). 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate static char * 411*23a1cceaSRoger A. Faulkner getaline(int bumpcur) 4127c478bd9Sstevel@tonic-gate { 4137c478bd9Sstevel@tonic-gate char *ret; 4147c478bd9Sstevel@tonic-gate if (bumpcur) 4157c478bd9Sstevel@tonic-gate curline++; 4167c478bd9Sstevel@tonic-gate ret = fgets(linbuf, LINSIZ, infile); 4177c478bd9Sstevel@tonic-gate return (ret); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* 4217c478bd9Sstevel@tonic-gate * Line_arg handles line number arguments. 4227c478bd9Sstevel@tonic-gate * line_arg takes as its argument a pointer to a character string 4237c478bd9Sstevel@tonic-gate * (assumed to be a line number). If that character string can be 4247c478bd9Sstevel@tonic-gate * converted to a number(long long), to_line is called with that number, 4257c478bd9Sstevel@tonic-gate * otherwise error. 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate static void 4297c478bd9Sstevel@tonic-gate line_arg(char *line) 4307c478bd9Sstevel@tonic-gate { 4317c478bd9Sstevel@tonic-gate long long to; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate if (asc_to_ll(line, &to) == ERR) 4347c478bd9Sstevel@tonic-gate fatal("%s: bad line number\n", line); 4357c478bd9Sstevel@tonic-gate to_line(to); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * Num_arg handles repeat arguments. 4407c478bd9Sstevel@tonic-gate * Num_arg copies the numeric argument to "rep" (error if number is 4417c478bd9Sstevel@tonic-gate * larger than 20 characters or } is left off). Num_arg then converts 4427c478bd9Sstevel@tonic-gate * the number and checks for validity. Next num_arg checks the mode 4437c478bd9Sstevel@tonic-gate * of the previous argument, and applys the argument the correct number 4447c478bd9Sstevel@tonic-gate * of times. If the mode is not set properly its an error. 4457c478bd9Sstevel@tonic-gate */ 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate static void 4487c478bd9Sstevel@tonic-gate num_arg(char *arg, int md) 4497c478bd9Sstevel@tonic-gate { 4507c478bd9Sstevel@tonic-gate offset_t repeat, toline; 4517c478bd9Sstevel@tonic-gate char rep[21]; 4527c478bd9Sstevel@tonic-gate char *ptr; 4537c478bd9Sstevel@tonic-gate int len; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate ptr = rep; 4567c478bd9Sstevel@tonic-gate for (++arg; *arg != '}'; arg += len) { 4577c478bd9Sstevel@tonic-gate if (*arg == NULL) 4587c478bd9Sstevel@tonic-gate fatal("%s: missing '}'\n", targ); 4597c478bd9Sstevel@tonic-gate if ((len = mblen(arg, MB_LEN_MAX)) <= 0) 4607c478bd9Sstevel@tonic-gate len = 1; 4617c478bd9Sstevel@tonic-gate if ((ptr + len) >= &rep[20]) 4627c478bd9Sstevel@tonic-gate fatal("%s: Repeat count too large\n", targ); 4637c478bd9Sstevel@tonic-gate (void) memcpy(ptr, arg, len); 4647c478bd9Sstevel@tonic-gate ptr += len; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate *ptr = NULL; 4677c478bd9Sstevel@tonic-gate if ((asc_to_ll(rep, &repeat) == ERR) || repeat < 0L) 4687c478bd9Sstevel@tonic-gate fatal("Illegal repeat count: %s\n", targ); 4697c478bd9Sstevel@tonic-gate if (md == LINMODE) { 4707c478bd9Sstevel@tonic-gate toline = offset = curline; 4717c478bd9Sstevel@tonic-gate for (; repeat > 0LL; repeat--) { 4727c478bd9Sstevel@tonic-gate toline += offset; 4737c478bd9Sstevel@tonic-gate to_line(toline); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate } else if (md == EXPMODE) 4767c478bd9Sstevel@tonic-gate for (; repeat > 0LL; repeat--) 4777c478bd9Sstevel@tonic-gate to_line(findline(expbuf, offset)); 4787c478bd9Sstevel@tonic-gate else 4797c478bd9Sstevel@tonic-gate fatal("No operation for %s\n", targ); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Re_arg handles regular expression arguments. 4847c478bd9Sstevel@tonic-gate * Re_arg takes a csplit regular expression argument. It checks for 4857c478bd9Sstevel@tonic-gate * delimiter balance, computes any offset, and compiles the regular 4867c478bd9Sstevel@tonic-gate * expression. Findline is called with the compiled expression and 4877c478bd9Sstevel@tonic-gate * offset, and returns the corresponding line number, which is used 4887c478bd9Sstevel@tonic-gate * as input to the to_line function. 4897c478bd9Sstevel@tonic-gate */ 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate static void 4927c478bd9Sstevel@tonic-gate re_arg(char *string) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate char *ptr; 4957c478bd9Sstevel@tonic-gate char ch; 4967c478bd9Sstevel@tonic-gate int len; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate ch = *string; 4997c478bd9Sstevel@tonic-gate ptr = string; 5007c478bd9Sstevel@tonic-gate ptr++; 5017c478bd9Sstevel@tonic-gate while (*ptr != ch) { 5027c478bd9Sstevel@tonic-gate if (*ptr == '\\') 5037c478bd9Sstevel@tonic-gate ++ptr; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if (*ptr == NULL) 5067c478bd9Sstevel@tonic-gate fatal("%s: missing delimiter\n", targ); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate if ((len = mblen(ptr, MB_LEN_MAX)) <= 0) 5097c478bd9Sstevel@tonic-gate len = 1; 5107c478bd9Sstevel@tonic-gate ptr += len; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * The line below was added because compile no longer supports 5157c478bd9Sstevel@tonic-gate * the fourth argument being passed. The fourth argument used 5167c478bd9Sstevel@tonic-gate * to be '/' or '%'. 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate *ptr = NULL; 5207c478bd9Sstevel@tonic-gate if (asc_to_ll(++ptr, &offset) == ERR) 5217c478bd9Sstevel@tonic-gate fatal("%s: illegal offset\n", string); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * The line below was added because INIT which did this for us 5257c478bd9Sstevel@tonic-gate * was removed from compile in regexp.h 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate string++; 5297c478bd9Sstevel@tonic-gate expbuf = compile(string, (char *)0, (char *)0); 5307c478bd9Sstevel@tonic-gate if (regerrno) 5317c478bd9Sstevel@tonic-gate PERROR(regerrno); 5327c478bd9Sstevel@tonic-gate to_line(findline(expbuf, offset)); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * Sig handles breaks. When a break occurs the signal is reset, 5377c478bd9Sstevel@tonic-gate * and fatal is called to clean up and print the argument which 5387c478bd9Sstevel@tonic-gate * was being processed at the time the interrupt occured. 5397c478bd9Sstevel@tonic-gate */ 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5427c478bd9Sstevel@tonic-gate static void 5437c478bd9Sstevel@tonic-gate sig(int s) 5447c478bd9Sstevel@tonic-gate { 5457c478bd9Sstevel@tonic-gate (void) signal(SIGINT, sig); 5467c478bd9Sstevel@tonic-gate fatal("Interrupt - program aborted at arg '%s'\n", targ); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * To_line creates split files. 5517c478bd9Sstevel@tonic-gate * To_line gets as its argument the line which the current argument 5527c478bd9Sstevel@tonic-gate * referenced. To_line calls getfile for a new output stream, which 5537c478bd9Sstevel@tonic-gate * does nothing if create is False. If to_line's argument is not LAST 5547c478bd9Sstevel@tonic-gate * it checks that the current line is not greater than its argument. 5557c478bd9Sstevel@tonic-gate * While the current line is less than the desired line to_line gets 5567c478bd9Sstevel@tonic-gate * lines and flushes(error if EOF is reached). 5577c478bd9Sstevel@tonic-gate * If to_line's argument is LAST, it checks for more lines, and gets 5587c478bd9Sstevel@tonic-gate * and flushes lines till the end of file. 5597c478bd9Sstevel@tonic-gate * Finally, to_line calls closefile to close the output stream. 5607c478bd9Sstevel@tonic-gate */ 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate static void 5637c478bd9Sstevel@tonic-gate to_line(offset_t ln) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate outfile = getfile(); 5667c478bd9Sstevel@tonic-gate if (ln != LAST) { 5677c478bd9Sstevel@tonic-gate if (curline > ln) 5687c478bd9Sstevel@tonic-gate fatal("%s - out of range\n", targ); 5697c478bd9Sstevel@tonic-gate while (curline < ln) { 570*23a1cceaSRoger A. Faulkner if (getaline(TRUE) == NULL) 5717c478bd9Sstevel@tonic-gate fatal("%s - out of range\n", targ); 5727c478bd9Sstevel@tonic-gate flush(); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate } else /* last file */ 575*23a1cceaSRoger A. Faulkner if (getaline(TRUE) != NULL) { 5767c478bd9Sstevel@tonic-gate flush(); 5777c478bd9Sstevel@tonic-gate for (;;) { 578*23a1cceaSRoger A. Faulkner if (getaline(TRUE) == NULL) 5797c478bd9Sstevel@tonic-gate break; 5807c478bd9Sstevel@tonic-gate flush(); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate } else 5837c478bd9Sstevel@tonic-gate fatal("%s - out of range\n", targ); 5847c478bd9Sstevel@tonic-gate closefile(); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate static void 5887c478bd9Sstevel@tonic-gate usage() 5897c478bd9Sstevel@tonic-gate { 5907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5917c478bd9Sstevel@tonic-gate "usage: csplit [-ks] [-f prefix] [-n number] " 5927c478bd9Sstevel@tonic-gate "file arg1 ...argn\n")); 5937c478bd9Sstevel@tonic-gate exit(1); 5947c478bd9Sstevel@tonic-gate } 595