diff options
Diffstat (limited to 'gcc/cccp.c')
-rw-r--r-- | gcc/cccp.c | 505 |
1 files changed, 292 insertions, 213 deletions
diff --git a/gcc/cccp.c b/gcc/cccp.c index d4d2a39fcf5..23a5077d628 100644 --- a/gcc/cccp.c +++ b/gcc/cccp.c @@ -72,11 +72,13 @@ typedef unsigned char U_CHAR; #define fopen(fname,mode) VMS_fopen (fname,mode) #define freopen(fname,mode,ofile) VMS_freopen (fname,mode,ofile) #define fstat(fd,stbuf) VMS_fstat (fd,stbuf) +#define fwrite(ptr,size,nitems,stream) VMS_fwrite (ptr,size,nitems,stream) static int VMS_fstat (), VMS_stat (); static int VMS_open (); static FILE *VMS_fopen (); static FILE *VMS_freopen (); -static int hack_vms_include_specification (); +static size_t VMS_fwrite (); +static void hack_vms_include_specification (); #define INO_T_EQ(a, b) (!bcmp((char *) &(a), (char *) &(b), sizeof (a))) #define INO_T_HASH(a) 0 #define INCLUDE_LEN_FUDGE 12 /* leave room for VMS syntax conversion */ @@ -243,6 +245,10 @@ static int warn_trigraphs; static int warn_undef; +/* Nonzero means warn if we find white space where it doesn't belong. */ + +static int warn_white_space; + /* Nonzero means warn if #import is used. */ static int warn_import = 1; @@ -783,7 +789,6 @@ static int do_sccs DO_PROTO; #endif static int do_unassert DO_PROTO; static int do_undef DO_PROTO; -static int do_warning DO_PROTO; static int do_xifdef DO_PROTO; /* Here is the actual list of #-directives, most-often-used first. */ @@ -802,7 +807,7 @@ static struct directive directive_table[] = { { 6, do_include, "import", T_IMPORT}, { 5, do_undef, "undef", T_UNDEF}, { 5, do_error, "error", T_ERROR}, - { 7, do_warning, "warning", T_WARNING}, + { 7, do_error, "warning", T_WARNING}, #ifdef SCCS_DIRECTIVE { 4, do_sccs, "sccs", T_SCCS}, #endif @@ -874,7 +879,6 @@ static int ignore_srcdir; static int safe_read PROTO((int, char *, int)); static void safe_write PROTO((int, char *, int)); -static void eprint_string PROTO((const char *, size_t)); int main PROTO((int, char **)); @@ -883,6 +887,7 @@ static void path_include PROTO((char *)); static U_CHAR *index0 PROTO((U_CHAR *, int, size_t)); static void trigraph_pcp PROTO((FILE_BUF *)); +static void check_white_space PROTO((FILE_BUF *)); static void newline_fix PROTO((U_CHAR *)); static void name_newline_fix PROTO((U_CHAR *)); @@ -962,7 +967,7 @@ static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, struct hashnode *, int *, int static int discard_comments PROTO((U_CHAR *, int, int)); -static int change_newlines PROTO((U_CHAR *, int)); +static void change_newlines PROTO((struct argdata *)); static void notice PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1; static void vnotice PROTO((const char *, va_list)); @@ -1088,33 +1093,6 @@ safe_write (desc, ptr, len) } } -/* Print a string to stderr, with extra handling in case it contains - embedded NUL characters. Any present are written as is. - - Using fwrite for this purpose produces undesireable results on VMS - when stderr happens to be a record oriented file, such as a batch log - file, rather than a stream oriented one. */ - -static void -eprint_string (string, length) - const char *string; - size_t length; -{ - size_t segment_length; - - do { - fprintf(stderr, "%s", string); - length -= (segment_length = strlen(string)); - if (length > 0) - { - fputc('\0', stderr); - length -= 1; - /* Advance past the portion which has already been printed. */ - string += segment_length + 1; - } - } while (length > 0); -} - static void print_help () @@ -1320,20 +1298,20 @@ main (argc, argv) case 'i': if (!strcmp (argv[i], "-include")) { - int temp = i; - if (i + 1 == argc) fatal ("Filename missing after `-include' option"); - else - simplify_filename (pend_includes[temp] = argv[++i]); + else { + simplify_filename (pend_includes[i] = argv[i]); + i++; + } } if (!strcmp (argv[i], "-imacros")) { - int temp = i; - if (i + 1 == argc) fatal ("Filename missing after `-imacros' option"); - else - simplify_filename (pend_files[temp] = argv[++i]); + else { + simplify_filename (pend_files[i] = argv[i]); + i++; + } } if (!strcmp (argv[i], "-iprefix")) { if (i + 1 == argc) @@ -1511,6 +1489,10 @@ main (argc, argv) warn_stringify = 1; else if (!strcmp (argv[i], "-Wno-traditional")) warn_stringify = 0; + else if (!strcmp (argv[i], "-Wwhite-space")) + warn_white_space = 1; + else if (!strcmp (argv[i], "-Wno-white-space")) + warn_white_space = 0; else if (!strcmp (argv[i], "-Wundef")) warn_undef = 1; else if (!strcmp (argv[i], "-Wno-undef")) @@ -1527,6 +1509,7 @@ main (argc, argv) { warn_trigraphs = 1; warn_comments = 1; + warn_white_space = 1; } break; @@ -1691,15 +1674,15 @@ main (argc, argv) case 'I': /* Add directory to path for includes. */ { struct file_name_list *dirtmp; + char *dir = argv[i][2] ? argv[i] + 2 : argv[++i]; - if (! ignore_srcdir && !strcmp (argv[i] + 2, "-")) { + if (! ignore_srcdir && !strcmp (dir, "-")) { ignore_srcdir = 1; /* Don't use any preceding -I directories for #include <...>. */ first_bracket_include = 0; } else { - dirtmp = new_include_prefix (last_include, NULL_PTR, "", - argv[i][2] ? argv[i] + 2 : argv[++i]); + dirtmp = new_include_prefix (last_include, NULL_PTR, "", dir); append_include_chain (dirtmp, dirtmp); } } @@ -1958,17 +1941,14 @@ main (argc, argv) else print_deps = 1; - s = spec; /* Find the space before the DEPS_TARGET, if there is one. */ - /* This should use index. (mrs) */ - while (*s != 0 && *s != ' ') s++; - if (*s != 0) { + s = index (spec, ' '); + if (s) { deps_target = s + 1; output_file = xmalloc (s - spec + 1); bcopy (spec, output_file, s - spec); output_file[s - spec] = 0; - } - else { + } else { deps_target = 0; output_file = spec; } @@ -2029,8 +2009,9 @@ main (argc, argv) strcpy (q, OBJECT_SUFFIX); deps_output (p, ':'); - deps_output (in_fname, ' '); } + + deps_output (in_fname, ' '); } /* Scan the -imacros files before the main input. @@ -2118,6 +2099,9 @@ main (argc, argv) if (!no_trigraphs) trigraph_pcp (fp); + if (warn_white_space) + check_white_space (fp); + /* Now that we know the input file is valid, open the output. */ if (!out_fname || !strcmp (out_fname, "")) @@ -2328,13 +2312,43 @@ trigraph_pcp (buf) warning_with_line (0, "%lu trigraph(s) encountered", (unsigned long) (fptr - bptr) / 2); } + +/* Warn about white space between backslash and end of line. */ + +static void +check_white_space (buf) + FILE_BUF *buf; +{ + register U_CHAR *sptr = buf->buf; + register U_CHAR *lptr = sptr + buf->length; + register U_CHAR *nptr; + int line = 0; + + nptr = sptr = buf->buf; + lptr = sptr + buf->length; + for (nptr = sptr; + (nptr = index0 (nptr, '\n', (size_t) (lptr - nptr))) != NULL; + nptr ++) { + register U_CHAR *p = nptr; + line++; + for (p = nptr; sptr < p; p--) { + if (! is_hor_space[p[-1]]) { + if (p[-1] == '\\' && p != nptr) + warning_with_line (line, + "`\\' followed by white space at end of line"); + break; + } + } + } +} /* Move all backslash-newline pairs out of embarrassing places. Exchange all such pairs following BP with any potentially-embarrassing characters that follow them. Potentially-embarrassing characters are / and * (because a backslash-newline inside a comment delimiter - would cause it not to be recognized). */ + would cause it not to be recognized). + We assume that *BP == '\\'. */ static void newline_fix (bp) @@ -2343,21 +2357,24 @@ newline_fix (bp) register U_CHAR *p = bp; /* First count the backslash-newline pairs here. */ - - while (p[0] == '\\' && p[1] == '\n') + do { + if (p[1] != '\n') + break; p += 2; + } while (*p == '\\'); /* What follows the backslash-newlines is not embarrassing. */ if (*p != '/' && *p != '*') + /* What follows the backslash-newlines is not embarrassing. */ return; /* Copy all potentially embarrassing characters that follow the backslash-newline pairs down to where the pairs originally started. */ - - while (*p == '*' || *p == '/') + do *bp++ = *p++; + while (*p == '*' || *p == '/'); /* Now write the same number of pairs after the embarrassing chars. */ while (bp < p) { @@ -2376,20 +2393,24 @@ name_newline_fix (bp) register U_CHAR *p = bp; /* First count the backslash-newline pairs here. */ - while (p[0] == '\\' && p[1] == '\n') + do { + if (p[1] != '\n') + break; p += 2; + } while (*p == '\\'); /* What follows the backslash-newlines is not embarrassing. */ if (!is_idchar[*p]) + /* What follows the backslash-newlines is not embarrassing. */ return; /* Copy all potentially embarrassing characters that follow the backslash-newline pairs down to where the pairs originally started. */ - - while (is_idchar[*p]) + do *bp++ = *p++; + while (is_idchar[*p]); /* Now write the same number of pairs after the embarrassing chars. */ while (bp < p) { @@ -2467,7 +2488,7 @@ get_lintcmd (ibp, limit, argstart, arglen, cmdlen) * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input * and insert them when appropriate. This is set while scanning macro * arguments before substitution. It is zero when scanning for final output. - * There are three types of Newline markers: + * There are two types of Newline markers: * * Newline - follows a macro name that was not expanded * because it appeared inside an expansion of the same macro. * This marker prevents future expansion of that identifier. @@ -2791,6 +2812,8 @@ do { ip = &instack[indepth]; \ *obp++ = *ibp; switch (*ibp++) { case '\n': + if (warn_white_space && ip->fname && is_hor_space[ibp[-2]]) + warning ("white space at end of line in string"); ++ip->lineno; ++op->lineno; /* Traditionally, end of line ends a string constant with no error. @@ -2818,9 +2841,10 @@ do { ip = &instack[indepth]; \ keep the line counts correct. But if we are reading from a macro, keep the backslash newline, since backslash newlines have already been processed. */ - if (ip->macro) + if (ip->macro) { *obp++ = '\n'; - else + ++op->lineno; + } else --obp; ++ibp; ++ip->lineno; @@ -2829,8 +2853,10 @@ do { ip = &instack[indepth]; \ is *not* prevented from combining with a newline. */ if (!ip->macro) { while (*ibp == '\\' && ibp[1] == '\n') { - ibp += 2; + *obp++ = *ibp++; + *obp++ = *ibp++; ++ip->lineno; + ++op->lineno; } } *obp++ = *ibp++; @@ -2868,7 +2894,7 @@ do { ip = &instack[indepth]; \ case '/': if (ip->macro != 0) goto randomchar; - if (*ibp == '\\' && ibp[1] == '\n') + if (*ibp == '\\') newline_fix (ibp); if (*ibp != '*' && !(cplusplus_comments && *ibp == '/')) @@ -2986,7 +3012,7 @@ do { ip = &instack[indepth]; \ case '*': if (ibp[-2] == '/' && warn_comments) warning ("`/*' within comment"); - if (*ibp == '\\' && ibp[1] == '\n') + if (*ibp == '\\') newline_fix (ibp); if (*ibp == '/') goto comment_end; @@ -3357,7 +3383,7 @@ randomchar: break; else if (*ibp == '/') { /* If a comment, copy it unchanged or discard it. */ - if (ibp[1] == '\\' && ibp[2] == '\n') + if (ibp[1] == '\\') newline_fix (ibp + 1); if (ibp[1] == '*') { if (put_out_comments) { @@ -3370,7 +3396,7 @@ randomchar: /* We need not worry about newline-marks, since they are never found in comments. */ if (ibp[0] == '*') { - if (ibp[1] == '\\' && ibp[2] == '\n') + if (ibp[1] == '\\') newline_fix (ibp + 1); if (ibp[1] == '/') { ibp += 2; @@ -3627,9 +3653,6 @@ expand_to_temp_buffer (buf, limit, output_marks, assertions) if (indepth != odepth) abort (); - /* Record the output. */ - obuf.length = obuf.bufp - obuf.buf; - assertions_flag = save_assertions_flag; return obuf; } @@ -3677,7 +3700,7 @@ handle_directive (ip, op) pedwarn_strange_white_space (*bp); bp++; } else if (*bp == '/') { - if (bp[1] == '\\' && bp[2] == '\n') + if (bp[1] == '\\') newline_fix (bp + 1); if (! (bp[1] == '*' || (cplusplus_comments && bp[1] == '/'))) break; @@ -3698,7 +3721,7 @@ handle_directive (ip, op) if (is_idchar[*cp]) cp++; else { - if (*cp == '\\' && cp[1] == '\n') + if (*cp == '\\') name_newline_fix (cp); if (is_idchar[*cp]) cp++; @@ -3789,14 +3812,12 @@ handle_directive (ip, op) register U_CHAR c = *bp++; switch (c) { case '\\': - if (bp < limit) { - if (*bp == '\n') { - ip->lineno++; - copy_directive = 1; - bp++; - } else if (traditional) - bp++; - } + if (*bp == '\n') { + ip->lineno++; + copy_directive = 1; + bp++; + } else if (traditional && bp < limit) + bp++; break; case '"': @@ -3848,7 +3869,7 @@ handle_directive (ip, op) break; case '/': - if (*bp == '\\' && bp[1] == '\n') + if (*bp == '\\') newline_fix (bp); if (*bp == '*' || (cplusplus_comments && *bp == '/')) { @@ -3931,12 +3952,13 @@ handle_directive (ip, op) register U_CHAR *xp = buf; /* Need to copy entire directive into temp buffer before dispatching */ - cp = (U_CHAR *) alloca (bp - buf + 5); /* room for directive plus - some slop */ + /* room for directive plus some slop */ + cp = (U_CHAR *) alloca (2 * (bp - buf) + 5); buf = cp; /* Copy to the new buffer, deleting comments - and backslash-newlines (and whitespace surrounding the latter). */ + and backslash-newlines (and whitespace surrounding the latter + if outside of char and string constants). */ while (xp < bp) { register U_CHAR c = *xp++; @@ -4043,7 +4065,8 @@ handle_directive (ip, op) directives through. */ if (!no_output && already_output == 0 - && (kt->type == T_DEFINE ? (int) dump_names <= (int) dump_macros + && ((kt->type == T_DEFINE || kt->type == T_UNDEF) + ? (int) dump_names <= (int) dump_macros : IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes : kt->type == T_PRAGMA)) { int len; @@ -4072,7 +4095,7 @@ handle_directive (ip, op) bcopy (buf, (char *) op->bufp, len); } op->bufp += len; - } /* Don't we need a newline or #line? */ + } /* Call the appropriate directive handler. buf now points to either the appropriate place in the input buffer, or to @@ -4094,12 +4117,19 @@ handle_directive (ip, op) static struct tm * timestamp () { - static struct tm *timebuf; - if (!timebuf) { + static struct tm tmbuf; + if (! tmbuf.tm_mday) { time_t t = time ((time_t *) 0); - timebuf = localtime (&t); + struct tm *tm = localtime (&t); + if (tm) + tmbuf = *tm; + else { + /* Use 0000-01-01 00:00:00 if local time is not available. */ + tmbuf.tm_year = -1900; + tmbuf.tm_mday = 1; + } } - return timebuf; + return &tmbuf; } static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -5284,6 +5314,9 @@ finclude (f, inc, op, system_header_p, dirptr) if (!no_trigraphs) trigraph_pcp (fp); + if (warn_white_space) + check_white_space (fp); + output_line_directive (fp, op, 0, enter_file); rescan (op, 0); @@ -5497,7 +5530,7 @@ pcfinclude (buf, name, op) tmpbuf = expand_to_temp_buffer (string_start, cp++, 0, 0); /* Lineno is already set in the precompiled file */ str->contents = tmpbuf.buf; - str->len = tmpbuf.length; + str->len = tmpbuf.bufp - tmpbuf.buf; str->writeflag = 0; str->filename = name; str->output_mark = outbuf.bufp - outbuf.buf; @@ -5521,6 +5554,7 @@ pcfinclude (buf, name, op) for (; nkeys--; free (tmpbuf.buf), cp = endofthiskey + 1) { KEYDEF *kp = (KEYDEF *) (GENERIC_PTR) cp; HASHNODE *hp; + U_CHAR *bp; /* It starts with a KEYDEF structure */ cp += sizeof (KEYDEF); @@ -5532,20 +5566,19 @@ pcfinclude (buf, name, op) /* Expand the key, and enter it into the hash table. */ tmpbuf = expand_to_temp_buffer (cp, endofthiskey, 0, 0); - tmpbuf.bufp = tmpbuf.buf; + bp = tmpbuf.buf; - while (is_hor_space[*tmpbuf.bufp]) - tmpbuf.bufp++; - if (!is_idstart[*tmpbuf.bufp] - || tmpbuf.bufp == tmpbuf.buf + tmpbuf.length) { + while (is_hor_space[*bp]) + bp++; + if (!is_idstart[*bp] || bp == tmpbuf.bufp) { str->writeflag = 1; continue; } - hp = lookup (tmpbuf.bufp, -1, -1); + hp = lookup (bp, -1, -1); if (hp == NULL) { kp->chain = 0; - install (tmpbuf.bufp, -1, T_PCSTRING, (char *) kp, -1); + install (bp, -1, T_PCSTRING, (char *) kp, -1); } else if (hp->type == T_PCSTRING) { kp->chain = hp->value.keydef; @@ -6136,7 +6169,7 @@ collect_expansion (buf, end, nargs, arglist) break; case '\\': - if (p < limit && expected_delimiter) { + if (expected_delimiter) { /* In a string, backslash goes through and makes next char ordinary. */ *exp_p++ = *p++; @@ -6804,6 +6837,7 @@ do_line (buf, limit, op, keyword) /* Point to macroexpanded line, which is null-terminated now. */ bp = tem.buf; + limit = tem.bufp; SKIP_WHITE_SPACE (bp); if (!ISDIGIT (*bp)) { @@ -6846,10 +6880,6 @@ do_line (buf, limit, op, keyword) p = bp; for (;;) switch ((*p++ = *bp++)) { - case '\0': - error ("invalid format `#line' directive"); - return 0; - case '\\': if (! ignore_escape_flag) { @@ -6974,50 +7004,39 @@ do_undef (buf, limit, op, keyword) return 0; } + /* Report an error detected by the program we are processing. - Use the text of the line in the error message. - (We use error because it prints the filename & line#.) */ + Use the text of the line in the error message. */ static int do_error (buf, limit, op, keyword) U_CHAR *buf, *limit; FILE_BUF *op ATTRIBUTE_UNUSED; - struct directive *keyword ATTRIBUTE_UNUSED; + struct directive *keyword; { int length = limit - buf; U_CHAR *copy = (U_CHAR *) alloca (length + 1); bcopy ((char *) buf, (char *) copy, length); copy[length] = 0; SKIP_WHITE_SPACE (copy); - error ("#error %s", copy); - return 0; -} -/* Report a warning detected by the program we are processing. - Use the text of the line in the warning message, then continue. - (We use error because it prints the filename & line#.) */ + switch (keyword->type) { + case T_ERROR: + error ("#error %s", copy); + break; -static int -do_warning (buf, limit, op, keyword) - U_CHAR *buf, *limit; - FILE_BUF *op ATTRIBUTE_UNUSED; - struct directive *keyword ATTRIBUTE_UNUSED; -{ - int length = limit - buf; - U_CHAR *copy = (U_CHAR *) alloca (length + 1); - bcopy ((char *) buf, (char *) copy, length); - copy[length] = 0; - SKIP_WHITE_SPACE (copy); + case T_WARNING: + if (pedantic && !instack[indepth].system_header_p) + pedwarn ("ANSI C does not allow `#warning'"); + warning ("#warning %s", copy); + break; - if (pedantic && !instack[indepth].system_header_p) - pedwarn ("ANSI C does not allow `#warning'"); + default: + abort (); + } - /* Use `pedwarn' not `warning', because #warning isn't in the C Standard; - if -pedantic-errors is given, #warning should cause an error. */ - pedwarn ("#warning %s", copy); return 0; } - /* Remember the name of the current file being read from so that we can avoid ever including it again. */ @@ -7092,8 +7111,9 @@ do_pragma (buf, limit, op, keyword) return 0; fname = p + 1; - if ((p = (U_CHAR *) index ((char *) fname, '\"'))) - *p = '\0'; + p = skip_quoted_string (p, limit, 0, NULL_PTR, NULL_PTR, NULL_PTR); + if (p[-1] == '"') + *--p = '\0'; for (h = 0; h < INCLUDE_HASHSIZE; h++) { struct include_file *inc; @@ -7198,7 +7218,8 @@ do_elif (buf, limit, op, keyword) && !bcmp (if_stack->fname, ip->nominal_fname, if_stack->fname_len))) { fprintf (stderr, ", file "); - eprint_string (if_stack->fname, if_stack->fname_len); + fwrite (if_stack->fname, sizeof if_stack->fname[0], + if_stack->fname_len, stderr); } fprintf (stderr, ")\n"); } @@ -7238,7 +7259,7 @@ eval_if_expression (buf, length) pcp_inside_if = 0; delete_macro (save_defined); /* clean up special symbol */ - temp_obuf.buf[temp_obuf.length] = '\n'; + *temp_obuf.bufp = '\n'; value = parse_c_expression ((char *) temp_obuf.buf, warn_undef && !instack[indepth].system_header_p); @@ -7417,7 +7438,7 @@ skip_if_group (ip, any, op) while (bp < endb) { switch (*bp++) { case '/': /* possible comment */ - if (*bp == '\\' && bp[1] == '\n') + if (*bp == '\\') newline_fix (bp); if (*bp == '*' || (cplusplus_comments && *bp == '/')) { @@ -7547,7 +7568,7 @@ skip_if_group (ip, any, op) else if (*bp == '\\' && bp[1] == '\n') bp += 2; else if (*bp == '/') { - if (bp[1] == '\\' && bp[2] == '\n') + if (bp[1] == '\\') newline_fix (bp + 1); if (bp[1] == '*') { for (bp += 2; ; bp++) { @@ -7556,7 +7577,7 @@ skip_if_group (ip, any, op) else if (*bp == '*') { if (bp[-1] == '/' && warn_comments) warning ("`/*' within comment"); - if (bp[1] == '\\' && bp[2] == '\n') + if (bp[1] == '\\') newline_fix (bp + 1); if (bp[1] == '/') break; @@ -7609,7 +7630,7 @@ skip_if_group (ip, any, op) if (is_idchar[*bp]) bp++; else { - if (*bp == '\\' && bp[1] == '\n') + if (*bp == '\\') name_newline_fix (bp); if (is_idchar[*bp]) bp++; @@ -7778,7 +7799,8 @@ do_else (buf, limit, op, keyword) && !bcmp (if_stack->fname, ip->nominal_fname, if_stack->fname_len))) { fprintf (stderr, ", file "); - eprint_string (if_stack->fname, if_stack->fname_len); + fwrite (if_stack->fname, sizeof if_stack->fname[0], + if_stack->fname_len, stderr); } fprintf (stderr, ")\n"); } @@ -7998,7 +8020,7 @@ skip_to_end_of_comment (ip, line_counter, nowarn) case '*': if (bp[-2] == '/' && !nowarn && warn_comments) warning ("`/*' within comment"); - if (*bp == '\\' && bp[1] == '\n') + if (*bp == '\\') newline_fix (bp); if (*bp == '/') { if (op) @@ -8041,7 +8063,8 @@ skip_to_end_of_comment (ip, line_counter, nowarn) The input stack state is not changed. If COUNT_NEWLINES is nonzero, it points to an int to increment - for each newline passed. + for each newline passed; also, warn about any white space + just before line end. If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it if we pass a backslash-newline. @@ -8097,15 +8120,18 @@ skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p, } if (match == '\'') { error_with_line (line_for_error (start_line), - "unterminated string or character constant"); + "unterminated character constant"); bp--; if (eofp) *eofp = 1; break; } /* If not traditional, then allow newlines inside strings. */ - if (count_newlines) + if (count_newlines) { + if (warn_white_space && is_hor_space[bp[-2]]) + warning ("white space at end of line in string"); ++*count_newlines; + } if (multiline_string_line == 0) { if (pedantic) pedwarn_with_line (line_for_error (start_line), @@ -8295,9 +8321,9 @@ output_line_directive (ip, op, conditional, file_change) /* This structure represents one parsed argument in a macro call. `raw' points to the argument text as written (`raw_length' is its length). `expanded' points to the argument's macro-expansion - (its length is `expand_length'). - `stringified_length' is the length the argument would have - if stringified. + (its length is `expand_length', and its allocated size is `expand_size'). + `stringified_length_bound' is an upper bound on the length + the argument would have if stringified. `use_count' is the number of times this macro arg is substituted into the macro. If the actual use count exceeds 10, the value stored is 10. @@ -8306,8 +8332,8 @@ output_line_directive (ip, op, conditional, file_change) struct argdata { U_CHAR *raw, *expanded; - int raw_length, expand_length; - int stringified_length; + int raw_length, expand_length, expand_size; + int stringified_length_bound; U_CHAR *free1, *free2; char newlines; char use_count; @@ -8358,8 +8384,8 @@ macroexpand (hp, op) for (i = 0; i < nargs; i++) { args[i].raw = (U_CHAR *) ""; args[i].expanded = 0; - args[i].raw_length = args[i].expand_length - = args[i].stringified_length = 0; + args[i].raw_length = args[i].expand_length = args[i].expand_size + = args[i].stringified_length_bound = 0; args[i].free1 = args[i].free2 = 0; args[i].use_count = 0; } @@ -8453,7 +8479,7 @@ macroexpand (hp, op) xbuf_len = defn->length; for (ap = defn->pattern; ap != NULL; ap = ap->next) { if (ap->stringify) - xbuf_len += args[ap->argno].stringified_length; + xbuf_len += args[ap->argno].stringified_length_bound; else if (ap->raw_before != 0 || ap->raw_after != 0 || traditional) /* Add 4 for two newline-space markers to prevent token concatenation. */ @@ -8468,13 +8494,20 @@ macroexpand (hp, op) 1, 0); args[ap->argno].expanded = obuf.buf; - args[ap->argno].expand_length = obuf.length; + args[ap->argno].expand_length = obuf.bufp - obuf.buf; + args[ap->argno].expand_size = obuf.length; args[ap->argno].free2 = obuf.buf; - } + xbuf_len += args[ap->argno].expand_length; + } else { + /* If the arg appears more than once, its later occurrences + may have newline turned into backslash-'n', which is a + factor of 2 expansion. */ + xbuf_len += 2 * args[ap->argno].expand_length; + } /* Add 4 for two newline-space markers to prevent token concatenation. */ - xbuf_len += args[ap->argno].expand_length + 4; + xbuf_len += 4; } if (args[ap->argno].use_count < 10) args[ap->argno].use_count++; @@ -8531,27 +8564,28 @@ macroexpand (hp, op) for (; i < arglen; i++) { c = arg->raw[i]; - if (! in_string) { - /* Special markers Newline Space + if (in_string) { + /* Generate nothing for backslash-newline in a string. */ + if (c == '\\' && arg->raw[i + 1] == '\n') { + i++; + continue; + } + } else { + /* Special markers generate nothing for a stringified argument. */ - if (c == '\n' && arg->raw[i+1] != '\n') { + if (c == '\n') { i++; continue; } /* Internal sequences of whitespace are replaced by one space - except within an string or char token. */ - if (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c]) { - while (1) { - /* Note that Newline Space does occur within whitespace - sequences; consider it part of the sequence. */ - if (c == '\n' && is_space[arg->raw[i+1]]) - i += 2; - else if (c != '\n' && is_space[c]) - i++; - else break; - c = arg->raw[i]; - } + except within a string or char token. */ + if (is_space[c]) { + i++; + while (is_space[(c = arg->raw[i])]) + /* Newline markers can occur within a whitespace sequence; + consider them part of the sequence. */ + i += (c == '\n') + 1; i--; c = ' '; } @@ -8583,8 +8617,15 @@ macroexpand (hp, op) in_string = c; } - /* Escape these chars */ - if (c == '\"' || (in_string && c == '\\')) + /* Escape double-quote, and backslashes in strings. + Newlines in strings are best escaped as \n, since + otherwise backslash-backslash-newline-newline is + mishandled. The C Standard doesn't allow newlines in + strings, so we can escape newlines as we please. */ + if (c == '\"' + || (in_string + && (c == '\\' + || (c == '\n' ? (c = 'n', 1) : 0)))) xbuf[totlen++] = '\\'; /* We used to output e.g. \008 for control characters here, but this doesn't conform to the C Standard. @@ -8660,8 +8701,7 @@ macroexpand (hp, op) /* Don't bother doing change_newlines for subsequent uses of arg. */ arg->use_count = 1; - arg->expand_length - = change_newlines (arg->expanded, arg->expand_length); + change_newlines (arg); } } @@ -8738,23 +8778,23 @@ macarg (argptr, rest_args) { FILE_BUF *ip = &instack[indepth]; int paren = 0; - int newlines = 0; + int lineno0 = ip->lineno; int comments = 0; int result = 0; /* Try to parse as much of the argument as exists at this input stack level. */ U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro, - &paren, &newlines, &comments, rest_args); + &paren, &ip->lineno, &comments, rest_args); /* If we find the end of the argument at this level, set up *ARGPTR to point at it in the input stack. */ - if (!(ip->fname != 0 && (newlines != 0 || comments != 0)) + if (!(ip->fname != 0 && (ip->lineno != lineno0 || comments != 0)) && bp != ip->buf + ip->length) { if (argptr != 0) { argptr->raw = ip->bufp; argptr->raw_length = bp - ip->bufp; - argptr->newlines = newlines; + argptr->newlines = ip->lineno - lineno0; } ip->bufp = bp; } else { @@ -8763,13 +8803,12 @@ macarg (argptr, rest_args) Therefore, we must allocate a temporary buffer and copy the macro argument into it. */ int bufsize = bp - ip->bufp; - int extra = newlines; + int extra = ip->lineno - lineno0; U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1); int final_start = 0; bcopy ((char *) ip->bufp, (char *) buffer, bufsize); ip->bufp = bp; - ip->lineno += newlines; while (bp == ip->buf + ip->length) { if (instack[indepth].macro == 0) { @@ -8780,18 +8819,17 @@ macarg (argptr, rest_args) if (ip->free_ptr) free (ip->free_ptr); ip = &instack[--indepth]; - newlines = 0; + lineno0 = ip->lineno; comments = 0; bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro, &paren, - &newlines, &comments, rest_args); + &ip->lineno, &comments, rest_args); final_start = bufsize; bufsize += bp - ip->bufp; - extra += newlines; + extra += ip->lineno - lineno0; buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1); bcopy ((char *) ip->bufp, (char *) (buffer + bufsize - (bp - ip->bufp)), bp - ip->bufp); ip->bufp = bp; - ip->lineno += newlines; } /* Now, if arg is actually wanted, record its raw form, @@ -8803,13 +8841,13 @@ macarg (argptr, rest_args) argptr->raw = buffer; argptr->raw_length = bufsize; argptr->free1 = buffer; - argptr->newlines = newlines; - if ((newlines || comments) && ip->fname != 0) + argptr->newlines = ip->lineno - lineno0; + if ((argptr->newlines || comments) && ip->fname != 0) argptr->raw_length = final_start + discard_comments (argptr->raw + final_start, argptr->raw_length - final_start, - newlines); + argptr->newlines); argptr->raw[argptr->raw_length] = 0; if (argptr->raw_length > bufsize + extra) abort (); @@ -8843,10 +8881,10 @@ macarg (argptr, rest_args) SKIP_ALL_WHITE_SPACE (buf); else #endif - if (c == '\"' || c == '\\') /* escape these chars */ + if (c == '\"' || c == '\\' || c == '\n') /* escape these chars */ totlen++; } - argptr->stringified_length = totlen; + argptr->stringified_length_bound = totlen; } return result; } @@ -8895,7 +8933,7 @@ macarg1 (start, limit, macro, depthptr, newlines, comments, rest_args) case '/': if (macro) break; - if (bp[1] == '\\' && bp[2] == '\n') + if (bp[1] == '\\') newline_fix (bp + 1); if (bp[1] == '*') { *comments = 1; @@ -8905,7 +8943,7 @@ macarg1 (start, limit, macro, depthptr, newlines, comments, rest_args) else if (*bp == '*') { if (bp[-1] == '/' && warn_comments) warning ("`/*' within comment"); - if (bp[1] == '\\' && bp[2] == '\n') + if (bp[1] == '\\') newline_fix (bp + 1); if (bp[1] == '/') { bp++; @@ -8952,18 +8990,18 @@ macarg1 (start, limit, macro, depthptr, newlines, comments, rest_args) case '\"': { int quotec; - for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) { + for (quotec = *bp++; bp < limit && *bp != quotec; bp++) { if (*bp == '\\') { bp++; if (*bp == '\n') ++*newlines; - if (!macro) { - while (*bp == '\\' && bp[1] == '\n') { - bp += 2; - ++*newlines; - } + while (*bp == '\\' && bp[1] == '\n') { + bp += 2; + ++*newlines; } } else if (*bp == '\n') { + if (warn_white_space && is_hor_space[bp[-1]] && ! macro) + warning ("white space at end of line in string"); ++*newlines; if (quotec == '\'') break; @@ -9047,7 +9085,7 @@ discard_comments (start, length, newlines) break; case '/': - if (*ibp == '\\' && ibp[1] == '\n') + if (*ibp == '\\') newline_fix (ibp); /* Delete any comment. */ if (cplusplus_comments && ibp[0] == '/') { @@ -9082,7 +9120,7 @@ discard_comments (start, length, newlines) obp[-1] = ' '; while (++ibp < limit) { if (ibp[0] == '*') { - if (ibp[1] == '\\' && ibp[2] == '\n') + if (ibp[1] == '\\') newline_fix (ibp + 1); if (ibp[1] == '/') { ibp += 2; @@ -9153,15 +9191,16 @@ discard_comments (start, length, newlines) return obp - start; } -/* Turn newlines to spaces in the string of length LENGTH at START, - except inside of string constants. - The string is copied into itself with its beginning staying fixed. */ +/* Turn newlines to spaces in the macro argument ARG. + Remove backslash-newline from string constants, + and turn other newlines in string constants to backslash-'n'. */ -static int -change_newlines (start, length) - U_CHAR *start; - int length; +static void +change_newlines (arg) + struct argdata *arg; { + U_CHAR *start = arg->expanded; + int length = arg->expand_length; register U_CHAR *ibp; register U_CHAR *obp; register U_CHAR *limit; @@ -9225,7 +9264,10 @@ change_newlines (start, length) } } - return obp - start; + arg->expand_length = obp - arg->expanded; + + if (start != arg->expanded) + free (start); } /* notice - output message to stderr */ @@ -9293,7 +9335,8 @@ verror (msgid, args) } if (ip != NULL) { - eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0], + ip->nominal_fname_len, stderr); fprintf (stderr, ":%d: ", ip->lineno); } vnotice (msgid, args); @@ -9320,7 +9363,8 @@ error_from_errno (name) } if (ip != NULL) { - eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0], + ip->nominal_fname_len, stderr); fprintf (stderr, ":%d: ", ip->lineno); } @@ -9372,7 +9416,8 @@ vwarning (msgid, args) } if (ip != NULL) { - eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0], + ip->nominal_fname_len, stderr); fprintf (stderr, ":%d: ", ip->lineno); } notice ("warning: "); @@ -9419,7 +9464,8 @@ verror_with_line (line, msgid, args) } if (ip != NULL) { - eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0], + ip->nominal_fname_len, stderr); fprintf (stderr, ":%d: ", line); } vnotice (msgid, args); @@ -9471,7 +9517,8 @@ vwarning_with_line (line, msgid, args) } if (ip != NULL) { - eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0], + ip->nominal_fname_len, stderr); fprintf (stderr, line ? ":%d: " : ": ", line); } notice ("warning: "); @@ -9553,7 +9600,7 @@ pedwarn_with_file_and_line VPROTO ((const char *file, size_t file_len, int line, #endif if (file) { - eprint_string (file, file_len); + fwrite (file, sizeof file[0], file_len, stderr); fprintf (stderr, ":%d: ", line); } if (pedantic_errors) @@ -9614,7 +9661,8 @@ print_containing_files () notice (",\n from "); } - eprint_string (ip->nominal_fname, ip->nominal_fname_len); + fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0], + ip->nominal_fname_len, stderr); fprintf (stderr, ":%d", ip->lineno); } if (! first) @@ -10207,8 +10255,18 @@ make_definition (str) NULL_PTR, NULL_PTR, &unterminated); if (unterminated) return; - while (p != p1) - *q++ = *p++; + while (p != p1) { + if (*p == '\\' && p[1] == '\n') + p += 2; + else if (*p == '\n') + { + *q++ = '\\'; + *q++ = 'n'; + p++; + } + else + *q++ = *p++; + } } else if (*p == '\\' && p[1] == '\n') p += 2; /* Change newline chars into newline-markers. */ @@ -11048,4 +11106,25 @@ VMS_stat (name, statbuf) return result; } + +static size_t +VMS_fwrite (ptr, size, nitems, stream) + void const *ptr; + size_t size; + size_t nitems; + FILE *stream; +{ + /* VMS fwrite has undesirable results + if STREAM happens to be a record oriented file. + Work around this problem by writing each character individually. */ + char const *p = ptr; + size_t bytes = size * nitems; + char *lim = p + bytes; + + while (p < lim) + if (putc (*p++, stream) == EOF) + return 0; + + return bytes; +} #endif /* VMS */ |