1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* 34*7c478bd9Sstevel@tonic-gate * csplit - Context or line file splitter 35*7c478bd9Sstevel@tonic-gate * Compile: cc -O -s -o csplit csplit.c 36*7c478bd9Sstevel@tonic-gate */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include <stdio.h> 39*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 40*7c478bd9Sstevel@tonic-gate #include <unistd.h> 41*7c478bd9Sstevel@tonic-gate #include <string.h> 42*7c478bd9Sstevel@tonic-gate #include <ctype.h> 43*7c478bd9Sstevel@tonic-gate #include <errno.h> 44*7c478bd9Sstevel@tonic-gate #include <limits.h> 45*7c478bd9Sstevel@tonic-gate #include <regexpr.h> 46*7c478bd9Sstevel@tonic-gate #include <signal.h> 47*7c478bd9Sstevel@tonic-gate #include <locale.h> 48*7c478bd9Sstevel@tonic-gate #include <libintl.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #define LAST 0LL 51*7c478bd9Sstevel@tonic-gate #define ERR -1 52*7c478bd9Sstevel@tonic-gate #define FALSE 0 53*7c478bd9Sstevel@tonic-gate #define TRUE 1 54*7c478bd9Sstevel@tonic-gate #define EXPMODE 2 55*7c478bd9Sstevel@tonic-gate #define LINMODE 3 56*7c478bd9Sstevel@tonic-gate #define LINSIZ LINE_MAX /* POSIX.2 - read lines LINE_MAX long */ 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* Globals */ 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate char linbuf[LINSIZ]; /* Input line buffer */ 61*7c478bd9Sstevel@tonic-gate char *expbuf; 62*7c478bd9Sstevel@tonic-gate char tmpbuf[BUFSIZ]; /* Temporary buffer for stdin */ 63*7c478bd9Sstevel@tonic-gate char file[8192] = "xx"; /* File name buffer */ 64*7c478bd9Sstevel@tonic-gate char *targ; /* Arg ptr for error messages */ 65*7c478bd9Sstevel@tonic-gate char *sptr; 66*7c478bd9Sstevel@tonic-gate FILE *infile, *outfile; /* I/O file streams */ 67*7c478bd9Sstevel@tonic-gate int silent, keep, create; /* Flags: -s(ilent), -k(eep), (create) */ 68*7c478bd9Sstevel@tonic-gate int errflg; 69*7c478bd9Sstevel@tonic-gate int fiwidth = 2; /* file index width (output file names) */ 70*7c478bd9Sstevel@tonic-gate extern int optind; 71*7c478bd9Sstevel@tonic-gate extern char *optarg; 72*7c478bd9Sstevel@tonic-gate offset_t offset; /* Regular expression offset value */ 73*7c478bd9Sstevel@tonic-gate offset_t curline; /* Current line in input file */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* 76*7c478bd9Sstevel@tonic-gate * These defines are needed for regexp handling(see regexp(7)) 77*7c478bd9Sstevel@tonic-gate */ 78*7c478bd9Sstevel@tonic-gate #define PERROR(x) fatal("%s: Illegal Regular Expression\n", targ); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate static int asc_to_ll(char *, long long *); 81*7c478bd9Sstevel@tonic-gate static void closefile(void); 82*7c478bd9Sstevel@tonic-gate static void fatal(char *, char *); 83*7c478bd9Sstevel@tonic-gate static offset_t findline(char *, offset_t); 84*7c478bd9Sstevel@tonic-gate static void flush(void); 85*7c478bd9Sstevel@tonic-gate static FILE *getfile(void); 86*7c478bd9Sstevel@tonic-gate static char *getline(int); 87*7c478bd9Sstevel@tonic-gate static void line_arg(char *); 88*7c478bd9Sstevel@tonic-gate static void num_arg(char *, int); 89*7c478bd9Sstevel@tonic-gate static void re_arg(char *); 90*7c478bd9Sstevel@tonic-gate static void sig(int); 91*7c478bd9Sstevel@tonic-gate static void to_line(offset_t); 92*7c478bd9Sstevel@tonic-gate static void usage(void); 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate int 95*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 96*7c478bd9Sstevel@tonic-gate { 97*7c478bd9Sstevel@tonic-gate int ch, mode; 98*7c478bd9Sstevel@tonic-gate char *ptr; 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 101*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 102*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 103*7c478bd9Sstevel@tonic-gate #endif 104*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, "skf:n:")) != EOF) { 107*7c478bd9Sstevel@tonic-gate switch (ch) { 108*7c478bd9Sstevel@tonic-gate case 'f': 109*7c478bd9Sstevel@tonic-gate (void) strcpy(file, optarg); 110*7c478bd9Sstevel@tonic-gate if ((ptr = strrchr(optarg, '/')) == NULL) 111*7c478bd9Sstevel@tonic-gate ptr = optarg; 112*7c478bd9Sstevel@tonic-gate else 113*7c478bd9Sstevel@tonic-gate ptr++; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate break; 116*7c478bd9Sstevel@tonic-gate case 'n': /* POSIX.2 */ 117*7c478bd9Sstevel@tonic-gate for (ptr = optarg; *ptr != NULL; ptr++) 118*7c478bd9Sstevel@tonic-gate if (!isdigit((int)*ptr)) 119*7c478bd9Sstevel@tonic-gate fatal("-n num\n", NULL); 120*7c478bd9Sstevel@tonic-gate fiwidth = atoi(optarg); 121*7c478bd9Sstevel@tonic-gate break; 122*7c478bd9Sstevel@tonic-gate case 'k': 123*7c478bd9Sstevel@tonic-gate keep++; 124*7c478bd9Sstevel@tonic-gate break; 125*7c478bd9Sstevel@tonic-gate case 's': 126*7c478bd9Sstevel@tonic-gate silent++; 127*7c478bd9Sstevel@tonic-gate break; 128*7c478bd9Sstevel@tonic-gate case '?': 129*7c478bd9Sstevel@tonic-gate errflg++; 130*7c478bd9Sstevel@tonic-gate } 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate argv = &argv[optind]; 134*7c478bd9Sstevel@tonic-gate argc -= optind; 135*7c478bd9Sstevel@tonic-gate if (argc <= 1 || errflg) 136*7c478bd9Sstevel@tonic-gate usage(); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate if (strcmp(*argv, "-") == 0) { 139*7c478bd9Sstevel@tonic-gate infile = tmpfile(); 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate while (fread(tmpbuf, 1, BUFSIZ, stdin) != 0) { 142*7c478bd9Sstevel@tonic-gate if (fwrite(tmpbuf, 1, BUFSIZ, infile) == 0) 143*7c478bd9Sstevel@tonic-gate if (errno == ENOSPC) { 144*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "csplit: "); 145*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 146*7c478bd9Sstevel@tonic-gate "No space left on device\n")); 147*7c478bd9Sstevel@tonic-gate exit(1); 148*7c478bd9Sstevel@tonic-gate } else { 149*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "csplit: "); 150*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 151*7c478bd9Sstevel@tonic-gate "Bad write to temporary " 152*7c478bd9Sstevel@tonic-gate "file\n")); 153*7c478bd9Sstevel@tonic-gate exit(1); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /* clear the buffer to get correct size when writing buffer */ 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate (void) memset(tmpbuf, '\0', sizeof (tmpbuf)); 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate rewind(infile); 161*7c478bd9Sstevel@tonic-gate } else if ((infile = fopen(*argv, "r")) == NULL) 162*7c478bd9Sstevel@tonic-gate fatal("Cannot open %s\n", *argv); 163*7c478bd9Sstevel@tonic-gate ++argv; 164*7c478bd9Sstevel@tonic-gate curline = (offset_t)1; 165*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, sig); 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate /* 168*7c478bd9Sstevel@tonic-gate * The following for loop handles the different argument types. 169*7c478bd9Sstevel@tonic-gate * A switch is performed on the first character of the argument 170*7c478bd9Sstevel@tonic-gate * and each case calls the appropriate argument handling routine. 171*7c478bd9Sstevel@tonic-gate */ 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate for (; *argv; ++argv) { 174*7c478bd9Sstevel@tonic-gate targ = *argv; 175*7c478bd9Sstevel@tonic-gate switch (**argv) { 176*7c478bd9Sstevel@tonic-gate case '/': 177*7c478bd9Sstevel@tonic-gate mode = EXPMODE; 178*7c478bd9Sstevel@tonic-gate create = TRUE; 179*7c478bd9Sstevel@tonic-gate re_arg(*argv); 180*7c478bd9Sstevel@tonic-gate break; 181*7c478bd9Sstevel@tonic-gate case '%': 182*7c478bd9Sstevel@tonic-gate mode = EXPMODE; 183*7c478bd9Sstevel@tonic-gate create = FALSE; 184*7c478bd9Sstevel@tonic-gate re_arg(*argv); 185*7c478bd9Sstevel@tonic-gate break; 186*7c478bd9Sstevel@tonic-gate case '{': 187*7c478bd9Sstevel@tonic-gate num_arg(*argv, mode); 188*7c478bd9Sstevel@tonic-gate mode = FALSE; 189*7c478bd9Sstevel@tonic-gate break; 190*7c478bd9Sstevel@tonic-gate default: 191*7c478bd9Sstevel@tonic-gate mode = LINMODE; 192*7c478bd9Sstevel@tonic-gate create = TRUE; 193*7c478bd9Sstevel@tonic-gate line_arg(*argv); 194*7c478bd9Sstevel@tonic-gate break; 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate create = TRUE; 198*7c478bd9Sstevel@tonic-gate to_line(LAST); 199*7c478bd9Sstevel@tonic-gate return (0); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * asc_to_ll takes an ascii argument(str) and converts it to a long long(plc) 204*7c478bd9Sstevel@tonic-gate * It returns ERR if an illegal character. The reason that asc_to_ll 205*7c478bd9Sstevel@tonic-gate * does not return an answer(long long) is that any value for the long 206*7c478bd9Sstevel@tonic-gate * long is legal, and this version of asc_to_ll detects error strings. 207*7c478bd9Sstevel@tonic-gate */ 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate static int 210*7c478bd9Sstevel@tonic-gate asc_to_ll(char *str, long long *plc) 211*7c478bd9Sstevel@tonic-gate { 212*7c478bd9Sstevel@tonic-gate int f; 213*7c478bd9Sstevel@tonic-gate *plc = 0; 214*7c478bd9Sstevel@tonic-gate f = 0; 215*7c478bd9Sstevel@tonic-gate for (; ; str++) { 216*7c478bd9Sstevel@tonic-gate switch (*str) { 217*7c478bd9Sstevel@tonic-gate case ' ': 218*7c478bd9Sstevel@tonic-gate case '\t': 219*7c478bd9Sstevel@tonic-gate continue; 220*7c478bd9Sstevel@tonic-gate case '-': 221*7c478bd9Sstevel@tonic-gate f++; 222*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 223*7c478bd9Sstevel@tonic-gate case '+': 224*7c478bd9Sstevel@tonic-gate str++; 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate break; 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate for (; *str != NULL; str++) 229*7c478bd9Sstevel@tonic-gate if (*str >= '0' && *str <= '9') 230*7c478bd9Sstevel@tonic-gate *plc = *plc * 10 + *str - '0'; 231*7c478bd9Sstevel@tonic-gate else 232*7c478bd9Sstevel@tonic-gate return (ERR); 233*7c478bd9Sstevel@tonic-gate if (f) 234*7c478bd9Sstevel@tonic-gate *plc = -(*plc); 235*7c478bd9Sstevel@tonic-gate return (TRUE); /* not error */ 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate /* 239*7c478bd9Sstevel@tonic-gate * Closefile prints the byte count of the file created,(via fseeko 240*7c478bd9Sstevel@tonic-gate * and ftello), if the create flag is on and the silent flag is not on. 241*7c478bd9Sstevel@tonic-gate * If the create flag is on closefile then closes the file(fclose). 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate static void 245*7c478bd9Sstevel@tonic-gate closefile() 246*7c478bd9Sstevel@tonic-gate { 247*7c478bd9Sstevel@tonic-gate if (!silent && create) { 248*7c478bd9Sstevel@tonic-gate (void) fseeko(outfile, (offset_t)0, SEEK_END); 249*7c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%lld\n", (offset_t)ftello(outfile)); 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate if (create) 252*7c478bd9Sstevel@tonic-gate (void) fclose(outfile); 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate /* 256*7c478bd9Sstevel@tonic-gate * Fatal handles error messages and cleanup. 257*7c478bd9Sstevel@tonic-gate * Because "arg" can be the global file, and the cleanup processing 258*7c478bd9Sstevel@tonic-gate * uses the global file, the error message is printed first. If the 259*7c478bd9Sstevel@tonic-gate * "keep" flag is not set, fatal unlinks all created files. If the 260*7c478bd9Sstevel@tonic-gate * "keep" flag is set, fatal closes the current file(if there is one). 261*7c478bd9Sstevel@tonic-gate * Fatal exits with a value of 1. 262*7c478bd9Sstevel@tonic-gate */ 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate static void 265*7c478bd9Sstevel@tonic-gate fatal(char *string, char *arg) 266*7c478bd9Sstevel@tonic-gate { 267*7c478bd9Sstevel@tonic-gate char *fls; 268*7c478bd9Sstevel@tonic-gate int num; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "csplit: "); 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* gettext dynamically replaces string */ 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(string), arg); 275*7c478bd9Sstevel@tonic-gate if (!keep) { 276*7c478bd9Sstevel@tonic-gate if (outfile) { 277*7c478bd9Sstevel@tonic-gate (void) fclose(outfile); 278*7c478bd9Sstevel@tonic-gate for (fls = file; *fls != '\0'; fls++) 279*7c478bd9Sstevel@tonic-gate continue; 280*7c478bd9Sstevel@tonic-gate fls -= fiwidth; 281*7c478bd9Sstevel@tonic-gate for (num = atoi(fls); num >= 0; num--) { 282*7c478bd9Sstevel@tonic-gate (void) sprintf(fls, "%.*d", fiwidth, num); 283*7c478bd9Sstevel@tonic-gate (void) unlink(file); 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate } else 287*7c478bd9Sstevel@tonic-gate if (outfile) 288*7c478bd9Sstevel@tonic-gate closefile(); 289*7c478bd9Sstevel@tonic-gate exit(1); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate /* 293*7c478bd9Sstevel@tonic-gate * Findline returns the line number referenced by the current argument. 294*7c478bd9Sstevel@tonic-gate * Its arguments are a pointer to the compiled regular expression(expr), 295*7c478bd9Sstevel@tonic-gate * and an offset(oset). The variable lncnt is used to count the number 296*7c478bd9Sstevel@tonic-gate * of lines searched. First the current stream location is saved via 297*7c478bd9Sstevel@tonic-gate * ftello(), and getline is called so that R.E. searching starts at the 298*7c478bd9Sstevel@tonic-gate * line after the previously referenced line. The while loop checks 299*7c478bd9Sstevel@tonic-gate * that there are more lines(error if none), bumps the line count, and 300*7c478bd9Sstevel@tonic-gate * checks for the R.E. on each line. If the R.E. matches on one of the 301*7c478bd9Sstevel@tonic-gate * lines the old stream location is restored, and the line number 302*7c478bd9Sstevel@tonic-gate * referenced by the R.E. and the offset is returned. 303*7c478bd9Sstevel@tonic-gate */ 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate static offset_t 306*7c478bd9Sstevel@tonic-gate findline(char *expr, offset_t oset) 307*7c478bd9Sstevel@tonic-gate { 308*7c478bd9Sstevel@tonic-gate static int benhere = 0; 309*7c478bd9Sstevel@tonic-gate offset_t lncnt = 0, saveloc; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate saveloc = ftello(infile); 312*7c478bd9Sstevel@tonic-gate if (curline != (offset_t)1 || benhere) /* If first line, first time, */ 313*7c478bd9Sstevel@tonic-gate (void) getline(FALSE); /* then don't skip */ 314*7c478bd9Sstevel@tonic-gate else 315*7c478bd9Sstevel@tonic-gate lncnt--; 316*7c478bd9Sstevel@tonic-gate benhere = 1; 317*7c478bd9Sstevel@tonic-gate while (getline(FALSE) != NULL) { 318*7c478bd9Sstevel@tonic-gate lncnt++; 319*7c478bd9Sstevel@tonic-gate if ((sptr = strrchr(linbuf, '\n')) != NULL) 320*7c478bd9Sstevel@tonic-gate *sptr = '\0'; 321*7c478bd9Sstevel@tonic-gate if (step(linbuf, expr)) { 322*7c478bd9Sstevel@tonic-gate (void) fseeko(infile, (offset_t)saveloc, SEEK_SET); 323*7c478bd9Sstevel@tonic-gate return (curline+lncnt+oset); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate (void) fseeko(infile, (offset_t)saveloc, SEEK_SET); 327*7c478bd9Sstevel@tonic-gate return (curline+lncnt+oset+2); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate /* 331*7c478bd9Sstevel@tonic-gate * Flush uses fputs to put lines on the output file stream(outfile) 332*7c478bd9Sstevel@tonic-gate * Since fputs does its own buffering, flush doesn't need to. 333*7c478bd9Sstevel@tonic-gate * Flush does nothing if the create flag is not set. 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate static void 337*7c478bd9Sstevel@tonic-gate flush() 338*7c478bd9Sstevel@tonic-gate { 339*7c478bd9Sstevel@tonic-gate if (create) 340*7c478bd9Sstevel@tonic-gate (void) fputs(linbuf, outfile); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate /* 344*7c478bd9Sstevel@tonic-gate * Getfile does nothing if the create flag is not set. If the create 345*7c478bd9Sstevel@tonic-gate * flag is set, getfile positions the file pointer(fptr) at the end of 346*7c478bd9Sstevel@tonic-gate * the file name prefix on the first call(fptr=0). The file counter is 347*7c478bd9Sstevel@tonic-gate * stored in the file name and incremented. If the subsequent fopen 348*7c478bd9Sstevel@tonic-gate * fails, the file name is copied to tfile for the error message, the 349*7c478bd9Sstevel@tonic-gate * previous file name is restored for cleanup, and fatal is called. If 350*7c478bd9Sstevel@tonic-gate * the fopen succeeds, the stream(opfil) is returned. 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate FILE * 354*7c478bd9Sstevel@tonic-gate getfile() 355*7c478bd9Sstevel@tonic-gate { 356*7c478bd9Sstevel@tonic-gate static char *fptr; 357*7c478bd9Sstevel@tonic-gate static int ctr; 358*7c478bd9Sstevel@tonic-gate FILE *opfil; 359*7c478bd9Sstevel@tonic-gate char tfile[15]; 360*7c478bd9Sstevel@tonic-gate char *delim; 361*7c478bd9Sstevel@tonic-gate char savedelim; 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate if (create) { 364*7c478bd9Sstevel@tonic-gate if (fptr == 0) 365*7c478bd9Sstevel@tonic-gate for (fptr = file; *fptr != NULL; fptr++); 366*7c478bd9Sstevel@tonic-gate (void) sprintf(fptr, "%.*d", fiwidth, ctr++); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* check for suffix length overflow */ 369*7c478bd9Sstevel@tonic-gate if (strlen(fptr) > fiwidth) { 370*7c478bd9Sstevel@tonic-gate fatal("Suffix longer than %ld chars; increase -n\n", 371*7c478bd9Sstevel@tonic-gate (char *)fiwidth); 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate /* check for filename length overflow */ 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate delim = strrchr(file, '/'); 377*7c478bd9Sstevel@tonic-gate if (delim == (char *)NULL) { 378*7c478bd9Sstevel@tonic-gate if (strlen(file) > pathconf(".", _PC_NAME_MAX)) { 379*7c478bd9Sstevel@tonic-gate fatal("Name too long: %s\n", file); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate } else { 382*7c478bd9Sstevel@tonic-gate /* truncate file at pathname delim to do pathconf */ 383*7c478bd9Sstevel@tonic-gate savedelim = *delim; 384*7c478bd9Sstevel@tonic-gate *delim = '\0'; 385*7c478bd9Sstevel@tonic-gate /* 386*7c478bd9Sstevel@tonic-gate * file: pppppppp\0fffff\0 387*7c478bd9Sstevel@tonic-gate * ..... ^ file 388*7c478bd9Sstevel@tonic-gate * ............. ^ delim 389*7c478bd9Sstevel@tonic-gate */ 390*7c478bd9Sstevel@tonic-gate if (strlen(delim + 1) > pathconf(file, _PC_NAME_MAX)) { 391*7c478bd9Sstevel@tonic-gate fatal("Name too long: %s\n", delim + 1); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate *delim = savedelim; 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate if ((opfil = fopen(file, "w")) == NULL) { 397*7c478bd9Sstevel@tonic-gate (void) strcpy(tfile, file); 398*7c478bd9Sstevel@tonic-gate (void) sprintf(fptr, "%.*d", fiwidth, (ctr-2)); 399*7c478bd9Sstevel@tonic-gate fatal("Cannot create %s\n", tfile); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate return (opfil); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate return (NULL); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* 407*7c478bd9Sstevel@tonic-gate * Getline gets a line via fgets from the input stream "infile". 408*7c478bd9Sstevel@tonic-gate * The line is put into linbuf and may not be larger than LINSIZ. 409*7c478bd9Sstevel@tonic-gate * If getline is called with a non-zero value, the current line 410*7c478bd9Sstevel@tonic-gate * is bumped, otherwise it is not(for R.E. searching). 411*7c478bd9Sstevel@tonic-gate */ 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate static char * 414*7c478bd9Sstevel@tonic-gate getline(int bumpcur) 415*7c478bd9Sstevel@tonic-gate { 416*7c478bd9Sstevel@tonic-gate char *ret; 417*7c478bd9Sstevel@tonic-gate if (bumpcur) 418*7c478bd9Sstevel@tonic-gate curline++; 419*7c478bd9Sstevel@tonic-gate ret = fgets(linbuf, LINSIZ, infile); 420*7c478bd9Sstevel@tonic-gate return (ret); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate /* 424*7c478bd9Sstevel@tonic-gate * Line_arg handles line number arguments. 425*7c478bd9Sstevel@tonic-gate * line_arg takes as its argument a pointer to a character string 426*7c478bd9Sstevel@tonic-gate * (assumed to be a line number). If that character string can be 427*7c478bd9Sstevel@tonic-gate * converted to a number(long long), to_line is called with that number, 428*7c478bd9Sstevel@tonic-gate * otherwise error. 429*7c478bd9Sstevel@tonic-gate */ 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate static void 432*7c478bd9Sstevel@tonic-gate line_arg(char *line) 433*7c478bd9Sstevel@tonic-gate { 434*7c478bd9Sstevel@tonic-gate long long to; 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate if (asc_to_ll(line, &to) == ERR) 437*7c478bd9Sstevel@tonic-gate fatal("%s: bad line number\n", line); 438*7c478bd9Sstevel@tonic-gate to_line(to); 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* 442*7c478bd9Sstevel@tonic-gate * Num_arg handles repeat arguments. 443*7c478bd9Sstevel@tonic-gate * Num_arg copies the numeric argument to "rep" (error if number is 444*7c478bd9Sstevel@tonic-gate * larger than 20 characters or } is left off). Num_arg then converts 445*7c478bd9Sstevel@tonic-gate * the number and checks for validity. Next num_arg checks the mode 446*7c478bd9Sstevel@tonic-gate * of the previous argument, and applys the argument the correct number 447*7c478bd9Sstevel@tonic-gate * of times. If the mode is not set properly its an error. 448*7c478bd9Sstevel@tonic-gate */ 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate static void 451*7c478bd9Sstevel@tonic-gate num_arg(char *arg, int md) 452*7c478bd9Sstevel@tonic-gate { 453*7c478bd9Sstevel@tonic-gate offset_t repeat, toline; 454*7c478bd9Sstevel@tonic-gate char rep[21]; 455*7c478bd9Sstevel@tonic-gate char *ptr; 456*7c478bd9Sstevel@tonic-gate int len; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate ptr = rep; 459*7c478bd9Sstevel@tonic-gate for (++arg; *arg != '}'; arg += len) { 460*7c478bd9Sstevel@tonic-gate if (*arg == NULL) 461*7c478bd9Sstevel@tonic-gate fatal("%s: missing '}'\n", targ); 462*7c478bd9Sstevel@tonic-gate if ((len = mblen(arg, MB_LEN_MAX)) <= 0) 463*7c478bd9Sstevel@tonic-gate len = 1; 464*7c478bd9Sstevel@tonic-gate if ((ptr + len) >= &rep[20]) 465*7c478bd9Sstevel@tonic-gate fatal("%s: Repeat count too large\n", targ); 466*7c478bd9Sstevel@tonic-gate (void) memcpy(ptr, arg, len); 467*7c478bd9Sstevel@tonic-gate ptr += len; 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate *ptr = NULL; 470*7c478bd9Sstevel@tonic-gate if ((asc_to_ll(rep, &repeat) == ERR) || repeat < 0L) 471*7c478bd9Sstevel@tonic-gate fatal("Illegal repeat count: %s\n", targ); 472*7c478bd9Sstevel@tonic-gate if (md == LINMODE) { 473*7c478bd9Sstevel@tonic-gate toline = offset = curline; 474*7c478bd9Sstevel@tonic-gate for (; repeat > 0LL; repeat--) { 475*7c478bd9Sstevel@tonic-gate toline += offset; 476*7c478bd9Sstevel@tonic-gate to_line(toline); 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate } else if (md == EXPMODE) 479*7c478bd9Sstevel@tonic-gate for (; repeat > 0LL; repeat--) 480*7c478bd9Sstevel@tonic-gate to_line(findline(expbuf, offset)); 481*7c478bd9Sstevel@tonic-gate else 482*7c478bd9Sstevel@tonic-gate fatal("No operation for %s\n", targ); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * Re_arg handles regular expression arguments. 487*7c478bd9Sstevel@tonic-gate * Re_arg takes a csplit regular expression argument. It checks for 488*7c478bd9Sstevel@tonic-gate * delimiter balance, computes any offset, and compiles the regular 489*7c478bd9Sstevel@tonic-gate * expression. Findline is called with the compiled expression and 490*7c478bd9Sstevel@tonic-gate * offset, and returns the corresponding line number, which is used 491*7c478bd9Sstevel@tonic-gate * as input to the to_line function. 492*7c478bd9Sstevel@tonic-gate */ 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate static void 495*7c478bd9Sstevel@tonic-gate re_arg(char *string) 496*7c478bd9Sstevel@tonic-gate { 497*7c478bd9Sstevel@tonic-gate char *ptr; 498*7c478bd9Sstevel@tonic-gate char ch; 499*7c478bd9Sstevel@tonic-gate int len; 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate ch = *string; 502*7c478bd9Sstevel@tonic-gate ptr = string; 503*7c478bd9Sstevel@tonic-gate ptr++; 504*7c478bd9Sstevel@tonic-gate while (*ptr != ch) { 505*7c478bd9Sstevel@tonic-gate if (*ptr == '\\') 506*7c478bd9Sstevel@tonic-gate ++ptr; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate if (*ptr == NULL) 509*7c478bd9Sstevel@tonic-gate fatal("%s: missing delimiter\n", targ); 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate if ((len = mblen(ptr, MB_LEN_MAX)) <= 0) 512*7c478bd9Sstevel@tonic-gate len = 1; 513*7c478bd9Sstevel@tonic-gate ptr += len; 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate /* 517*7c478bd9Sstevel@tonic-gate * The line below was added because compile no longer supports 518*7c478bd9Sstevel@tonic-gate * the fourth argument being passed. The fourth argument used 519*7c478bd9Sstevel@tonic-gate * to be '/' or '%'. 520*7c478bd9Sstevel@tonic-gate */ 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate *ptr = NULL; 523*7c478bd9Sstevel@tonic-gate if (asc_to_ll(++ptr, &offset) == ERR) 524*7c478bd9Sstevel@tonic-gate fatal("%s: illegal offset\n", string); 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate /* 527*7c478bd9Sstevel@tonic-gate * The line below was added because INIT which did this for us 528*7c478bd9Sstevel@tonic-gate * was removed from compile in regexp.h 529*7c478bd9Sstevel@tonic-gate */ 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate string++; 532*7c478bd9Sstevel@tonic-gate expbuf = compile(string, (char *)0, (char *)0); 533*7c478bd9Sstevel@tonic-gate if (regerrno) 534*7c478bd9Sstevel@tonic-gate PERROR(regerrno); 535*7c478bd9Sstevel@tonic-gate to_line(findline(expbuf, offset)); 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate /* 539*7c478bd9Sstevel@tonic-gate * Sig handles breaks. When a break occurs the signal is reset, 540*7c478bd9Sstevel@tonic-gate * and fatal is called to clean up and print the argument which 541*7c478bd9Sstevel@tonic-gate * was being processed at the time the interrupt occured. 542*7c478bd9Sstevel@tonic-gate */ 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 545*7c478bd9Sstevel@tonic-gate static void 546*7c478bd9Sstevel@tonic-gate sig(int s) 547*7c478bd9Sstevel@tonic-gate { 548*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, sig); 549*7c478bd9Sstevel@tonic-gate fatal("Interrupt - program aborted at arg '%s'\n", targ); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * To_line creates split files. 554*7c478bd9Sstevel@tonic-gate * To_line gets as its argument the line which the current argument 555*7c478bd9Sstevel@tonic-gate * referenced. To_line calls getfile for a new output stream, which 556*7c478bd9Sstevel@tonic-gate * does nothing if create is False. If to_line's argument is not LAST 557*7c478bd9Sstevel@tonic-gate * it checks that the current line is not greater than its argument. 558*7c478bd9Sstevel@tonic-gate * While the current line is less than the desired line to_line gets 559*7c478bd9Sstevel@tonic-gate * lines and flushes(error if EOF is reached). 560*7c478bd9Sstevel@tonic-gate * If to_line's argument is LAST, it checks for more lines, and gets 561*7c478bd9Sstevel@tonic-gate * and flushes lines till the end of file. 562*7c478bd9Sstevel@tonic-gate * Finally, to_line calls closefile to close the output stream. 563*7c478bd9Sstevel@tonic-gate */ 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate static void 566*7c478bd9Sstevel@tonic-gate to_line(offset_t ln) 567*7c478bd9Sstevel@tonic-gate { 568*7c478bd9Sstevel@tonic-gate outfile = getfile(); 569*7c478bd9Sstevel@tonic-gate if (ln != LAST) { 570*7c478bd9Sstevel@tonic-gate if (curline > ln) 571*7c478bd9Sstevel@tonic-gate fatal("%s - out of range\n", targ); 572*7c478bd9Sstevel@tonic-gate while (curline < ln) { 573*7c478bd9Sstevel@tonic-gate if (getline(TRUE) == NULL) 574*7c478bd9Sstevel@tonic-gate fatal("%s - out of range\n", targ); 575*7c478bd9Sstevel@tonic-gate flush(); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate } else /* last file */ 578*7c478bd9Sstevel@tonic-gate if (getline(TRUE) != NULL) { 579*7c478bd9Sstevel@tonic-gate flush(); 580*7c478bd9Sstevel@tonic-gate for (;;) { 581*7c478bd9Sstevel@tonic-gate if (getline(TRUE) == NULL) 582*7c478bd9Sstevel@tonic-gate break; 583*7c478bd9Sstevel@tonic-gate flush(); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate } else 586*7c478bd9Sstevel@tonic-gate fatal("%s - out of range\n", targ); 587*7c478bd9Sstevel@tonic-gate closefile(); 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate static void 591*7c478bd9Sstevel@tonic-gate usage() 592*7c478bd9Sstevel@tonic-gate { 593*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 594*7c478bd9Sstevel@tonic-gate "usage: csplit [-ks] [-f prefix] [-n number] " 595*7c478bd9Sstevel@tonic-gate "file arg1 ...argn\n")); 596*7c478bd9Sstevel@tonic-gate exit(1); 597*7c478bd9Sstevel@tonic-gate } 598