emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 27d1018 2/3: Prefer more inline functions in character.h


From: Paul Eggert
Subject: master 27d1018 2/3: Prefer more inline functions in character.h
Date: Fri, 17 Apr 2020 12:17:43 -0400 (EDT)

branch: master
commit 27d101832ada36e431ae6cdecb5c82a180566377
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Prefer more inline functions in character.h
    
    * src/buffer.h (fetch_char_advance, fetch_char_advance_no_check)
    (buf_next_char_len, next_char_len, buf_prev_char_len)
    (prev_char_len, inc_both, dec_both): New inline functions,
    replacing the old character.h macros FETCH_CHAR_ADVANCE,
    FETCH_CHAR_ADVANCE_NO_CHECK, BUF_INC_POS, INC_POS, BUF_DEC_POS,
    DEC_POS, INC_BOTH, DEC_BOTH respectively.  All callers changed.
    These new functions all assume buffer primitives and so need
    to be here rather than in character.h.
    * src/casefiddle.c (make_char_unibyte): New static function,
    replacing the old MAKE_CHAR_UNIBYTE macro.  All callers changed.
    (do_casify_unibyte_string): Use SINGLE_BYTE_CHAR_P instead
    of open-coding it.
    * src/ccl.c (GET_TRANSLATION_TABLE): New static function,
    replacing the old macro of the same name.
    * src/character.c (string_char): Omit 2nd arg.  3rd arg can no
    longer be NULL.  All callers changed.
    * src/character.h (SINGLE_BYTE_CHAR_P): Move up.
    (MAKE_CHAR_UNIBYTE, MAKE_CHAR_MULTIBYTE, PREV_CHAR_BOUNDARY)
    (STRING_CHAR_AND_LENGTH, STRING_CHAR_ADVANCE)
    (FETCH_STRING_CHAR_ADVANCE)
    (FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE)
    (FETCH_STRING_CHAR_ADVANCE_NO_CHECK, FETCH_CHAR_ADVANCE)
    (FETCH_CHAR_ADVANCE_NO_CHECK, INC_POS, DEC_POS, INC_BOTH)
    (DEC_BOTH, BUF_INC_POS, BUF_DEC_POS): Remove.
    (make_char_multibyte): New static function, replacing
    the old macro MAKE_CHAR_MULTIBYTE.  All callers changed.
    (CHAR_STRING_ADVANCE): Remove; all callers changed to use
    CHAR_STRING.
    (NEXT_CHAR_BOUNDARY): Remove; it was unused.
    (raw_prev_char_len): New inline function, replacing the
    old PREV_CHAR_BOUNDARY macro.  All callers changed.
    (string_char_and_length): New inline function, replacing the
    old STRING_CHAR_AND_LENGTH macro.  All callers changed.
    (STRING_CHAR): Rewrite in terms of string_char_and_length.
    (string_char_advance): New inline function, replacing the old
    STRING_CHAR_ADVANCE macro.  All callers changed.
    (fetch_string_char_advance): New inline function, replacing the
    old FETCH_STRING_CHAR_ADVANCE macro.  All callers changed.
    (fetch_string_char_as_multibyte_advance): New inline function,
    replacing the old FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE macro.
    All callers changed.
    (fetch_string_char_advance_no_check): New inline function,
    replacing the old FETCH_STRING_CHAR_ADVANCE_NO_CHECK macro.  All
    callers changed.
    * src/regex-emacs.c (HEAD_ADDR_VSTRING): Remove; no longer used.
    * src/syntax.c (scan_lists): Use dec_bytepos instead of
    open-coding it.
    * src/xdisp.c (string_char_and_length): Rename from
    string_char_and_length to avoid name conflict with new function in
    character.h.  All callers changed.
---
 src/bidi.c        |  20 +--
 src/buffer.c      |   8 +-
 src/buffer.h      | 101 ++++++++++++
 src/bytecode.c    |   2 +-
 src/casefiddle.c  |  30 ++--
 src/ccl.c         |  11 +-
 src/character.c   |  31 ++--
 src/character.h   | 449 +++++++++++++++++-------------------------------------
 src/charset.c     |   4 +-
 src/chartab.c     |  10 +-
 src/cmds.c        |   2 +-
 src/coding.c      |  61 ++++----
 src/composite.c   |  42 +++--
 src/dispextern.h  |   4 +-
 src/editfns.c     |  26 ++--
 src/fns.c         |  52 +++----
 src/font.c        |  38 +++--
 src/ftcrfont.c    |   5 +-
 src/indent.c      |  24 ++-
 src/insdel.c      |   7 +-
 src/keyboard.c    |  10 +-
 src/keymap.c      |   6 +-
 src/lread.c       |  33 ++--
 src/marker.c      |  10 +-
 src/menu.c        |   4 +-
 src/msdos.c       |   2 +-
 src/nsfont.m      |   2 +-
 src/print.c       |  31 ++--
 src/regex-emacs.c |  28 ++--
 src/search.c      |  46 +++---
 src/syntax.c      | 113 +++++++-------
 src/sysdep.c      |  14 +-
 src/xdisp.c       |  71 ++++-----
 src/xfont.c       |   2 +-
 src/xterm.c       |   2 +-
 35 files changed, 579 insertions(+), 722 deletions(-)

diff --git a/src/bidi.c b/src/bidi.c
index 3abde7f..1017bd2 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -109,7 +109,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
    -------------------
 
    In a nutshell, fetching the next character boils down to calling
-   STRING_CHAR_AND_LENGTH, passing it the address of a buffer or
+   string_char_and_length, passing it the address of a buffer or
    string position.  See bidi_fetch_char.  However, if the next
    character is "covered" by a display property of some kind,
    bidi_fetch_char returns the u+FFFC "object replacement character"
@@ -1269,7 +1269,6 @@ bidi_fetch_char (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t *disp_pos,
   ptrdiff_t endpos
     = (string->s || STRINGP (string->lstring)) ? string->schars : ZV;
   struct text_pos pos;
-  int len;
 
   /* If we got past the last known position of display string, compute
      the position of the next one.  That position could be at CHARPOS.  */
@@ -1341,10 +1340,10 @@ bidi_fetch_char (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t *disp_pos,
     normal_char:
       if (string->s)
        {
-
          if (!string->unibyte)
            {
-             ch = STRING_CHAR_AND_LENGTH (string->s + bytepos, len);
+             int len;
+             ch = string_char_and_length (string->s + bytepos, &len);
              *ch_len = len;
            }
          else
@@ -1357,8 +1356,9 @@ bidi_fetch_char (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t *disp_pos,
        {
          if (!string->unibyte)
            {
-             ch = STRING_CHAR_AND_LENGTH (SDATA (string->lstring) + bytepos,
-                                          len);
+             int len;
+             ch = string_char_and_length (SDATA (string->lstring) + bytepos,
+                                          &len);
              *ch_len = len;
            }
          else
@@ -1369,9 +1369,11 @@ bidi_fetch_char (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t *disp_pos,
        }
       else
        {
-         ch = STRING_CHAR_AND_LENGTH (BYTE_POS_ADDR (bytepos), len);
+         int len;
+         ch = string_char_and_length (BYTE_POS_ADDR (bytepos), &len);
          *ch_len = len;
        }
+
       *nchars = 1;
     }
 
@@ -1550,7 +1552,7 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t 
pos_byte)
         display string?  And what if a display string covering some
         of the text over which we scan back includes
         paragraph_start_re?  */
-      DEC_BOTH (pos, pos_byte);
+      dec_both (&pos, &pos_byte);
       if (bpc && region_cache_backward (cache_buffer, bpc, pos, &next))
        {
          pos = next, pos_byte = CHAR_TO_BYTE (pos);
@@ -1763,7 +1765,7 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it 
*bidi_it, bool no_default_p)
                    /* FXIME: What if p is covered by a display
                       string?  See also a FIXME inside
                       bidi_find_paragraph_start.  */
-                   DEC_BOTH (p, pbyte);
+                   dec_both (&p, &pbyte);
                    prevpbyte = bidi_find_paragraph_start (p, pbyte);
                  }
                pstartbyte = prevpbyte;
diff --git a/src/buffer.c b/src/buffer.c
index f3532a8..5398414 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2308,7 +2308,7 @@ advance_to_char_boundary (ptrdiff_t byte_pos)
          c = FETCH_BYTE (byte_pos);
        }
       while (! CHAR_HEAD_P (c) && byte_pos > BEG);
-      INC_POS (byte_pos);
+      byte_pos += next_char_len (byte_pos);
       if (byte_pos < orig_byte_pos)
        byte_pos = orig_byte_pos;
       /* If C is a constituent of a multibyte sequence, BYTE_POS was
@@ -2552,8 +2552,6 @@ current buffer is cleared.  */)
       p = BEG_ADDR;
       while (1)
        {
-         int c, bytes;
-
          if (pos == stop)
            {
              if (pos == Z)
@@ -2565,7 +2563,7 @@ current buffer is cleared.  */)
            p++, pos++;
          else if (CHAR_BYTE8_HEAD_P (*p))
            {
-             c = STRING_CHAR_AND_LENGTH (p, bytes);
+             int bytes, c = string_char_and_length (p, &bytes);
              /* Delete all bytes for this 8-bit character but the
                 last one, and change the last one to the character
                 code.  */
@@ -2582,7 +2580,7 @@ current buffer is cleared.  */)
            }
          else
            {
-             bytes = BYTES_BY_CHAR_HEAD (*p);
+             int bytes = BYTES_BY_CHAR_HEAD (*p);
              p += bytes, pos += bytes;
            }
        }
diff --git a/src/buffer.h b/src/buffer.h
index 9875b8a..3da4941 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -1562,6 +1562,107 @@ CHARACTER_WIDTH (int c)
          : !NILP (BVAR (current_buffer, ctl_arrow)) ? 2 : 4);
 }
 
+
+/* Like fetch_string_char_advance, but fetch character from the current
+   buffer.  */
+
+INLINE int
+fetch_char_advance (ptrdiff_t *charidx, ptrdiff_t *byteidx)
+{
+  int output;
+  ptrdiff_t c = *charidx, b = *byteidx;
+  c++;
+  unsigned char *chp = BYTE_POS_ADDR (b);
+  if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
+    {
+      int chlen;
+      output = string_char_and_length (chp, &chlen);
+      b += chlen;
+    }
+  else
+    {
+      output = *chp;
+      b++;
+    }
+  *charidx = c;
+  *byteidx = b;
+  return output;
+}
+
+
+/* Like fetch_char_advance, but assumes the current buffer is multibyte.  */
+
+INLINE int
+fetch_char_advance_no_check (ptrdiff_t *charidx, ptrdiff_t *byteidx)
+{
+  int output;
+  ptrdiff_t c = *charidx, b = *byteidx;
+  c++;
+  unsigned char *chp = BYTE_POS_ADDR (b);
+  int chlen;
+  output = string_char_and_length (chp, &chlen);
+  b += chlen;
+  *charidx = c;
+  *byteidx = b;
+  return output;
+}
+
+/* Return the number of bytes in the multibyte character in BUF
+   that starts at position POS_BYTE.  This relies on the fact that
+   *GPT_ADDR and *Z_ADDR are always accessible and the values are
+   '\0'.  No range checking of POS_BYTE.  */
+
+INLINE int
+buf_next_char_len (struct buffer *buf, ptrdiff_t pos_byte)
+{
+  unsigned char *chp = BUF_BYTE_ADDRESS (buf, pos_byte);
+  return BYTES_BY_CHAR_HEAD (*chp);
+}
+
+INLINE int
+next_char_len (ptrdiff_t pos_byte)
+{
+  return buf_next_char_len (current_buffer, pos_byte);
+}
+
+/* Return the number of bytes in the multibyte character in BUF just
+   before POS_BYTE.  No range checking of POS_BYTE.  */
+
+INLINE int
+buf_prev_char_len (struct buffer *buf, ptrdiff_t pos_byte)
+{
+  unsigned char *chp
+    = (BUF_BEG_ADDR (buf) + pos_byte - BEG_BYTE
+       + (pos_byte <= BUF_GPT_BYTE (buf) ? 0 : BUF_GAP_SIZE (buf)));
+  return raw_prev_char_len (chp);
+}
+
+INLINE int
+prev_char_len (ptrdiff_t pos_byte)
+{
+  return buf_prev_char_len (current_buffer, pos_byte);
+}
+
+/* Increment both *CHARPOS and *BYTEPOS, each in the appropriate way.  */
+
+INLINE void
+inc_both (ptrdiff_t *charpos, ptrdiff_t *bytepos)
+{
+  (*charpos)++;
+  (*bytepos) += (!NILP (BVAR (current_buffer, enable_multibyte_characters))
+                ? next_char_len (*bytepos) : 1);
+}
+
+/* Decrement both *CHARPOS and *BYTEPOS, each in the appropriate way.  */
+
+INLINE void
+dec_both (ptrdiff_t *charpos, ptrdiff_t *bytepos)
+{
+  (*charpos)--;
+  (*bytepos) -= (!NILP (BVAR (current_buffer, enable_multibyte_characters))
+                ? prev_char_len (*bytepos) : 1);
+}
+
 INLINE_HEADER_END
 
 #endif /* EMACS_BUFFER_H */
diff --git a/src/bytecode.c b/src/bytecode.c
index 4624379..3c90544 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -1172,7 +1172,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, 
Lisp_Object maxdepth,
            CHECK_CHARACTER (TOP);
            int c = XFIXNAT (TOP);
            if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
-             MAKE_CHAR_MULTIBYTE (c);
+             c = make_char_multibyte (c);
            XSETFASTINT (TOP, syntax_code_spec[SYNTAX (c)]);
          }
          NEXT;
diff --git a/src/casefiddle.c b/src/casefiddle.c
index 5018b7b..9a711a8 100644
--- a/src/casefiddle.c
+++ b/src/casefiddle.c
@@ -220,6 +220,13 @@ case_character (struct casing_str_buf *buf, struct 
casing_context *ctx,
   return changed;
 }
 
+/* If C is not ASCII, make it unibyte. */
+static int
+make_char_unibyte (int c)
+{
+  return ASCII_CHAR_P (c) ? c : CHAR_TO_BYTE8 (c);
+}
+
 static Lisp_Object
 do_casify_natnum (struct casing_context *ctx, Lisp_Object obj)
 {
@@ -243,13 +250,13 @@ do_casify_natnum (struct casing_context *ctx, Lisp_Object 
obj)
                    || !NILP (BVAR (current_buffer,
                                    enable_multibyte_characters)));
   if (! multibyte)
-    MAKE_CHAR_MULTIBYTE (ch);
+    ch = make_char_multibyte (ch);
   int cased = case_single_character (ctx, ch);
   if (cased == ch)
     return obj;
 
   if (! multibyte)
-    MAKE_CHAR_UNIBYTE (cased);
+    cased = make_char_unibyte (cased);
   return make_fixed_natnum (cased | flags);
 }
 
