10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*13093SRoger.Faulkner@Oracle.COM * Common Development and Distribution License (the "License").
6*13093SRoger.Faulkner@Oracle.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
26*13093SRoger.Faulkner@Oracle.COM /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27*13093SRoger.Faulkner@Oracle.COM /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * csplit - Context or line file splitter
310Sstevel@tonic-gate * Compile: cc -O -s -o csplit csplit.c
320Sstevel@tonic-gate */
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <unistd.h>
370Sstevel@tonic-gate #include <string.h>
380Sstevel@tonic-gate #include <ctype.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate #include <limits.h>
410Sstevel@tonic-gate #include <regexpr.h>
420Sstevel@tonic-gate #include <signal.h>
430Sstevel@tonic-gate #include <locale.h>
440Sstevel@tonic-gate #include <libintl.h>
450Sstevel@tonic-gate
460Sstevel@tonic-gate #define LAST 0LL
470Sstevel@tonic-gate #define ERR -1
480Sstevel@tonic-gate #define FALSE 0
490Sstevel@tonic-gate #define TRUE 1
500Sstevel@tonic-gate #define EXPMODE 2
510Sstevel@tonic-gate #define LINMODE 3
520Sstevel@tonic-gate #define LINSIZ LINE_MAX /* POSIX.2 - read lines LINE_MAX long */
530Sstevel@tonic-gate
540Sstevel@tonic-gate /* Globals */
550Sstevel@tonic-gate
560Sstevel@tonic-gate char linbuf[LINSIZ]; /* Input line buffer */
570Sstevel@tonic-gate char *expbuf;
580Sstevel@tonic-gate char tmpbuf[BUFSIZ]; /* Temporary buffer for stdin */
590Sstevel@tonic-gate char file[8192] = "xx"; /* File name buffer */
600Sstevel@tonic-gate char *targ; /* Arg ptr for error messages */
610Sstevel@tonic-gate char *sptr;
620Sstevel@tonic-gate FILE *infile, *outfile; /* I/O file streams */
630Sstevel@tonic-gate int silent, keep, create; /* Flags: -s(ilent), -k(eep), (create) */
640Sstevel@tonic-gate int errflg;
650Sstevel@tonic-gate int fiwidth = 2; /* file index width (output file names) */
660Sstevel@tonic-gate extern int optind;
670Sstevel@tonic-gate extern char *optarg;
680Sstevel@tonic-gate offset_t offset; /* Regular expression offset value */
690Sstevel@tonic-gate offset_t curline; /* Current line in input file */
700Sstevel@tonic-gate
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate * These defines are needed for regexp handling(see regexp(7))
730Sstevel@tonic-gate */
740Sstevel@tonic-gate #define PERROR(x) fatal("%s: Illegal Regular Expression\n", targ);
750Sstevel@tonic-gate
760Sstevel@tonic-gate static int asc_to_ll(char *, long long *);
770Sstevel@tonic-gate static void closefile(void);
780Sstevel@tonic-gate static void fatal(char *, char *);
790Sstevel@tonic-gate static offset_t findline(char *, offset_t);
800Sstevel@tonic-gate static void flush(void);
810Sstevel@tonic-gate static FILE *getfile(void);
82*13093SRoger.Faulkner@Oracle.COM static char *getaline(int);
830Sstevel@tonic-gate static void line_arg(char *);
840Sstevel@tonic-gate static void num_arg(char *, int);
850Sstevel@tonic-gate static void re_arg(char *);
860Sstevel@tonic-gate static void sig(int);
870Sstevel@tonic-gate static void to_line(offset_t);
880Sstevel@tonic-gate static void usage(void);
890Sstevel@tonic-gate
900Sstevel@tonic-gate int
main(int argc,char ** argv)910Sstevel@tonic-gate main(int argc, char **argv)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate int ch, mode;
940Sstevel@tonic-gate char *ptr;
950Sstevel@tonic-gate
960Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
970Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
980Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
990Sstevel@tonic-gate #endif
1000Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate while ((ch = getopt(argc, argv, "skf:n:")) != EOF) {
1030Sstevel@tonic-gate switch (ch) {
1040Sstevel@tonic-gate case 'f':
1050Sstevel@tonic-gate (void) strcpy(file, optarg);
1060Sstevel@tonic-gate if ((ptr = strrchr(optarg, '/')) == NULL)
1070Sstevel@tonic-gate ptr = optarg;
1080Sstevel@tonic-gate else
1090Sstevel@tonic-gate ptr++;
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate break;
1120Sstevel@tonic-gate case 'n': /* POSIX.2 */
1130Sstevel@tonic-gate for (ptr = optarg; *ptr != NULL; ptr++)
1140Sstevel@tonic-gate if (!isdigit((int)*ptr))
1150Sstevel@tonic-gate fatal("-n num\n", NULL);
1160Sstevel@tonic-gate fiwidth = atoi(optarg);
1170Sstevel@tonic-gate break;
1180Sstevel@tonic-gate case 'k':
1190Sstevel@tonic-gate keep++;
1200Sstevel@tonic-gate break;
1210Sstevel@tonic-gate case 's':
1220Sstevel@tonic-gate silent++;
1230Sstevel@tonic-gate break;
1240Sstevel@tonic-gate case '?':
1250Sstevel@tonic-gate errflg++;
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate argv = &argv[optind];
1300Sstevel@tonic-gate argc -= optind;
1310Sstevel@tonic-gate if (argc <= 1 || errflg)
1320Sstevel@tonic-gate usage();
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate if (strcmp(*argv, "-") == 0) {
1350Sstevel@tonic-gate infile = tmpfile();
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate while (fread(tmpbuf, 1, BUFSIZ, stdin) != 0) {
1380Sstevel@tonic-gate if (fwrite(tmpbuf, 1, BUFSIZ, infile) == 0)
1390Sstevel@tonic-gate if (errno == ENOSPC) {
1400Sstevel@tonic-gate (void) fprintf(stderr, "csplit: ");
1410Sstevel@tonic-gate (void) fprintf(stderr, gettext(
142*13093SRoger.Faulkner@Oracle.COM "No space left on device\n"));
1430Sstevel@tonic-gate exit(1);
1440Sstevel@tonic-gate } else {
1450Sstevel@tonic-gate (void) fprintf(stderr, "csplit: ");
1460Sstevel@tonic-gate (void) fprintf(stderr, gettext(
147*13093SRoger.Faulkner@Oracle.COM "Bad write to temporary "
148*13093SRoger.Faulkner@Oracle.COM "file\n"));
1490Sstevel@tonic-gate exit(1);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /* clear the buffer to get correct size when writing buffer */
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate (void) memset(tmpbuf, '\0', sizeof (tmpbuf));
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate rewind(infile);
1570Sstevel@tonic-gate } else if ((infile = fopen(*argv, "r")) == NULL)
1580Sstevel@tonic-gate fatal("Cannot open %s\n", *argv);
1590Sstevel@tonic-gate ++argv;
1600Sstevel@tonic-gate curline = (offset_t)1;
1610Sstevel@tonic-gate (void) signal(SIGINT, sig);
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate /*
1640Sstevel@tonic-gate * The following for loop handles the different argument types.
1650Sstevel@tonic-gate * A switch is performed on the first character of the argument
1660Sstevel@tonic-gate * and each case calls the appropriate argument handling routine.
1670Sstevel@tonic-gate */
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate for (; *argv; ++argv) {
1700Sstevel@tonic-gate targ = *argv;
1710Sstevel@tonic-gate switch (**argv) {
1720Sstevel@tonic-gate case '/':
1730Sstevel@tonic-gate mode = EXPMODE;
1740Sstevel@tonic-gate create = TRUE;
1750Sstevel@tonic-gate re_arg(*argv);
1760Sstevel@tonic-gate break;
1770Sstevel@tonic-gate case '%':
1780Sstevel@tonic-gate mode = EXPMODE;
1790Sstevel@tonic-gate create = FALSE;
1800Sstevel@tonic-gate re_arg(*argv);
1810Sstevel@tonic-gate break;
1820Sstevel@tonic-gate case '{':
1830Sstevel@tonic-gate num_arg(*argv, mode);
1840Sstevel@tonic-gate mode = FALSE;
1850Sstevel@tonic-gate break;
1860Sstevel@tonic-gate default:
1870Sstevel@tonic-gate mode = LINMODE;
1880Sstevel@tonic-gate create = TRUE;
1890Sstevel@tonic-gate line_arg(*argv);
1900Sstevel@tonic-gate break;
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate create = TRUE;
1940Sstevel@tonic-gate to_line(LAST);
1950Sstevel@tonic-gate return (0);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * asc_to_ll takes an ascii argument(str) and converts it to a long long(plc)
2000Sstevel@tonic-gate * It returns ERR if an illegal character. The reason that asc_to_ll
2010Sstevel@tonic-gate * does not return an answer(long long) is that any value for the long
2020Sstevel@tonic-gate * long is legal, and this version of asc_to_ll detects error strings.
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate static int
asc_to_ll(char * str,long long * plc)2060Sstevel@tonic-gate asc_to_ll(char *str, long long *plc)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate int f;
2090Sstevel@tonic-gate *plc = 0;
2100Sstevel@tonic-gate f = 0;
2110Sstevel@tonic-gate for (; ; str++) {
2120Sstevel@tonic-gate switch (*str) {
2130Sstevel@tonic-gate case ' ':
2140Sstevel@tonic-gate case '\t':
2150Sstevel@tonic-gate continue;
2160Sstevel@tonic-gate case '-':
2170Sstevel@tonic-gate f++;
2180Sstevel@tonic-gate /* FALLTHROUGH */
2190Sstevel@tonic-gate case '+':
2200Sstevel@tonic-gate str++;
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate break;
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate for (; *str != NULL; str++)
2250Sstevel@tonic-gate if (*str >= '0' && *str <= '9')
2260Sstevel@tonic-gate *plc = *plc * 10 + *str - '0';
2270Sstevel@tonic-gate else
2280Sstevel@tonic-gate return (ERR);
2290Sstevel@tonic-gate if (f)
2300Sstevel@tonic-gate *plc = -(*plc);
2310Sstevel@tonic-gate return (TRUE); /* not error */
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate * Closefile prints the byte count of the file created,(via fseeko
2360Sstevel@tonic-gate * and ftello), if the create flag is on and the silent flag is not on.
2370Sstevel@tonic-gate * If the create flag is on closefile then closes the file(fclose).
2380Sstevel@tonic-gate */
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate static void
closefile()2410Sstevel@tonic-gate closefile()
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate if (!silent && create) {
2440Sstevel@tonic-gate (void) fseeko(outfile, (offset_t)0, SEEK_END);
2450Sstevel@tonic-gate (void) fprintf(stdout, "%lld\n", (offset_t)ftello(outfile));
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate if (create)
2480Sstevel@tonic-gate (void) fclose(outfile);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate /*
2520Sstevel@tonic-gate * Fatal handles error messages and cleanup.
2530Sstevel@tonic-gate * Because "arg" can be the global file, and the cleanup processing
2540Sstevel@tonic-gate * uses the global file, the error message is printed first. If the
2550Sstevel@tonic-gate * "keep" flag is not set, fatal unlinks all created files. If the
2560Sstevel@tonic-gate * "keep" flag is set, fatal closes the current file(if there is one).
2570Sstevel@tonic-gate * Fatal exits with a value of 1.
2580Sstevel@tonic-gate */
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate static void
fatal(char * string,char * arg)2610Sstevel@tonic-gate fatal(char *string, char *arg)
2620Sstevel@tonic-gate {
2630Sstevel@tonic-gate char *fls;
2640Sstevel@tonic-gate int num;
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate (void) fprintf(stderr, "csplit: ");
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /* gettext dynamically replaces string */
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate (void) fprintf(stderr, gettext(string), arg);
2710Sstevel@tonic-gate if (!keep) {
2720Sstevel@tonic-gate if (outfile) {
2730Sstevel@tonic-gate (void) fclose(outfile);
2740Sstevel@tonic-gate for (fls = file; *fls != '\0'; fls++)
2750Sstevel@tonic-gate continue;
2760Sstevel@tonic-gate fls -= fiwidth;
2770Sstevel@tonic-gate for (num = atoi(fls); num >= 0; num--) {
2780Sstevel@tonic-gate (void) sprintf(fls, "%.*d", fiwidth, num);
2790Sstevel@tonic-gate (void) unlink(file);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate } else
2830Sstevel@tonic-gate if (outfile)
2840Sstevel@tonic-gate closefile();
2850Sstevel@tonic-gate exit(1);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate * Findline returns the line number referenced by the current argument.
2900Sstevel@tonic-gate * Its arguments are a pointer to the compiled regular expression(expr),
2910Sstevel@tonic-gate * and an offset(oset). The variable lncnt is used to count the number
2920Sstevel@tonic-gate * of lines searched. First the current stream location is saved via
293*13093SRoger.Faulkner@Oracle.COM * ftello(), and getaline is called so that R.E. searching starts at the
2940Sstevel@tonic-gate * line after the previously referenced line. The while loop checks
2950Sstevel@tonic-gate * that there are more lines(error if none), bumps the line count, and
2960Sstevel@tonic-gate * checks for the R.E. on each line. If the R.E. matches on one of the
2970Sstevel@tonic-gate * lines the old stream location is restored, and the line number
2980Sstevel@tonic-gate * referenced by the R.E. and the offset is returned.
2990Sstevel@tonic-gate */
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate static offset_t
findline(char * expr,offset_t oset)3020Sstevel@tonic-gate findline(char *expr, offset_t oset)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate static int benhere = 0;
3050Sstevel@tonic-gate offset_t lncnt = 0, saveloc;
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate saveloc = ftello(infile);
3080Sstevel@tonic-gate if (curline != (offset_t)1 || benhere) /* If first line, first time, */
309*13093SRoger.Faulkner@Oracle.COM (void) getaline(FALSE); /* then don't skip */
3100Sstevel@tonic-gate else
3110Sstevel@tonic-gate lncnt--;
3120Sstevel@tonic-gate benhere = 1;
313*13093SRoger.Faulkner@Oracle.COM while (getaline(FALSE) != NULL) {
3140Sstevel@tonic-gate lncnt++;
3150Sstevel@tonic-gate if ((sptr = strrchr(linbuf, '\n')) != NULL)
3160Sstevel@tonic-gate *sptr = '\0';
3170Sstevel@tonic-gate if (step(linbuf, expr)) {
3180Sstevel@tonic-gate (void) fseeko(infile, (offset_t)saveloc, SEEK_SET);
3190Sstevel@tonic-gate return (curline+lncnt+oset);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate (void) fseeko(infile, (offset_t)saveloc, SEEK_SET);
3230Sstevel@tonic-gate return (curline+lncnt+oset+2);
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate * Flush uses fputs to put lines on the output file stream(outfile)
3280Sstevel@tonic-gate * Since fputs does its own buffering, flush doesn't need to.
3290Sstevel@tonic-gate * Flush does nothing if the create flag is not set.
3300Sstevel@tonic-gate */
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate static void
flush()3330Sstevel@tonic-gate flush()
3340Sstevel@tonic-gate {
3350Sstevel@tonic-gate if (create)
3360Sstevel@tonic-gate (void) fputs(linbuf, outfile);
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate * Getfile does nothing if the create flag is not set. If the create
3410Sstevel@tonic-gate * flag is set, getfile positions the file pointer(fptr) at the end of
3420Sstevel@tonic-gate * the file name prefix on the first call(fptr=0). The file counter is
3430Sstevel@tonic-gate * stored in the file name and incremented. If the subsequent fopen
3440Sstevel@tonic-gate * fails, the file name is copied to tfile for the error message, the
3450Sstevel@tonic-gate * previous file name is restored for cleanup, and fatal is called. If
3460Sstevel@tonic-gate * the fopen succeeds, the stream(opfil) is returned.
3470Sstevel@tonic-gate */
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate FILE *
getfile()3500Sstevel@tonic-gate getfile()
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate static char *fptr;
3530Sstevel@tonic-gate static int ctr;
3540Sstevel@tonic-gate FILE *opfil;
3550Sstevel@tonic-gate char tfile[15];
3560Sstevel@tonic-gate char *delim;
3570Sstevel@tonic-gate char savedelim;
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate if (create) {
3600Sstevel@tonic-gate if (fptr == 0)
361*13093SRoger.Faulkner@Oracle.COM for (fptr = file; *fptr != NULL; fptr++)
362*13093SRoger.Faulkner@Oracle.COM continue;
3630Sstevel@tonic-gate (void) sprintf(fptr, "%.*d", fiwidth, ctr++);
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /* check for suffix length overflow */
3660Sstevel@tonic-gate if (strlen(fptr) > fiwidth) {
3670Sstevel@tonic-gate fatal("Suffix longer than %ld chars; increase -n\n",
3680Sstevel@tonic-gate (char *)fiwidth);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate /* check for filename length overflow */
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate delim = strrchr(file, '/');
3740Sstevel@tonic-gate if (delim == (char *)NULL) {
3750Sstevel@tonic-gate if (strlen(file) > pathconf(".", _PC_NAME_MAX)) {
3760Sstevel@tonic-gate fatal("Name too long: %s\n", file);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate } else {
3790Sstevel@tonic-gate /* truncate file at pathname delim to do pathconf */
3800Sstevel@tonic-gate savedelim = *delim;
3810Sstevel@tonic-gate *delim = '\0';
3820Sstevel@tonic-gate /*
3830Sstevel@tonic-gate * file: pppppppp\0fffff\0
3840Sstevel@tonic-gate * ..... ^ file
3850Sstevel@tonic-gate * ............. ^ delim
3860Sstevel@tonic-gate */
3870Sstevel@tonic-gate if (strlen(delim + 1) > pathconf(file, _PC_NAME_MAX)) {
3880Sstevel@tonic-gate fatal("Name too long: %s\n", delim + 1);
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate *delim = savedelim;
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate if ((opfil = fopen(file, "w")) == NULL) {
3940Sstevel@tonic-gate (void) strcpy(tfile, file);
3950Sstevel@tonic-gate (void) sprintf(fptr, "%.*d", fiwidth, (ctr-2));
3960Sstevel@tonic-gate fatal("Cannot create %s\n", tfile);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate return (opfil);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate return (NULL);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate /*
4040Sstevel@tonic-gate * Getline gets a line via fgets from the input stream "infile".
4050Sstevel@tonic-gate * The line is put into linbuf and may not be larger than LINSIZ.
406*13093SRoger.Faulkner@Oracle.COM * If getaline is called with a non-zero value, the current line
4070Sstevel@tonic-gate * is bumped, otherwise it is not(for R.E. searching).
4080Sstevel@tonic-gate */
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate static char *
getaline(int bumpcur)411*13093SRoger.Faulkner@Oracle.COM getaline(int bumpcur)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate char *ret;
4140Sstevel@tonic-gate if (bumpcur)
4150Sstevel@tonic-gate curline++;
4160Sstevel@tonic-gate ret = fgets(linbuf, LINSIZ, infile);
4170Sstevel@tonic-gate return (ret);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate /*
4210Sstevel@tonic-gate * Line_arg handles line number arguments.
4220Sstevel@tonic-gate * line_arg takes as its argument a pointer to a character string
4230Sstevel@tonic-gate * (assumed to be a line number). If that character string can be
4240Sstevel@tonic-gate * converted to a number(long long), to_line is called with that number,
4250Sstevel@tonic-gate * otherwise error.
4260Sstevel@tonic-gate */
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate static void
line_arg(char * line)4290Sstevel@tonic-gate line_arg(char *line)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate long long to;
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate if (asc_to_ll(line, &to) == ERR)
4340Sstevel@tonic-gate fatal("%s: bad line number\n", line);
4350Sstevel@tonic-gate to_line(to);
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate
4380Sstevel@tonic-gate /*
4390Sstevel@tonic-gate * Num_arg handles repeat arguments.
4400Sstevel@tonic-gate * Num_arg copies the numeric argument to "rep" (error if number is
4410Sstevel@tonic-gate * larger than 20 characters or } is left off). Num_arg then converts
4420Sstevel@tonic-gate * the number and checks for validity. Next num_arg checks the mode
4430Sstevel@tonic-gate * of the previous argument, and applys the argument the correct number
4440Sstevel@tonic-gate * of times. If the mode is not set properly its an error.
4450Sstevel@tonic-gate */
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate static void
num_arg(char * arg,int md)4480Sstevel@tonic-gate num_arg(char *arg, int md)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate offset_t repeat, toline;
4510Sstevel@tonic-gate char rep[21];
4520Sstevel@tonic-gate char *ptr;
4530Sstevel@tonic-gate int len;
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate ptr = rep;
4560Sstevel@tonic-gate for (++arg; *arg != '}'; arg += len) {
4570Sstevel@tonic-gate if (*arg == NULL)
4580Sstevel@tonic-gate fatal("%s: missing '}'\n", targ);
4590Sstevel@tonic-gate if ((len = mblen(arg, MB_LEN_MAX)) <= 0)
4600Sstevel@tonic-gate len = 1;
4610Sstevel@tonic-gate if ((ptr + len) >= &rep[20])
4620Sstevel@tonic-gate fatal("%s: Repeat count too large\n", targ);
4630Sstevel@tonic-gate (void) memcpy(ptr, arg, len);
4640Sstevel@tonic-gate ptr += len;
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate *ptr = NULL;
4670Sstevel@tonic-gate if ((asc_to_ll(rep, &repeat) == ERR) || repeat < 0L)
4680Sstevel@tonic-gate fatal("Illegal repeat count: %s\n", targ);
4690Sstevel@tonic-gate if (md == LINMODE) {
4700Sstevel@tonic-gate toline = offset = curline;
4710Sstevel@tonic-gate for (; repeat > 0LL; repeat--) {
4720Sstevel@tonic-gate toline += offset;
4730Sstevel@tonic-gate to_line(toline);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate } else if (md == EXPMODE)
4760Sstevel@tonic-gate for (; repeat > 0LL; repeat--)
4770Sstevel@tonic-gate to_line(findline(expbuf, offset));
4780Sstevel@tonic-gate else
4790Sstevel@tonic-gate fatal("No operation for %s\n", targ);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate * Re_arg handles regular expression arguments.
4840Sstevel@tonic-gate * Re_arg takes a csplit regular expression argument. It checks for
4850Sstevel@tonic-gate * delimiter balance, computes any offset, and compiles the regular
4860Sstevel@tonic-gate * expression. Findline is called with the compiled expression and
4870Sstevel@tonic-gate * offset, and returns the corresponding line number, which is used
4880Sstevel@tonic-gate * as input to the to_line function.
4890Sstevel@tonic-gate */
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate static void
re_arg(char * string)4920Sstevel@tonic-gate re_arg(char *string)
4930Sstevel@tonic-gate {
4940Sstevel@tonic-gate char *ptr;
4950Sstevel@tonic-gate char ch;
4960Sstevel@tonic-gate int len;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate ch = *string;
4990Sstevel@tonic-gate ptr = string;
5000Sstevel@tonic-gate ptr++;
5010Sstevel@tonic-gate while (*ptr != ch) {
5020Sstevel@tonic-gate if (*ptr == '\\')
5030Sstevel@tonic-gate ++ptr;
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate if (*ptr == NULL)
5060Sstevel@tonic-gate fatal("%s: missing delimiter\n", targ);
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate if ((len = mblen(ptr, MB_LEN_MAX)) <= 0)
5090Sstevel@tonic-gate len = 1;
5100Sstevel@tonic-gate ptr += len;
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate /*
5140Sstevel@tonic-gate * The line below was added because compile no longer supports
5150Sstevel@tonic-gate * the fourth argument being passed. The fourth argument used
5160Sstevel@tonic-gate * to be '/' or '%'.
5170Sstevel@tonic-gate */
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate *ptr = NULL;
5200Sstevel@tonic-gate if (asc_to_ll(++ptr, &offset) == ERR)
5210Sstevel@tonic-gate fatal("%s: illegal offset\n", string);
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate * The line below was added because INIT which did this for us
5250Sstevel@tonic-gate * was removed from compile in regexp.h
5260Sstevel@tonic-gate */
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate string++;
5290Sstevel@tonic-gate expbuf = compile(string, (char *)0, (char *)0);
5300Sstevel@tonic-gate if (regerrno)
5310Sstevel@tonic-gate PERROR(regerrno);
5320Sstevel@tonic-gate to_line(findline(expbuf, offset));
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate /*
5360Sstevel@tonic-gate * Sig handles breaks. When a break occurs the signal is reset,
5370Sstevel@tonic-gate * and fatal is called to clean up and print the argument which
5380Sstevel@tonic-gate * was being processed at the time the interrupt occured.
5390Sstevel@tonic-gate */
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate /* ARGSUSED */
5420Sstevel@tonic-gate static void
sig(int s)5430Sstevel@tonic-gate sig(int s)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate (void) signal(SIGINT, sig);
5460Sstevel@tonic-gate fatal("Interrupt - program aborted at arg '%s'\n", targ);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate /*
5500Sstevel@tonic-gate * To_line creates split files.
5510Sstevel@tonic-gate * To_line gets as its argument the line which the current argument
5520Sstevel@tonic-gate * referenced. To_line calls getfile for a new output stream, which
5530Sstevel@tonic-gate * does nothing if create is False. If to_line's argument is not LAST
5540Sstevel@tonic-gate * it checks that the current line is not greater than its argument.
5550Sstevel@tonic-gate * While the current line is less than the desired line to_line gets
5560Sstevel@tonic-gate * lines and flushes(error if EOF is reached).
5570Sstevel@tonic-gate * If to_line's argument is LAST, it checks for more lines, and gets
5580Sstevel@tonic-gate * and flushes lines till the end of file.
5590Sstevel@tonic-gate * Finally, to_line calls closefile to close the output stream.
5600Sstevel@tonic-gate */
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate static void
to_line(offset_t ln)5630Sstevel@tonic-gate to_line(offset_t ln)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate outfile = getfile();
5660Sstevel@tonic-gate if (ln != LAST) {
5670Sstevel@tonic-gate if (curline > ln)
5680Sstevel@tonic-gate fatal("%s - out of range\n", targ);
5690Sstevel@tonic-gate while (curline < ln) {
570*13093SRoger.Faulkner@Oracle.COM if (getaline(TRUE) == NULL)
5710Sstevel@tonic-gate fatal("%s - out of range\n", targ);
5720Sstevel@tonic-gate flush();
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate } else /* last file */
575*13093SRoger.Faulkner@Oracle.COM if (getaline(TRUE) != NULL) {
5760Sstevel@tonic-gate flush();
5770Sstevel@tonic-gate for (;;) {
578*13093SRoger.Faulkner@Oracle.COM if (getaline(TRUE) == NULL)
5790Sstevel@tonic-gate break;
5800Sstevel@tonic-gate flush();
5810Sstevel@tonic-gate }
5820Sstevel@tonic-gate } else
5830Sstevel@tonic-gate fatal("%s - out of range\n", targ);
5840Sstevel@tonic-gate closefile();
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate static void
usage()5880Sstevel@tonic-gate usage()
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate (void) fprintf(stderr, gettext(
591*13093SRoger.Faulkner@Oracle.COM "usage: csplit [-ks] [-f prefix] [-n number] "
592*13093SRoger.Faulkner@Oracle.COM "file arg1 ...argn\n"));
5930Sstevel@tonic-gate exit(1);
5940Sstevel@tonic-gate }
595