From 1628305811247bd652099dad92f6498fc244d8dc Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 7 Jul 2017 18:12:16 -0700
Subject: [PATCH] Avoid ungetc when loading charset maps from files

* src/charset.c (read_hex): New args LOOKAHEAD and TERMINATOR,
replacing the old EOF.  All callers changed.  This avoids the
need to call ungetc.
---
 src/charset.c | 90 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 49 insertions(+), 41 deletions(-)

diff --git a/src/charset.c b/src/charset.c
index 9c3b8db2a53..6ce2f902c81 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -407,44 +407,49 @@ load_charset_map (struct charset *charset, struct charset_map_entries *entries,
 
 
 /* Read a hexadecimal number (preceded by "0x") from the file FP while
-   paying attention to comment character '#'.  */
+   paying attention to comment character '#'.  LOOKAHEAD is the
+   lookahead byte if it is nonnegative.  Store into *TERMINATOR the
+   input byte after the number, or EOF if an end-of-file or input
+   error occurred.  Set *OVERFLOW if the number overflows.  */
 
 static unsigned
-read_hex (FILE *fp, bool *eof, bool *overflow)
+read_hex (FILE *fp, int lookahead, int *terminator, bool *overflow)
 {
-  int c;
-  unsigned n;
+  int c = lookahead < 0 ? getc_unlocked (fp) : lookahead;
 
-  while ((c = getc_unlocked (fp)) != EOF)
+  while (true)
     {
       if (c == '#')
-	{
-	  while ((c = getc_unlocked (fp)) != EOF && c != '\n');
-	}
+	do
+	  c = getc_unlocked (fp);
+	while (0 <= c && c != '\n');
       else if (c == '0')
 	{
-	  if ((c = getc_unlocked (fp)) == EOF || c == 'x')
+	  c = getc_unlocked (fp);
+	  if (c < 0 || c == 'x')
 	    break;
 	}
-    }
-  if (c == EOF)
-    {
-      *eof = 1;
-      return 0;
-    }
-  n = 0;
-  while (true)
-    {
-      c = getc_unlocked (fp);
-      int digit = char_hexdigit (c);
-      if (digit < 0)
+      if (c < 0)
 	break;
-      if (INT_LEFT_SHIFT_OVERFLOW (n, 4))
-	*overflow = 1;
-      n = (n << 4) + digit;
+      c = getc_unlocked (fp);
     }
-  if (c != EOF)
-    ungetc (c, fp);
+
+  unsigned n = 0;
+  bool v = false;
+
+  if (0 <= c)
+    while (true)
+      {
+	c = getc_unlocked (fp);
+	int digit = char_hexdigit (c);
+	if (digit < 0)
+	  break;
+	v |= INT_LEFT_SHIFT_OVERFLOW (n, 4);
+	n = (n << 4) + digit;
+      }
+
+  *terminator = c;
+  *overflow |= v;
   return n;
 }
 
@@ -499,23 +504,26 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
   memset (entries, 0, sizeof (struct charset_map_entries));
 
   n_entries = 0;
-  while (1)
+  int ch = -1;
+  while (true)
     {
-      unsigned from, to, c;
-      int idx;
-      bool eof = 0, overflow = 0;
-
-      from = read_hex (fp, &eof, &overflow);
-      if (eof)
+      bool overflow = false;
+      unsigned from = read_hex (fp, ch, &ch, &overflow), to;
+      if (ch < 0)
 	break;
-      if (getc_unlocked (fp) == '-')
-	to = read_hex (fp, &eof, &overflow);
+      if (ch == '-')
+	{
+	  to = read_hex (fp, -1, &ch, &overflow);
+	  if (ch < 0)
+	    break;
+	}
       else
-	to = from;
-      if (eof)
-	break;
-      c = read_hex (fp, &eof, &overflow);
-      if (eof)
+	{
+	  to = from;
+	  ch = -1;
+	}
+      unsigned c = read_hex (fp, ch, &ch, &overflow);
+      if (ch < 0)
 	break;
 
       if (overflow)
@@ -530,7 +538,7 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
 	  memset (entries, 0, sizeof (struct charset_map_entries));
 	  n_entries = 0;
 	}
-      idx = n_entries;
+      int idx = n_entries;
       entries->entry[idx].from = from;
       entries->entry[idx].to = to;
       entries->entry[idx].c = c;
-- 
2.39.5