@@ -278,7 +285,7 @@ do_casify_multibyte_string (struct casing_context *ctx, 
Lisp_Object obj)
     {
       if (dst_end - o < sizeof (struct casing_str_buf))
        string_overflow ();
-      int ch = STRING_CHAR_ADVANCE (src);
+      int ch = string_char_advance (&src);
       case_character ((struct casing_str_buf *) o, ctx, ch,
                      size > 1 ? src : NULL);
       n += ((struct casing_str_buf *) o)->len_chars;
@@ -299,15 +306,14 @@ do_casify_unibyte_string (struct casing_context *ctx, 
Lisp_Object obj)
   obj = Fcopy_sequence (obj);
   for (i = 0; i < size; i++)
     {
-      ch = SREF (obj, i);
-      MAKE_CHAR_MULTIBYTE (ch);
+      ch = make_char_multibyte (SREF (obj, i));
       cased = case_single_character (ctx, ch);
       if (ch == cased)
        continue;
-      MAKE_CHAR_UNIBYTE (cased);
+      cased = make_char_unibyte (cased);
       /* If the char can't be converted to a valid byte, just don't
         change it.  */
-      if (cased >= 0 && cased < 256)
+      if (SINGLE_BYTE_CHAR_P (cased))
        SSET (obj, i, cased);
     }
   return obj;
@@ -397,9 +403,7 @@ do_casify_unibyte_region (struct casing_context *ctx,
 
   for (ptrdiff_t pos = *startp; pos < end; ++pos)
     {
-      int ch = FETCH_BYTE (pos);
-      MAKE_CHAR_MULTIBYTE (ch);
-
+      int ch = make_char_multibyte (FETCH_BYTE (pos));
       int cased = case_single_character (ctx, ch);
       if (cased == ch)
        continue;
@@ -408,8 +412,7 @@ do_casify_unibyte_region (struct casing_context *ctx,
       if (first < 0)
        first = pos;
 
-      MAKE_CHAR_UNIBYTE (cased);
-      FETCH_BYTE (pos) = cased;
+      FETCH_BYTE (pos) = make_char_unibyte (cased);
     }
 
   *startp = first;
@@ -433,8 +436,7 @@ do_casify_multibyte_region (struct casing_context *ctx,
 
   for (; size; --size)
     {
-      int len;
-      int ch = STRING_CHAR_AND_LENGTH (BYTE_POS_ADDR (pos_byte), len);
+      int len, ch = string_char_and_length (BYTE_POS_ADDR (pos_byte), &len);
       struct casing_str_buf buf;
       if (!case_character (&buf, ctx, ch,
                           size > 1 ? BYTE_POS_ADDR (pos_byte + len) : NULL))
diff --git a/src/ccl.c b/src/ccl.c
index ac44dc1..0f82b97 100644
--- a/src/ccl.c
+++ b/src/ccl.c
@@ -855,6 +855,13 @@ struct ccl_prog_stack
 /* For the moment, we only support depth 256 of stack.  */
 static struct ccl_prog_stack ccl_prog_stack_struct[256];
 
+/* Return a translation table of id number ID.  */
+static Lisp_Object
+GET_TRANSLATION_TABLE (int id)
+{
+  return XCDR (XVECTOR (Vtranslation_table_vector)->contents[id]);
+}
+
 void
 ccl_driver (struct ccl_program *ccl, int *source, int *destination, int 
src_size, int dst_size, Lisp_Object charset_list)
 {
@@ -2101,7 +2108,7 @@ usage: (ccl-execute-on-string CCL-PROGRAM STATUS STRING 
&optional CONTINUE UNIBY
          source[j++] = *p++;
       else
        while (j < CCL_EXECUTE_BUF_SIZE && p < endp)
-         source[j++] = STRING_CHAR_ADVANCE (p);
+         source[j++] = string_char_advance (&p);
       consumed_chars += j;
       consumed_bytes = p - SDATA (str);
 
@@ -2126,7 +2133,7 @@ usage: (ccl-execute-on-string CCL-PROGRAM STATUS STRING 
&optional CONTINUE UNIBY
          if (NILP (unibyte_p))
            {
              for (j = 0; j < ccl.produced; j++)
-               CHAR_STRING_ADVANCE (destination[j], outp);
+               outp += CHAR_STRING (destination[j], outp);
            }
          else
            {
diff --git a/src/character.c b/src/character.c
index c938e9f..303c83c 100644
--- a/src/character.c
+++ b/src/character.c
@@ -141,15 +141,11 @@ char_string (unsigned int c, unsigned char *p)
 }
 
 
-/* Return a character whose multibyte form is at P.  If LEN is not
-   NULL, it must be a pointer to integer.  In that case, set *LEN to
-   the byte length of the multibyte form.  If ADVANCED is not NULL, it
-   must be a pointer to unsigned char.  In that case, set *ADVANCED to
-   the ending address (i.e., the starting address of the next
-   character) of the multibyte form.  */
+/* Return a character whose multibyte form is at P.  Set *LEN to the
+   byte length of the multibyte form.  */
 
 int
-string_char (const unsigned char *p, const unsigned char **advanced, int *len)
+string_char (const unsigned char *p, int *len)
 {
   int c;
   const unsigned char *saved_p = p;
@@ -157,7 +153,7 @@ string_char (const unsigned char *p, const unsigned char 
**advanced, int *len)
   if (*p < 0x80 || ! (*p & 0x20) || ! (*p & 0x10))
     {
       /* 1-, 2-, and 3-byte sequences can be handled by the macro.  */
-      c = STRING_CHAR_ADVANCE (p);
+      c = string_char_advance (&p);
     }
   else if (! (*p & 0x08))
     {
@@ -185,10 +181,7 @@ string_char (const unsigned char *p, const unsigned char 
**advanced, int *len)
       p += 5;
     }
 
-  if (len)
-    *len = p - saved_p;
-  if (advanced)
-    *advanced = p;
+  *len = p - saved_p;
   return c;
 }
 
@@ -248,8 +241,7 @@ DEFUN ("unibyte-char-to-multibyte", 
Funibyte_char_to_multibyte,
   c = XFIXNAT (ch);
   if (c >= 0x100)
     error ("Not a unibyte character: %d", c);
-  MAKE_CHAR_MULTIBYTE (c);
-  return make_fixnum (c);
+  return make_fixnum (make_char_multibyte (c));
 }
 
 DEFUN ("multibyte-char-to-unibyte", Fmultibyte_char_to_unibyte,
@@ -340,8 +332,7 @@ c_string_width (const unsigned char *str, ptrdiff_t len, 
int precision,
 
   while (i_byte < len)
     {
-      int bytes;
-      int c = STRING_CHAR_AND_LENGTH (str + i_byte, bytes);
+      int bytes, c = string_char_and_length (str + i_byte, &bytes);
       ptrdiff_t thiswidth = char_width (c, dp);
 
       if (0 < precision && precision - width < thiswidth)
@@ -418,7 +409,7 @@ lisp_string_width (Lisp_Object string, ptrdiff_t precision,
          if (multibyte)
            {
              int cbytes;
-             c = STRING_CHAR_AND_LENGTH (str + i_byte, cbytes);
+             c = string_char_and_length (str + i_byte, &cbytes);
              bytes = cbytes;
            }
          else
@@ -706,7 +697,7 @@ str_as_unibyte (unsigned char *str, ptrdiff_t bytes)
       len = BYTES_BY_CHAR_HEAD (c);
       if (CHAR_BYTE8_HEAD_P (c))
        {
-         c = STRING_CHAR_ADVANCE (p);
+         c = string_char_advance (&p);
          *to++ = CHAR_TO_BYTE8 (c);
        }
       else
@@ -730,7 +721,7 @@ str_to_unibyte (const unsigned char *src, unsigned char 
*dst, ptrdiff_t chars)
 
   for (i = 0; i < chars; i++)
     {
-      int c = STRING_CHAR_ADVANCE (src);
+      int c = string_char_advance (&src);
 
       if (CHAR_BYTE8_P (c))
        c = CHAR_TO_BYTE8 (c);
@@ -823,7 +814,7 @@ string_escape_byte8 (Lisp_Object string)
 
        if (CHAR_BYTE8_HEAD_P (c))
          {
-           c = STRING_CHAR_ADVANCE (src);
+           c = string_char_advance (&src);
            c = CHAR_TO_BYTE8 (c);
            dst += sprintf ((char *) dst, "\\%03o", c + 0u);
          }
diff --git a/src/character.h b/src/character.h
index d4bc718..81320de 100644
--- a/src/character.h
+++ b/src/character.h
@@ -81,14 +81,20 @@ enum
 };
 
 extern int char_string (unsigned, unsigned char *);
-extern int string_char (const unsigned char *,
-                        const unsigned char **, int *);
+extern int string_char (const unsigned char *, int *);
 
 /* UTF-8 encodings.  Use \x escapes, so they are portable to pre-C11
    compilers and can be concatenated with ordinary string literals.  */
 #define uLSQM "\xE2\x80\x98" /* U+2018 LEFT SINGLE QUOTATION MARK */
 #define uRSQM "\xE2\x80\x99" /* U+2019 RIGHT SINGLE QUOTATION MARK */
 
+/* True iff C is a character of code less than 0x100.  */
+INLINE bool
+SINGLE_BYTE_CHAR_P (intmax_t c)
+{
+  return 0 <= c && c < 0x100;
+}
+
 /* True iff C is a character that corresponds to a raw 8-bit
    byte.  */
 INLINE bool
@@ -133,17 +139,13 @@ CHAR_BYTE8_HEAD_P (int byte)
   return byte == 0xC0 || byte == 0xC1;
 }
 
-/* If C is not ASCII, make it unibyte. */
-#define MAKE_CHAR_UNIBYTE(c)   \
-  do {                         \
-    if (! ASCII_CHAR_P (c))    \
-      c = CHAR_TO_BYTE8 (c);   \
-  } while (false)
-
-
 /* If C is not ASCII, make it multibyte.  Assumes C < 256.  */
-#define MAKE_CHAR_MULTIBYTE(c) \
-  (eassert ((c) >= 0 && (c) < 256), (c) = UNIBYTE_TO_CHAR (c))
+INLINE int
+make_char_multibyte (int c)
+{
+  eassert (SINGLE_BYTE_CHAR_P (c));
+  return UNIBYTE_TO_CHAR (c);
+}
 
 /* This is the maximum byte length of multibyte form.  */
 enum { MAX_MULTIBYTE_LENGTH = 5 };
@@ -181,13 +183,6 @@ CHECK_CHARACTER_CDR (Lisp_Object x)
   CHECK_CHARACTER (XCDR (x));
 }
 
-/* True iff C is a character of code less than 0x100.  */
-INLINE bool
-SINGLE_BYTE_CHAR_P (intmax_t c)
-{
-  return 0 <= c && c < 0x100;
-}
-
 /* True if character C has a printable glyph.  */
 INLINE bool
 CHAR_PRINTABLE_P (int c)
@@ -264,29 +259,6 @@ BYTE8_STRING (int b, unsigned char *p)
 }
 
 
-/* Store multibyte form of the character C in P and advance P to the
-   end of the multibyte form.  The caller should allocate at least
-   MAX_MULTIBYTE_LENGTH bytes area at P in advance.  */
-
-#define CHAR_STRING_ADVANCE(c, p)              \
-  do {                                         \
-    if ((c) <= MAX_1_BYTE_CHAR)                        \
-      *(p)++ = (c);                            \
-    else if ((c) <= MAX_2_BYTE_CHAR)           \
-      *(p)++ = (0xC0 | ((c) >> 6)),            \
-       *(p)++ = (0x80 | ((c) & 0x3F));         \
-    else if ((c) <= MAX_3_BYTE_CHAR)           \
-      *(p)++ = (0xE0 | ((c) >> 12)),           \
-       *(p)++ = (0x80 | (((c) >> 6) & 0x3F)),  \
-       *(p)++ = (0x80 | ((c) & 0x3F));         \
-    else                                       \
-      {                                                \
-       verify (sizeof (c) <= sizeof (unsigned));       \
-       (p) += char_string (c, p);              \
-      }                                                \
-  } while (false)
-
-
 /* True iff BYTE starts a non-ASCII character in a multibyte form.  */
 INLINE bool
 LEADING_CODE_P (int byte)
@@ -365,281 +337,144 @@ MULTIBYTE_LENGTH_NO_CHECK (unsigned char const *p)
          : 0);
 }
 
-/* If P is before LIMIT, advance P to the next character boundary.
+
+/* Return number of bytes in the multibyte character just before P.
    Assumes that P is already at a character boundary of the same
-   multibyte form whose end address is LIMIT.  */
+   multibyte form, and is not at the start of that form.  */
 
-#define NEXT_CHAR_BOUNDARY(p, limit)   \
-  do {                                 \
-    if ((p) < (limit))                 \
-      (p) += BYTES_BY_CHAR_HEAD (*(p));        \
-  } while (false)
+INLINE int
+raw_prev_char_len (unsigned char const *p)
+{
+  for (int len = 1; ; len++)
+    if (CHAR_HEAD_P (p[-len]))
+      return len;
+}
 
 
-/* If P is after LIMIT, advance P to the previous character boundary.
-   Assumes that P is already at a character boundary of the same
-   multibyte form whose beginning address is LIMIT.  */
-
-#define PREV_CHAR_BOUNDARY(p, limit)                                   \
-  do {                                                                 \
-    if ((p) > (limit))                                                 \
-      {                                                                        
\
-       const unsigned char *chp = (p);                                 \
-       do {                                                            \
-         chp--;                                                        \
-       } while (chp >= limit && ! CHAR_HEAD_P (*chp));                 \
-       (p) = (BYTES_BY_CHAR_HEAD (*chp) == (p) - chp) ? chp : (p) - 1; \
-      }                                                                        
\
-  } while (false)
+/* Return the character code of character whose multibyte form is at P,
+   and set *LENGTH to its length.  */
+
+INLINE int
+string_char_and_length (unsigned char const *p, int *length)
+{
+  int c, len;
+
+  if (! (p[0] & 0x80))
+    {
+      len = 1;
+      c = p[0];
+    }
+  else if (! (p[0] & 0x20))
+    {
+      len = 2;
+      c = ((((p[0] & 0x1F) << 6)
+           | (p[1] & 0x3F))
+          + (p[0] < 0xC2 ? 0x3FFF80 : 0));
+    }
+  else if (! (p[0] & 0x10))
+    {
+      len = 3;
+      c = (((p[0] & 0x0F) << 12)
+          | ((p[1] & 0x3F) << 6)
+          | (p[2] & 0x3F));
+    }
+  else
+    c = string_char (p, &len);
+
+  eassume (0 < len && len <= MAX_MULTIBYTE_LENGTH);
+  *length = len;
+  return c;
+}
 
 /* Return the character code of character whose multibyte form is at P.  */
 
 INLINE int
 STRING_CHAR (unsigned char const *p)
 {
-  return (!(p[0] & 0x80)
-         ? p[0]
-         : ! (p[0] & 0x20)
-         ? ((((p[0] & 0x1F) << 6)
-             | (p[1] & 0x3F))
-            + (p[0] < 0xC2 ? 0x3FFF80 : 0))
-         : ! (p[0] & 0x10)
-         ? (((p[0] & 0x0F) << 12)
-            | ((p[1] & 0x3F) << 6)
-            | (p[2] & 0x3F))
-         : string_char (p, NULL, NULL));
-}
-
-
-/* Like STRING_CHAR, but set ACTUAL_LEN to the length of multibyte
-   form.  */
-
-#define STRING_CHAR_AND_LENGTH(p, actual_len)                  \
-  (!((p)[0] & 0x80)                                            \
-   ? ((actual_len) = 1, (p)[0])                                        \
-   : ! ((p)[0] & 0x20)                                         \
-   ? ((actual_len) = 2,                                                \
-      (((((p)[0] & 0x1F) << 6)                                 \
-       | ((p)[1] & 0x3F))                                      \
-       + (((unsigned char) (p)[0]) < 0xC2 ? 0x3FFF80 : 0)))    \
-   : ! ((p)[0] & 0x10)                                         \
-   ? ((actual_len) = 3,                                                \
-      ((((p)[0] & 0x0F) << 12)                                 \
-       | (((p)[1] & 0x3F) << 6)                                        \
-       | ((p)[2] & 0x3F)))                                     \
-   : string_char ((p), NULL, &actual_len))
-
-
-/* Like STRING_CHAR, but advance P to the end of multibyte form.  */
-
-#define STRING_CHAR_ADVANCE(p)                                 \
-  (!((p)[0] & 0x80)                                            \
-   ? *(p)++                                                    \
-   : ! ((p)[0] & 0x20)                                         \
-   ? ((p) += 2,                                                        \
-      ((((p)[-2] & 0x1F) << 6)                                 \
-       | ((p)[-1] & 0x3F)                                      \
-       | ((unsigned char) ((p)[-2]) < 0xC2 ? 0x3FFF80 : 0)))   \
-   : ! ((p)[0] & 0x10)                                         \
-   ? ((p) += 3,                                                        \
-      ((((p)[-3] & 0x0F) << 12)                                        \
-       | (((p)[-2] & 0x3F) << 6)                               \
-       | ((p)[-1] & 0x3F)))                                    \
-   : string_char ((p), &(p), NULL))
-
-
-/* Fetch the "next" character from Lisp string STRING at byte position
-   BYTEIDX, character position CHARIDX.  Store it into OUTPUT.
-
-   All the args must be side-effect-free.
-   BYTEIDX and CHARIDX must be lvalues;
-   we increment them past the character fetched.  */
-
-#define FETCH_STRING_CHAR_ADVANCE(OUTPUT, STRING, CHARIDX, BYTEIDX)    \
-  do                                                                    \
-    {                                                                  \
-      CHARIDX++;                                                       \
-      if (STRING_MULTIBYTE (STRING))                                   \
-       {                                                               \
-         unsigned char *chp = &SDATA (STRING)[BYTEIDX];                \
-         int chlen;                                                    \
-                                                                       \
-         OUTPUT = STRING_CHAR_AND_LENGTH (chp, chlen);                 \
-         BYTEIDX += chlen;                                             \
-       }                                                               \
-      else                                                             \
-       {                                                               \
-         OUTPUT = SREF (STRING, BYTEIDX);                              \
-         BYTEIDX++;                                                    \
-       }                                                               \
-    }                                                                  \
-  while (false)
-
-/* Like FETCH_STRING_CHAR_ADVANCE, but return a multibyte character
+  int len;
+  return string_char_and_length (p, &len);
+}
+
+
+/* Like STRING_CHAR (*PP), but advance *PP to the end of multibyte form.  */
+
+INLINE int
+string_char_advance (unsigned char const **pp)
+{
+  unsigned char const *p = *pp;
+  int len, c = string_char_and_length (p, &len);
+  *pp = p + len;
+  return c;
+}
+
+
+/* Return the next character from Lisp string STRING at byte position
+   *BYTEIDX, character position *CHARIDX.  Update *BYTEIDX and
+   *CHARIDX past the character fetched.  */
+
+INLINE int
+fetch_string_char_advance (Lisp_Object string,
+                          ptrdiff_t *charidx, ptrdiff_t *byteidx)
+{
+  int output;
+  ptrdiff_t b = *byteidx;
+  unsigned char *chp = SDATA (string) + b;
+  if (STRING_MULTIBYTE (string))
+    {
+      int chlen;
+      output = string_char_and_length (chp, &chlen);
+      b += chlen;
+    }
+  else
+    {
+      output = *chp;
+      b++;
+    }
+  (*charidx)++;
+  *byteidx = b;
+  return output;
+}
+
+/* Like fetch_string_char_advance, but return a multibyte character
    even if STRING is unibyte.  */
 
-#define FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE(OUTPUT, STRING, CHARIDX, 
BYTEIDX) \
-  do                                                                          \
-    {                                                                        \
-      CHARIDX++;                                                             \
-      if (STRING_MULTIBYTE (STRING))                                         \
-       {                                                                     \
-         unsigned char *chp = &SDATA (STRING)[BYTEIDX];                      \
-         int chlen;                                                          \
-                                                                             \
-         OUTPUT = STRING_CHAR_AND_LENGTH (chp, chlen);                       \
-         BYTEIDX += chlen;                                                   \
-       }                                                                     \
-      else                                                                   \
-       {                                                                     \
-         OUTPUT = SREF (STRING, BYTEIDX);                                    \
-         BYTEIDX++;                                                          \
-         MAKE_CHAR_MULTIBYTE (OUTPUT);                                       \
-       }                                                                     \
-    }                                                                        \
-  while (false)
-
-
-/* Like FETCH_STRING_CHAR_ADVANCE, but assumes STRING is multibyte.  */
-
-#define FETCH_STRING_CHAR_ADVANCE_NO_CHECK(OUTPUT, STRING, CHARIDX, BYTEIDX) \
-  do                                                                        \
-    {                                                                       \
-      unsigned char *fetch_ptr = &SDATA (STRING)[BYTEIDX];                  \
-      int fetch_len;                                                        \
-                                                                            \
-      OUTPUT = STRING_CHAR_AND_LENGTH (fetch_ptr, fetch_len);               \
-      BYTEIDX += fetch_len;                                                 \
-      CHARIDX++;                                                            \
-    }                                                                       \
-  while (false)
-
-
-/* Like FETCH_STRING_CHAR_ADVANCE, but fetch character from the current
-   buffer.  */
-
-#define FETCH_CHAR_ADVANCE(OUTPUT, CHARIDX, BYTEIDX)           \
-  do                                                           \
-    {                                                          \
-      CHARIDX++;                                               \
-      if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))  \
-       {                                                       \
-         unsigned char *chp = BYTE_POS_ADDR (BYTEIDX);         \
-         int chlen;                                            \
-                                                               \
-         OUTPUT = STRING_CHAR_AND_LENGTH (chp, chlen);         \
-         BYTEIDX += chlen;                                     \
-       }                                                       \
-      else                                                     \
-       {                                                       \
-         OUTPUT = *(BYTE_POS_ADDR (BYTEIDX));                  \
-         BYTEIDX++;                                            \
-       }                                                       \
-    }                                                          \
-  while (false)
-
-
-/* Like FETCH_CHAR_ADVANCE, but assumes the current buffer is multibyte.  */
-
-#define FETCH_CHAR_ADVANCE_NO_CHECK(OUTPUT, CHARIDX, BYTEIDX)  \
-  do                                                           \
-    {                                                          \
-      unsigned char *chp = BYTE_POS_ADDR (BYTEIDX);            \
-      int chlen;                                                       \
-                                                               \
-      OUTPUT = STRING_CHAR_AND_LENGTH (chp, chlen);            \
-      BYTEIDX += chlen;                                                \
-      CHARIDX++;                                               \
-    }                                                          \
-  while (false)
-
-
-/* Increment the buffer byte position POS_BYTE of the current buffer to
-   the next character boundary.  No range checking of POS.  */
-
-#define INC_POS(pos_byte)                              \
-  do {                                                 \
-    unsigned char *chp = BYTE_POS_ADDR (pos_byte);     \
-    pos_byte += BYTES_BY_CHAR_HEAD (*chp);             \
-  } while (false)
-
-
-/* Decrement the buffer byte position POS_BYTE of the current buffer to
-   the previous character boundary.  No range checking of POS.  */
-
-#define DEC_POS(pos_byte)                      \
-  do {                                         \
-    unsigned char *chp;                                \
-                                               \
-    pos_byte--;                                        \
-    if (pos_byte < GPT_BYTE)                   \
-      chp = BEG_ADDR + pos_byte - BEG_BYTE;    \
-    else                                       \
-      chp = BEG_ADDR + GAP_SIZE + pos_byte - BEG_BYTE; \
-    while (!CHAR_HEAD_P (*chp))                        \
-      {                                                \
-       chp--;                                  \
-       pos_byte--;                             \
-      }                                                \
-  } while (false)
-
-/* Increment both CHARPOS and BYTEPOS, each in the appropriate way.  */
-
-#define INC_BOTH(charpos, bytepos)                             \
-  do                                                           \
-    {                                                          \
-      (charpos)++;                                             \
-      if (NILP (BVAR (current_buffer, enable_multibyte_characters)))   \
-       (bytepos)++;                                            \
-      else                                                     \
-       INC_POS ((bytepos));                                    \
-    }                                                          \
-  while (false)
-
-
-/* Decrement both CHARPOS and BYTEPOS, each in the appropriate way.  */
-
-#define DEC_BOTH(charpos, bytepos)                             \
-  do                                                           \
-    {                                                          \
-      (charpos)--;                                             \
-      if (NILP (BVAR (current_buffer, enable_multibyte_characters)))   \
-       (bytepos)--;                                            \
-      else                                                     \
-       DEC_POS ((bytepos));                                    \
-    }                                                          \
-  while (false)
-
-
-/* Increment the buffer byte position POS_BYTE of the current buffer to
-   the next character boundary.  This macro relies on the fact that
-   *GPT_ADDR and *Z_ADDR are always accessible and the values are
-   '\0'.  No range checking of POS_BYTE.  */
-
-#define BUF_INC_POS(buf, pos_byte)                             \
-  do {                                                         \
-    unsigned char *chp = BUF_BYTE_ADDRESS (buf, pos_byte);     \
-    pos_byte += BYTES_BY_CHAR_HEAD (*chp);                     \
-  } while (false)
-
-
-/* Decrement the buffer byte position POS_BYTE of the current buffer to
-   the previous character boundary.  No range checking of POS_BYTE.  */
-
-#define BUF_DEC_POS(buf, pos_byte)                                     \
-  do {                                                                 \
-    unsigned char *chp;                                                        
\
-    pos_byte--;                                                                
\
-    if (pos_byte < BUF_GPT_BYTE (buf))                                 \
-      chp = BUF_BEG_ADDR (buf) + pos_byte - BEG_BYTE;                  \
-    else                                                               \
-      chp = BUF_BEG_ADDR (buf) + BUF_GAP_SIZE (buf) + pos_byte - BEG_BYTE;\
-    while (!CHAR_HEAD_P (*chp))                                                
\
-      {                                                                        
\
-       chp--;                                                          \
-       pos_byte--;                                                     \
-      }                                                                        
\
-  } while (false)
+INLINE int
+fetch_string_char_as_multibyte_advance (Lisp_Object string,
+                                       ptrdiff_t *charidx, ptrdiff_t *byteidx)
+{
+  int output;
+  ptrdiff_t b = *byteidx;
+  unsigned char *chp = SDATA (string) + b;
+  if (STRING_MULTIBYTE (string))
+    {
+      int chlen;
+      output = string_char_and_length (chp, &chlen);
+      b += chlen;
+    }
+  else
+    {
+      output = make_char_multibyte (*chp);
+      b++;
+    }
+  (*charidx)++;
+  *byteidx = b;
+  return output;
+}
+
+
+/* Like fetch_string_char_advance, but assumes STRING is multibyte.  */
+
+INLINE int
+fetch_string_char_advance_no_check (Lisp_Object string,
+                                   ptrdiff_t *charidx, ptrdiff_t *byteidx)
+{
+  ptrdiff_t b = *byteidx;
+  unsigned char *chp = SDATA (string) + b;
+  int chlen, output = string_char_and_length (chp, &chlen);
+  (*charidx)++;
+  *byteidx = b + chlen;
+  return output;
+}
 
 
 /* If C is a variation selector, return the index of the
@@ -728,10 +563,6 @@ extern bool graphicp (int);
 extern bool printablep (int);
 extern bool blankp (int);
 
-/* Return a translation table of id number ID.  */
-#define GET_TRANSLATION_TABLE(id) \
-  (XCDR (XVECTOR (Vtranslation_table_vector)->contents[(id)]))
-
 /* Look up the element in char table OBJ at index CH, and return it as
    an integer.  If the element is not a character, return CH itself.  */
 
diff --git a/src/charset.c b/src/charset.c
index 9e55d0c..8635aad 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -1460,7 +1460,7 @@ string_xstring_p (Lisp_Object string)
 
   while (p < endp)
     {
-      int c = STRING_CHAR_ADVANCE (p);
+      int c = string_char_advance (&p);
 
       if (c >= 0x100)
        return 2;
@@ -1504,7 +1504,7 @@ find_charsets_in_text (const unsigned char *ptr, 
ptrdiff_t nchars,
     {
       while (ptr < pend)
        {
-         int c = STRING_CHAR_ADVANCE (ptr);
+         int c = string_char_advance (&ptr);
          struct charset *charset;
 
          if (!NILP (table))
diff --git a/src/chartab.c b/src/chartab.c
index 04205ac..cb2ced5 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -1117,10 +1117,10 @@ uniprop_table_uncompress (Lisp_Object table, int idx)
     {
       /* SIMPLE TABLE */
       p++;
-      idx = STRING_CHAR_ADVANCE (p);
+      idx = string_char_advance (&p);
       while (p < pend && idx < chartab_chars[2])
        {
-         int v = STRING_CHAR_ADVANCE (p);
+         int v = string_char_advance (&p);
          set_sub_char_table_contents
            (sub, idx++, v > 0 ? make_fixnum (v) : Qnil);
        }
@@ -1131,13 +1131,13 @@ uniprop_table_uncompress (Lisp_Object table, int idx)
       p++;
       for (idx = 0; p < pend; )
        {
-         int v = STRING_CHAR_ADVANCE (p);
+         int v = string_char_advance (&p);
          int count = 1;
-         int len;
 
          if (p < pend)
            {
-             count = STRING_CHAR_AND_LENGTH (p, len);
+             int len;
+             count = string_char_and_length (p, &len);
              if (count < 128)
                count = 1;
              else
diff --git a/src/cmds.c b/src/cmds.c
index c342cd8..9f96f21 100644
--- a/src/cmds.c
+++ b/src/cmds.c
@@ -389,7 +389,7 @@ internal_self_insert (int c, EMACS_INT n)
                  /* We will delete too many columns.  Let's fill columns
                     by spaces so that the remaining text won't move.  */
                  ptrdiff_t actual = PT_BYTE;
-                 DEC_POS (actual);
+                 actual -= prev_char_len (actual);
                  if (FETCH_CHAR (actual) == '\t')
                    /* Rather than add spaces, let's just keep the tab. */
                    chars_to_delete--;
diff --git a/src/coding.c b/src/coding.c
index 0daa390..716b0d9 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -643,7 +643,7 @@ growable_destination (struct coding_system *coding)
        else                                            \
          {                                             \
            src--;                                      \
-           c = - string_char (src, &src, NULL);        \
+           c = - string_char_advance (&src);           \
            record_conversion_result                    \
              (coding, CODING_RESULT_INVALID_SRC);      \
          }                                             \
@@ -728,7 +728,7 @@ growable_destination (struct coding_system *coding)
        unsigned ch = (c);              \
        if (ch >= 0x80)                 \
          ch = BYTE8_TO_CHAR (ch);      \
-       CHAR_STRING_ADVANCE (ch, dst);  \
+       dst += CHAR_STRING (ch, dst);   \
       }                                        \
     else                               \
       *dst++ = (c);                    \
@@ -747,11 +747,11 @@ growable_destination (struct coding_system *coding)
        ch = (c1);                      \
        if (ch >= 0x80)                 \
          ch = BYTE8_TO_CHAR (ch);      \
-       CHAR_STRING_ADVANCE (ch, dst);  \
+       dst += CHAR_STRING (ch, dst);   \
        ch = (c2);                      \
        if (ch >= 0x80)                 \
          ch = BYTE8_TO_CHAR (ch);      \
-       CHAR_STRING_ADVANCE (ch, dst);  \
+       dst += CHAR_STRING (ch, dst);   \
       }                                        \
     else                               \
       {                                        \
@@ -884,18 +884,18 @@ record_conversion_result (struct coding_system *coding,
 
 
 /* Store multibyte form of the character C in P, and advance P to the
-   end of the multibyte form.  This used to be like CHAR_STRING_ADVANCE
+   end of the multibyte form.  This used to be like adding CHAR_STRING
    without ever calling MAYBE_UNIFY_CHAR, but nowadays we don't call
-   MAYBE_UNIFY_CHAR in CHAR_STRING_ADVANCE.  */
+   MAYBE_UNIFY_CHAR in CHAR_STRING.  */
 
-#define CHAR_STRING_ADVANCE_NO_UNIFY(c, p)  CHAR_STRING_ADVANCE(c, p)
+#define CHAR_STRING_ADVANCE_NO_UNIFY(c, p) ((p) += CHAR_STRING (c, p))
 
 /* Return the character code of character whose multibyte form is at
    P, and advance P to the end of the multibyte form.  This used to be
-   like STRING_CHAR_ADVANCE without ever calling MAYBE_UNIFY_CHAR, but
-   nowadays STRING_CHAR_ADVANCE doesn't call MAYBE_UNIFY_CHAR.  */
+   like string_char_advance without ever calling MAYBE_UNIFY_CHAR, but
+   nowadays string_char_advance doesn't call MAYBE_UNIFY_CHAR.  */
 
-#define STRING_CHAR_ADVANCE_NO_UNIFY(p) STRING_CHAR_ADVANCE(p)
+#define STRING_CHAR_ADVANCE_NO_UNIFY(p) string_char_advance (&(p))
 
 /* Set coding->source from coding->src_object.  */
 
@@ -5131,7 +5131,7 @@ decode_coding_ccl (struct coding_system *coding)
          while (i < 1024 && p < src_end)
            {
              source_byteidx[i] = p - src;
-             source_charbuf[i++] = STRING_CHAR_ADVANCE (p);
+             source_charbuf[i++] = string_char_advance (&p);
            }
          source_byteidx[i] = p - src;
        }
@@ -5308,15 +5308,10 @@ encode_coding_raw_text (struct coding_system *coding)
              }
            else
              {
-               unsigned char str[MAX_MULTIBYTE_LENGTH], *p0 = str, *p1 = str;
-
-               CHAR_STRING_ADVANCE (c, p1);
-               do
-                 {
-                   EMIT_ONE_BYTE (*p0);
-                   p0++;
-                 }
-               while (p0 < p1);
+               unsigned char str[MAX_MULTIBYTE_LENGTH];
+               int len = CHAR_STRING (c, str);
+               for (int i = 0; i < len; i++)
+                 EMIT_ONE_BYTE (str[i]);
              }
          }
       else
@@ -5342,7 +5337,7 @@ encode_coding_raw_text (struct coding_system *coding)
              else if (CHAR_BYTE8_P (c))
                *dst++ = CHAR_TO_BYTE8 (c);
              else
-               CHAR_STRING_ADVANCE (c, dst);
+               dst += CHAR_STRING (c, dst);
            }
        }
       else
@@ -7457,7 +7452,7 @@ decode_coding (struct coding_system *coding)
              if (coding->src_multibyte
                  && CHAR_BYTE8_HEAD_P (*src) && nbytes > 0)
                {
-                 c = STRING_CHAR_ADVANCE (src);
+                 c = string_char_advance (&src);
                  nbytes--;
                }
              else
@@ -7551,10 +7546,8 @@ handle_composition_annotation (ptrdiff_t pos, ptrdiff_t 
limit,
                  len = SCHARS (components);
                  i = i_byte = 0;
                  while (i < len)
-                   {
-                     FETCH_STRING_CHAR_ADVANCE (*buf, components, i, i_byte);
-                     buf++;
-                   }
+                   *buf++ = fetch_string_char_advance (components,
+                                                       &i, &i_byte);
                }
              else if (FIXNUMP (components))
                {
@@ -7715,7 +7708,7 @@ consume_chars (struct coding_system *coding, Lisp_Object 
translation_table,
 
          lookup_buf[0] = c;
          for (i = 1; i < max_lookup && p < src_end; i++)
-           lookup_buf[i] = STRING_CHAR_ADVANCE (p);
+           lookup_buf[i] = string_char_advance (&p);
          lookup_buf_end = lookup_buf + i;
          trans = get_translation (trans, lookup_buf, lookup_buf_end,
                                   &from_nchars);
@@ -9075,7 +9068,7 @@ DEFUN ("find-coding-systems-region-internal",
        p++;
       else
        {
-         c = STRING_CHAR_ADVANCE (p);
+         c = string_char_advance (&p);
          if (!NILP (char_table_ref (work_table, c)))
            /* This character was already checked.  Ignore it.  */
            continue;
@@ -9208,7 +9201,7 @@ to the string and treated as in `substring'.  */)
          p = GAP_END_ADDR;
        }
 
-      c = STRING_CHAR_ADVANCE (p);
+      c = string_char_advance (&p);
       if (! (ASCII_CHAR_P (c) && ascii_compatible)
          && ! char_charset (translate_char (translation_table, c),
                             charset_list, NULL))
@@ -9326,7 +9319,7 @@ is nil.  */)
        p++;
       else
        {
-         c = STRING_CHAR_ADVANCE (p);
+         c = string_char_advance (&p);
 
          charset_map_loaded = 0;
          for (tail = list; CONSP (tail); tail = XCDR (tail))
@@ -9728,7 +9721,7 @@ encode_string_utf_8 (Lisp_Object string, Lisp_Object 
buffer,
              || (len == 2 ? ! CHAR_BYTE8_HEAD_P (c)
                  : (EQ (handle_over_uni, Qt)
                     || (len == 4
-                        && string_char (p, NULL, NULL) <= MAX_UNICODE_CHAR))))
+                        && STRING_CHAR (p) <= MAX_UNICODE_CHAR))))
            {
              p += len;
              continue;
@@ -10010,8 +10003,7 @@ decode_string_utf_8 (Lisp_Object string, const char 
*str, ptrdiff_t str_len,
                  && (len == 3
                      || (UTF_8_EXTRA_OCTET_P (p[3])
                          && len == 4
-                         && (string_char (p, NULL, NULL)
-                             <= MAX_UNICODE_CHAR))))))
+                         && STRING_CHAR (p) <= MAX_UNICODE_CHAR)))))
        {
          p += len;
          continue;
@@ -10148,8 +10140,7 @@ decode_string_utf_8 (Lisp_Object string, const char 
*str, ptrdiff_t str_len,
                   mlen++);
              if (mlen == len
                  && (len <= 3
-                     || (len == 4
-                         && string_char (p, NULL, NULL) <= MAX_UNICODE_CHAR)
+                     || (len == 4 && STRING_CHAR (p) <= MAX_UNICODE_CHAR)
                      || EQ (handle_over_uni, Qt)))
                {
                  p += len;
diff --git a/src/composite.c b/src/composite.c
index a00a454..518502b 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -170,7 +170,6 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t nchars,
   ptrdiff_t hash_index;
   enum composition_method method;
   struct composition *cmp;
-  ptrdiff_t i;
   int ch;
 
   /* Maximum length of a string of glyphs.  XftGlyphExtents limits
@@ -224,15 +223,15 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t nchars,
     {
       key = make_uninit_vector (nchars);
       if (STRINGP (string))
-       for (i = 0; i < nchars; i++)
+       for (ptrdiff_t i = 0; i < nchars; i++)
          {
-           FETCH_STRING_CHAR_ADVANCE (ch, string, charpos, bytepos);
+           ch = fetch_string_char_advance (string, &charpos, &bytepos);
            ASET (key, i, make_fixnum (ch));
          }
       else
-       for (i = 0; i < nchars; i++)
+       for (ptrdiff_t i = 0; i < nchars; i++)
          {
-           FETCH_CHAR_ADVANCE (ch, charpos, bytepos);
+           ch = fetch_char_advance (&charpos, &bytepos);
            ASET (key, i, make_fixnum (ch));
          }
     }
@@ -273,7 +272,7 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t nchars,
       /* COMPONENTS is a glyph-string.  */
       ptrdiff_t len = ASIZE (key);
 
-      for (i = 1; i < len; i++)
+      for (ptrdiff_t i = 1; i < len; i++)
        if (! VECTORP (AREF (key, i)))
          goto invalid_composition;
     }
@@ -286,7 +285,7 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t nchars,
        goto invalid_composition;
       /* All elements should be integers (character or encoded
          composition rule).  */
-      for (i = 0; i < len; i++)
+      for (ptrdiff_t i = 0; i < len; i++)
        {
          if (!FIXNUMP (key_contents[i]))
            goto invalid_composition;
@@ -328,7 +327,7 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t nchars,
     {
       /* Relative composition.  */
       cmp->width = 0;
-      for (i = 0; i < glyph_len; i++)
+      for (ptrdiff_t i = 0; i < glyph_len; i++)
        {
          int this_width;
          ch = XFIXNUM (key_contents[i]);
@@ -347,7 +346,7 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, 
ptrdiff_t nchars,
       ch = XFIXNUM (key_contents[0]);
       rightmost = ch != '\t' ? CHARACTER_WIDTH (ch) : 1;
 
-      for (i = 1; i < glyph_len; i += 2)
+      for (ptrdiff_t i = 1; i < glyph_len; i += 2)
        {
          int rule, gref, nref;
          int this_width;
@@ -800,12 +799,10 @@ fill_gstring_header (ptrdiff_t from, ptrdiff_t from_byte,
   ASET (header, 0, font_object);
   for (ptrdiff_t i = 0; i < len; i++)
     {
-      int c;
-
-      if (NILP (string))
-       FETCH_CHAR_ADVANCE_NO_CHECK (c, from, from_byte);
-      else
-       FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, from, from_byte);
+      int c
+       = (NILP (string)
+          ? fetch_char_advance_no_check (&from, &from_byte)
+          : fetch_string_char_advance_no_check (string, &from, &from_byte));
       ASET (header, i + 1, make_fixnum (c));
     }
   return header;
@@ -1012,10 +1009,9 @@ composition_compute_stop_pos (struct composition_it 
*cmp_it, ptrdiff_t charpos,
       /* Forward search.  */
       while (charpos < endpos)
        {
-         if (STRINGP (string))
-           FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
-         else
-           FETCH_CHAR_ADVANCE (c, charpos, bytepos);
+         c = (STRINGP (string)
+              ? fetch_string_char_advance (string, &charpos, &bytepos)
+              : fetch_char_advance (&charpos, &bytepos));
          if (c == '\n')
            {
              cmp_it->ch = -2;
@@ -1070,7 +1066,7 @@ composition_compute_stop_pos (struct composition_it 
*cmp_it, ptrdiff_t charpos,
        p = BYTE_POS_ADDR (bytepos);
       else
        p = SDATA (string) + bytepos;
-      c = STRING_CHAR_AND_LENGTH (p, len);
+      c = string_char_and_length (p, &len);
       limit = bytepos + len;
       while (char_composable_p (c))
        {
@@ -1132,7 +1128,7 @@ composition_compute_stop_pos (struct composition_it 
*cmp_it, ptrdiff_t charpos,
            }
          else
            {
-             DEC_BOTH (charpos, bytepos);
+             dec_both (&charpos, &bytepos);
              p = BYTE_POS_ADDR (bytepos);
            }
          c = STRING_CHAR (p);
@@ -1145,7 +1141,7 @@ composition_compute_stop_pos (struct composition_it 
*cmp_it, ptrdiff_t charpos,
        {
          while (charpos - 1 > endpos && ! char_composable_p (c))
            {
-             DEC_BOTH (charpos, bytepos);
+             dec_both (&charpos, &bytepos);
              c = FETCH_MULTIBYTE_CHAR (bytepos);
            }
        }
@@ -1290,7 +1286,7 @@ composition_reseat_it (struct composition_it *cmp_it, 
ptrdiff_t charpos,
     {
       charpos++;
       if (NILP (string))
-       INC_POS (bytepos);
+       bytepos += next_char_len (bytepos);
       else
        bytepos += BYTES_BY_CHAR_HEAD (*(SDATA (string) + bytepos));
     }
diff --git a/src/dispextern.h b/src/dispextern.h
index ae994d7..d6fe68c 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -234,7 +234,7 @@ struct text_pos
        {                                       \
         ++(POS).charpos;                       \
          if (MULTIBYTE_P)                      \
-          INC_POS ((POS).bytepos);             \
+          (POS).bytepos += next_char_len ((POS).bytepos); \
         else                                   \
           ++(POS).bytepos;                     \
        }                                       \
@@ -247,7 +247,7 @@ struct text_pos
        {                                       \
         --(POS).charpos;                       \
          if (MULTIBYTE_P)                      \
-          DEC_POS ((POS).bytepos);             \
+          (POS).bytepos -= prev_char_len ((POS).bytepos); \
         else                                   \
           --(POS).bytepos;                     \
        }                                       \
diff --git a/src/editfns.c b/src/editfns.c
index 90520d0..d9da119 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -999,7 +999,7 @@ At the beginning of the buffer or accessible region, return 
0.  */)
   else if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
     {
       ptrdiff_t pos = PT_BYTE;
-      DEC_POS (pos);
+      pos -= prev_char_len (pos);
       XSETFASTINT (temp, FETCH_CHAR (pos));
     }
   else
@@ -1112,7 +1112,7 @@ If POS is out of range, the value is nil.  */)
 
   if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
     {
-      DEC_POS (pos_byte);
+      pos_byte -= prev_char_len (pos_byte);
       XSETFASTINT (val, FETCH_CHAR (pos_byte));
     }
   else
@@ -1549,7 +1549,7 @@ from adjoining text, if those properties are sticky.  */)
    make_uninit_string, which can cause the buffer arena to be
    compacted.  make_string has no way of knowing that the data has
    been moved, and thus copies the wrong data into the string.  This
-   doesn't effect most of the other users of make_string, so it should
+   doesn't affect most of the other users of make_string, so it should
    be left as is.  But we should use this function when conjuring
    buffer substrings.  */
 
@@ -1830,26 +1830,24 @@ determines whether case is significant or ignored.  */)
       if (! NILP (BVAR (bp1, enable_multibyte_characters)))
        {
          c1 = BUF_FETCH_MULTIBYTE_CHAR (bp1, i1_byte);
-         BUF_INC_POS (bp1, i1_byte);
+         i1_byte += buf_next_char_len (bp1, i1_byte);
          i1++;
        }
       else
        {
-         c1 = BUF_FETCH_BYTE (bp1, i1);
-         MAKE_CHAR_MULTIBYTE (c1);
+         c1 = make_char_multibyte (BUF_FETCH_BYTE (bp1, i1));
          i1++;
        }
 
       if (! NILP (BVAR (bp2, enable_multibyte_characters)))
        {
          c2 = BUF_FETCH_MULTIBYTE_CHAR (bp2, i2_byte);
-         BUF_INC_POS (bp2, i2_byte);
+         i2_byte += buf_next_char_len (bp2, i2_byte);
          i2++;
        }
       else
        {
-         c2 = BUF_FETCH_BYTE (bp2, i2);
-         MAKE_CHAR_MULTIBYTE (c2);
+         c2 = make_char_multibyte (BUF_FETCH_BYTE (bp2, i2));
          i2++;
        }
 
@@ -2304,7 +2302,7 @@ Both characters must have the same length of multi-byte 
form.  */)
        }
       p = BYTE_POS_ADDR (pos_byte);
       if (multibyte_p)
-       INC_POS (pos_byte_next);
+       pos_byte_next += next_char_len (pos_byte_next);
       else
        ++pos_byte_next;
       if (pos_byte_next - pos_byte == len
@@ -2365,7 +2363,7 @@ Both characters must have the same length of multi-byte 
form.  */)
                   decrease it now.  */
                pos--;
              else
-               INC_POS (pos_byte_next);
+               pos_byte_next += next_char_len (pos_byte_next);
 
              if (! NILP (noundo))
                bset_undo_list (current_buffer, tem);
@@ -2442,7 +2440,7 @@ check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, 
ptrdiff_t end,
                        memcpy (bufalloc, buf, sizeof initial_buf);
                      buf = bufalloc;
                    }
-                 buf[buf_used++] = STRING_CHAR_AND_LENGTH (p, len1);
+                 buf[buf_used++] = string_char_and_length (p, &len1);
                  pos_byte += len1;
                }
              if (XFIXNUM (AREF (elt, i)) != buf[i])
@@ -2501,7 +2499,7 @@ It returns the number of characters changed.  */)
       int len, oc;
 
       if (multibyte)
-       oc = STRING_CHAR_AND_LENGTH (p, len);
+       oc = string_char_and_length (p, &len);
       else
        oc = *p, len = 1;
       if (oc < translatable_chars)
@@ -2518,7 +2516,7 @@ It returns the number of characters changed.  */)
              if (string_multibyte)
                {
                  str = tt + string_char_to_byte (table, oc);
-                 nc = STRING_CHAR_AND_LENGTH (str, str_len);
+                 nc = string_char_and_length (str, &str_len);
                }
              else
                {
diff --git a/src/fns.c b/src/fns.c
index e22fbaa..cefdf38 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -226,12 +226,12 @@ Letter-case is significant, but text properties are 
ignored. */)
       for (x = 1; x <= len2; x++)
         {
           column[0] = x;
-          FETCH_STRING_CHAR_ADVANCE (c2, string2, i2, i2_byte);
+          c2 = fetch_string_char_advance (string2, &i2, &i2_byte);
           i1 = i1_byte = 0;
           for (y = 1, lastdiag = x - 1; y <= len1; y++)
             {
               olddiag = column[y];
-              FETCH_STRING_CHAR_ADVANCE (c1, string1, i1, i1_byte);
+              c1 = fetch_string_char_advance (string1, &i1, &i1_byte);
               column[y] = min (min (column[y] + 1, column[y-1] + 1),
                               lastdiag + (c1 == c2 ? 0 : 1));
               lastdiag = olddiag;
@@ -312,10 +312,8 @@ If string STR1 is greater, the value is a positive number 
N;
     {
       /* When we find a mismatch, we must compare the
         characters, not just the bytes.  */
-      int c1, c2;
-
-      FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE (c1, str1, i1, i1_byte);
-      FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE (c2, str2, i2, i2_byte);
+      int c1 = fetch_string_char_as_multibyte_advance (str1, &i1, &i1_byte);
+      int c2 = fetch_string_char_as_multibyte_advance (str2, &i2, &i2_byte);
 
       if (c1 == c2)
        continue;
@@ -350,11 +348,8 @@ DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 
0,
        doc: /* Return non-nil if STRING1 is less than STRING2 in lexicographic 
order.
 Case is significant.
 Symbols are also allowed; their print names are used instead.  */)
-  (register Lisp_Object string1, Lisp_Object string2)
+  (Lisp_Object string1, Lisp_Object string2)
 {
-  register ptrdiff_t end;
-  register ptrdiff_t i1, i1_byte, i2, i2_byte;
-
   if (SYMBOLP (string1))
     string1 = SYMBOL_NAME (string1);
   if (SYMBOLP (string2))
@@ -362,21 +357,15 @@ Symbols are also allowed; their print names are used 
instead.  */)
   CHECK_STRING (string1);
   CHECK_STRING (string2);
 
-  i1 = i1_byte = i2 = i2_byte = 0;
-
-  end = SCHARS (string1);
-  if (end > SCHARS (string2))
-    end = SCHARS (string2);
+  ptrdiff_t i1 = 0, i1_byte = 0, i2 = 0, i2_byte = 0;
+  ptrdiff_t end = min (SCHARS (string1), SCHARS (string2));
 
   while (i1 < end)
     {
       /* When we find a mismatch, we must compare the
         characters, not just the bytes.  */
-      int c1, c2;
-
-      FETCH_STRING_CHAR_ADVANCE (c1, string1, i1, i1_byte);
-      FETCH_STRING_CHAR_ADVANCE (c2, string2, i2, i2_byte);
-
+      int c1 = fetch_string_char_advance (string1, &i1, &i1_byte);
+      int c2 = fetch_string_char_advance (string2, &i2, &i2_byte);
       if (c1 != c2)
        return c1 < c2 ? Qt : Qnil;
     }
@@ -767,8 +756,8 @@ concat (ptrdiff_t nargs, Lisp_Object *args,
     {
       Lisp_Object thislen;
       ptrdiff_t thisleni = 0;
-      register ptrdiff_t thisindex = 0;
-      register ptrdiff_t thisindex_byte = 0;
+      ptrdiff_t thisindex = 0;
+      ptrdiff_t thisindex_byte = 0;
 
       this = args[argnum];
       if (!CONSP (this))
@@ -821,9 +810,8 @@ concat (ptrdiff_t nargs, Lisp_Object *args,
              {
                int c;
                if (STRING_MULTIBYTE (this))
-                 FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, this,
-                                                     thisindex,
-                                                     thisindex_byte);
+                 c = fetch_string_char_advance_no_check (this, &thisindex,
+                                                         &thisindex_byte);
                else
                  {
                    c = SREF (this, thisindex); thisindex++;
@@ -1961,9 +1949,7 @@ See also the function `nreverse', which is used more 
often.  */)
          p = SDATA (seq), q = SDATA (new) + bytes;
          while (q > SDATA (new))
            {
-             int ch, len;
-
-             ch = STRING_CHAR_AND_LENGTH (p, len);
+             int len, ch = string_char_and_length (p, &len);
              p += len, q -= len;
              CHAR_STRING (ch, q);
            }
@@ -2641,10 +2627,8 @@ mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object 
fn, Lisp_Object seq)
 
       for (i = 0, i_byte = 0; i < leni;)
        {
-         int c;
          ptrdiff_t i_before = i;
-
-         FETCH_STRING_CHAR_ADVANCE (c, seq, i, i_byte);
+         int c = fetch_string_char_advance (seq, &i, &i_byte);
          XSETFASTINT (dummy, c);
          dummy = call1 (fn, dummy);
          if (vals)
@@ -3451,7 +3435,7 @@ base64_encode_1 (const char *from, char *to, ptrdiff_t 
length,
     {
       if (multibyte)
        {
-         c = STRING_CHAR_AND_LENGTH ((unsigned char *) from + i, bytes);
+         c = string_char_and_length ((unsigned char *) from + i, &bytes);
          if (CHAR_BYTE8_P (c))
            c = CHAR_TO_BYTE8 (c);
          else if (c >= 256)
@@ -3494,7 +3478,7 @@ base64_encode_1 (const char *from, char *to, ptrdiff_t 
length,
 
       if (multibyte)
        {
-         c = STRING_CHAR_AND_LENGTH ((unsigned char *) from + i, bytes);
+         c = string_char_and_length ((unsigned char *) from + i, &bytes);
          if (CHAR_BYTE8_P (c))
            c = CHAR_TO_BYTE8 (c);
          else if (c >= 256)
@@ -3519,7 +3503,7 @@ base64_encode_1 (const char *from, char *to, ptrdiff_t 
length,
 
       if (multibyte)
        {
-         c = STRING_CHAR_AND_LENGTH ((unsigned char *) from + i, bytes);
+         c = string_char_and_length ((unsigned char *) from + i, &bytes);
          if (CHAR_BYTE8_P (c))
            c = CHAR_TO_BYTE8 (c);
          else if (c >= 256)
diff --git a/src/font.c b/src/font.c
index 0c9e752..ab00402 100644
--- a/src/font.c
+++ b/src/font.c
@@ -3856,13 +3856,10 @@ font_range (ptrdiff_t pos, ptrdiff_t pos_byte, 
ptrdiff_t *limit,
 
   while (pos < *limit)
     {
-      Lisp_Object category;
-
-      if (NILP (string))
-       FETCH_CHAR_ADVANCE_NO_CHECK (c, pos, pos_byte);
-      else
-       FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, pos, pos_byte);
-      category = CHAR_TABLE_REF (Vunicode_category_table, c);
+      c = (NILP (string)
+          ? fetch_char_advance_no_check (&pos, &pos_byte)
+          : fetch_string_char_advance_no_check (string, &pos, &pos_byte));
+      Lisp_Object category = CHAR_TABLE_REF (Vunicode_category_table, c);
       if (FIXNUMP (category)
          && (XFIXNUM (category) == UNICODE_CATEGORY_Cf
              || CHAR_VARIATION_SELECTOR_P (c)))
@@ -4891,7 +4888,7 @@ the corresponding element is nil.  */)
    Lisp_Object object)
 {
   struct font *font = CHECK_FONT_GET_OBJECT (font_object);
-  ptrdiff_t i, len;
+  ptrdiff_t len;
   Lisp_Object *chars, vec;
   USE_SAFE_ALLOCA;
 
@@ -4906,10 +4903,9 @@ the corresponding element is nil.  */)
       SAFE_ALLOCA_LISP (chars, len);
       charpos = XFIXNAT (from);
       bytepos = CHAR_TO_BYTE (charpos);
-      for (i = 0; charpos < XFIXNAT (to); i++)
+      for (ptrdiff_t i = 0; charpos < XFIXNAT (to); i++)
        {
-         int c;
-         FETCH_CHAR_ADVANCE (c, charpos, bytepos);
+         int c = fetch_char_advance (&charpos, &bytepos);
          chars[i] = make_fixnum (c);
        }
     }
@@ -4929,18 +4925,18 @@ the corresponding element is nil.  */)
          int c;
 
          /* Skip IFROM characters from the beginning.  */
-         for (i = 0; i < ifrom; i++)
-           c = STRING_CHAR_ADVANCE (p);
+         for (ptrdiff_t i = 0; i < ifrom; i++)
+           p += BYTES_BY_CHAR_HEAD (*p);
 
          /* Now fetch an interesting characters.  */
-         for (i = 0; i < len; i++)
-         {
-           c = STRING_CHAR_ADVANCE (p);
-           chars[i] = make_fixnum (c);
-         }
+         for (ptrdiff_t i = 0; i < len; i++)
+           {
+             c = string_char_advance (&p);
+             chars[i] = make_fixnum (c);
+           }
        }
       else
-       for (i = 0; i < len; i++)
+       for (ptrdiff_t i = 0; i < len; i++)
          chars[i] = make_fixnum (p[ifrom + i]);
     }
   else if (VECTORP (object))
@@ -4951,7 +4947,7 @@ the corresponding element is nil.  */)
       if (ifrom == ito)
        return Qnil;
       len = ito - ifrom;
-      for (i = 0; i < len; i++)
+      for (ptrdiff_t i = 0; i < len; i++)
        {
          Lisp_Object elt = AREF (object, ifrom + i);
          CHECK_CHARACTER (elt);
@@ -4962,7 +4958,7 @@ the corresponding element is nil.  */)
     wrong_type_argument (Qarrayp, object);
 
   vec = make_uninit_vector (len);
-  for (i = 0; i < len; i++)
+  for (ptrdiff_t i = 0; i < len; i++)
     {
       Lisp_Object g;
       int c = XFIXNAT (chars[i]);
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index a0e18e1..7832d4f 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -328,14 +328,13 @@ ftcrfont_encode_char (struct font *font, int c)
   struct font_info *ftcrfont_info = (struct font_info *) font;
   unsigned code = FONT_INVALID_CODE;
   unsigned char utf8[MAX_MULTIBYTE_LENGTH];
-  unsigned char *p = utf8;
+  int utf8len = CHAR_STRING (c, utf8);
   cairo_glyph_t stack_glyph;
   cairo_glyph_t *glyphs = &stack_glyph;
   int num_glyphs = 1;
 
-  CHAR_STRING_ADVANCE (c, p);
   if (cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font, 0, 0,
-                                       (char *) utf8, p - utf8,
+                                       (char *) utf8, utf8len,
                                        &glyphs, &num_glyphs,
                                        NULL, NULL, NULL)
       == CAIRO_STATUS_SUCCESS)
diff --git a/src/indent.c b/src/indent.c
index 06f11a2..c0b4c13b 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -285,9 +285,7 @@ skip_invisible (ptrdiff_t pos, ptrdiff_t *next_boundary_p, 
ptrdiff_t to, Lisp_Ob
 
 #define MULTIBYTE_BYTES_WIDTH(p, dp, bytes, width)                     \
   do {                                                                 \
-    int ch;                                                            \
-                                                                       \
-    ch = STRING_CHAR_AND_LENGTH (p, bytes);                            \
+    int ch = string_char_and_length (p, &(bytes));                     \
     if (BYTES_BY_CHAR_HEAD (*p) != bytes)                              \
       width = bytes * 4;                                               \
     else                                                               \
@@ -942,7 +940,7 @@ position_indentation (ptrdiff_t pos_byte)
            if (CHAR_HAS_CATEGORY (c, ' '))
              {
                column++;
-               INC_POS (pos_byte);
+               pos_byte += next_char_len (pos_byte);
                p = BYTE_POS_ADDR (pos_byte);
              }
            else
@@ -961,7 +959,7 @@ indented_beyond_p (ptrdiff_t pos, ptrdiff_t pos_byte, 
EMACS_INT column)
 {
   while (pos > BEGV && FETCH_BYTE (pos_byte) == '\n')
     {
-      DEC_BOTH (pos, pos_byte);
+      dec_both (&pos, &pos_byte);
       pos = find_newline (pos, pos_byte, BEGV, BEGV_BYTE,
                          -1, NULL, &pos_byte, 0);
     }
@@ -1010,7 +1008,7 @@ The return value is the current column.  */)
       int c;
       ptrdiff_t pos_byte = PT_BYTE;
 
-      DEC_POS (pos_byte);
+      pos_byte -= prev_char_len (pos_byte);
       c = FETCH_CHAR (pos_byte);
       if (c == '\t' && prev_col < goal)
        {
@@ -1605,7 +1603,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, 
EMACS_INT fromvpos,
                            {
                              pos = find_before_next_newline (pos, to, 1, 
&pos_byte);
                              if (pos < to)
-                               INC_BOTH (pos, pos_byte);
+                               inc_both (&pos, &pos_byte);
                              rarely_quit (++quit_count);
                            }
                          while (pos < to
@@ -1618,7 +1616,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, 
EMACS_INT fromvpos,
                              if (hpos >= width)
                                hpos = width;
                            }
-                         DEC_BOTH (pos, pos_byte);
+                         dec_both (&pos, &pos_byte);
                          /* We have skipped the invis text, but not the
                             newline after.  */
                        }
@@ -1820,8 +1818,8 @@ visible section of the buffer, and pass LINE and COL as 
TOPOS.  */)
 static struct position val_vmotion;
 
 struct position *
-vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
-        register EMACS_INT vtarget, struct window *w)
+vmotion (ptrdiff_t from, ptrdiff_t from_byte,
+        EMACS_INT vtarget, struct window *w)
 {
   ptrdiff_t hscroll = w->hscroll;
   struct position pos;
@@ -1862,7 +1860,7 @@ vmotion (register ptrdiff_t from, register ptrdiff_t 
from_byte,
          Lisp_Object propval;
 
          prevline = from;
-         DEC_BOTH (prevline, bytepos);
+         dec_both (&prevline, &bytepos);
          prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
 
          while (prevline > BEGV
@@ -1875,7 +1873,7 @@ vmotion (register ptrdiff_t from, register ptrdiff_t 
from_byte,
                                                       text_prop_object),
                         TEXT_PROP_MEANS_INVISIBLE (propval))))
            {
-             DEC_BOTH (prevline, bytepos);
+             dec_both (&prevline, &bytepos);
              prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
            }
          pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
@@ -1925,7 +1923,7 @@ vmotion (register ptrdiff_t from, register ptrdiff_t 
from_byte,
                                                   text_prop_object),
                     TEXT_PROP_MEANS_INVISIBLE (propval))))
        {
-         DEC_BOTH (prevline, bytepos);
+         dec_both (&prevline, &bytepos);
          prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
        }
       pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
diff --git a/src/insdel.c b/src/insdel.c
index dfa1cc3..c37b071 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -382,10 +382,10 @@ count_bytes (ptrdiff_t pos, ptrdiff_t bytepos, ptrdiff_t 
endpos)
 
   if (pos <= endpos)
     for ( ; pos < endpos; pos++)
-      INC_POS (bytepos);
+      bytepos += next_char_len (bytepos);
   else
     for ( ; pos > endpos; pos--)
-      DEC_POS (bytepos);
+      bytepos -= prev_char_len (bytepos);
 
   return bytepos;
 }
@@ -626,8 +626,7 @@ copy_text (const unsigned char *from_addr, unsigned char 
*to_addr,
 
       while (bytes_left > 0)
        {
-         int thislen, c;
-         c = STRING_CHAR_AND_LENGTH (from_addr, thislen);
+         int thislen, c = string_char_and_length (from_addr, &thislen);
          if (! ASCII_CHAR_P (c))
            c &= 0xFF;
          *to_addr++ = c;
diff --git a/src/keyboard.c b/src/keyboard.c
index b4e62c3..c94d794 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -2279,7 +2279,7 @@ read_decoded_event_from_main_queue (struct timespec 
*end_time,
                      eassert (coding->carryover_bytes == 0);
                      n = 0;
                      while (n < coding->produced_char)
-                       events[n++] = make_fixnum (STRING_CHAR_ADVANCE (p));
+                       events[n++] = make_fixnum (string_char_advance (&p));
                    }
                }
            }
@@ -10466,9 +10466,8 @@ Internal use only.  */)
   this_command_key_count = 0;
   this_single_command_key_start = 0;
 
-  int charidx = 0, byteidx = 0;
-  int key0;
-  FETCH_STRING_CHAR_ADVANCE (key0, keys, charidx, byteidx);
+  ptrdiff_t charidx = 0, byteidx = 0;
+  int key0 = fetch_string_char_advance (keys, &charidx, &byteidx);
   if (CHAR_BYTE8_P (key0))
     key0 = CHAR_TO_BYTE8 (key0);
 
@@ -10480,8 +10479,7 @@ Internal use only.  */)
     add_command_key (make_fixnum (key0));
   for (ptrdiff_t i = 1; i < SCHARS (keys); i++)
     {
-      int key_i;
-      FETCH_STRING_CHAR_ADVANCE (key_i, keys, charidx, byteidx);
+      int key_i = fetch_string_char_advance (keys, &charidx, &byteidx);
       if (CHAR_BYTE8_P (key_i))
        key_i = CHAR_TO_BYTE8 (key_i);
       add_command_key (make_fixnum (key_i));
diff --git a/src/keymap.c b/src/keymap.c
index cfba98c..8a6881a 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1949,8 +1949,7 @@ then the value includes only maps for prefixes that start 
with PREFIX.  */)
              for (ptrdiff_t i = 0; i < SCHARS (prefix); )
                {
                  ptrdiff_t i_before = i;
-                 int c;
-                 FETCH_STRING_CHAR_ADVANCE (c, prefix, i, i_byte);
+                 int c = fetch_string_char_advance (prefix, &i, &i_byte);
                  if (SINGLE_BYTE_CHAR_P (c) && (c & 0200))
                    c ^= 0200 | meta_modifier;
                  ASET (copy, i_before, make_fixnum (c));
@@ -2065,8 +2064,7 @@ For an approximate inverse of this, see `kbd'.  */)
     {
       if (STRINGP (list))
        {
-         int c;
-         FETCH_STRING_CHAR_ADVANCE (c, list, i, i_byte);
+         int c = fetch_string_char_advance (list, &i, &i_byte);
          if (SINGLE_BYTE_CHAR_P (c) && (c & 0200))
            c ^= 0200 | meta_modifier;
          XSETFASTINT (key, c);
diff --git a/src/lread.c b/src/lread.c
index 8ec9e32..c6607a8 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -225,8 +225,9 @@ readchar (Lisp_Object readcharfun, bool *multibyte)
        {
          /* Fetch the character code from the buffer.  */
          unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, pt_byte);
-         BUF_INC_POS (inbuffer, pt_byte);
-         c = STRING_CHAR (p);
+         int clen;
+         c = string_char_and_length (p, &clen);
+         pt_byte += clen;
          if (multibyte)
            *multibyte = 1;
        }
@@ -254,8 +255,9 @@ readchar (Lisp_Object readcharfun, bool *multibyte)
        {
          /* Fetch the character code from the buffer.  */
          unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, bytepos);
-         BUF_INC_POS (inbuffer, bytepos);
-         c = STRING_CHAR (p);
+         int clen;
+         c = string_char_and_length (p, &clen);
+         bytepos += clen;
          if (multibyte)
            *multibyte = 1;
        }
@@ -294,9 +296,10 @@ readchar (Lisp_Object readcharfun, bool *multibyte)
        {
          if (multibyte)
            *multibyte = 1;
-         FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, readcharfun,
-                                             read_from_string_index,
-                                             read_from_string_index_byte);
+         c = (fetch_string_char_advance_no_check
+              (readcharfun,
+               &read_from_string_index,
+               &read_from_string_index_byte));
        }
       else
        {
@@ -427,7 +430,7 @@ unreadchar (Lisp_Object readcharfun, int c)
       ptrdiff_t bytepos = BUF_PT_BYTE (b);
 
       if (! NILP (BVAR (b, enable_multibyte_characters)))
-       BUF_DEC_POS (b, bytepos);
+       bytepos -= buf_prev_char_len (b, bytepos);
       else
        bytepos--;
 
@@ -440,7 +443,7 @@ unreadchar (Lisp_Object readcharfun, int c)
 
       XMARKER (readcharfun)->charpos--;
       if (! NILP (BVAR (b, enable_multibyte_characters)))
-       BUF_DEC_POS (b, bytepos);
+       bytepos -= buf_prev_char_len (b, bytepos);
       else
        bytepos--;
 
@@ -526,13 +529,11 @@ readbyte_from_string (int c, Lisp_Object readcharfun)
        = string_char_to_byte (string, read_from_string_index);
     }
 
-  if (read_from_string_index >= read_from_string_limit)
-    c = -1;
-  else
-    FETCH_STRING_CHAR_ADVANCE (c, string,
-                              read_from_string_index,
-                              read_from_string_index_byte);
-  return c;
+  return (read_from_string_index < read_from_string_limit
+         ? fetch_string_char_advance (string,
+                                      &read_from_string_index,
+                                      &read_from_string_index_byte)
+         : -1);
 }
 
 
diff --git a/src/marker.c b/src/marker.c
index 684b750..64f210d 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -221,7 +221,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
       while (best_below != charpos)
        {
          best_below++;
-         BUF_INC_POS (b, best_below_byte);
+         best_below_byte += buf_next_char_len (b, best_below_byte);
        }
 
       /* If this position is quite far from the nearest known position,
@@ -246,7 +246,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
       while (best_above != charpos)
        {
          best_above--;
-         BUF_DEC_POS (b, best_above_byte);
+         best_above_byte -= buf_prev_char_len (b, best_above_byte);
        }
 
       /* If this position is quite far from the nearest known position,
@@ -372,7 +372,7 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
       while (best_below_byte < bytepos)
        {
          best_below++;
-         BUF_INC_POS (b, best_below_byte);
+         best_below_byte += buf_next_char_len (b, best_below_byte);
        }
 
       /* If this position is quite far from the nearest known position,
@@ -399,7 +399,7 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
       while (best_above_byte > bytepos)
        {
          best_above--;
-         BUF_DEC_POS (b, best_above_byte);
+         best_above_byte -= buf_prev_char_len (b, best_above_byte);
        }
 
       /* If this position is quite far from the nearest known position,
@@ -804,7 +804,7 @@ verify_bytepos (ptrdiff_t charpos)
   while (below != charpos)
     {
       below++;
-      BUF_INC_POS (current_buffer, below_byte);
+      below_byte += buf_next_char_len (current_buffer, below_byte);
     }
 
   return below_byte;
diff --git a/src/menu.c b/src/menu.c
index 6b8b5dd..e4fda57 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -1036,9 +1036,7 @@ menu_item_width (const unsigned char *str)
 
   for (len = 0, p = str; *p; )
     {
-      int ch_len;
-      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
-
+      int ch_len, ch = string_char_and_length (p, &ch_len);
       len += CHARACTER_WIDTH (ch);
       p += ch_len;
     }
diff --git a/src/msdos.c b/src/msdos.c
index a09b3ba..b5f06c9 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -2905,7 +2905,7 @@ IT_menu_display (XMenu *menu, int y, int x, int pn, int 
*faces, int disp_help)
       p++;
       for (j = 0, q = menu->text[i]; *q; j++)
        {
-         unsigned c = STRING_CHAR_ADVANCE (q);
+         unsigned c = string_char_advance (&q);
 
          if (c > 26)
            {
diff --git a/src/nsfont.m b/src/nsfont.m
index e41a698..691becd 100644
--- a/src/nsfont.m
+++ b/src/nsfont.m
@@ -1090,7 +1090,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, 
int x, int y,
         twidth += cwidth;
 #ifdef NS_IMPL_GNUSTEP
         *adv++ = cwidth;
-        CHAR_STRING_ADVANCE (*t, c); /* This converts the char to UTF-8.  */
+        c += CHAR_STRING (*t, c); /* This converts the char to UTF-8.  */
 #else
         (*adv++).width = cwidth;
 #endif
diff --git a/src/print.c b/src/print.c
index 634169d..bd17691 100644
--- a/src/print.c
+++ b/src/print.c
@@ -368,8 +368,8 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t 
size_byte,
          int len;
          for (ptrdiff_t i = 0; i < size_byte; i += len)
            {
-             int ch = STRING_CHAR_AND_LENGTH ((const unsigned char *) ptr + i,
-                                              len);
+             int ch = string_char_and_length ((const unsigned char *) ptr + i,
+                                              &len);
              printchar_to_stream (ch, stdout);
            }
        }
@@ -400,8 +400,8 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t 
size_byte,
          int len;
          for (i = 0; i < size_byte; i += len)
            {
-             int ch = STRING_CHAR_AND_LENGTH ((const unsigned char *) ptr + i,
-                                              len);
+             int ch = string_char_and_length ((const unsigned char *) ptr + i,
+                                              &len);
              insert_char (ch);
            }
        }
@@ -426,9 +426,8 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t 
size_byte,
              /* Here, we must convert each multi-byte form to the
                 corresponding character code before handing it to
                 PRINTCHAR.  */
-             int len;
-             int ch = STRING_CHAR_AND_LENGTH ((const unsigned char *) ptr + i,
-                                              len);
+             int len, ch = (string_char_and_length
+                            ((const unsigned char *) ptr + i, &len));
              printchar (ch, printcharfun);
              i += len;
            }
@@ -510,8 +509,7 @@ print_string (Lisp_Object string, Lisp_Object printcharfun)
          {
            /* Here, we must convert each multi-byte form to the
               corresponding character code before handing it to PRINTCHAR.  */
-           int len;
-           int ch = STRING_CHAR_AND_LENGTH (SDATA (string) + i, len);
+           int len, ch = string_char_and_length (SDATA (string) + i, &len);
            printchar (ch, printcharfun);
            i += len;
          }
@@ -1307,15 +1305,13 @@ print_check_string_charset_prop (INTERVAL interval, 
Lisp_Object string)
     }
   if (! (print_check_string_result & PRINT_STRING_UNSAFE_CHARSET_FOUND))
     {
-      int i, c;
       ptrdiff_t charpos = interval->position;
       ptrdiff_t bytepos = string_char_to_byte (string, charpos);
-      Lisp_Object charset;
+      Lisp_Object charset = XCAR (XCDR (val));
 
-      charset = XCAR (XCDR (val));
-      for (i = 0; i < LENGTH (interval); i++)
+      for (ptrdiff_t i = 0; i < LENGTH (interval); i++)
        {
-         FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
+         int c = fetch_string_char_advance (string, &charpos, &bytepos);
          if (! ASCII_CHAR_P (c)
              && ! EQ (CHARSET_NAME (CHAR_CHARSET (c)), charset))
            {
@@ -1943,9 +1939,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, 
bool escapeflag)
            {
              /* Here, we must convert each multi-byte form to the
                 corresponding character code before handing it to printchar.  
*/
-             int c;
-
-             FETCH_STRING_CHAR_ADVANCE (c, obj, i, i_byte);
+             int c = fetch_string_char_advance (obj, &i, &i_byte);
 
              maybe_quit ();
 
@@ -2036,8 +2030,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, 
bool escapeflag)
          {
            /* Here, we must convert each multi-byte form to the
               corresponding character code before handing it to PRINTCHAR.  */
-           int c;
-           FETCH_STRING_CHAR_ADVANCE (c, name, i, i_byte);
+           int c = fetch_string_char_advance (name, &i, &i_byte);
            maybe_quit ();
 
            if (escapeflag)
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index 0ae004e..9fd2394 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -58,7 +58,7 @@
 #define RE_STRING_CHAR(p, multibyte) \
   (multibyte ? STRING_CHAR (p) : *(p))
 #define RE_STRING_CHAR_AND_LENGTH(p, len, multibyte) \
-  (multibyte ? STRING_CHAR_AND_LENGTH (p, len) : ((len) = 1, *(p)))
+  (multibyte ? string_char_and_length (p, &(len)) : ((len) = 1, *(p)))
 
 #define RE_CHAR_TO_MULTIBYTE(c) UNIBYTE_TO_CHAR (c)
 
@@ -89,7 +89,7 @@
 #define GET_CHAR_AFTER(c, p, len)              \
   do {                                         \
     if (target_multibyte)                      \
-      (c) = STRING_CHAR_AND_LENGTH (p, len);   \
+      (c) = string_char_and_length (p, &(len));        \
     else                                       \
       {                                                \
        (c) = *p;                               \
@@ -3167,10 +3167,6 @@ re_search (struct re_pattern_buffer *bufp, const char 
*string, ptrdiff_t size,
                      regs, size);
 }
 
-/* Head address of virtual concatenation of string.  */
-#define HEAD_ADDR_VSTRING(P)           \
-  (((P) >= size1 ? string2 : string1))
-
 /* Address of POS in the concatenation of virtual string. */
 #define POS_ADDR_VSTRING(POS)                                  \
   (((POS) >= size1 ? string2 - size1 : string1) + (POS))
@@ -3300,7 +3296,7 @@ re_search_2 (struct re_pattern_buffer *bufp, const char 
*str1, ptrdiff_t size1,
                      {
                        int buf_charlen;
 
-                       buf_ch = STRING_CHAR_AND_LENGTH (d, buf_charlen);
+                       buf_ch = string_char_and_length (d, &buf_charlen);
                        buf_ch = RE_TRANSLATE (translate, buf_ch);
                        if (fastmap[CHAR_LEADING_CODE (buf_ch)])
                          break;
@@ -3330,7 +3326,7 @@ re_search_2 (struct re_pattern_buffer *bufp, const char 
*str1, ptrdiff_t size1,
                      {
                        int buf_charlen;
 
-                       buf_ch = STRING_CHAR_AND_LENGTH (d, buf_charlen);
+                       buf_ch = string_char_and_length (d, &buf_charlen);
                        if (fastmap[CHAR_LEADING_CODE (buf_ch)])
                          break;
                        range -= buf_charlen;
@@ -3413,16 +3409,12 @@ re_search_2 (struct re_pattern_buffer *bufp, const char 
*str1, ptrdiff_t size1,
          if (multibyte)
            {
              re_char *p = POS_ADDR_VSTRING (startpos) + 1;
-             re_char *p0 = p;
-             re_char *phead = HEAD_ADDR_VSTRING (startpos);
+             int len = raw_prev_char_len (p);
 
-             /* Find the head of multibyte form.  */
-             PREV_CHAR_BOUNDARY (p, phead);
-             range += p0 - 1 - p;
+             range += len - 1;
              if (range > 0)
                break;
-
-             startpos -= p0 - 1 - p;
+             startpos -= len - 1;
            }
        }
     }
@@ -4218,13 +4210,13 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
 
                PREFETCH ();
                if (multibyte)
-                 pat_ch = STRING_CHAR_AND_LENGTH (p, pat_charlen);
+                 pat_ch = string_char_and_length (p, &pat_charlen);
                else
                  {
                    pat_ch = RE_CHAR_TO_MULTIBYTE (*p);
                    pat_charlen = 1;
                  }
-               buf_ch = STRING_CHAR_AND_LENGTH (d, buf_charlen);
+               buf_ch = string_char_and_length (d, &buf_charlen);
 
                if (TRANSLATE (buf_ch) != pat_ch)
                  {
@@ -4246,7 +4238,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp,
                PREFETCH ();
                if (multibyte)
                  {
-                   pat_ch = STRING_CHAR_AND_LENGTH (p, pat_charlen);
+                   pat_ch = string_char_and_length (p, &pat_charlen);
                    pat_ch = RE_CHAR_TO_UNIBYTE (pat_ch);
                  }
                else
diff --git a/src/search.c b/src/search.c
index 08b57c5..567270a 100644
--- a/src/search.c
+++ b/src/search.c
@@ -994,7 +994,7 @@ find_before_next_newline (ptrdiff_t from, ptrdiff_t to,
   if (counted == cnt)
     {
       if (bytepos)
-       DEC_BOTH (pos, *bytepos);
+       dec_both (&pos, &*bytepos);
       else
        pos--;
     }
@@ -1353,8 +1353,8 @@ search_buffer_non_re (Lisp_Object string, ptrdiff_t pos,
       while (--len >= 0)
         {
           unsigned char str_base[MAX_MULTIBYTE_LENGTH], *str;
-          int c, translated, inverse;
-          int in_charlen, charlen;
+          int translated, inverse;
+          int charlen;
 
           /* If we got here and the RE flag is set, it's because we're
              dealing with a regexp known to be trivial, so the backslash
@@ -1367,7 +1367,7 @@ search_buffer_non_re (Lisp_Object string, ptrdiff_t pos,
               base_pat++;
             }
 
-          c = STRING_CHAR_AND_LENGTH (base_pat, in_charlen);
+          int in_charlen, c = string_char_and_length (base_pat, &in_charlen);
 
           if (NILP (trt))
             {
@@ -1550,12 +1550,10 @@ simple_search (EMACS_INT n, unsigned char *pat,
 
            while (this_len > 0)
              {
-               int charlen, buf_charlen;
-               int pat_ch, buf_ch;
-
-               pat_ch = STRING_CHAR_AND_LENGTH (p, charlen);
-               buf_ch = STRING_CHAR_AND_LENGTH (BYTE_POS_ADDR (this_pos_byte),
-                                                buf_charlen);
+               int charlen, pat_ch = string_char_and_length (p, &charlen);
+               int buf_charlen, buf_ch
+                 = string_char_and_length (BYTE_POS_ADDR (this_pos_byte),
+                                           &buf_charlen);
                TRANSLATE (buf_ch, trt, buf_ch);
 
                if (buf_ch != pat_ch)
@@ -1576,7 +1574,7 @@ simple_search (EMACS_INT n, unsigned char *pat,
                break;
              }
 
-           INC_BOTH (pos, pos_byte);
+           inc_both (&pos, &pos_byte);
          }
 
        n--;
@@ -1638,8 +1636,8 @@ simple_search (EMACS_INT n, unsigned char *pat,
              {
                int pat_ch, buf_ch;
 
-               DEC_BOTH (this_pos, this_pos_byte);
-               PREV_CHAR_BOUNDARY (p, pat);
+               dec_both (&this_pos, &this_pos_byte);
+               p -= raw_prev_char_len (p);
                pat_ch = STRING_CHAR (p);
                buf_ch = STRING_CHAR (BYTE_POS_ADDR (this_pos_byte));
                TRANSLATE (buf_ch, trt, buf_ch);
@@ -1658,7 +1656,7 @@ simple_search (EMACS_INT n, unsigned char *pat,
                break;
              }
 
-           DEC_BOTH (pos, pos_byte);
+           dec_both (&pos, &pos_byte);
          }
 
        n++;
@@ -2437,10 +2435,11 @@ since only regular expressions have distinguished 
subexpressions.  */)
          if (NILP (string))
            {
              c = FETCH_CHAR_AS_MULTIBYTE (pos_byte);
-             INC_BOTH (pos, pos_byte);
+             inc_both (&pos, &pos_byte);
            }
          else
-           FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE (c, string, pos, pos_byte);
+           c = fetch_string_char_as_multibyte_advance (string,
+                                                       &pos, &pos_byte);
 
          if (lowercasep (c))
            {
@@ -2513,11 +2512,11 @@ since only regular expressions have distinguished 
subexpressions.  */)
              ptrdiff_t subend = 0;
              bool delbackslash = 0;
 
-             FETCH_STRING_CHAR_ADVANCE (c, newtext, pos, pos_byte);
+             c = fetch_string_char_advance (newtext, &pos, &pos_byte);
 
              if (c == '\\')
                {
-                 FETCH_STRING_CHAR_ADVANCE (c, newtext, pos, pos_byte);
+                 c = fetch_string_char_advance (newtext, &pos, &pos_byte);
 
                  if (c == '&')
                    {
@@ -2625,7 +2624,8 @@ since only regular expressions have distinguished 
subexpressions.  */)
 
          if (str_multibyte)
            {
-             FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, newtext, pos, pos_byte);
+             c = fetch_string_char_advance_no_check (newtext,
+                                                     &pos, &pos_byte);
              if (!buf_multibyte)
                c = CHAR_TO_BYTE8 (c);
            }
@@ -2634,7 +2634,7 @@ since only regular expressions have distinguished 
subexpressions.  */)
              /* Note that we don't have to increment POS.  */
              c = SREF (newtext, pos_byte++);
              if (buf_multibyte)
-               MAKE_CHAR_MULTIBYTE (c);
+               c = make_char_multibyte (c);
            }
 
          /* Either set ADD_STUFF and ADD_LEN to the text to put in SUBSTED,
@@ -2647,8 +2647,8 @@ since only regular expressions have distinguished 
subexpressions.  */)
 
              if (str_multibyte)
                {
-                 FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, newtext,
-                                                     pos, pos_byte);
+                 c = fetch_string_char_advance_no_check (newtext,
+                                                         &pos, &pos_byte);
                  if (!buf_multibyte && !ASCII_CHAR_P (c))
                    c = CHAR_TO_BYTE8 (c);
                }
@@ -2656,7 +2656,7 @@ since only regular expressions have distinguished 
subexpressions.  */)
                {
                  c = SREF (newtext, pos_byte++);
                  if (buf_multibyte)
-                   MAKE_CHAR_MULTIBYTE (c);
+                   c = make_char_multibyte (c);
                }
 
              if (c == '&')
diff --git a/src/syntax.c b/src/syntax.c
index ff125b1..bcf4dc0 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -535,7 +535,7 @@ char_quoted (ptrdiff_t charpos, ptrdiff_t bytepos)
   while (charpos > beg)
     {
       int c;
-      DEC_BOTH (charpos, bytepos);
+      dec_both (&charpos, &bytepos);
 
       UPDATE_SYNTAX_TABLE_BACKWARD (charpos);
       c = FETCH_CHAR_AS_MULTIBYTE (bytepos);
@@ -556,11 +556,9 @@ char_quoted (ptrdiff_t charpos, ptrdiff_t bytepos)
 static ptrdiff_t
 dec_bytepos (ptrdiff_t bytepos)
 {
-  if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
-    return bytepos - 1;
-
-  DEC_POS (bytepos);
-  return bytepos;
+  return (bytepos
+         - (!NILP (BVAR (current_buffer, enable_multibyte_characters))
+            ? prev_char_len (bytepos) : 1));
 }
 
 /* Return a defun-start position before POS and not too far before.
@@ -667,7 +665,7 @@ prev_char_comend_first (ptrdiff_t pos, ptrdiff_t pos_byte)
   int c;
   bool val;
 
-  DEC_BOTH (pos, pos_byte);
+  dec_both (&pos, &pos_byte);
   UPDATE_SYNTAX_TABLE_BACKWARD (pos);
   c = FETCH_CHAR (pos_byte);
   val = SYNTAX_COMEND_FIRST (c);
@@ -738,7 +736,7 @@ back_comment (ptrdiff_t from, ptrdiff_t from_byte, 
ptrdiff_t stop,
       bool com2start, com2end, comstart;
 
       /* Move back and examine a character.  */
-      DEC_BOTH (from, from_byte);
+      dec_both (&from, &from_byte);
       UPDATE_SYNTAX_TABLE_BACKWARD (from);
 
       prev_syntax = syntax;
@@ -773,7 +771,7 @@ back_comment (ptrdiff_t from, ptrdiff_t from_byte, 
ptrdiff_t stop,
        {
          ptrdiff_t next = from, next_byte = from_byte;
          int next_c, next_syntax;
-         DEC_BOTH (next, next_byte);
+         dec_both (&next, &next_byte);
          UPDATE_SYNTAX_TABLE_BACKWARD (next);
          next_c = FETCH_CHAR_AS_MULTIBYTE (next_byte);
          next_syntax = SYNTAX_WITH_FLAGS (next_c);
@@ -1150,8 +1148,7 @@ the value of a `syntax-table' text property.  */)
 
   if (*p)
     {
-      int len;
-      int character = STRING_CHAR_AND_LENGTH (p, len);
+      int len, character = string_char_and_length (p, &len);
       XSETINT (match, character);
       if (XFIXNAT (match) == ' ')
        match = Qnil;
@@ -1455,7 +1452,7 @@ scan_words (ptrdiff_t from, EMACS_INT count)
          UPDATE_SYNTAX_TABLE_FORWARD (from);
          ch0 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX (ch0);
-         INC_BOTH (from, from_byte);
+         inc_both (&from, &from_byte);
          if (words_include_escapes
              && (code == Sescape || code == Scharquote))
            break;
@@ -1488,7 +1485,7 @@ scan_words (ptrdiff_t from, EMACS_INT count)
                       || (code != Sescape && code != Scharquote)))
                  || word_boundary_p (ch0, ch1))
                break;
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              ch0 = ch1;
              rarely_quit (from);
            }
@@ -1501,7 +1498,7 @@ scan_words (ptrdiff_t from, EMACS_INT count)
        {
          if (from == beg)
            return 0;
-         DEC_BOTH (from, from_byte);
+         dec_both (&from, &from_byte);
          UPDATE_SYNTAX_TABLE_BACKWARD (from);
          ch1 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX (ch1);
@@ -1530,7 +1527,7 @@ scan_words (ptrdiff_t from, EMACS_INT count)
            {
              if (from == beg)
                break;
-             DEC_BOTH (from, from_byte);
+             dec_both (&from, &from_byte);
              UPDATE_SYNTAX_TABLE_BACKWARD (from);
              ch0 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
              code = SYNTAX (ch0);
@@ -1539,7 +1536,7 @@ scan_words (ptrdiff_t from, EMACS_INT count)
                       || (code != Sescape && code != Scharquote)))
                  || word_boundary_p (ch0, ch1))
                {
-                 INC_BOTH (from, from_byte);
+                 inc_both (&from, &from_byte);
                  break;
                }
              ch1 = ch0;
@@ -1818,7 +1815,7 @@ skip_chars (bool forwardp, Lisp_Object string, 
Lisp_Object lim,
 
              leading_code = str[i_byte];
            }
-         c = STRING_CHAR_AND_LENGTH (str + i_byte, len);
+         c = string_char_and_length (str + i_byte, &len);
          i_byte += len;
 
 
@@ -1834,14 +1831,14 @@ skip_chars (bool forwardp, Lisp_Object string, 
Lisp_Object lim,
 
              /* Get the end of the range.  */
              leading_code2 = str[i_byte];
-             c2 = STRING_CHAR_AND_LENGTH (str + i_byte, len);
+             c2 = string_char_and_length (str + i_byte, &len);
              i_byte += len;
 
              if (c2 == '\\'
                  && i_byte < size_byte)
                {
                  leading_code2 = str[i_byte];
-                 c2 = STRING_CHAR_AND_LENGTH (str + i_byte, len);
+                 c2 = string_char_and_length (str + i_byte, &len);
                  i_byte += len;
                }
 
@@ -1953,7 +1950,7 @@ skip_chars (bool forwardp, Lisp_Object string, 
Lisp_Object lim,
                  p = GAP_END_ADDR;
                  stop = endp;
                }
-             c = STRING_CHAR_AND_LENGTH (p, nbytes);
+             c = string_char_and_length (p, &nbytes);
              if (! NILP (iso_classes) && in_classes (c, iso_classes))
                {
                  if (negate)
@@ -2175,7 +2172,7 @@ skip_syntaxes (bool forwardp, Lisp_Object string, 
Lisp_Object lim)
                    stop = endp;
                  }
                if (multibyte)
-                 c = STRING_CHAR_AND_LENGTH (p, nbytes);
+                 c = string_char_and_length (p, &nbytes);
                else
                  c = *p, nbytes = 1;
                if (! fastmap[SYNTAX (c)])
@@ -2357,7 +2354,7 @@ forw_comment (ptrdiff_t from, ptrdiff_t from_byte, 
ptrdiff_t stop,
        /* We have encountered a nested comment of the same style
           as the comment sequence which began this comment section.  */
        nesting++;
-      INC_BOTH (from, from_byte);
+      inc_both (&from, &from_byte);
       UPDATE_SYNTAX_TABLE_FORWARD (from);
 
     forw_incomment:
@@ -2378,7 +2375,7 @@ forw_comment (ptrdiff_t from, ptrdiff_t from_byte, 
ptrdiff_t stop,
            break;
          else
            {
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              UPDATE_SYNTAX_TABLE_FORWARD (from);
            }
        }
@@ -2395,7 +2392,7 @@ forw_comment (ptrdiff_t from, ptrdiff_t from_byte, 
ptrdiff_t stop,
           as the comment sequence which began this comment section.  */
        {
           syntax = Smax; /* So that "#|#" isn't also a comment ender. */
-         INC_BOTH (from, from_byte);
+         inc_both (&from, &from_byte);
          UPDATE_SYNTAX_TABLE_FORWARD (from);
          nesting++;
        }
@@ -2456,7 +2453,7 @@ between them, return t; otherwise return nil.  */)
          comstart_first = SYNTAX_FLAGS_COMSTART_FIRST (syntax);
          comnested = SYNTAX_FLAGS_COMMENT_NESTED (syntax);
          comstyle = SYNTAX_FLAGS_COMMENT_STYLE (syntax, 0);
-         INC_BOTH (from, from_byte);
+         inc_both (&from, &from_byte);
          UPDATE_SYNTAX_TABLE_FORWARD (from);
          if (from < stop && comstart_first
              && (c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte),
@@ -2471,7 +2468,7 @@ between them, return t; otherwise return nil.  */)
              code = Scomment;
              comstyle = SYNTAX_FLAGS_COMMENT_STYLE (other_syntax, syntax);
              comnested |= SYNTAX_FLAGS_COMMENT_NESTED (other_syntax);
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              UPDATE_SYNTAX_TABLE_FORWARD (from);
            }
          rarely_quit (++quit_count);
@@ -2482,7 +2479,7 @@ between them, return t; otherwise return nil.  */)
        comstyle = ST_COMMENT_STYLE;
       else if (code != Scomment)
        {
-         DEC_BOTH (from, from_byte);
+         dec_both (&from, &from_byte);
          SET_PT_BOTH (from, from_byte);
          return Qnil;
        }
@@ -2495,7 +2492,7 @@ between them, return t; otherwise return nil.  */)
          SET_PT_BOTH (from, from_byte);
          return Qnil;
        }
