@node Global Actions, Directives, Top, Top
@section Transformations Made Globally
+@cindex ASCII NUL handling
Most C preprocessor features are inactive unless you give specific directives
to request their use. (Preprocessing directives are lines starting with
option to enable trigraph processing. @xref{Invocation}.
@end itemize
+The preprocessor handles null characters embedded in the input file
+depending upon the context in which the null appears. Note that here we
+are referring not to the two-character escape sequence "\0", but to the
+single character ASCII NUL.
+
+There are three different contexts in which a null character may
+appear:-
+
+@itemize @bullet
+@item
+Within comments. Here, null characters are silently ignored.
+
+@item
+Within a string or character constant. Here the preprocessor emits a
+warning, but preserves the null character and passes it through to the
+output file.
+
+@item
+In any other context, the preprocessor issues a warning, and discards
+the null character. In all other respects the preprocessor treats it
+like whitespace, combining it with any surrounding whitespace to become
+a single whitespace token. Representing the null character by "^@@",
+this means that code like
+
+@example
+#define X^@@1
+@end example
+
+is equivalent to
+
+@example
+#define X 1
+@end example
+
+and X is defined with replacement text "1".
+@end itemize
+
@node Directives, Header Files, Global Actions, Top
@section Preprocessing Directives
static void parse_string PARAMS ((cpp_reader *, int));
static U_CHAR *find_position PARAMS ((U_CHAR *, U_CHAR *, unsigned long *));
static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
+static void null_warning PARAMS ((cpp_reader *, unsigned int));
/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */
return ' ';
}
+static void
+null_warning (pfile, count)
+ cpp_reader *pfile;
+ unsigned int count;
+{
+ if (count == 1)
+ cpp_warning (pfile, "embedded null character ignored");
+ else
+ cpp_warning (pfile, "embedded null characters ignored");
+}
+
/* Skip whitespace \-newline and comments. Does not macro-expand. */
void
_cpp_skip_hspace (pfile)
cpp_reader *pfile;
{
+ unsigned int null_count = 0;
int c;
+
while (1)
{
c = GETC();
if (c == EOF)
- return;
+ goto out;
else if (is_hspace(c))
{
if ((c == '\f' || c == '\v') && CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "%s in preprocessing directive",
c == '\f' ? "formfeed" : "vertical tab");
+ else if (c == '\0')
+ null_count++;
}
else if (c == '\r')
{
break;
}
FORWARD(-1);
+ out:
+ if (null_count)
+ null_warning (pfile, null_count);
}
/* Read and discard the rest of the current line. */
int c;
{
long start_line, start_column;
- cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
+ unsigned int null_count = 0;
+ cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
while (1)
{
int cc = GETC();
pfile->multiline_string_line, -1,
"possible real start of unterminated constant");
pfile->multiline_string_line = 0;
- return;
+ goto out;
+ case '\0':
+ null_count++;
+ break;
+
case '\n':
CPP_BUMP_LINE (pfile);
/* In Fortran and assembly language, silently terminate
|| CPP_OPTION (pfile, lang_asm))
{
FORWARD(-1);
- return;
+ goto out;
}
/* Character constants may not extend over multiple lines.
In Standard C, neither may strings. We accept multiline
cpp_error_with_line (pfile, start_line, start_column,
"unterminated character constant");
FORWARD(-1);
- return;
+ goto out;
}
if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
cpp_pedwarn_with_line (pfile, start_line, start_column,
case '\"':
case '\'':
if (cc == c)
- return;
+ goto out;
break;
}
}
+
+ out:
+ if (null_count == 1)
+ cpp_warning (pfile, "null character in string or character constant");
+ else if (null_count > 1)
+ cpp_warning (pfile, "null characters in string or character constant");
}
/* Parse a string and copy it to the output. */
_cpp_parse_name (pfile, c);
return CPP_MACRO;
- case ' ': case '\t': case '\v': case '\f':
- for (;;)
- {
- CPP_PUTC (pfile, c);
- c = PEEKC ();
- if (c == EOF || !is_hspace(c))
- break;
- FORWARD(1);
- }
- return CPP_HSPACE;
+ case ' ': case '\t': case '\v': case '\f': case '\0':
+ {
+ int null_count = 0;
+
+ for (;;)
+ {
+ if (c == '\0')
+ null_count++;
+ else
+ CPP_PUTC (pfile, c);
+ c = PEEKC ();
+ if (c == EOF || !is_hspace(c))
+ break;
+ FORWARD(1);
+ }
+ if (null_count)
+ null_warning (pfile, null_count);
+ return CPP_HSPACE;
+ }
case '\r':
if (CPP_BUFFER (pfile)->has_escapes)