From 14390d1fed75bd2efd7fa1bf5fe977eb51c5d2cf Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Tue, 17 Oct 1995 13:13:19 +0000 Subject: Protoize. Reorder functions to obviate forward dcls. Remove forward dcls. --- src/cat.c | 816 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 404 insertions(+), 412 deletions(-) (limited to 'src/cat.c') diff --git a/src/cat.c b/src/cat.c index d216c33d9..a4421ee8c 100644 --- a/src/cat.c +++ b/src/cat.c @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + /* Differences from the Unix cat: * Always unbuffered, -u is ignored. * Usually much faster than other versions of cat, the difference @@ -43,10 +43,6 @@ char *xmalloc (); int full_write (); int safe_read (); -static void cat (); -static void next_line_num (); -static void simple_cat (); - /* Name under which this program was invoked. */ char *program_name; @@ -114,433 +110,164 @@ With no FILE, or when FILE is -, read standard input.\n\ exit (status); } - -void -main (argc, argv) - int argc; - char *argv[]; -{ - /* Optimal size of i/o operations of output. */ - int outsize; - - /* Optimal size of i/o operations of input. */ - int insize; - - /* Pointer to the input buffer. */ - unsigned char *inbuf; +/* Compute the next line number. */ - /* Pointer to the output buffer. */ - unsigned char *outbuf; +static void +next_line_num () +{ + char *endp = line_num_end; + do + { + if ((*endp)++ < '9') + return; + *endp-- = '0'; + } + while (endp >= line_num_start); + *--line_num_start = '1'; + if (line_num_start < line_num_print) + line_num_print--; +} - int c; +/* Plain cat. Copies the file behind `input_desc' to the file behind + `output_desc'. */ - /* Index in argv to processed argument. */ - int argind; +static void +simple_cat ( + /* Pointer to the buffer, used by reads and writes. */ + unsigned char *buf, - /* Device number of the output (file or whatever). */ - int out_dev; + /* Number of characters preferably read or written by each read and write + call. */ + int bufsize) +{ + /* Actual number of characters read, and therefore written. */ + int n_read; - /* I-node number of the output. */ - int out_ino; + /* Loop until the end of the file. */ - /* Nonzero if the output file should not be the same as any input file. */ - int check_redirection = 1; + for (;;) + { + /* Read a block of input. */ - /* Nonzero if we have ever read standard input. */ - int have_read_stdin = 0; + n_read = safe_read (input_desc, buf, bufsize); + if (n_read < 0) + { + error (0, errno, "%s", infile); + exit_stat = 1; + return; + } - struct stat stat_buf; + /* End of this file? */ - /* Variables that are set according to the specified options. */ - int numbers = 0; - int numbers_at_empty_lines = 1; - int squeeze_empty_lines = 0; - int mark_line_ends = 0; - int quote = 0; - int output_tabs = 1; + if (n_read == 0) + break; -/* If non-zero, call cat, otherwise call simple_cat to do the actual work. */ - int options = 0; + /* Write this block out. */ - /* If non-zero, display usage information and exit. */ - static int show_help; + if (full_write (output_desc, buf, n_read) < 0) + error (1, errno, _("write error")); + } +} - /* If non-zero, print the version on standard output then exit. */ - static int show_version; +/* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC. + Called if any option more than -u was specified. - static struct option const long_options[] = - { - {"number-nonblank", no_argument, NULL, 'b'}, - {"number", no_argument, NULL, 'n'}, - {"squeeze-blank", no_argument, NULL, 's'}, - {"show-nonprinting", no_argument, NULL, 'v'}, - {"show-ends", no_argument, NULL, 'E'}, - {"show-tabs", no_argument, NULL, 'T'}, - {"show-all", no_argument, NULL, 'A'}, - {"help", no_argument, &show_help, 1}, - {"version", no_argument, &show_version, 1}, - {NULL, 0, NULL, 0} - }; + A newline character is always put at the end of the buffer, to make + an explicit test for buffer end unnecessary. */ - program_name = argv[0]; +static void +cat ( + /* Pointer to the beginning of the input buffer. */ + unsigned char *inbuf, - /* Parse command line options. */ + /* Number of characters read in each read call. */ + int insize, - while ((c = getopt_long (argc, argv, "benstuvAET", long_options, (int *) 0)) - != EOF) - { - switch (c) - { - case 0: - break; + /* Pointer to the beginning of the output buffer. */ + unsigned char *outbuf, - case 'b': - ++options; - numbers = 1; - numbers_at_empty_lines = 0; - break; + /* Number of characters written by each write call. */ + int outsize, - case 'e': - ++options; - mark_line_ends = 1; - quote = 1; - break; + /* Variables that have values according to the specified options. */ + int quote, + int output_tabs, + int numbers, + int numbers_at_empty_lines, + int mark_line_ends, + int squeeze_empty_lines) +{ + /* Last character read from the input buffer. */ + unsigned char ch; - case 'n': - ++options; - numbers = 1; - break; + /* Pointer to the next character in the input buffer. */ + unsigned char *bpin; - case 's': - ++options; - squeeze_empty_lines = 1; - break; + /* Pointer to the first non-valid byte in the input buffer, i.e. the + current end of the buffer. */ + unsigned char *eob; - case 't': - ++options; - output_tabs = 0; - quote = 1; - break; + /* Pointer to the position where the next character shall be written. */ + unsigned char *bpout; - case 'u': - /* We provide the -u feature unconditionally. */ - break; + /* Number of characters read by the last read call. */ + int n_read; - case 'v': - ++options; - quote = 1; - break; + /* Determines how many consecutive newlines there have been in the + input. 0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1, + etc. Initially 0 to indicate that we are at the beginning of a + new line. The "state" of the procedure is determined by + NEWLINES. */ + int newlines = newlines2; - case 'A': - ++options; - quote = 1; - mark_line_ends = 1; - output_tabs = 0; - break; +#ifdef FIONREAD + /* If nonzero, use the FIONREAD ioctl, as an optimization. + (On Ultrix, it is not supported on NFS filesystems.) */ + int use_fionread = 1; +#endif - case 'E': - ++options; - mark_line_ends = 1; - break; + /* The inbuf pointers are initialized so that BPIN > EOB, and thereby input + is read immediately. */ - case 'T': - ++options; - output_tabs = 0; - break; + eob = inbuf; + bpin = eob + 1; - default: - usage (2); - } - } + bpout = outbuf; - if (show_version) + for (;;) { - printf ("cat - %s\n", version_string); - exit (0); - } - - if (show_help) - usage (0); - - output_desc = 1; + do + { + /* Write if there are at least OUTSIZE bytes in OUTBUF. */ - /* Get device, i-node number, and optimal blocksize of output. */ + if (bpout - outbuf >= outsize) + { + unsigned char *wp = outbuf; + do + { + if (full_write (output_desc, wp, outsize) < 0) + error (1, errno, _("write error")); + wp += outsize; + } + while (bpout - wp >= outsize); - if (fstat (output_desc, &stat_buf) < 0) - error (1, errno, _("standard output")); + /* Move the remaining bytes to the beginning of the + buffer. */ - outsize = ST_BLKSIZE (stat_buf); - /* Input file can be output file for non-regular files. - fstat on pipes returns S_IFSOCK on some systems, S_IFIFO - on others, so the checking should not be done for those types, - and to allow things like cat < /dev/tty > /dev/tty, checking - is not done for device files either. */ + memmove (outbuf, wp, bpout - wp); + bpout = outbuf + (bpout - wp); + } - if (S_ISREG (stat_buf.st_mode)) - { - out_dev = stat_buf.st_dev; - out_ino = stat_buf.st_ino; - } - else - { - check_redirection = 0; -#ifdef lint /* Suppress `used before initialized' warning. */ - out_dev = 0; - out_ino = 0; -#endif - } + /* Is INBUF empty? */ - /* Check if any of the input files are the same as the output file. */ + if (bpin > eob) + { +#ifdef FIONREAD + int n_to_read = 0; - /* Main loop. */ - - infile = "-"; - argind = optind; - - do - { - if (argind < argc) - infile = argv[argind]; - - if (infile[0] == '-' && infile[1] == 0) - { - have_read_stdin = 1; - input_desc = 0; - } - else - { - input_desc = open (infile, O_RDONLY); - if (input_desc < 0) - { - error (0, errno, "%s", infile); - exit_stat = 1; - continue; - } - } - - if (fstat (input_desc, &stat_buf) < 0) - { - error (0, errno, "%s", infile); - exit_stat = 1; - goto contin; - } - insize = ST_BLKSIZE (stat_buf); - - /* Compare the device and i-node numbers of this input file with - the corresponding values of the (output file associated with) - stdout, and skip this input file if they coincide. Input - files cannot be redirected to themselves. */ - - if (check_redirection - && stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino) - { - error (0, 0, _("%s: input file is output file"), infile); - exit_stat = 1; - goto contin; - } - - /* Select which version of `cat' to use. If any options (more than -u, - --version, or --help) were specified, use `cat', otherwise use - `simple_cat'. */ - - if (options == 0) - { - insize = max (insize, outsize); - inbuf = (unsigned char *) xmalloc (insize); - - simple_cat (inbuf, insize); - } - else - { - inbuf = (unsigned char *) xmalloc (insize + 1); - - /* Why are (OUTSIZE - 1 + INSIZE * 4 + 13) bytes allocated for - the output buffer? - - A test whether output needs to be written is done when the input - buffer empties or when a newline appears in the input. After - output is written, at most (OUTSIZE - 1) bytes will remain in the - buffer. Now INSIZE bytes of input is read. Each input character - may grow by a factor of 4 (by the prepending of M-^). If all - characters do, and no newlines appear in this block of input, we - will have at most (OUTSIZE - 1 + INSIZE) bytes in the buffer. If - the last character in the preceding block of input was a - newline, a line number may be written (according to the given - options) as the first thing in the output buffer. (Done after the - new input is read, but before processing of the input begins.) A - line number requires seldom more than 13 positions. */ - - outbuf = (unsigned char *) xmalloc (outsize - 1 + insize * 4 + 13); - - cat (inbuf, insize, outbuf, outsize, quote, - output_tabs, numbers, numbers_at_empty_lines, mark_line_ends, - squeeze_empty_lines); - - free (outbuf); - } - - free (inbuf); - - contin: - if (strcmp (infile, "-") && close (input_desc) < 0) - { - error (0, errno, "%s", infile); - exit_stat = 1; - } - } - while (++argind < argc); - - if (have_read_stdin && close (0) < 0) - error (1, errno, "-"); - if (close (1) < 0) - error (1, errno, _("write error")); - - exit (exit_stat); -} - -/* Plain cat. Copies the file behind `input_desc' to the file behind - `output_desc'. */ - -static void -simple_cat (buf, bufsize) - /* Pointer to the buffer, used by reads and writes. */ - unsigned char *buf; - - /* Number of characters preferably read or written by each read and write - call. */ - int bufsize; -{ - /* Actual number of characters read, and therefore written. */ - int n_read; - - /* Loop until the end of the file. */ - - for (;;) - { - /* Read a block of input. */ - - n_read = safe_read (input_desc, buf, bufsize); - if (n_read < 0) - { - error (0, errno, "%s", infile); - exit_stat = 1; - return; - } - - /* End of this file? */ - - if (n_read == 0) - break; - - /* Write this block out. */ - - if (full_write (output_desc, buf, n_read) < 0) - error (1, errno, _("write error")); - } -} - -/* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC. - Called if any option more than -u was specified. - - A newline character is always put at the end of the buffer, to make - an explicit test for buffer end unnecessary. */ - -static void -cat (inbuf, insize, outbuf, outsize, quote, - output_tabs, numbers, numbers_at_empty_lines, - mark_line_ends, squeeze_empty_lines) - - /* Pointer to the beginning of the input buffer. */ - unsigned char *inbuf; - - /* Number of characters read in each read call. */ - int insize; - - /* Pointer to the beginning of the output buffer. */ - unsigned char *outbuf; - - /* Number of characters written by each write call. */ - int outsize; - - /* Variables that have values according to the specified options. */ - int quote; - int output_tabs; - int numbers; - int numbers_at_empty_lines; - int mark_line_ends; - int squeeze_empty_lines; -{ - /* Last character read from the input buffer. */ - unsigned char ch; - - /* Pointer to the next character in the input buffer. */ - unsigned char *bpin; - - /* Pointer to the first non-valid byte in the input buffer, i.e. the - current end of the buffer. */ - unsigned char *eob; - - /* Pointer to the position where the next character shall be written. */ - unsigned char *bpout; - - /* Number of characters read by the last read call. */ - int n_read; - - /* Determines how many consecutive newlines there have been in the - input. 0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1, - etc. Initially 0 to indicate that we are at the beginning of a - new line. The "state" of the procedure is determined by - NEWLINES. */ - int newlines = newlines2; - -#ifdef FIONREAD - /* If nonzero, use the FIONREAD ioctl, as an optimization. - (On Ultrix, it is not supported on NFS filesystems.) */ - int use_fionread = 1; -#endif - - /* The inbuf pointers are initialized so that BPIN > EOB, and thereby input - is read immediately. */ - - eob = inbuf; - bpin = eob + 1; - - bpout = outbuf; - - for (;;) - { - do - { - /* Write if there are at least OUTSIZE bytes in OUTBUF. */ - - if (bpout - outbuf >= outsize) - { - unsigned char *wp = outbuf; - do - { - if (full_write (output_desc, wp, outsize) < 0) - error (1, errno, _("write error")); - wp += outsize; - } - while (bpout - wp >= outsize); - - /* Move the remaining bytes to the beginning of the - buffer. */ - - memmove (outbuf, wp, bpout - wp); - bpout = outbuf + (bpout - wp); - } - - /* Is INBUF empty? */ - - if (bpin > eob) - { -#ifdef FIONREAD - int n_to_read = 0; - - /* Is there any input to read immediately? - If not, we are about to wait, - so write all buffered output before waiting. */ + /* Is there any input to read immediately? + If not, we are about to wait, + so write all buffered output before waiting. */ if (use_fionread && ioctl (input_desc, FIONREAD, &n_to_read) < 0) @@ -713,20 +440,285 @@ cat (inbuf, insize, outbuf, outsize, quote, } } -/* Compute the next line number. */ - -static void -next_line_num () +void +main (argc, argv) + int argc; + char *argv[]; { - char *endp = line_num_end; - do - { - if ((*endp)++ < '9') - return; - *endp-- = '0'; - } - while (endp >= line_num_start); - *--line_num_start = '1'; - if (line_num_start < line_num_print) - line_num_print--; + /* Optimal size of i/o operations of output. */ + int outsize; + + /* Optimal size of i/o operations of input. */ + int insize; + + /* Pointer to the input buffer. */ + unsigned char *inbuf; + + /* Pointer to the output buffer. */ + unsigned char *outbuf; + + int c; + + /* Index in argv to processed argument. */ + int argind; + + /* Device number of the output (file or whatever). */ + int out_dev; + + /* I-node number of the output. */ + int out_ino; + + /* Nonzero if the output file should not be the same as any input file. */ + int check_redirection = 1; + + /* Nonzero if we have ever read standard input. */ + int have_read_stdin = 0; + + struct stat stat_buf; + + /* Variables that are set according to the specified options. */ + int numbers = 0; + int numbers_at_empty_lines = 1; + int squeeze_empty_lines = 0; + int mark_line_ends = 0; + int quote = 0; + int output_tabs = 1; + +/* If non-zero, call cat, otherwise call simple_cat to do the actual work. */ + int options = 0; + + /* If non-zero, display usage information and exit. */ + static int show_help; + + /* If non-zero, print the version on standard output then exit. */ + static int show_version; + + static struct option const long_options[] = + { + {"number-nonblank", no_argument, NULL, 'b'}, + {"number", no_argument, NULL, 'n'}, + {"squeeze-blank", no_argument, NULL, 's'}, + {"show-nonprinting", no_argument, NULL, 'v'}, + {"show-ends", no_argument, NULL, 'E'}, + {"show-tabs", no_argument, NULL, 'T'}, + {"show-all", no_argument, NULL, 'A'}, + {"help", no_argument, &show_help, 1}, + {"version", no_argument, &show_version, 1}, + {NULL, 0, NULL, 0} + }; + + program_name = argv[0]; + + /* Parse command line options. */ + + while ((c = getopt_long (argc, argv, "benstuvAET", long_options, (int *) 0)) + != EOF) + { + switch (c) + { + case 0: + break; + + case 'b': + ++options; + numbers = 1; + numbers_at_empty_lines = 0; + break; + + case 'e': + ++options; + mark_line_ends = 1; + quote = 1; + break; + + case 'n': + ++options; + numbers = 1; + break; + + case 's': + ++options; + squeeze_empty_lines = 1; + break; + + case 't': + ++options; + output_tabs = 0; + quote = 1; + break; + + case 'u': + /* We provide the -u feature unconditionally. */ + break; + + case 'v': + ++options; + quote = 1; + break; + + case 'A': + ++options; + quote = 1; + mark_line_ends = 1; + output_tabs = 0; + break; + + case 'E': + ++options; + mark_line_ends = 1; + break; + + case 'T': + ++options; + output_tabs = 0; + break; + + default: + usage (2); + } + } + + if (show_version) + { + printf ("cat - %s\n", version_string); + exit (0); + } + + if (show_help) + usage (0); + + output_desc = 1; + + /* Get device, i-node number, and optimal blocksize of output. */ + + if (fstat (output_desc, &stat_buf) < 0) + error (1, errno, _("standard output")); + + outsize = ST_BLKSIZE (stat_buf); + /* Input file can be output file for non-regular files. + fstat on pipes returns S_IFSOCK on some systems, S_IFIFO + on others, so the checking should not be done for those types, + and to allow things like cat < /dev/tty > /dev/tty, checking + is not done for device files either. */ + + if (S_ISREG (stat_buf.st_mode)) + { + out_dev = stat_buf.st_dev; + out_ino = stat_buf.st_ino; + } + else + { + check_redirection = 0; +#ifdef lint /* Suppress `used before initialized' warning. */ + out_dev = 0; + out_ino = 0; +#endif + } + + /* Check if any of the input files are the same as the output file. */ + + /* Main loop. */ + + infile = "-"; + argind = optind; + + do + { + if (argind < argc) + infile = argv[argind]; + + if (infile[0] == '-' && infile[1] == 0) + { + have_read_stdin = 1; + input_desc = 0; + } + else + { + input_desc = open (infile, O_RDONLY); + if (input_desc < 0) + { + error (0, errno, "%s", infile); + exit_stat = 1; + continue; + } + } + + if (fstat (input_desc, &stat_buf) < 0) + { + error (0, errno, "%s", infile); + exit_stat = 1; + goto contin; + } + insize = ST_BLKSIZE (stat_buf); + + /* Compare the device and i-node numbers of this input file with + the corresponding values of the (output file associated with) + stdout, and skip this input file if they coincide. Input + files cannot be redirected to themselves. */ + + if (check_redirection + && stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino) + { + error (0, 0, _("%s: input file is output file"), infile); + exit_stat = 1; + goto contin; + } + + /* Select which version of `cat' to use. If any options (more than -u, + --version, or --help) were specified, use `cat', otherwise use + `simple_cat'. */ + + if (options == 0) + { + insize = max (insize, outsize); + inbuf = (unsigned char *) xmalloc (insize); + + simple_cat (inbuf, insize); + } + else + { + inbuf = (unsigned char *) xmalloc (insize + 1); + + /* Why are (OUTSIZE - 1 + INSIZE * 4 + 13) bytes allocated for + the output buffer? + + A test whether output needs to be written is done when the input + buffer empties or when a newline appears in the input. After + output is written, at most (OUTSIZE - 1) bytes will remain in the + buffer. Now INSIZE bytes of input is read. Each input character + may grow by a factor of 4 (by the prepending of M-^). If all + characters do, and no newlines appear in this block of input, we + will have at most (OUTSIZE - 1 + INSIZE) bytes in the buffer. If + the last character in the preceding block of input was a + newline, a line number may be written (according to the given + options) as the first thing in the output buffer. (Done after the + new input is read, but before processing of the input begins.) A + line number requires seldom more than 13 positions. */ + + outbuf = (unsigned char *) xmalloc (outsize - 1 + insize * 4 + 13); + + cat (inbuf, insize, outbuf, outsize, quote, + output_tabs, numbers, numbers_at_empty_lines, mark_line_ends, + squeeze_empty_lines); + + free (outbuf); + } + + free (inbuf); + + contin: + if (strcmp (infile, "-") && close (input_desc) < 0) + { + error (0, errno, "%s", infile); + exit_stat = 1; + } + } + while (++argind < argc); + + if (have_read_stdin && close (0) < 0) + error (1, errno, "-"); + if (close (1) < 0) + error (1, errno, _("write error")); + + exit (exit_stat); } -- cgit v1.2.3-54-g00ecf