-      INC_BOTH (from, from_byte);
+      inc_both (&from, &from_byte);
       UPDATE_SYNTAX_TABLE_FORWARD (from);
       /* We have skipped one comment.  */
       count1--;
@@ -2511,7 +2508,7 @@ between them, return t; otherwise return nil.  */)
              return Qnil;
            }
 
-         DEC_BOTH (from, from_byte);
+         dec_both (&from, &from_byte);
          /* char_quoted does UPDATE_SYNTAX_TABLE_BACKWARD (from).  */
          bool quoted = char_quoted (from, from_byte);
          c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
@@ -2529,7 +2526,7 @@ between them, return t; otherwise return nil.  */)
              /* We must record the comment style encountered so that
                 later, we can match only the proper comment begin
                 sequence of the same style.  */
-             DEC_BOTH (from, from_byte);
+             dec_both (&from, &from_byte);
              code = Sendcomment;
              /* Calling char_quoted, above, set up global syntax position
                 at the new value of FROM.  */
@@ -2547,7 +2544,7 @@ between them, return t; otherwise return nil.  */)
 
              while (1)
                {
-                 DEC_BOTH (from, from_byte);
+                 dec_both (&from, &from_byte);
                  UPDATE_SYNTAX_TABLE_BACKWARD (from);
                  c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
                  if (SYNTAX (c) == Scomment_fence
@@ -2588,7 +2585,7 @@ between them, return t; otherwise return nil.  */)
                         not-quite-endcomment.  */
                      if (SYNTAX (c) != code)
                        /* It was a two-char Sendcomment.  */
-                       INC_BOTH (from, from_byte);
+                       inc_both (&from, &from_byte);
                      goto leave;
                    }
                }
