cppfiles.c (initialize_input_buffer): New function.

1999-05-10 18:21 -0400  Zack Weinberg  <zack@rabi.columbia.edu>
	* cppfiles.c (initialize_input_buffer): New function.
	(finclude): Call it, if pfile->input_buffer is NULL.  Accept
	any character device as an input file.
	(read_and_prescan): Use pfile->input_buffer and
	pfile->input_speccase.
	* cppinit.c (cpp_cleanup): Free pfile->input_buffer and
	pfile->input_speccase.
	* cpplib.h (cpp_reader): Add input_buffer, input_speccase, and
	input_buffer_len members.  Use memcpy in CPP_PUTS_Q.
	* cppmain.c: Buffer output in the token_buffer; throttle
	number of calls to fwrite; check for errors from fwrite.

From-SVN: r26869
This commit is contained in:
Zack Weinberg 1999-05-10 11:24:36 -04:00 committed by Dave Brolley
parent 4338f578a7
commit 2c826217f4
4 changed files with 129 additions and 56 deletions

View File

@ -45,6 +45,9 @@ static long read_and_prescan PROTO ((cpp_reader *, cpp_buffer *,
int, size_t)); int, size_t));
static struct file_name_list *actual_directory PROTO ((cpp_reader *, char *)); static struct file_name_list *actual_directory PROTO ((cpp_reader *, char *));
static void initialize_input_buffer PROTO ((cpp_reader *, int,
struct stat *));
#if 0 #if 0
static void hack_vms_include_specification PROTO ((char *)); static void hack_vms_include_specification PROTO ((char *));
#endif #endif
@ -648,10 +651,12 @@ finclude (pfile, fd, ihash)
} }
} }
else if (S_ISFIFO (st.st_mode) || S_ISSOCK (st.st_mode) else if (S_ISFIFO (st.st_mode) || S_ISSOCK (st.st_mode)
/* Permit any kind of character device: the sensible ones are
ttys and /dev/null, but weeding out the others is too hard. */
|| S_ISCHR (st.st_mode)
/* Some 4.x (x<4) derivatives have a bug that makes fstat() of a /* Some 4.x (x<4) derivatives have a bug that makes fstat() of a
socket or pipe return a stat struct with most fields zeroed. */ socket or pipe return a stat struct with most fields zeroed. */
|| (st.st_mode == 0 && st.st_nlink == 0 && st.st_size == 0) || (st.st_mode == 0 && st.st_nlink == 0 && st.st_size == 0))
|| (S_ISCHR (st.st_mode) && isatty (fd)))
{ {
/* Cannot get its file size before reading. 4k is a decent /* Cannot get its file size before reading. 4k is a decent
first guess. */ first guess. */
@ -663,6 +668,9 @@ finclude (pfile, fd, ihash)
goto fail; goto fail;
} }
if (pfile->input_buffer == NULL)
initialize_input_buffer (pfile, fd, &st);
/* Read the file, converting end-of-line characters and trigraphs /* Read the file, converting end-of-line characters and trigraphs
(if enabled). */ (if enabled). */
fp->ihash = ihash; fp->ihash = ihash;
@ -758,8 +766,7 @@ actual_directory (pfile, fname)
return x; return x;
} }
/* Almost but not quite the same as adjust_position in cpplib.c. /* Determine the current line and column. Used only by read_and_prescan. */
Used only by read_and_prescan. */
static void static void
find_position (start, limit, linep, colp) find_position (start, limit, linep, colp)
U_CHAR *start; U_CHAR *start;
@ -804,9 +811,14 @@ find_position (start, limit, linep, colp)
If your file has more than one kind of end-of-line marker, you If your file has more than one kind of end-of-line marker, you
will get messed-up line numbering. */ will get messed-up line numbering. */
#ifndef PIPE_BUF /* Table of characters that can't be handled in the inner loop.
#define PIPE_BUF 4096 Keep these contiguous to optimize the performance of the code generated
#endif for the switch that uses them. */
#define SPECCASE_EMPTY 0
#define SPECCASE_NUL 1
#define SPECCASE_CR 2
#define SPECCASE_BACKSLASH 3
#define SPECCASE_QUESTION 4
static long static long
read_and_prescan (pfile, fp, desc, len) read_and_prescan (pfile, fp, desc, len)
@ -818,45 +830,24 @@ read_and_prescan (pfile, fp, desc, len)
U_CHAR *buf = (U_CHAR *) xmalloc (len); U_CHAR *buf = (U_CHAR *) xmalloc (len);
U_CHAR *ip, *op, *line_base; U_CHAR *ip, *op, *line_base;
U_CHAR *ibase; U_CHAR *ibase;
U_CHAR *speccase = pfile->input_speccase;
unsigned long line; unsigned long line;
unsigned int deferred_newlines; unsigned int deferred_newlines;
int count; int count;
size_t offset; size_t offset;
/* PIPE_BUF bytes of buffer proper, 2 to detect running off the end
without address arithmetic all the time, and 2 for pushback in
the case there's a potential trigraph or end-of-line digraph at
the end of a block. */
U_CHAR intermed[PIPE_BUF + 2 + 2];
/* Table of characters that can't be handled in the inner loop.
Keep these contiguous to optimize the performance of the code generated
for the switch that uses them. */
#define SPECCASE_EMPTY 0
#define SPECCASE_NUL 1
#define SPECCASE_CR 2
#define SPECCASE_BACKSLASH 3
#define SPECCASE_QUESTION 4
U_CHAR speccase[256];
offset = 0; offset = 0;
op = buf; op = buf;
line_base = buf; line_base = buf;
line = 1; line = 1;
ibase = intermed + 2; ibase = pfile->input_buffer + 2;
deferred_newlines = 0; deferred_newlines = 0;
memset (speccase, SPECCASE_EMPTY, sizeof (speccase));
speccase['\0'] = SPECCASE_NUL;
speccase['\r'] = SPECCASE_CR;
speccase['\\'] = SPECCASE_BACKSLASH;
if (CPP_OPTIONS (pfile)->trigraphs || CPP_OPTIONS (pfile)->warn_trigraphs)
speccase['?'] = SPECCASE_QUESTION;
for (;;) for (;;)
{ {
read_next: read_next:
count = read (desc, intermed + 2, PIPE_BUF); count = read (desc, pfile->input_buffer + 2, pfile->input_buffer_len);
if (count < 0) if (count < 0)
goto error; goto error;
else if (count == 0) else if (count == 0)
@ -864,7 +855,7 @@ read_and_prescan (pfile, fp, desc, len)
offset += count; offset += count;
ip = ibase; ip = ibase;
ibase = intermed + 2; ibase = pfile->input_buffer + 2;
ibase[count] = ibase[count+1] = '\0'; ibase[count] = ibase[count+1] = '\0';
if (offset > len) if (offset > len)
@ -924,8 +915,7 @@ read_and_prescan (pfile, fp, desc, len)
ip++; ip++;
else if (*ip == '\0') else if (*ip == '\0')
{ {
--ibase; *--ibase = '\r';
intermed[1] = '\r';
goto read_next; goto read_next;
} }
else if (ip[-2] == '\n') else if (ip[-2] == '\n')
@ -941,8 +931,7 @@ read_and_prescan (pfile, fp, desc, len)
and come back next pass. */ and come back next pass. */
if (*ip == '\0') if (*ip == '\0')
{ {
--ibase; *--ibase = '\\';
intermed[1] = '\\';
goto read_next; goto read_next;
} }
else if (*ip == '\n') else if (*ip == '\n')
@ -965,9 +954,8 @@ read_and_prescan (pfile, fp, desc, len)
if (*ip == '\n') ip++; if (*ip == '\n') ip++;
else if (*ip == '\0') else if (*ip == '\0')
{ {
ibase -= 2; *--ibase = '\r';
intermed[0] = '\\'; *--ibase = '\\';
intermed[1] = '\r';
goto read_next; goto read_next;
} }
else if (*ip == '\r' || *ip == '\t' || *ip == ' ') else if (*ip == '\r' || *ip == '\t' || *ip == ' ')
@ -991,8 +979,7 @@ read_and_prescan (pfile, fp, desc, len)
d = ip[0]; d = ip[0];
if (d == '\0') if (d == '\0')
{ {
--ibase; *--ibase = '?';
intermed[1] = '?';
goto read_next; goto read_next;
} }
if (d != '?') if (d != '?')
@ -1003,8 +990,8 @@ read_and_prescan (pfile, fp, desc, len)
d = ip[1]; d = ip[1];
if (d == '\0') if (d == '\0')
{ {
ibase -= 2; *--ibase = '?';
intermed[0] = intermed[1] = '?'; *--ibase = '?';
goto read_next; goto read_next;
} }
if (!trigraph_table[d]) if (!trigraph_table[d])
@ -1047,7 +1034,7 @@ read_and_prescan (pfile, fp, desc, len)
This may be any of: ?? ? \ \r \n \\r \\n. This may be any of: ?? ? \ \r \n \\r \\n.
\r must become \n, \\r or \\n must become \r. \r must become \n, \\r or \\n must become \r.
We know we have space already. */ We know we have space already. */
if (ibase == intermed) if (ibase == pfile->input_buffer)
{ {
if (*ibase == '?') if (*ibase == '?')
{ {
@ -1057,7 +1044,7 @@ read_and_prescan (pfile, fp, desc, len)
else else
*op++ = '\r'; *op++ = '\r';
} }
else if (ibase == intermed + 1) else if (ibase == pfile->input_buffer + 1)
{ {
if (*ibase == '\r') if (*ibase == '\r')
*op++ = '\n'; *op++ = '\n';
@ -1095,6 +1082,67 @@ read_and_prescan (pfile, fp, desc, len)
return -1; return -1;
} }
/* Initialize the `input_buffer' and `input_speccase' tables.
These are only used by read_and_prescan, but they're large and
somewhat expensive to set up, so we want them allocated once for
the duration of the cpp run. */
static void
initialize_input_buffer (pfile, fd, st)
cpp_reader *pfile;
int fd;
struct stat *st;
{
long pipe_buf;
U_CHAR *tmp;
/* Table of characters that cannot be handled by the
read_and_prescan inner loop. The number of non-EMPTY entries
should be as small as humanly possible. */
tmp = xmalloc (1 << CHAR_BIT);
memset (tmp, SPECCASE_EMPTY, 1 << CHAR_BIT);
tmp['\0'] = SPECCASE_NUL;
tmp['\r'] = SPECCASE_CR;
tmp['\\'] = SPECCASE_BACKSLASH;
if (CPP_OPTIONS (pfile)->trigraphs || CPP_OPTIONS (pfile)->warn_trigraphs)
tmp['?'] = SPECCASE_QUESTION;
pfile->input_speccase = tmp;
/* Determine the appropriate size for the input buffer. Normal C
source files are smaller than eight K. If we are reading a pipe,
we want to make sure the input buffer is bigger than the kernel's
pipe buffer. */
pipe_buf = -1;
if (! S_ISREG (st->st_mode))
{
#ifdef _PC_PIPE_BUF
pipe_buf = fpathconf (fd, _PC_PIPE_BUF);
#endif
if (pipe_buf == -1)
{
#ifdef PIPE_BUF
pipe_buf = PIPE_BUF;
#else
pipe_buf = 8192;
#endif
}
}
if (pipe_buf < 8192)
pipe_buf = 8192;
/* PIPE_BUF bytes of buffer proper, 2 to detect running off the end
without address arithmetic all the time, and 2 for pushback in
the case there's a potential trigraph or end-of-line digraph at
the end of a block. */
tmp = xmalloc (pipe_buf + 2 + 2);
pfile->input_buffer = tmp;
pfile->input_buffer_len = pipe_buf;
}
/* Add output to `deps_buffer' for the -M switch. /* Add output to `deps_buffer' for the -M switch.
STRING points to the text to be output. STRING points to the text to be output.
SPACER is ':' for targets, ' ' for dependencies, zero for text SPACER is ':' for targets, ' ' for dependencies, zero for text

View File

@ -569,6 +569,14 @@ cpp_cleanup (pfile)
pfile->deps_allocated_size = 0; pfile->deps_allocated_size = 0;
} }
if (pfile->input_buffer)
{
free (pfile->input_buffer);
free (pfile->input_speccase);
pfile->input_buffer = pfile->input_speccase = NULL;
pfile->input_buffer_len = 0;
}
while (pfile->if_stack) while (pfile->if_stack)
{ {
IF_STACK_FRAME *temp = pfile->if_stack; IF_STACK_FRAME *temp = pfile->if_stack;

View File

@ -241,6 +241,13 @@ struct cpp_reader
/* Number of bytes since the last newline. */ /* Number of bytes since the last newline. */
int deps_column; int deps_column;
/* A buffer and a table, used only by read_and_prescan (in cppfiles.c)
which are allocated once per cpp_reader object to keep them off the
stack and avoid setup costs. */
U_CHAR *input_buffer;
U_CHAR *input_speccase;
size_t input_buffer_len;
}; };
#define CPP_FATAL_LIMIT 1000 #define CPP_FATAL_LIMIT 1000
@ -269,7 +276,7 @@ struct cpp_reader
/* Append string STR (of length N) to PFILE's output buffer. /* Append string STR (of length N) to PFILE's output buffer.
Assume there is enough space. */ Assume there is enough space. */
#define CPP_PUTS_Q(PFILE, STR, N) \ #define CPP_PUTS_Q(PFILE, STR, N) \
(bcopy (STR, (PFILE)->limit, (N)), (PFILE)->limit += (N)) (memcpy ((PFILE)->limit, STR, (N)), (PFILE)->limit += (N))
/* Append string STR (of length N) to PFILE's output buffer. Make space. */ /* Append string STR (of length N) to PFILE's output buffer. Make space. */
#define CPP_PUTS(PFILE, STR, N) CPP_RESERVE(PFILE, N), CPP_PUTS_Q(PFILE, STR,N) #define CPP_PUTS(PFILE, STR, N) CPP_RESERVE(PFILE, N), CPP_PUTS_Q(PFILE, STR,N)
/* Append character CH to PFILE's output buffer. Assume sufficient space. */ /* Append character CH to PFILE's output buffer. Assume sufficient space. */

View File

@ -46,6 +46,7 @@ main (argc, argv)
char *p; char *p;
int argi = 1; /* Next argument to handle. */ int argi = 1; /* Next argument to handle. */
struct cpp_options *opts = &options; struct cpp_options *opts = &options;
enum cpp_token kind;
p = argv[0] + strlen (argv[0]); p = argv[0] + strlen (argv[0]);
while (p != argv[0] && p[-1] != '/') --p; while (p != argv[0] && p[-1] != '/') --p;
@ -80,21 +81,30 @@ main (argc, argv)
else if (! freopen (opts->out_fname, "w", stdout)) else if (! freopen (opts->out_fname, "w", stdout))
cpp_pfatal_with_name (&parse_in, opts->out_fname); cpp_pfatal_with_name (&parse_in, opts->out_fname);
for (;;) do
{ {
enum cpp_token kind;
if (! opts->no_output)
{
fwrite (parse_in.token_buffer, 1, CPP_WRITTEN (&parse_in), stdout);
}
CPP_SET_WRITTEN (&parse_in, 0);
kind = cpp_get_token (&parse_in); kind = cpp_get_token (&parse_in);
if (kind == CPP_EOF) if (CPP_WRITTEN (&parse_in) >= BUFSIZ || kind == CPP_EOF)
break; {
if (! opts->no_output)
{
size_t rem, count = CPP_WRITTEN (&parse_in);
rem = fwrite (parse_in.token_buffer, 1, count, stdout);
if (rem < count)
/* Write error. */
cpp_pfatal_with_name (&parse_in, opts->out_fname);
}
CPP_SET_WRITTEN (&parse_in, 0);
}
} }
while (kind != CPP_EOF);
cpp_finish (&parse_in); cpp_finish (&parse_in);
fwrite (parse_in.token_buffer, 1, CPP_WRITTEN (&parse_in), stdout); if (fwrite (parse_in.token_buffer, 1, CPP_WRITTEN (&parse_in), stdout)
< CPP_WRITTEN (&parse_in))
cpp_pfatal_with_name (&parse_in, opts->out_fname);
if (parse_in.errors) if (parse_in.errors)
exit (FATAL_EXIT_CODE); exit (FATAL_EXIT_CODE);