aboutsummaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog9
-rw-r--r--libcpp/traditional.c69
2 files changed, 69 insertions, 9 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 335686f..574e054 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,12 @@
+2008-01-07 Fred Fish <fnf@specifix.com>
+
+ PR preprocessor/30363:
+ * traditional.c (replace_args_and_push): Add local variable
+ cxtquote, calculate the replacement text size assuming a
+ worst case of every input character quoted with backslash,
+ and properly handle output quoting of quote characters in
+ actual arguments used in function-like macros.
+
2008-01-03 Tom Tromey <tromey@redhat.com>
PR preprocessor/34602.
diff --git a/libcpp/traditional.c b/libcpp/traditional.c
index 7ca3cfd..6c4dda1 100644
--- a/libcpp/traditional.c
+++ b/libcpp/traditional.c
@@ -1,5 +1,5 @@
/* CPP Library - traditional lexical analysis and macro expansion.
- Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
Contributed by Neil Booth, May 2002
This program is free software; you can redistribute it and/or modify it
@@ -832,8 +832,11 @@ replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
uchar *p;
_cpp_buff *buff;
size_t len = 0;
+ int cxtquote = 0;
- /* Calculate the length of the argument-replaced text. */
+ /* Get an estimate of the length of the argument-replaced text.
+ This is a worst case estimate, assuming that every replacement
+ text character needs quoting. */
for (exp = macro->exp.text;;)
{
struct block *b = (struct block *) exp;
@@ -841,8 +844,8 @@ replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
len += b->text_len;
if (b->arg_index == 0)
break;
- len += (fmacro->args[b->arg_index]
- - fmacro->args[b->arg_index - 1] - 1);
+ len += 2 * (fmacro->args[b->arg_index]
+ - fmacro->args[b->arg_index - 1] - 1);
exp += BLOCK_LEN (b->text_len);
}
@@ -850,21 +853,69 @@ replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
buff = _cpp_get_buff (pfile, len + 1);
/* Copy the expansion and replace arguments. */
+ /* Accumulate actual length, including quoting as necessary */
p = BUFF_FRONT (buff);
+ len = 0;
for (exp = macro->exp.text;;)
{
struct block *b = (struct block *) exp;
size_t arglen;
+ int argquote;
+ uchar *base;
+ uchar *in;
- memcpy (p, b->text, b->text_len);
- p += b->text_len;
+ len += b->text_len;
+ /* Copy the non-argument text literally, keeping
+ track of whether matching quotes have been seen. */
+ for (arglen = b->text_len, in = b->text; arglen > 0; arglen--)
+ {
+ if (*in == '"')
+ cxtquote = ! cxtquote;
+ *p++ = *in++;
+ }
+ /* Done if no more arguments */
if (b->arg_index == 0)
break;
arglen = (fmacro->args[b->arg_index]
- fmacro->args[b->arg_index - 1] - 1);
- memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1],
- arglen);
- p += arglen;
+ base = pfile->out.base + fmacro->args[b->arg_index - 1];
+ in = base;
+#if 0
+ /* Skip leading whitespace in the text for the argument to
+ be substituted. To be compatible with gcc 2.95, we would
+ also need to trim trailing whitespace. Gcc 2.95 trims
+ leading and trailing whitespace, which may be a bug. The
+ current gcc testsuite explicitly checks that this leading
+ and trailing whitespace in actual arguments is
+ preserved. */
+ while (arglen > 0 && is_space (*in))
+ {
+ in++;
+ arglen--;
+ }
+#endif
+ for (argquote = 0; arglen > 0; arglen--)
+ {
+ if (cxtquote && *in == '"')
+ {
+ if (in > base && *(in-1) != '\\')
+ argquote = ! argquote;
+ /* Always add backslash before double quote if argument
+ is expanded in a quoted context */
+ *p++ = '\\';
+ len++;
+ }
+ else if (cxtquote && argquote && *in == '\\')
+ {
+ /* Always add backslash before a backslash in an argument
+ that is expanded in a quoted context and also in the
+ range of a quoted context in the argument itself. */
+ *p++ = '\\';
+ len++;
+ }
+ *p++ = *in++;
+ len++;
+ }
exp += BLOCK_LEN (b->text_len);
}