@@ -2602,7 +2599,7 @@ between them, return t; otherwise return nil.  */)
          else if (code != Swhitespace || quoted)
            {
            leave:
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              SET_PT_BOTH (from, from_byte);
              return Qnil;
            }
@@ -2676,7 +2673,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
          prefix = SYNTAX_FLAGS_PREFIX (syntax);
          if (depth == min_depth)
            last_good = from;
-         INC_BOTH (from, from_byte);
+         inc_both (&from, &from_byte);
          UPDATE_SYNTAX_TABLE_FORWARD (from);
          if (from < stop && comstart_first
              && (c = FETCH_CHAR_AS_MULTIBYTE (from_byte),
@@ -2692,7 +2689,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
              code = Scomment;
              comstyle = SYNTAX_FLAGS_COMMENT_STYLE (other_syntax, syntax);
              comnested |= SYNTAX_FLAGS_COMMENT_NESTED (other_syntax);
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              UPDATE_SYNTAX_TABLE_FORWARD (from);
            }
 
@@ -2705,7 +2702,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
            case Scharquote:
              if (from == stop)
                goto lose;
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              /* Treat following character as a word constituent.  */
              FALLTHROUGH;
            case Sword:
@@ -2721,7 +2718,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                    {
                    case Scharquote:
                    case Sescape:
-                     INC_BOTH (from, from_byte);
+                     inc_both (&from, &from_byte);
                      if (from == stop)
                        goto lose;
                      break;
@@ -2732,7 +2729,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                    default:
                      goto done;
                    }
-                 INC_BOTH (from, from_byte);
+                 inc_both (&from, &from_byte);
                  rarely_quit (++quit_count);
                }
              goto done;
