Problem with debugging quoted backslash-newline in macro (cont'd)

Paul Eggert eggert@twinsun.com
Sun Dec 6 02:14:00 GMT 1998


Whoops, in my previous message I sent the patch description but not
the patch itself.  Sorry.  Here it is.  This patch has been installed
in the GCC2 sources.

===================================================================
RCS file: cpp.texi,v
retrieving revision 2.8.0.2
diff -pu -r2.8.0.2 cpp.texi
--- cpp.texi	1998/02/08 11:56:47	2.8.0.2
+++ cpp.texi	1998/07/05 04:59:08
@@ -2619,10 +2619,6 @@ as when text other than a comment follow
 Like @samp{-pedantic}, except that errors are produced rather than
 warnings.
 
-@item -Wtrigraphs
-@findex -Wtrigraphs
-Warn if any trigraphs are encountered (assuming they are enabled).
-
 @item -Wcomment
 @findex -Wcomment
 @ignore
@@ -2635,10 +2631,19 @@ Warn if any trigraphs are encountered (a
 Warn whenever a comment-start sequence @samp{/*} appears in a @samp{/*}
 comment, or whenever a Backslash-Newline appears in a @samp{//} comment.
 
+@item -Wtrigraphs
+@findex -Wtrigraphs
+Warn if any trigraphs are encountered (assuming they are enabled).
+
+@item -Wwhite-space
+@findex -Wwhite-space
+Warn about possible white space confusion, e.g. white space between a
+backslash and a newline.
+
 @item -Wall
 @findex -Wall
-Requests both @samp{-Wtrigraphs} and @samp{-Wcomment} (but not
-@samp{-Wtraditional} or @samp{-Wundef}). 
+Requests @samp{-Wcomment}, @samp{-Wtrigraphs}, and @samp{-Wwhite-space}
+(but not @samp{-Wtraditional} or @samp{-Wundef}).
 
 @item -Wtraditional
 @findex -Wtraditional
===================================================================
RCS file: cccp.c,v
retrieving revision 2.8.1.7
diff -pu -r2.8.1.7 cccp.c
--- cccp.c	1998/12/03 02:28:47	2.8.1.7
+++ cccp.c	1998/12/05 11:50:23
@@ -87,10 +87,12 @@ 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 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
@@ -160,8 +162,10 @@ extern char *update_path PROTO((char *, 
 extern int sys_nerr;
 extern char *sys_errlist[];
 #else	/* HAVE_STRERROR */
+#ifdef NEED_DECLARATION_STRERROR
 char *strerror ();
 #endif
+#endif
 #else	/* VMS */
 char *strerror (int,...);
 #endif
@@ -309,6 +313,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;
@@ -845,7 +853,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.  */
@@ -864,7 +871,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
@@ -932,7 +939,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((char *, size_t));
 
 int main PROTO((int, char **));
 
@@ -941,6 +947,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 *));
@@ -1020,7 +1027,7 @@ static U_CHAR *macarg1 PROTO((U_CHAR *, 
 
 static int discard_comments PROTO((U_CHAR *, int, int));
 
-static int change_newlines PROTO((U_CHAR *, int));
+static void change_newlines PROTO((struct argdata *));
 
 char *my_strerror PROTO((int));
 static void notice PRINTF_PROTO_1((char *, ...));
@@ -1068,7 +1075,7 @@ static void append_include_chain PROTO((
 static int quote_string_for_make PROTO((char *, char *));
 static void deps_output PROTO((char *, int));
 
-static void fatal PRINTF_PROTO_1((char *, ...)) __attribute__ ((noreturn));
+void fatal PRINTF_PROTO_1((char *, ...)) __attribute__ ((noreturn));
 void fancy_abort PROTO((void)) __attribute__ ((noreturn));
 static void perror_with_name PROTO((char *));
 static void pfatal_with_name PROTO((char *)) __attribute__ ((noreturn));
@@ -1149,34 +1156,6 @@ safe_write (desc, ptr, len)
     len -= written;
   }
 }
-
-/* 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)
-     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);
-}
-
 
 int
 main (argc, argv)
@@ -1487,6 +1466,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"))
@@ -1503,6 +1486,7 @@ main (argc, argv)
 	  {
 	    warn_trigraphs = 1;
 	    warn_comments = 1;
+	    warn_white_space = 1;
 	  }
 	break;
 
@@ -1989,17 +1973,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;
     }
@@ -2060,8 +2041,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.
@@ -2149,6 +2131,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, ""))
@@ -2359,13 +2344,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)
@@ -2374,21 +2389,22 @@ 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;
-
-  /* What follows the backslash-newlines is not embarrassing.  */
+  } while (*p == '\\');
 
   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) {
@@ -2407,20 +2423,22 @@ 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;
-
-  /* What follows the backslash-newlines is not embarrassing.  */
+  } while (*p == '\\');
 
   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) {
@@ -2498,7 +2516,7 @@ get_lintcmd (ibp, limit, argstart, argle
  * 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.
@@ -2822,6 +2840,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.
@@ -2849,9 +2869,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;
@@ -2860,8 +2881,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++;
@@ -2899,7 +2922,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 == '/'))
@@ -3011,7 +3034,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;
@@ -3382,7 +3405,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) {
@@ -3395,7 +3418,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;
@@ -3645,9 +3668,6 @@ expand_to_temp_buffer (buf, limit, outpu
   if (indepth != odepth)
     abort ();
 
-  /* Record the output.  */
-  obuf.length = obuf.bufp - obuf.buf;
-
   assertions_flag = save_assertions_flag;
   return obuf;
 }
@@ -3693,7 +3713,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;
@@ -3714,7 +3734,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++;
@@ -3804,14 +3824,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 '"':
@@ -3863,7 +3881,7 @@ handle_directive (ip, op)
 	  break;
 
 	case '/':
-	  if (*bp == '\\' && bp[1] == '\n')
+	  if (*bp == '\\')
 	    newline_fix (bp);
 	  if (*bp == '*'
 	      || (cplusplus_comments && *bp == '/')) {
@@ -3946,12 +3964,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++;
@@ -3998,8 +4017,16 @@ handle_directive (ip, op)
 	      register U_CHAR *bp1
 		= skip_quoted_string (xp - 1, bp, ip->lineno,
 				      NULL_PTR, NULL_PTR, NULL_PTR);
-	      while (xp != bp1)
-		*cp++ = *xp++;
+	      while (xp != bp1) {
+		if ((*cp++ = *xp++) == '\n') {
+		  if (xp[-2] == '\\')
+		    cp -= 2;
+		  else {
+		    cp[-1] = '\\';
+		    *cp++ = 'n';
+		  }
+		}
+	      }
 	    }
 	    break;
 
@@ -4066,7 +4093,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
@@ -4088,12 +4115,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",
@@ -5219,6 +5253,9 @@ finclude (f, inc, op, system_header_p, d
   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);
 
@@ -5432,7 +5469,7 @@ pcfinclude (buf, limit, 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;
@@ -5456,6 +5493,7 @@ pcfinclude (buf, limit, 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);
@@ -5467,20 +5505,19 @@ pcfinclude (buf, limit, 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;
@@ -6041,7 +6078,7 @@ collect_expansion (buf, end, nargs, argl
 	break;
 
       case '\\':
-	if (p < limit && expected_delimiter) {
+	if (expected_delimiter) {
 	  /* In a string, backslash goes through
 	     and makes next char ordinary.  */
 	  *exp_p++ = *p++;
@@ -6709,6 +6746,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)) {
@@ -6751,10 +6789,6 @@ do_line (buf, limit, op, keyword)
     p = bp;
     for (;;)
       switch ((*p++ = *bp++)) {
-      case '\0':
-	error ("invalid format `#line' directive");
-	return 0;
-
       case '\\':
 	{
 	  char *bpc = (char *) bp;
@@ -6879,8 +6913,7 @@ do_undef (buf, limit, op, keyword)
 }
 
 /* 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)
@@ -6893,32 +6926,22 @@ do_error (buf, limit, op, keyword)
   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;
-     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);
+  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;
 }
 
@@ -6990,14 +7013,15 @@ do_pragma (buf, limit, op, keyword)
        been included yet.  */
 
     int h;
-    U_CHAR *p = buf + 14, *fname;
+    U_CHAR *p = buf + 14, *f, *fname;
     SKIP_WHITE_SPACE (p);
     if (*p != '\"')
       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;
@@ -7102,7 +7126,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");
     }
@@ -7142,7 +7167,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);
 
@@ -7321,7 +7346,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 == '/')) {
@@ -7451,7 +7476,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++) {
@@ -7460,7 +7485,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;
@@ -7511,7 +7536,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++;
@@ -7680,7 +7705,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");
     }
@@ -7895,7 +7921,7 @@ skip_to_end_of_comment (ip, line_counter
     case '*':
       if (bp[-2] == '/' && !nowarn && warn_comments)
 	warning ("`/*' within comment");
-      if (*bp == '\\' && bp[1] == '\n')
+      if (*bp == '\\')
 	newline_fix (bp);
       if (*bp == '/') {
         if (op)
@@ -7938,7 +7964,8 @@ skip_to_end_of_comment (ip, line_counter
    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.
@@ -7994,15 +8021,18 @@ skip_quoted_string (bp, limit, start_lin
       }
       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),
@@ -8192,9 +8222,9 @@ output_line_directive (ip, op, condition
 /* 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.
@@ -8203,8 +8233,8 @@ output_line_directive (ip, op, condition
 
 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;
@@ -8255,8 +8285,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;
     }
@@ -8350,7 +8380,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.  */
@@ -8365,13 +8395,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++;
@@ -8428,27 +8465,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 = ' ';
 	      }
@@ -8480,8 +8518,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.
@@ -8557,8 +8602,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);
 	  }
 	}
 
@@ -8635,23 +8679,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 {
@@ -8660,13 +8704,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) {
@@ -8677,18 +8720,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,
@@ -8700,13 +8742,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 ();
@@ -8740,10 +8782,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;
 }
@@ -8792,7 +8834,7 @@ macarg1 (start, limit, macro, depthptr, 
     case '/':
       if (macro)
 	break;
-      if (bp[1] == '\\' && bp[2] == '\n')
+      if (bp[1] == '\\')
 	newline_fix (bp + 1);
       if (bp[1] == '*') {
 	*comments = 1;
@@ -8802,7 +8844,7 @@ macarg1 (start, limit, macro, depthptr, 
 	  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++;
@@ -8845,18 +8887,18 @@ macarg1 (start, limit, macro, depthptr, 
     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;
@@ -8940,7 +8982,7 @@ discard_comments (start, length, newline
       break;
 
     case '/':
-      if (*ibp == '\\' && ibp[1] == '\n')
+      if (*ibp == '\\')
 	newline_fix (ibp);
       /* Delete any comment.  */
       if (cplusplus_comments && ibp[0] == '/') {
@@ -8976,7 +9018,7 @@ discard_comments (start, length, newline
 	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;
@@ -9047,27 +9089,26 @@ discard_comments (start, length, newline
   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;
-  register int c;
 
   ibp = start;
   limit = start + length;
   obp = start;
 
   while (ibp < limit) {
-    *obp++ = c = *ibp++;
-    switch (c) {
+    switch ((*obp++ = *ibp++)) {
     case '\n':
       /* If this is a NEWLINE NEWLINE, then this is a real newline in the
 	 string.  Skip past the newline and its duplicate.
@@ -9082,27 +9123,45 @@ change_newlines (start, length)
 
     case '\'':
     case '\"':
-      /* Notice and skip strings, so that we don't delete newlines in them.  */
+      /* Notice and skip strings, to handle their newlines properly.  */
       {
-	int quotec = c;
-	while (ibp < limit) {
-	  *obp++ = c = *ibp++;
-	  if (c == quotec)
-	    {
-	      if (ibp[-2] != '\\')
-		break;
+	U_CHAR *ibp1 = skip_quoted_string (ibp - 1, limit, 0,
+					   NULL_PTR, NULL_PTR, NULL_PTR);
+	while (ibp != ibp1) {
+	  switch ((*obp++ = *ibp++)) {
+	  case '\\':
+	    /* Replace backslash-newline with nothing.  */
+	    if (*ibp == '\n') {
+	      ++ibp;
+	      --obp;
 	    }
-	  else if (c == '\n')
-	    {
-	      if (quotec == '\'')
-		break;
+	    break;
+
+	  case '\n':
+	    /* Replace non-backslashed newline with backslash-'n',
+	       replacing the arg buffer with a new one if this hasn't
+	       been done already.  */
+
+	    if (start == arg->expanded) {
+	      int olength = obp - arg->expanded;
+	      U_CHAR *newbuf;
+	      arg->expand_size = 2 * arg->expand_length;
+	      newbuf = (U_CHAR *) xmalloc (arg->expand_size);
+	      arg->free2 = arg->expanded = newbuf;
+	      obp = newbuf + olength;
+	      bcopy ((char *) start, (char *) newbuf, olength);
 	    }
-	  else
-	    {
+
+	    obp[-1] = '\\';
+	    *obp++ = 'n';
+	    break;
+
 #ifdef MULTIBYTE_CHARS
+	  default:
+	    {
 	      int length;
 	      ibp--;
-	      length = local_mblen (ibp, limit - ibp);
+	      length = local_mblen (ibp, ibp1 - ibp);
 	      if (length > 1)
 		{
 		  obp--;
@@ -9112,15 +9171,19 @@ change_newlines (start, length)
 		}
 	      else
 		ibp++;
-#endif
 	    }
+#endif
+	  }
 	}
       }
       break;
     }
   }
 
-  return obp - start;
+  arg->expand_length = obp - arg->expanded;
+
+  if (start != arg->expanded)
+    free (start);
 }
 
 /* my_strerror - return the descriptive text associated with an
@@ -9206,7 +9269,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);
@@ -9233,7 +9297,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);
   }
 
@@ -9278,7 +9343,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: ");
@@ -9320,7 +9386,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);
@@ -9368,7 +9435,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: ");
@@ -9431,7 +9499,7 @@ pedwarn_with_file_and_line (file, file_l
   if (!pedantic_errors && inhibit_warnings)
     return;
   if (file) {
-    eprint_string (file, file_len);
+    fwrite (file, sizeof file[0], file_len, stderr);
     fprintf (stderr, ":%d: ", line);
   }
   if (pedantic_errors)
@@ -9493,7 +9561,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)
@@ -10090,8 +10159,18 @@ make_definition (str, op)
 					 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.  */
@@ -10452,7 +10531,7 @@ deps_output (string, spacer)
   deps_buffer[deps_size] = 0;
 }
 
-static void
+void
 fatal (PRINTF_ALIST (msgid))
      PRINTF_DCL (msgid)
 {
@@ -10832,4 +10911,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 */
===================================================================
RCS file: cexp.y,v
retrieving revision 2.8.1.1
diff -pu -r2.8.1.1 cexp.y
--- cexp.y	1998/12/03 02:28:48	2.8.1.1
+++ cexp.y	1998/12/05 11:09:34
@@ -225,6 +225,7 @@ HOST_WIDE_INT parse_escape PROTO((char *
 int check_assertion PROTO((U_CHAR *, int, int, struct arglist *));
 struct hashnode *lookup PROTO((U_CHAR *, int, int));
 void error PRINTF_PROTO_1((char *, ...));
+void fatal PRINTF_PROTO_1((char *, ...)) __attribute__ ((noreturn));
 void verror PROTO((char *, va_list));
 void pedwarn PRINTF_PROTO_1((char *, ...));
 void warning PRINTF_PROTO_1((char *, ...));
@@ -612,7 +613,7 @@ yylex ()
   register unsigned char *tokstart;
   register struct token *toktab;
   int wide_flag;
-  HOST_WIDE_INT mask;
+  HOST_WIDE_INT mask = ~ (HOST_WIDE_INT) 0;
 
  retry:
 
@@ -644,21 +645,18 @@ yylex ()
       {
 	lexptr++;
 	wide_flag = 1;
-	mask = MAX_WCHAR_TYPE_MASK;
 	goto char_constant;
       }
     if (lexptr[1] == '"')
       {
 	lexptr++;
 	wide_flag = 1;
-	mask = MAX_WCHAR_TYPE_MASK;
 	goto string_constant;
       }
     break;
 
   case '\'':
     wide_flag = 0;
-    mask = MAX_CHAR_TYPE_MASK;
   char_constant:
     lexptr++;
     if (keyword_parsing) {
@@ -666,7 +664,7 @@ yylex ()
       while (1) {
 	c = *lexptr++;
 	if (c == '\\')
-	  c = parse_escape (&lexptr, mask);
+	  parse_escape (&lexptr, mask);
 	else if (c == '\'')
 	  break;
       }
@@ -696,15 +694,16 @@ yylex ()
 
       while (1)
 	{
+ 	  HOST_WIDE_INT ch;
 	  c = *lexptr++;
 
-	  if (c == '\'' || c == EOF)
+ 	  if (c == '\'')
 	    break;
 
 	  ++chars_seen;
 	  if (c == '\\')
 	    {
-	      c = parse_escape (&lexptr, mask);
+	      ch = parse_escape (&lexptr, mask);
 	    }
 	  else
 	    {
@@ -751,23 +750,27 @@ yylex ()
 	      if (wide_flag)
 		c = wc;
 #endif /* ! MULTIBYTE_CHARS */
+	      ch = c & mask;
 	    }
 
 	  if (wide_flag)
 	    {
 	      if (chars_seen == 1) /* only keep the first one */
-		result = c;
+		result = ch;
+	      mask = MAX_WCHAR_TYPE_MASK;
 	      continue;
 	    }
 
+ 	  mask = MAX_CHAR_TYPE_MASK;
+
 	  /* Merge character into result; ignore excess chars.  */
 	  num_chars++;
 	  if (num_chars <= max_chars)
 	    {
-	      if (width < HOST_BITS_PER_INT)
-		result = (result << width) | (c & ((1 << width) - 1));
+	      if (width < HOST_BITS_PER_WIDE_INT)
+		result = (result << width) | ch;
 	      else
-		result = c;
+		result = ch;
 	    }
 	}
 
@@ -845,7 +848,6 @@ yylex ()
     return c;
 
   case '"':
-    mask = MAX_CHAR_TYPE_MASK;
   string_constant:
     if (keyword_parsing) {
       char *start_ptr = lexptr;
@@ -853,7 +855,7 @@ yylex ()
       while (1) {
 	c = *lexptr++;
 	if (c == '\\')
-	  c = parse_escape (&lexptr, mask);
+	  parse_escape (&lexptr, mask);
 	else if (c == '"')
 	  break;
       }
@@ -916,11 +918,10 @@ yylex ()
    RESULT_MASK is used to mask out the result;
    an error is reported if bits are lost thereby.
 
-   A negative value means the sequence \ newline was seen,
-   which is supposed to be equivalent to nothing at all.
+   Returning -1 means an incomplete escape sequence was seen.
 
-   If \ is followed by a null character, we return a negative
-   value and leave the string pointer pointing at the null character.
+   Returning -2 means the sequence \ newline was seen,
+   which is supposed to be equivalent to nothing at all.
 
    If \ is followed by 000, we return 0 and leave the string pointer
    after the zeros.  A value of 0 does not mean end of string.  */
@@ -930,33 +931,45 @@ parse_escape (string_ptr, result_mask)
      char **string_ptr;
      HOST_WIDE_INT result_mask;
 {
-  register int c = *(*string_ptr)++;
+  register char *p = *string_ptr;
+  register int c;
+  register HOST_WIDE_INT i;
+
+  while ((c = *p++) == '\\' && *p == '\n')
+    p++;
+
   switch (c)
     {
     case 'a':
-      return TARGET_BELL;
+      i = TARGET_BELL;
+      break;
     case 'b':
-      return TARGET_BS;
+      i = TARGET_BS;
+      break;
     case 'e':
     case 'E':
       if (pedantic)
 	pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
-      return 033;
+      i = 033;
+      break;
     case 'f':
-      return TARGET_FF;
+      i = TARGET_FF;
+      break;
     case 'n':
-      return TARGET_NEWLINE;
+      i = TARGET_NEWLINE;
+      break;
     case 'r':
-      return TARGET_CR;
+      i = TARGET_CR;
+      break;
     case 't':
-      return TARGET_TAB;
+      i = TARGET_TAB;
+      break;
     case 'v':
-      return TARGET_VT;
+      i = TARGET_VT;
+      break;
     case '\n':
-      return -2;
-    case 0:
-      (*string_ptr)--;
-      return 0;
+      i = -2;
+      break;
       
     case '0':
     case '1':
@@ -967,16 +980,17 @@ parse_escape (string_ptr, result_mask)
     case '6':
     case '7':
       {
-	register HOST_WIDE_INT i = c - '0';
 	register int count = 0;
+	i = c - '0';
 	while (++count < 3)
 	  {
-	    c = *(*string_ptr)++;
+	    while ((c = *p++) == '\\' && *p == '\n')
+	      p++;
 	    if (c >= '0' && c <= '7')
 	      i = (i << 3) + c - '0';
 	    else
 	      {
-		(*string_ptr)--;
+		p--;
 		break;
 	      }
 	  }
@@ -985,15 +999,16 @@ parse_escape (string_ptr, result_mask)
 	    i &= result_mask;
 	    pedwarn ("octal escape sequence out of range");
 	  }
-	return i;
       }
+      break;
     case 'x':
       {
-	register unsigned_HOST_WIDE_INT i = 0, overflow = 0;
+	register unsigned_HOST_WIDE_INT u = 0, overflow = 0;
 	register int digits_found = 0, digit;
 	for (;;)
 	  {
-	    c = *(*string_ptr)++;
+	    while ((c = *p++) == '\\' && *p == '\n')
+	      p++;
 	    if (c >= '0' && c <= '9')
 	      digit = c - '0';
 	    else if (c >= 'a' && c <= 'f')
@@ -1002,25 +1017,30 @@ parse_escape (string_ptr, result_mask)
 	      digit = c - 'A' + 10;
 	    else
 	      {
-		(*string_ptr)--;
+		p--;
 		break;
 	      }
-	    overflow |= i ^ (i << 4 >> 4);
-	    i = (i << 4) + digit;
+	    overflow |= u ^ (u << 4 >> 4);
+	    u = (u << 4) + digit;
 	    digits_found = 1;
 	  }
 	if (!digits_found)
 	  yyerror ("\\x used with no following hex digits");
-	if (overflow | (i != (i & result_mask)))
+	if (overflow | (u != (u & result_mask)))
 	  {
-	    i &= result_mask;
+	    u &= result_mask;
 	    pedwarn ("hex escape sequence out of range");
 	  }
-	return i;
+	i = u;
       }
+      break;
     default:
-      return c;
+      i = c;
+      break;
     }
+
+  *string_ptr = p;
+  return i;
 }
 
 static void



More information about the Gcc-bugs mailing list