From 4a1868023371fba8ab9f8f225d6f466e9aa47d77 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Wed, 20 Oct 1993 02:08:24 +0000 Subject: patch from rfg --- src/csplit.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 231 insertions(+), 20 deletions(-) diff --git a/src/csplit.c b/src/csplit.c index 48a11a8d8..4a40693d6 100644 --- a/src/csplit.c +++ b/src/csplit.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "regex.h" #include "system.h" #include "version.h" @@ -155,6 +156,9 @@ static char *filename_space = NULL; /* Prefix part of output file names. */ static char *prefix = NULL; +/* Suffix part of output file names. */ +static char *suffix = NULL; + /* Number of digits to use in output file names. */ static int digits = 2; @@ -167,6 +171,9 @@ static unsigned bytes_written; /* Output file pointer. */ static FILE *output_stream = NULL; +/* Output file name. */ +static char *output_filename = NULL; + /* Perhaps it would be cleaner to pass arg values instead of indexes. */ static char **global_argv; @@ -176,6 +183,9 @@ static boolean suppress_count; /* If TRUE, remove output files on error. */ static boolean remove_files; +/* If TRUE, remove all output files which have a zero length. */ +static boolean abandon_null_files; + /* The compiled pattern arguments, which determine how to split the input file. */ static struct control *controls; @@ -192,10 +202,12 @@ static int show_version; static struct option const longopts[] = { {"digits", required_argument, NULL, 'n'}, - {"quiet", no_argument, NULL, 's'}, + {"quiet", no_argument, NULL, 'q'}, {"silent", no_argument, NULL, 's'}, {"keep-files", no_argument, NULL, 'k'}, + {"abandon-null-files", no_argument, NULL, 'z'}, {"prefix", required_argument, NULL, 'f'}, + {"suffix", required_argument, NULL, 'b'}, {"help", no_argument, &show_help, 1}, {"version", no_argument, &show_version, 1}, {NULL, 0, NULL, 0} @@ -849,7 +861,19 @@ process_regexp (p, repetition) { line = find_line (++current_line); if (line == NULL) - regexp_error (p, repetition, ignore); + { + if (p->repeat == INT_MAX) + { + if (!ignore) + { + dump_rest_of_file (); + close_output_file (); + } + exit (0); + } + else + regexp_error (p, repetition, ignore); + } line_len = line->len; if (line->str[line_len - 1] == '\n') line_len--; @@ -877,7 +901,19 @@ process_regexp (p, repetition) { line = find_line (++current_line); if (line == NULL) - regexp_error (p, repetition, ignore); + { + if (p->repeat == INT_MAX) + { + if (!ignore) + { + dump_rest_of_file (); + close_output_file (); + } + exit (0); + } + else + regexp_error (p, repetition, ignore); + } line_len = line->len; if (line->str[line_len - 1] == '\n') line_len--; @@ -936,7 +972,11 @@ static char * make_filename (num) int num; { - sprintf (filename_space, "%s%0*d", prefix, digits, num); + strcpy (filename_space, prefix); + if (suffix) + sprintf (filename_space+strlen(prefix), suffix, num); + else + sprintf (filename_space+strlen(prefix), "%0*d", digits, num); return filename_space; } @@ -945,13 +985,11 @@ make_filename (num) static void create_output_file () { - char *name; - - name = make_filename (files_created); - output_stream = fopen (name, "w"); + output_filename = make_filename (files_created); + output_stream = fopen (output_filename, "w"); if (output_stream == NULL) { - error (0, errno, "%s", name); + error (0, errno, "%s", output_filename); cleanup (); } files_created++; @@ -984,11 +1022,18 @@ close_output_file () { if (fclose (output_stream) == EOF) { - error (0, errno, "write error"); + error (0, errno, "write error for `%s'", output_filename); cleanup (); } - if (!suppress_count) - fprintf (stdout, "%d\n", bytes_written); + if (bytes_written == 0 && abandon_null_files) + { + if (unlink (output_filename)) + error (0, errno, "%s", output_filename); + files_created--; + } + else + if (!suppress_count) + fprintf (stdout, "%d\n", bytes_written); output_stream = NULL; } } @@ -1112,9 +1157,12 @@ parse_repeat_count (argnum, p, str) error (1, 0, "%s: `}' is required in repeat count", str); *end = '\0'; - if (!string_to_number (&p->repeat, str + 1)) - error (1, 0, "%s}: integer required between `{' and `}'", - global_argv[argnum]); + if (str+1 == end-1 && *(str+1) == '*') + p->repeat = INT_MAX; + else + if (!string_to_number (&p->repeat, str + 1)) + error (1, 0, "%s}: integer required between `{' and `}'", + global_argv[argnum]); *end = '}'; } @@ -1200,6 +1248,156 @@ parse_patterns (argc, start, argv) } } +static unsigned +get_format_flags (format_ptr) + register char **format_ptr; +{ + register unsigned count = 0; + + for (; **format_ptr; (*format_ptr)++) + switch (**format_ptr) + { + case '-': + break; + + case '+': + count++; + break; + + case ' ': + count++; + break; + + case '#': + count += 2; /* Allow for 0x prefix preceeding an `x' conversion */ + break; + + default: + return count; + } +} + +static unsigned +get_format_width (format_ptr) + register char **format_ptr; +{ + register unsigned count = 0; + register char *start; + register int ch_save; + + start = *format_ptr; + for (; **format_ptr; (*format_ptr)++) + if (**format_ptr < '0' || **format_ptr > '9') + break; + + ch_save = **format_ptr; + **format_ptr = '\0'; + /* In the case where no minimum field width is explicitly specified, + allow for enough digits to encode (in octal) the value of LONG_MAX + for a 32 bit machine. If the user attempts to use csplit to create + anywhere near 077777777777 output files... well... he'll probably + run into other problems before he runs out of space in the area set + aside to hold the filenames. */ + count = (*format_ptr == start) ? 11 : atoi (start); + **format_ptr = ch_save; + return count; +} + +static unsigned +get_format_prec (format_ptr) + register char **format_ptr; +{ + register unsigned count = 0; + register char *start; + register int ch_save; + register int is_negative; + + if (**format_ptr != '.') + return 0; + (*format_ptr)++; + + if (**format_ptr == '-' || **format_ptr == '+') + { + is_negative = (**format_ptr == '-'); + (*format_ptr)++; + } + + start = *format_ptr; + for (; **format_ptr; (*format_ptr)++) + if (**format_ptr < '0' || **format_ptr > '9') + break; + + /* ANSI 4.9.6.1 says that is the precision is negative, it's as good as + not there. */ + if (is_negative) + start = *format_ptr; + + ch_save = **format_ptr; + **format_ptr = '\0'; + count = (*format_ptr == start) ? 11 : atoi (start); + **format_ptr = ch_save; + + return count; +} + +static void +get_format_conv_type (format_ptr) + register char **format_ptr; +{ + register int ch = *((*format_ptr)++); + + switch (ch) + { + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': + break; + + default: + if (ch < '~' && ch > ' ') + error (1, 0, "invalid conversion specifier in suffix: %c", ch); + else + error (1, 0, "invalid conversion specifier in suffix: \\%.3o", ch); + } +} + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +static unsigned +max_out (format) + char *format; +{ + register unsigned out_count = 0; + register unsigned percents = 0; + + for (; *format; ) + { + register int ch = *format++; + + if (ch != '%') + out_count++; + else + { + percents++; + out_count += get_format_flags (&format); + { + register width = get_format_width (&format); + register prec = get_format_prec (&format); + + out_count += max (width, prec); + } + get_format_conv_type (&format); + } + } + + if (percents == 0) + error (1, 0, "missing % conversion specification in suffix"); + else if (percents > 1) + error (1, 0, "too many % conversion specification in suffix"); + + return out_count; +} + static void interrupt_handler () { @@ -1256,7 +1454,7 @@ main (argc, argv) signal (SIGTERM, interrupt_handler); #endif - while ((optc = getopt_long (argc, argv, "f:kn:s", longopts, (int *) 0)) + while ((optc = getopt_long (argc, argv, "f:b:kn:sqz", longopts, (int *) 0)) != EOF) switch (optc) { @@ -1267,6 +1465,10 @@ main (argc, argv) prefix = optarg; break; + case 'b': + suffix = optarg; + break; + case 'k': remove_files = FALSE; break; @@ -1277,9 +1479,14 @@ main (argc, argv) break; case 's': + case 'q': suppress_count = TRUE; break; + case 'z': + abandon_null_files = TRUE; + break; + default: usage (); } @@ -1296,7 +1503,10 @@ main (argc, argv) if (optind >= argc - 1) usage (); - filename_space = (char *) xmalloc (strlen (prefix) + digits + 2); + if (suffix) + filename_space = (char *) xmalloc (strlen (prefix) + max_out (suffix) + 2); + else + filename_space = (char *) xmalloc (strlen (prefix) + digits + 2); set_input_file (argv[optind++]); @@ -1317,9 +1527,10 @@ static void usage () { fprintf (stderr, "\ -Usage: %s [-sk] [-f prefix] [-n digits] [--prefix=prefix]\n\ - [--digits=digits] [--quiet] [--silent] [--keep-files]\n\ - [--help] [--version] file pattern...\n", +Usage: %s [-sqkz] [-f prefix] [-b suffix] [-n digits] [--prefix=prefix]\n\ + [--suffix=suffix] [--digits=digits] [--quiet] [--silent]\n\ + [--keep-files] [--abandon-null-files] [--help] [--version]\n\ + file pattern...\n", program_name); exit (1); } -- cgit v1.2.3-70-g09d2