@@ -2754,7 +2751,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                    goto done;
                  goto lose;
                }
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              UPDATE_SYNTAX_TABLE_FORWARD (from);
              break;
 
@@ -2763,7 +2760,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                break;
              if (from != stop && c == FETCH_CHAR_AS_MULTIBYTE (from_byte))
                {
-                 INC_BOTH (from, from_byte);
+                 inc_both (&from, &from_byte);
                }
              if (mathexit)
                {
@@ -2803,11 +2800,11 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                    break;
 
                  if (c_code == Scharquote || c_code == Sescape)
-                   INC_BOTH (from, from_byte);
-                 INC_BOTH (from, from_byte);
+                   inc_both (&from, &from_byte);
+                 inc_both (&from, &from_byte);
                  rarely_quit (++quit_count);
                }
-             INC_BOTH (from, from_byte);
+             inc_both (&from, &from_byte);
              if (!depth && sexpflag) goto done;
              break;
            default:
@@ -2832,7 +2829,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
       while (from > stop)
        {
          rarely_quit (++quit_count);
-         DEC_BOTH (from, from_byte);
+         dec_both (&from, &from_byte);
          UPDATE_SYNTAX_TABLE_BACKWARD (from);
          c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          int syntax = SYNTAX_WITH_FLAGS (c);
@@ -2851,7 +2848,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                 later, we can match only the proper comment begin
                 sequence of the same style.  */
              int c2, other_syntax;
-             DEC_BOTH (from, from_byte);
+             dec_both (&from, &from_byte);
              UPDATE_SYNTAX_TABLE_BACKWARD (from);
              code = Sendcomment;
              c2 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
@@ -2865,7 +2862,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
             if we decremented FROM in the if-statement above.  */
          if (code != Sendcomment && char_quoted (from, from_byte))
            {
-             DEC_BOTH (from, from_byte);
+             dec_both (&from, &from_byte);
              code = Sword;
            }
          else if (SYNTAX_FLAGS_PREFIX (syntax))
@@ -2882,11 +2879,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                 after passing it.  */
              while (from > stop)
                {
-                 temp_pos = from_byte;
-                 if (! NILP (BVAR (current_buffer, 
enable_multibyte_characters)))
-                   DEC_POS (temp_pos);
-                 else
-                   temp_pos--;
+                 temp_pos = dec_bytepos (from_byte);
                  UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
                  c1 = FETCH_CHAR_AS_MULTIBYTE (temp_pos);
                  /* Don't allow comment-end to be quoted.  */
@@ -2895,7 +2888,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                  quoted = char_quoted (from - 1, temp_pos);
                  if (quoted)
                    {
-                     DEC_BOTH (from, from_byte);
+                     dec_both (&from, &from_byte);
                      temp_pos = dec_bytepos (temp_pos);
                      UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
                    }
@@ -2906,7 +2899,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                      case Sword: case Ssymbol: case Squote: break;
                      default: goto done2;
                      }
-                 DEC_BOTH (from, from_byte);
+                 dec_both (&from, &from_byte);
                  rarely_quit (++quit_count);
                }
              goto done2;
@@ -2919,7 +2912,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                  temp_pos = dec_bytepos (from_byte);
                  UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
                  if (from != stop && c == FETCH_CHAR_AS_MULTIBYTE (temp_pos))
-                   DEC_BOTH (from, from_byte);
+                   dec_both (&from, &from_byte);
                }
              if (mathexit)
                {
@@ -2962,7 +2955,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                {
                  if (from == stop)
                    goto lose;
-                 DEC_BOTH (from, from_byte);
+                 dec_both (&from, &from_byte);
                  UPDATE_SYNTAX_TABLE_BACKWARD (from);
                  if (!char_quoted (from, from_byte))
                    {
@@ -2981,7 +2974,7 @@ scan_lists (EMACS_INT from, EMACS_INT count, EMACS_INT 
depth, bool sexpflag)
                {
                  if (from == stop)
                    goto lose;
-                 DEC_BOTH (from, from_byte);
+                 dec_both (&from, &from_byte);
                  UPDATE_SYNTAX_TABLE_BACKWARD (from);
                  if (!char_quoted (from, from_byte))
                    {
@@ -3091,7 +3084,7 @@ the prefix syntax flag (p).  */)
 
   SETUP_SYNTAX_TABLE (pos, -1);
 
-  DEC_BOTH (pos, pos_byte);
+  dec_both (&pos, &pos_byte);
 
   while (!char_quoted (pos, pos_byte)
         /* Previous statement updates syntax table.  */
@@ -3103,7 +3096,7 @@ the prefix syntax flag (p).  */)
 
       if (pos <= beg)
         break;
-      DEC_BOTH (pos, pos_byte);
+      dec_both (&pos, &pos_byte);
       rarely_quit (pos);
     }
 
@@ -3180,7 +3173,7 @@ scan_sexps_forward (struct lisp_parse_state *state,
   prev_from = from;
   prev_from_byte = from_byte;
   if (from != BEGV)
-    DEC_BOTH (prev_from, prev_from_byte);
+    dec_both (&prev_from, &prev_from_byte);
 
   /* Use this macro instead of `from++'.  */
 #define INC_FROM                               \
@@ -3189,7 +3182,7 @@ do { prev_from = from;                            \
      temp = FETCH_CHAR_AS_MULTIBYTE (prev_from_byte);  \
      prev_prev_from_syntax = prev_from_syntax;  \
      prev_from_syntax = SYNTAX_WITH_FLAGS (temp); \
-     INC_BOTH (from, from_byte);               \
+     inc_both (&from, &from_byte);             \
      if (from < end)                           \
        UPDATE_SYNTAX_TABLE_FORWARD (from);     \
   } while (0)
diff --git a/src/sysdep.c b/src/sysdep.c
index 149d80f..86e7c20 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -4133,14 +4133,20 @@ str_collate (Lisp_Object s1, Lisp_Object s2,
   len = SCHARS (s1); i = i_byte = 0;
   SAFE_NALLOCA (p1, 1, len + 1);
   while (i < len)
-    FETCH_STRING_CHAR_ADVANCE (*(p1+i-1), s1, i, i_byte);
-  *(p1+len) = 0;
+    {
+      wchar_t *p = &p1[i];
+      *p = fetch_string_char_advance (s1, &i, &i_byte);
+    }
+  p1[len] = 0;
 
   len = SCHARS (s2); i = i_byte = 0;
   SAFE_NALLOCA (p2, 1, len + 1);
   while (i < len)
-    FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte);
-  *(p2+len) = 0;
+    {
+      wchar_t *p = &p2[i];
+      *p = fetch_string_char_advance (s2, &i, &i_byte);
+    }
+  p2[len] = 0;
 
   if (STRINGP (locale))
     {
diff --git a/src/xdisp.c b/src/xdisp.c
index cce434e..86ae8e7 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -1901,16 +1901,14 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int 
*x, int *y,
 
 
 /* Return the next character from STR.  Return in *LEN the length of
-   the character.  This is like STRING_CHAR_AND_LENGTH but never
+   the character.  This is like string_char_and_length but never
    returns an invalid character.  If we find one, we return a `?', but
    with the length of the invalid character.  */
 
 static int
-string_char_and_length (const unsigned char *str, int *len)
+check_char_and_length (const unsigned char *str, int *len)
 {
-  int c;
-
-  c = STRING_CHAR_AND_LENGTH (str, *len);
+  int c = string_char_and_length (str, len);
   if (!CHAR_VALID_P (c))
     /* We may not change the length here because other places in Emacs
        don't use this function, i.e. they silently accept invalid
@@ -1933,11 +1931,10 @@ string_pos_nchars_ahead (struct text_pos pos, 
Lisp_Object string, ptrdiff_t ncha
   if (STRING_MULTIBYTE (string))
     {
       const unsigned char *p = SDATA (string) + BYTEPOS (pos);
-      int len;
 
       while (nchars--)
        {
-         string_char_and_length (p, &len);
+         int len = BYTES_BY_CHAR_HEAD (*p);
          p += len;
          CHARPOS (pos) += 1;
          BYTEPOS (pos) += len;
@@ -1978,12 +1975,10 @@ c_string_pos (ptrdiff_t charpos, const char *s, bool 
multibyte_p)
 
   if (multibyte_p)
     {
-      int len;
-
       SET_TEXT_POS (pos, 0, 0);
       while (charpos--)
        {
-         string_char_and_length ((const unsigned char *) s, &len);
+         int len = BYTES_BY_CHAR_HEAD (*s);
          s += len;
          CHARPOS (pos) += 1;
          BYTEPOS (pos) += len;
@@ -2007,12 +2002,11 @@ number_of_chars (const char *s, bool multibyte_p)
   if (multibyte_p)
     {
       ptrdiff_t rest = strlen (s);
-      int len;
       const unsigned char *p = (const unsigned char *) s;
 
       for (nchars = 0; rest > 0; ++nchars)
        {
-         string_char_and_length (p, &len);
+         int len = BYTES_BY_CHAR_HEAD (*p);
          rest -= len, p += len;
        }
     }
@@ -3819,8 +3813,7 @@ compute_stop_pos (struct it *it)
          ptrdiff_t bpos = CHAR_TO_BYTE (pos);
          while (pos < endpos)
            {
-             int ch;
-             FETCH_CHAR_ADVANCE_NO_CHECK (ch, pos, bpos);
+             int ch = fetch_char_advance_no_check (&pos, &bpos);
              if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\f')
                {
                  found = true;
@@ -4479,10 +4472,8 @@ face_before_or_after_it_pos (struct it *it, bool 
before_p)
        {
          struct text_pos pos1 = string_pos (charpos, it->string);
          const unsigned char *p = SDATA (it->string) + BYTEPOS (pos1);
-         int c, len;
          struct face *face = FACE_FROM_ID (it->f, face_id);
-
-         c = string_char_and_length (p, &len);
+         int len, c = check_char_and_length (p, &len);
          face_id = FACE_FOR_CHAR (it->f, face, c, charpos, it->string);
        }
     }
@@ -6577,7 +6568,7 @@ back_to_previous_line_start (struct it *it)
 {
   ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
 
-  DEC_BOTH (cp, bp);
+  dec_both (&cp, &bp);
   IT_CHARPOS (*it) = find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it));
 }
 
@@ -8391,7 +8382,7 @@ next_element_from_string (struct it *it)
        {
          const unsigned char *s = (SDATA (it->string)
                                    + IT_STRING_BYTEPOS (*it));
-         it->c = string_char_and_length (s, &it->len);
+         it->c = check_char_and_length (s, &it->len);
        }
       else
        {
@@ -8429,7 +8420,7 @@ next_element_from_string (struct it *it)
        {
          const unsigned char *s = (SDATA (it->string)
                                    + IT_STRING_BYTEPOS (*it));
-         it->c = string_char_and_length (s, &it->len);
+         it->c = check_char_and_length (s, &it->len);
        }
       else
        {
@@ -8487,7 +8478,7 @@ next_element_from_c_string (struct it *it)
       BYTEPOS (it->position) = CHARPOS (it->position) = -1;
     }
   else if (it->multibyte_p)
-    it->c = string_char_and_length (it->s + IT_BYTEPOS (*it), &it->len);
+    it->c = check_char_and_length (it->s + IT_BYTEPOS (*it), &it->len);
   else
     it->c = it->s[IT_BYTEPOS (*it)], it->len = 1;
 
@@ -8784,7 +8775,7 @@ next_element_from_buffer (struct it *it)
       /* Get the next character, maybe multibyte.  */
       p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
       if (it->multibyte_p && !ASCII_CHAR_P (*p))
-       it->c = STRING_CHAR_AND_LENGTH (p, it->len);
+       it->c = string_char_and_length (p, &it->len);
       else
        it->c = *p, it->len = 1;
 
@@ -10073,7 +10064,7 @@ move_it_vertically_backward (struct it *it, int dy)
        {
          ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
 
-         DEC_BOTH (cp, bp);
+         dec_both (&cp, &bp);
          cp = find_newline_no_quit (cp, bp, -1, NULL);
          move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
        }
@@ -10667,32 +10658,26 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool 
nlflag, bool multibyte)
       if (multibyte
          && NILP (BVAR (current_buffer, enable_multibyte_characters)))
        {
-         ptrdiff_t i;
-         int c, char_bytes;
-         char work[1];
-
          /* Convert a multibyte string to single-byte
             for the *Message* buffer.  */
-         for (i = 0; i < nbytes; i += char_bytes)
+         for (ptrdiff_t i = 0; i < nbytes; )
            {
-             c = string_char_and_length (msg + i, &char_bytes);
-             work[0] = CHAR_TO_BYTE8 (c);
-             insert_1_both (work, 1, 1, true, false, false);
+             int char_bytes, c = check_char_and_length (msg + i, &char_bytes);
+             char work = CHAR_TO_BYTE8 (c);
+             insert_1_both (&work, 1, 1, true, false, false);
+             i += char_bytes;
            }
        }
       else if (! multibyte
               && ! NILP (BVAR (current_buffer, enable_multibyte_characters)))
        {
-         ptrdiff_t i;
-         int c, char_bytes;
-         unsigned char str[MAX_MULTIBYTE_LENGTH];
          /* Convert a single-byte string to multibyte
             for the *Message* buffer.  */
-         for (i = 0; i < nbytes; i++)
+         for (ptrdiff_t i = 0; i < nbytes; i++)
            {
-             c = msg[i];
-             MAKE_CHAR_MULTIBYTE (c);
-             char_bytes = CHAR_STRING (c, str);
+             int c = make_char_multibyte (msg[i]);
+             unsigned char str[MAX_MULTIBYTE_LENGTH];
+             int char_bytes = CHAR_STRING (c, str);
              insert_1_both ((char *) str, 1, char_bytes, true, false, false);
            }
        }
@@ -21151,7 +21136,7 @@ get_overlay_arrow_glyph_row (struct window *w, 
Lisp_Object overlay_arrow_string)
 
       /* Get the next character.  */
       if (multibyte_p)
-       it.c = it.char_to_display = string_char_and_length (p, &it.len);
+       it.c = it.char_to_display = check_char_and_length (p, &it.len);
       else
        {
          it.c = it.char_to_display = *p, it.len = 1;
@@ -22504,7 +22489,7 @@ find_row_edges (struct it *it, struct glyph_row *row,
             required when scanning back, because max_pos will already
             have a much larger value.  */
          if (CHARPOS (row->end.pos) > max_pos)
-           INC_BOTH (max_pos, max_bpos);
+           inc_both (&max_pos, &max_bpos);
          SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
        }
       else if (CHARPOS (it->eol_pos) > 0)
@@ -22522,7 +22507,7 @@ find_row_edges (struct it *it, struct glyph_row *row,
            SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
          else
            {
-             INC_BOTH (max_pos, max_bpos);
+             inc_both (&max_pos, &max_bpos);
              SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
            }
        }
@@ -23932,7 +23917,7 @@ See also `bidi-paragraph-direction'.  */)
         to make sure we are within that paragraph.  To that end, find
         the previous non-empty line.  */
       if (pos >= ZV && pos > BEGV)
-       DEC_BOTH (pos, bytepos);
+       dec_both (&pos, &bytepos);
       AUTO_STRING (trailing_white_space, "[\f\t ]*\n");
       if (fast_looking_at (trailing_white_space,
                           pos, bytepos, ZV, ZV_BYTE, Qnil) > 0)
@@ -29279,7 +29264,7 @@ produce_stretch_glyph (struct it *it)
 
       it2 = *it;
       if (it->multibyte_p)
-       it2.c = it2.char_to_display = STRING_CHAR_AND_LENGTH (p, it2.len);
+       it2.c = it2.char_to_display = string_char_and_length (p, &it2.len);
       else
        {
          it2.c = it2.char_to_display = *p, it2.len = 1;
diff --git a/src/xfont.c b/src/xfont.c
index f6131dc..1563b43 100644
--- a/src/xfont.c
+++ b/src/xfont.c
@@ -166,7 +166,7 @@ xfont_encode_coding_xlfd (char *xlfd)
 
   while (*p0)
     {
-      int c = STRING_CHAR_ADVANCE (p0);
+      int c = string_char_advance (&p0);
 
       if (c >= 0x100)
        return -1;
diff --git a/src/xterm.c b/src/xterm.c
index ae5dad9..afe9c3d 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -8706,7 +8706,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                if (nchars == nbytes)
                  ch = copy_bufptr[i], len = 1;
                else
-                 ch = STRING_CHAR_AND_LENGTH (copy_bufptr + i, len);
+                 ch = string_char_and_length (copy_bufptr + i, &len);
                inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
                                ? ASCII_KEYSTROKE_EVENT
                                : MULTIBYTE_CHAR_KEYSTROKE_EVENT);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]