]> code.delx.au - gnu-emacs/blobdiff - src/indent.c
Fix bug ref
[gnu-emacs] / src / indent.c
index a57094c99029c8a86c56dbd5b4a21e7004731352..b368a7aeb0921ff23be3c7dd4bda74656b4cfc7e 100644 (file)
@@ -1,6 +1,5 @@
 /* Indentation functions.
-   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1998, 2000, 2001,
-                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+   Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2012
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -20,11 +19,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include <stdio.h>
-#include <setjmp.h>
 
 #include "lisp.h"
-#include "buffer.h"
 #include "character.h"
+#include "buffer.h"
 #include "category.h"
 #include "composite.h"
 #include "indent.h"
@@ -38,11 +36,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "dispextern.h"
 #include "region-cache.h"
 
-/* Indentation can insert tabs if this is non-zero;
-   otherwise always uses spaces.  */
-
-static int indent_tabs_mode;
-
 #define CR 015
 
 /* These three values memorize the current column to avoid recalculation.  */
@@ -51,32 +44,32 @@ static int indent_tabs_mode;
    Some things in set last_known_column_point to -1
    to mark the memorized value as invalid.  */
 
-static double last_known_column;
+static ptrdiff_t last_known_column;
 
 /* Value of point when current_column was called.  */
 
-EMACS_INT last_known_column_point;
+ptrdiff_t last_known_column_point;
 
 /* Value of MODIFF when current_column was called.  */
 
-static int last_known_column_modified;
+static EMACS_INT last_known_column_modified;
 
-static double current_column_1 P_ ((void));
-static double position_indentation P_ ((int));
+static ptrdiff_t current_column_1 (void);
+static ptrdiff_t position_indentation (ptrdiff_t);
 
 /* Cache of beginning of line found by the last call of
    current_column. */
 
-static EMACS_INT current_column_bol_cache;
+static ptrdiff_t current_column_bol_cache;
 
 /* Get the display table to use for the current buffer.  */
 
 struct Lisp_Char_Table *
-buffer_display_table ()
+buffer_display_table (void)
 {
   Lisp_Object thisbuf;
 
-  thisbuf = current_buffer->display_table;
+  thisbuf = BVAR (current_buffer, display_table);
   if (DISP_TABLE_P (thisbuf))
     return XCHAR_TABLE (thisbuf);
   if (DISP_TABLE_P (Vstandard_display_table))
@@ -89,9 +82,7 @@ buffer_display_table ()
 /* Return the width of character C under display table DP.  */
 
 static int
-character_width (c, dp)
-     int c;
-     struct Lisp_Char_Table *dp;
+character_width (int c, struct Lisp_Char_Table *dp)
 {
   Lisp_Object elt;
 
@@ -101,7 +92,7 @@ character_width (c, dp)
   /* Everything can be handled by the display table, if it's
      present and the element is right.  */
   if (dp && (elt = DISP_CHAR_VECTOR (dp, c), VECTORP (elt)))
-    return XVECTOR_SIZE (elt);
+    return ASIZE (elt);
 
   /* Some characters are special.  */
   if (c == '\n' || c == '\t' || c == '\015')
@@ -124,15 +115,13 @@ character_width (c, dp)
    for characters as WIDTHTAB.  We use this to decide when to
    invalidate the buffer's width_run_cache.  */
 
-int
-disptab_matches_widthtab (disptab, widthtab)
-     struct Lisp_Char_Table *disptab;
-     struct Lisp_Vector *widthtab;
+bool
+disptab_matches_widthtab (struct Lisp_Char_Table *disptab, struct Lisp_Vector *widthtab)
 {
   int i;
 
   if (widthtab->header.size != 256)
-    abort ();
+    emacs_abort ();
 
   for (i = 0; i < 256; i++)
     if (character_width (i, disptab)
@@ -145,18 +134,16 @@ disptab_matches_widthtab (disptab, widthtab)
 /* Recompute BUF's width table, using the display table DISPTAB.  */
 
 void
-recompute_width_table (buf, disptab)
-     struct buffer *buf;
-     struct Lisp_Char_Table *disptab;
+recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
 {
   int i;
   struct Lisp_Vector *widthtab;
 
-  if (!VECTORP (buf->width_table))
-    buf->width_table = Fmake_vector (make_number (256), make_number (0));
-  widthtab = XVECTOR (buf->width_table);
+  if (!VECTORP (BVAR (buf, width_table)))
+    bset_width_table (buf, Fmake_vector (make_number (256), make_number (0)));
+  widthtab = XVECTOR (BVAR (buf, width_table));
   if (widthtab->header.size != 256)
-    abort ();
+    emacs_abort ();
 
   for (i = 0; i < 256; i++)
     XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
@@ -166,19 +153,19 @@ recompute_width_table (buf, disptab)
    state of current_buffer's cache_long_line_scans variable.  */
 
 static void
-width_run_cache_on_off ()
+width_run_cache_on_off (void)
 {
-  if (NILP (current_buffer->cache_long_line_scans)
+  if (NILP (BVAR (current_buffer, cache_long_line_scans))
       /* And, for the moment, this feature doesn't work on multibyte
          characters.  */
-      || !NILP (current_buffer->enable_multibyte_characters))
+      || !NILP (BVAR (current_buffer, enable_multibyte_characters)))
     {
       /* It should be off.  */
       if (current_buffer->width_run_cache)
         {
           free_region_cache (current_buffer->width_run_cache);
           current_buffer->width_run_cache = 0;
-          current_buffer->width_table = Qnil;
+          bset_width_table (current_buffer, Qnil);
         }
     }
   else
@@ -216,16 +203,12 @@ width_run_cache_on_off ()
    characters immediately following, then *NEXT_BOUNDARY_P
    will equal the return value.  */
 
-EMACS_INT
-skip_invisible (pos, next_boundary_p, to, window)
-     EMACS_INT pos;
-     EMACS_INT *next_boundary_p;
-     EMACS_INT to;
-     Lisp_Object window;
+ptrdiff_t
+skip_invisible (ptrdiff_t pos, ptrdiff_t *next_boundary_p, ptrdiff_t to, Lisp_Object window)
 {
   Lisp_Object prop, position, overlay_limit, proplimit;
   Lisp_Object buffer, tmp;
-  EMACS_INT end;
+  ptrdiff_t end;
   int inv_p;
 
   XSETFASTINT (position, pos);
@@ -287,25 +270,22 @@ skip_invisible (pos, next_boundary_p, to, window)
 
    DP is a display table or NULL.
 
-   This macro is used in current_column_1, Fmove_to_column, and
+   This macro is used in scan_for_column and in
    compute_motion.  */
 
-#define MULTIBYTE_BYTES_WIDTH(p, dp)                                   \
+#define MULTIBYTE_BYTES_WIDTH(p, dp, bytes, width)                     \
   do {                                                                 \
-    int c                                                            \
+    int ch;                                                            \
                                                                        \
-    wide_column = 0;                                                   \
-    c = STRING_CHAR_AND_LENGTH (p, bytes);                             \
+    ch = STRING_CHAR_AND_LENGTH (p, bytes);                            \
     if (BYTES_BY_CHAR_HEAD (*p) != bytes)                              \
       width = bytes * 4;                                               \
     else                                                               \
       {                                                                        \
-       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))              \
-         width = XVECTOR_SIZE (DISP_CHAR_VECTOR (dp, c));              \
+       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, ch)))             \
+         width = sanitize_char_width (ASIZE (DISP_CHAR_VECTOR (dp, ch))); \
        else                                                            \
-         width = CHAR_WIDTH (c);                                       \
-       if (width > 1)                                                  \
-         wide_column = width;                                          \
+         width = CHAR_WIDTH (ch);                                      \
       }                                                                        \
   } while (0)
 
@@ -322,32 +302,32 @@ Whether the line is visible (if `selective-display' is t) has no effect;
 however, ^M is treated as end of line when `selective-display' is t.
 Text that has an invisible property is considered as having width 0, unless
 `buffer-invisibility-spec' specifies that it is replaced by an ellipsis.  */)
-     ()
+  (void)
 {
   Lisp_Object temp;
-  XSETFASTINT (temp, (int) current_column ()); /* iftc */
+  XSETFASTINT (temp, current_column ());
   return temp;
 }
 
 /* Cancel any recorded value of the horizontal position.  */
 
 void
-invalidate_current_column ()
+invalidate_current_column (void)
 {
   last_known_column_point = 0;
 }
 
-double
-current_column ()
+ptrdiff_t
+current_column (void)
 {
-  register int col;
-  register unsigned char *ptr, *stop;
-  register int tab_seen;
-  int post_tab;
-  register int c;
-  register int tab_width = XINT (current_buffer->tab_width);
-  int ctl_arrow = !NILP (current_buffer->ctl_arrow);
-  register struct Lisp_Char_Table *dp = buffer_display_table ();
+  ptrdiff_t col;
+  unsigned char *ptr, *stop;
+  bool tab_seen;
+  ptrdiff_t post_tab;
+  int c;
+  int tab_width = SANE_TAB_WIDTH (current_buffer);
+  bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
+  struct Lisp_Char_Table *dp = buffer_display_table ();
 
   if (PT == last_known_column_point
       && MODIFF == last_known_column_modified)
@@ -355,9 +335,8 @@ current_column ()
 
   /* If the buffer has overlays, text properties,
      or multibyte characters, use a more general algorithm.  */
-  if (BUF_INTERVALS (current_buffer)
-      || current_buffer->overlays_before
-      || current_buffer->overlays_after
+  if (buffer_intervals (current_buffer)
+      || buffer_has_overlays ()
       || Z != Z_BYTE)
     return current_column_1 ();
 
@@ -375,14 +354,11 @@ current_column ()
   else
     stop = GAP_END_ADDR;
 
-  if (tab_width <= 0 || tab_width > 1000)
-    tab_width = 8;
-
   col = 0, tab_seen = 0, post_tab = 0;
 
   while (1)
     {
-      EMACS_INT i, n;
+      ptrdiff_t i, n;
       Lisp_Object charvec;
 
       if (ptr == stop)
@@ -422,8 +398,7 @@ current_column ()
                 next_element_from_display_vector does it.  */
              Lisp_Object entry = AREF (charvec, i);
 
-             if (GLYPH_CODE_P (entry)
-                 && GLYPH_CODE_CHAR_VALID_P (entry))
+             if (GLYPH_CODE_P (entry))
                c = GLYPH_CODE_CHAR (entry);
              else
                c = ' ';
@@ -433,7 +408,7 @@ current_column ()
            col++;
          else if (c == '\n'
                   || (c == '\r'
-                      && EQ (current_buffer->selective_display, Qt)))
+                      && EQ (BVAR (current_buffer, selective_display), Qt)))
            {
              ptr++;
              goto start_of_line_found;
@@ -479,7 +454,6 @@ current_column ()
   return col;
 }
 \f
-extern Lisp_Object Qspace, QCwidth, QCalign_to;
 
 /* Check the presence of a display property and compute its width.
    If a property was found and its width was found as well, return
@@ -487,29 +461,37 @@ extern Lisp_Object Qspace, QCwidth, QCalign_to;
    in ENDPOS.
    Otherwise just return -1.  */
 static int
-check_display_width (EMACS_INT pos, EMACS_INT col, EMACS_INT *endpos)
+check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
 {
   Lisp_Object val, overlay;
 
   if (CONSP (val = get_char_property_and_overlay
             (make_number (pos), Qdisplay, Qnil, &overlay))
       && EQ (Qspace, XCAR (val)))
-    { /* FIXME: Use calc_pixel_width_or_height, as in term.c.  */
+    { /* FIXME: Use calc_pixel_width_or_height.  */
       Lisp_Object plist = XCDR (val), prop;
       int width = -1;
+      EMACS_INT align_to_max =
+       (col < MOST_POSITIVE_FIXNUM - INT_MAX
+        ? (EMACS_INT) INT_MAX + col
+        : MOST_POSITIVE_FIXNUM);
 
-      if ((prop = Fplist_get (plist, QCwidth), NATNUMP (prop)))
+      if ((prop = Fplist_get (plist, QCwidth),
+          RANGED_INTEGERP (0, prop, INT_MAX)))
        width = XINT (prop);
-      else if (FLOATP (prop))
+      else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop)
+              && XFLOAT_DATA (prop) <= INT_MAX)
        width = (int)(XFLOAT_DATA (prop) + 0.5);
-      else if ((prop = Fplist_get (plist, QCalign_to), NATNUMP (prop)))
+      else if ((prop = Fplist_get (plist, QCalign_to),
+               RANGED_INTEGERP (col, prop, align_to_max)))
        width = XINT (prop) - col;
-      else if (FLOATP (prop))
+      else if (FLOATP (prop) && col <= XFLOAT_DATA (prop)
+              && (XFLOAT_DATA (prop) <= align_to_max))
        width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
-           
+
       if (width >= 0)
        {
-         EMACS_INT start;
+         ptrdiff_t start;
          if (OVERLAYP (overlay))
            *endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
          else
@@ -527,24 +509,24 @@ check_display_width (EMACS_INT pos, EMACS_INT col, EMACS_INT *endpos)
    PREVCOL gets set to the column of the previous position (it's always
    strictly smaller than the goal column).  */
 static void
-scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
+scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
 {
-  register EMACS_INT tab_width = XINT (current_buffer->tab_width);
-  register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
-  register struct Lisp_Char_Table *dp = buffer_display_table ();
-  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  int tab_width = SANE_TAB_WIDTH (current_buffer);
+  bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
+  struct Lisp_Char_Table *dp = buffer_display_table ();
+  bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
   struct composition_it cmp_it;
   Lisp_Object window;
   struct window *w;
 
   /* Start the scan at the beginning of this line with column number 0.  */
-  register EMACS_INT col = 0, prev_col = 0;
+  register ptrdiff_t col = 0, prev_col = 0;
   EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
-  EMACS_INT end = endpos ? *endpos : PT;
-  EMACS_INT scan, scan_byte;
-  EMACS_INT next_boundary;
+  ptrdiff_t end = endpos ? *endpos : PT;
+  ptrdiff_t scan, scan_byte;
+  ptrdiff_t next_boundary;
   {
-  EMACS_INT opoint = PT, opoint_byte = PT_BYTE;
+  ptrdiff_t opoint = PT, opoint_byte = PT_BYTE;
   scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
   current_column_bol_cache = PT;
   scan = PT, scan_byte = PT_BYTE;
@@ -555,8 +537,7 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
   window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
   w = ! NILP (window) ? XWINDOW (window) : NULL;
 
-  if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
-  bzero (&cmp_it, sizeof cmp_it);
+  memset (&cmp_it, 0, sizeof cmp_it);
   cmp_it.id = -1;
   composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
 
@@ -568,7 +549,7 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
       /* Occasionally we may need to skip invisible text.  */
       while (scan == next_boundary)
        {
-         EMACS_INT old_scan = scan;
+         ptrdiff_t old_scan = scan;
          /* This updates NEXT_BOUNDARY to the next place
             where we might need to skip more invisible text.  */
          scan = skip_invisible (scan, &next_boundary, end, Qnil);
@@ -586,14 +567,14 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
       prev_col = col;
 
       { /* Check display property.  */
-       EMACS_INT end;
-       int width = check_display_width (scan, col, &end);
+       ptrdiff_t endp;
+       int width = check_display_width (scan, col, &endp);
        if (width >= 0)
          {
            col += width;
-           if (end > scan) /* Avoid infinite loops with 0-width overlays.  */
+           if (endp > scan) /* Avoid infinite loops with 0-width overlays.  */
              {
-               scan = end; scan_byte = charpos_to_bytepos (scan);
+               scan = endp; scan_byte = charpos_to_bytepos (scan);
                continue;
              }
          }
@@ -628,11 +609,11 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
         to this character.  */
 
       if (dp != 0
-         && ! (multibyte && BASE_LEADING_CODE_P (c))
+         && ! (multibyte && LEADING_CODE_P (c))
          && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
          Lisp_Object charvec;
-         EMACS_INT i, n;
+         ptrdiff_t i, n;
 
          /* This character is displayed using a vector of glyphs.
             Update the column/position based on those glyphs.  */
@@ -646,15 +627,14 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
                 next_element_from_display_vector does it.  */
              Lisp_Object entry = AREF (charvec, i);
 
-             if (GLYPH_CODE_P (entry)
-                 && GLYPH_CODE_CHAR_VALID_P (entry))
+             if (GLYPH_CODE_P (entry))
                c = GLYPH_CODE_CHAR (entry);
              else
                c = ' ';
 
              if (c == '\n')
                goto endloop;
-             if (c == '\r' && EQ (current_buffer->selective_display, Qt))
+             if (c == '\r' && EQ (BVAR (current_buffer, selective_display), Qt))
                goto endloop;
              if (c == '\t')
                {
@@ -672,21 +652,21 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
 
          if (c == '\n')
            goto endloop;
-         if (c == '\r' && EQ (current_buffer->selective_display, Qt))
+         if (c == '\r' && EQ (BVAR (current_buffer, selective_display), Qt))
            goto endloop;
          if (c == '\t')
            {
              col += tab_width;
              col = col / tab_width * tab_width;
            }
-         else if (multibyte && BASE_LEADING_CODE_P (c))
+         else if (multibyte && LEADING_CODE_P (c))
            {
              /* Start of multi-byte form.  */
              unsigned char *ptr;
-             int bytes, width, wide_column;
+             int bytes, width;
 
              ptr = BYTE_POS_ADDR (scan_byte);
-             MULTIBYTE_BYTES_WIDTH (ptr, dp);
+             MULTIBYTE_BYTES_WIDTH (ptr, dp, bytes, width);
              /* Subtract one to compensate for the increment
                 that is going to happen below.  */
              scan_byte += bytes - 1;
@@ -722,11 +702,11 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
    This function handles characters that are invisible
    due to text properties or overlays.  */
 
-static double
-current_column_1 ()
+static ptrdiff_t
+current_column_1 (void)
 {
   EMACS_INT col = MOST_POSITIVE_FIXNUM;
-  EMACS_INT opoint = PT;
+  ptrdiff_t opoint = PT;
 
   scan_for_column (&opoint, &col, NULL);
   return col;
@@ -740,17 +720,16 @@ current_column_1 ()
    If END is nil, that stands for the end of STRING.  */
 
 static double
-string_display_width (string, beg, end)
-     Lisp_Object string, beg, end;
+string_display_width (Lisp_Object string, Lisp_Object beg, Lisp_Object end)
 {
-  register int col;
-  register unsigned char *ptr, *stop;
-  register int tab_seen;
+  int col;
+  unsigned char *ptr, *stop;
+  bool tab_seen;
   int post_tab;
-  register int c;
-  register int tab_width = XINT (current_buffer->tab_width);
-  int ctl_arrow = !NILP (current_buffer->ctl_arrow);
-  register struct Lisp_Char_Table *dp = buffer_display_table ();
+  int c;
+  int tab_width = SANE_TAB_WIDTH (current_buffer);
+  bool ctl_arrow = !NILP (current_buffer->ctl_arrow);
+  struct Lisp_Char_Table *dp = buffer_display_table ();
   int b, e;
 
   if (NILP (end))
@@ -775,8 +754,6 @@ string_display_width (string, beg, end)
      going backwards from point.  */
   stop = SDATA (string) + b;
 
-  if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
-
   col = 0, tab_seen = 0, post_tab = 0;
 
   while (1)
@@ -786,7 +763,7 @@ string_display_width (string, beg, end)
 
       c = *--ptr;
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
-       col += XVECTOR_SIZE (DISP_CHAR_VECTOR (dp, c));
+       col += ASIZE (DISP_CHAR_VECTOR (dp, c));
       else if (c >= 040 && c < 0177)
        col++;
       else if (c == '\n')
@@ -822,12 +799,11 @@ Optional second argument MINIMUM says always do at least MINIMUM spaces
 even if that goes past COLUMN; by default, MINIMUM is zero.
 
 The return value is COLUMN.  */)
-     (column, minimum)
-     Lisp_Object column, minimum;
+  (Lisp_Object column, Lisp_Object minimum)
 {
-  int mincol;
-  register int fromcol;
-  register int tab_width = XINT (current_buffer->tab_width);
+  EMACS_INT mincol;
+  register ptrdiff_t fromcol;
+  int tab_width = SANE_TAB_WIDTH (current_buffer);
 
   CHECK_NUMBER (column);
   if (NILP (minimum))
@@ -841,8 +817,6 @@ The return value is COLUMN.  */)
   if (fromcol == mincol)
     return make_number (mincol);
 
-  if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
-
   if (indent_tabs_mode)
     {
       Lisp_Object n;
@@ -867,38 +841,33 @@ The return value is COLUMN.  */)
 }
 
 \f
-static double position_indentation P_ ((int));
-
 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
        0, 0, 0,
        doc: /* Return the indentation of the current line.
 This is the horizontal position of the character
 following any initial whitespace.  */)
-     ()
+  (void)
 {
   Lisp_Object val;
-  int opoint = PT, opoint_byte = PT_BYTE;
+  ptrdiff_t opoint = PT, opoint_byte = PT_BYTE;
 
   scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
 
-  XSETFASTINT (val, (int) position_indentation (PT_BYTE)); /* iftc */
+  XSETFASTINT (val, position_indentation (PT_BYTE));
   SET_PT_BOTH (opoint, opoint_byte);
   return val;
 }
 
-static double
-position_indentation (pos_byte)
-     register int pos_byte;
+static ptrdiff_t
+position_indentation (ptrdiff_t pos_byte)
 {
-  register EMACS_INT column = 0;
-  register EMACS_INT tab_width = XINT (current_buffer->tab_width);
+  register ptrdiff_t column = 0;
+  int tab_width = SANE_TAB_WIDTH (current_buffer);
   register unsigned char *p;
   register unsigned char *stop;
   unsigned char *start;
-  EMACS_INT next_boundary_byte = pos_byte;
-  EMACS_INT ceiling = next_boundary_byte;
-
-  if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
+  ptrdiff_t next_boundary_byte = pos_byte;
+  ptrdiff_t ceiling = next_boundary_byte;
 
   p = BYTE_POS_ADDR (pos_byte);
   /* STOP records the value of P at which we will need
@@ -911,7 +880,7 @@ position_indentation (pos_byte)
     {
       while (p == stop)
        {
-         EMACS_INT stop_pos_byte;
+         ptrdiff_t stop_pos_byte;
 
          /* If we have updated P, set POS_BYTE to match.
             The first time we enter the loop, POS_BYTE is already right.  */
@@ -922,8 +891,8 @@ position_indentation (pos_byte)
            return column;
          if (pos_byte == next_boundary_byte)
            {
-             EMACS_INT next_boundary;
-             EMACS_INT pos = BYTE_TO_CHAR (pos_byte);
+             ptrdiff_t next_boundary;
+             ptrdiff_t pos = BYTE_TO_CHAR (pos_byte);
              pos = skip_invisible (pos, &next_boundary, ZV, Qnil);
              pos_byte = CHAR_TO_BYTE (pos);
              next_boundary_byte = CHAR_TO_BYTE (next_boundary);
@@ -943,7 +912,7 @@ position_indentation (pos_byte)
       switch (*p++)
        {
        case 0240:
-         if (! NILP (current_buffer->enable_multibyte_characters))
+         if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
            return column;
        case ' ':
          column++;
@@ -953,7 +922,7 @@ position_indentation (pos_byte)
          break;
        default:
          if (ASCII_BYTE_P (p[-1])
-             || NILP (current_buffer->enable_multibyte_characters))
+             || NILP (BVAR (current_buffer, enable_multibyte_characters)))
            return column;
          {
            int c;
@@ -976,13 +945,11 @@ position_indentation (pos_byte)
    Blank lines are treated as if they had the same indentation as the
    preceding line.  */
 
-int
-indented_beyond_p (pos, pos_byte, column)
-     int pos, pos_byte;
-     double column;
+bool
+indented_beyond_p (ptrdiff_t pos, ptrdiff_t pos_byte, EMACS_INT column)
 {
-  double val;
-  int opoint = PT, opoint_byte = PT_BYTE;
+  ptrdiff_t val;
+  ptrdiff_t opoint = PT, opoint_byte = PT_BYTE;
 
   SET_PT_BOTH (pos, pos_byte);
   while (PT > BEGV && FETCH_BYTE (PT_BYTE) == '\n')
@@ -990,10 +957,11 @@ indented_beyond_p (pos, pos_byte, column)
 
   val = position_indentation (PT_BYTE);
   SET_PT_BOTH (opoint, opoint_byte);
-  return val >= column;                 /* hmm, float comparison */
+  return val >= column;
 }
 \f
-DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
+DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2,
+       "NMove to column: ",
        doc: /* Move point to column COLUMN in the current line.
 Interactively, COLUMN is the value of prefix numeric argument.
 The column of a character is calculated by adding together the widths
@@ -1011,11 +979,10 @@ In addition, if FORCE is t, and the line is too short to reach
 COLUMN, add spaces/tabs to get there.
 
 The return value is the current column.  */)
-     (column, force)
-     Lisp_Object column, force;
+  (Lisp_Object column, Lisp_Object force)
 {
-  EMACS_INT pos;
-  EMACS_INT col, prev_col;
+  ptrdiff_t pos, prev_col;
+  EMACS_INT col;
   EMACS_INT goal;
 
   CHECK_NATNUM (column);
@@ -1032,13 +999,13 @@ The return value is the current column.  */)
   if (!NILP (force) && col > goal)
     {
       int c;
-      EMACS_INT pos_byte = PT_BYTE;
+      ptrdiff_t pos_byte = PT_BYTE;
 
       DEC_POS (pos_byte);
       c = FETCH_CHAR (pos_byte);
       if (c == '\t' && prev_col < goal)
        {
-         EMACS_INT goal_pt, goal_pt_byte;
+         ptrdiff_t goal_pt, goal_pt_byte;
 
          /* Insert spaces in front of the tab to reach GOAL.  Do this
             first so that a marker at the end of the tab gets
@@ -1071,7 +1038,7 @@ The return value is the current column.  */)
 \f
 /* compute_motion: compute buffer posn given screen posn and vice versa */
 
-struct position val_compute_motion;
+static struct position val_compute_motion;
 
 /* Scan the current buffer forward from offset FROM, pretending that
    this is at line FROMVPOS, column FROMHPOS, until reaching buffer
@@ -1080,11 +1047,11 @@ struct position val_compute_motion;
    can't hit the requested column exactly (because of a tab or other
    multi-column character), overshoot.
 
-   DID_MOTION is 1 if FROMHPOS has already accounted for overlay strings
+   DID_MOTION is true if FROMHPOS has already accounted for overlay strings
    at FROM.  This is the case if FROMVPOS and FROMVPOS came from an
    earlier call to compute_motion.  The other common case is that FROMHPOS
    is zero and FROM is a position that "belongs" at column zero, but might
-   be shifted by overlay strings; in this case DID_MOTION should be 0.
+   be shifted by overlay strings; in this case DID_MOTION should be false.
 
    WIDTH is the number of columns available to display text;
    compute_motion uses this to handle continuation lines and such.
@@ -1129,89 +1096,82 @@ struct position val_compute_motion;
            WINDOW_HAS_VERTICAL_SCROLL_BAR (window)
          and frame_cols = FRAME_COLS (XFRAME (window->frame))
 
-   Or you can let window_box_text_cols do this all for you, and write:
-       window_box_text_cols (w) - 1
+   Or you can let window_body_cols do this all for you, and write:
+       window_body_cols (w) - 1
 
    The `-1' accounts for the continuation-line backslashes; the rest
    accounts for window borders if the window is split horizontally, and
    the scroll bars if they are turned on.  */
 
 struct position *
-compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hscroll, tab_offset, win)
-     EMACS_INT from, fromvpos, fromhpos, to, tovpos, tohpos;
-     int did_motion;
-     EMACS_INT width;
-     EMACS_INT hscroll, tab_offset;
-     struct window *win;
+compute_motion (ptrdiff_t from, EMACS_INT fromvpos, EMACS_INT fromhpos,
+               bool did_motion, ptrdiff_t to,
+               EMACS_INT tovpos, EMACS_INT tohpos, EMACS_INT width,
+               ptrdiff_t hscroll, int tab_offset, struct window *win)
 {
-  register EMACS_INT hpos = fromhpos;
-  register EMACS_INT vpos = fromvpos;
-
-  register EMACS_INT pos;
-  EMACS_INT pos_byte;
-  register int c = 0;
-  register EMACS_INT tab_width = XFASTINT (current_buffer->tab_width);
-  register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
-  register struct Lisp_Char_Table *dp = window_display_table (win);
-  int selective
-    = (INTEGERP (current_buffer->selective_display)
-       ? XINT (current_buffer->selective_display)
-       : !NILP (current_buffer->selective_display) ? -1 : 0);
-  int selective_rlen
+  EMACS_INT hpos = fromhpos;
+  EMACS_INT vpos = fromvpos;
+
+  ptrdiff_t pos;
+  ptrdiff_t pos_byte;
+  int c = 0;
+  int tab_width = SANE_TAB_WIDTH (current_buffer);
+  bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
+  struct Lisp_Char_Table *dp = window_display_table (win);
+  EMACS_INT selective
+    = (INTEGERP (BVAR (current_buffer, selective_display))
+       ? XINT (BVAR (current_buffer, selective_display))
+       : !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
+  ptrdiff_t selective_rlen
     = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
-       ? XVECTOR_SIZE (DISP_INVIS_VECTOR (dp)) : 0);
+       ? ASIZE (DISP_INVIS_VECTOR (dp)) : 0);
   /* The next location where the `invisible' property changes, or an
      overlay starts or ends.  */
-  EMACS_INT next_boundary = from;
+  ptrdiff_t next_boundary = from;
 
   /* For computing runs of characters with similar widths.
      Invariant: width_run_width is zero, or all the characters
      from width_run_start to width_run_end have a fixed width of
      width_run_width.  */
-  EMACS_INT width_run_start = from;
-  EMACS_INT width_run_end   = from;
-  EMACS_INT width_run_width = 0;
+  ptrdiff_t width_run_start = from;
+  ptrdiff_t width_run_end   = from;
+  ptrdiff_t width_run_width = 0;
   Lisp_Object *width_table;
-  Lisp_Object buffer;
 
   /* The next buffer pos where we should consult the width run cache. */
-  EMACS_INT next_width_run = from;
+  ptrdiff_t next_width_run = from;
   Lisp_Object window;
 
-  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
   /* If previous char scanned was a wide character,
      this is the column where it ended.  Otherwise, this is 0.  */
   EMACS_INT wide_column_end_hpos = 0;
-  EMACS_INT prev_pos;          /* Previous buffer position.  */
-  EMACS_INT prev_pos_byte;     /* Previous buffer position.  */
+  ptrdiff_t prev_pos;          /* Previous buffer position.  */
+  ptrdiff_t prev_pos_byte;     /* Previous buffer position.  */
   EMACS_INT prev_hpos = 0;
   EMACS_INT prev_vpos = 0;
   EMACS_INT contin_hpos;       /* HPOS of last column of continued line.  */
-  EMACS_INT prev_tab_offset;   /* Previous tab offset.  */
-  EMACS_INT continuation_glyph_width;
+  int prev_tab_offset;         /* Previous tab offset.  */
+  int continuation_glyph_width;
 
   struct composition_it cmp_it;
 
-  XSETBUFFER (buffer, current_buffer);
   XSETWINDOW (window, win);
 
   width_run_cache_on_off ();
   if (dp == buffer_display_table ())
-    width_table = (VECTORP (current_buffer->width_table)
-                   ? XVECTOR (current_buffer->width_table)->contents
+    width_table = (VECTORP (BVAR (current_buffer, width_table))
+                   ? XVECTOR (BVAR (current_buffer, width_table))->contents
                    : 0);
   else
     /* If the window has its own display table, we can't use the width
        run cache, because that's based on the buffer's display table.  */
     width_table = 0;
 
-  if (tab_width <= 0 || tab_width > 1000)
-    tab_width = 8;
-
   /* Negative width means use all available text columns.  */
   if (width < 0)
     {
-      width = window_box_text_cols (win);
+      width = window_body_cols (win);
       /* We must make room for continuation marks if we don't have fringes.  */
 #ifdef HAVE_WINDOW_SYSTEM
       if (!FRAME_WINDOW_P (XFRAME (win->frame)))
@@ -1232,7 +1192,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
   pos_byte = prev_pos_byte = CHAR_TO_BYTE (from);
   contin_hpos = 0;
   prev_tab_offset = tab_offset;
-  bzero (&cmp_it, sizeof cmp_it);
+  memset (&cmp_it, 0, sizeof cmp_it);
   cmp_it.id = -1;
   composition_compute_stop_pos (&cmp_it, pos, pos_byte, to, Qnil);
 
@@ -1240,8 +1200,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
     {
       while (pos == next_boundary)
        {
-         EMACS_INT pos_here = pos;
-         EMACS_INT newpos;
+         ptrdiff_t pos_here = pos;
+         ptrdiff_t newpos;
 
          /* Don't skip invisible if we are already at the margin.  */
          if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
@@ -1275,9 +1235,9 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
               to be changed here.  */
            {
              unsigned char *ovstr;
-             int ovlen = overlay_strings (pos, win, &ovstr);
+             ptrdiff_t ovlen = overlay_strings (pos, win, &ovstr);
              hpos += ((multibyte && ovlen > 0)
-                      ? strwidth (ovstr, ovlen) : ovlen);
+                      ? strwidth ((char *) ovstr, ovlen) : ovlen);
            }
          did_motion = 0;
 
@@ -1350,8 +1310,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
 
       if (hpos > width)
        {
-         int total_width = width + continuation_glyph_width;
-         int truncate = 0;
+         EMACS_INT total_width = width + continuation_glyph_width;
+         bool truncate = 0;
 
          if (!NILP (Vtruncate_partial_width_windows)
              && (total_width < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
@@ -1364,7 +1324,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
            }
 
          if (hscroll || truncate
-             || !NILP (current_buffer->truncate_lines))
+             || !NILP (BVAR (current_buffer, truncate_lines)))
            {
              /* Truncating: skip to newline, unless we are already past
                  TO (we need to go back below).  */
@@ -1469,7 +1429,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
          the text character-by-character.  */
       if (current_buffer->width_run_cache && pos >= next_width_run)
         {
-          int run_end;
+          ptrdiff_t run_end;
           int common_width
             = region_cache_forward (current_buffer,
                                     current_buffer->width_run_cache,
@@ -1480,7 +1440,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
              want to skip over it for some other reason.  */
           if (common_width != 0)
             {
-              int run_end_hpos;
+              ptrdiff_t run_end_hpos;
 
               /* Don't go past the final buffer posn the user
                  requested.  */
@@ -1520,7 +1480,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
       /* We have to scan the text character-by-character.  */
       else
        {
-         EMACS_INT i, n;
+         ptrdiff_t i, n;
          Lisp_Object charvec;
 
          /* Check composition sequence.  */
@@ -1577,7 +1537,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
            }
 
          if (dp != 0
-             && ! (multibyte && BASE_LEADING_CODE_P (c))
+             && ! (multibyte && LEADING_CODE_P (c))
              && VECTORP (DISP_CHAR_VECTOR (dp, c)))
            {
              charvec = DISP_CHAR_VECTOR (dp, c);
@@ -1589,7 +1549,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
              n = 1;
            }
 
-         for (i = n - 1; i >= 0; --i)
+         for (i = 0; i < n; ++i)
            {
              if (VECTORP (charvec))
                {
@@ -1597,8 +1557,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
                     next_element_from_display_vector does it.  */
                  Lisp_Object entry = AREF (charvec, i);
 
-                 if (GLYPH_CODE_P (entry)
-                     && GLYPH_CODE_CHAR_VALID_P (entry))
+                 if (GLYPH_CODE_P (entry))
                    c = GLYPH_CODE_CHAR (entry);
                  else
                    c = ' ';
@@ -1617,8 +1576,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
              else if (c == '\n')
                {
                  if (selective > 0
-                     && indented_beyond_p (pos, pos_byte,
-                                            (double) selective)) /* iftc */
+                     && indented_beyond_p (pos, pos_byte, selective))
                    {
                      /* If (pos == to), we don't have to take care of
                         selective display.  */
@@ -1634,7 +1592,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
                            }
                          while (pos < to
                                 && indented_beyond_p (pos, pos_byte,
-                                                       (double) selective)); /* iftc */
+                                                       selective));
                          /* Allow for the " ..." that is displayed for them. */
                          if (selective_rlen)
                            {
@@ -1683,19 +1641,19 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
                        hpos = width;
                    }
                }
-             else if (multibyte && BASE_LEADING_CODE_P (c))
+             else if (multibyte && LEADING_CODE_P (c))
                {
                  /* Start of multi-byte form.  */
                  unsigned char *ptr;
-                 int bytes, width, wide_column;
+                 int mb_bytes, mb_width;
 
                  pos_byte--;   /* rewind POS_BYTE */
                  ptr = BYTE_POS_ADDR (pos_byte);
-                 MULTIBYTE_BYTES_WIDTH (ptr, dp);
-                 pos_byte += bytes;
-                 if (wide_column)
-                   wide_column_end_hpos = hpos + wide_column;
-                 hpos += width;
+                 MULTIBYTE_BYTES_WIDTH (ptr, dp, mb_bytes, mb_width);
+                 pos_byte += mb_bytes;
+                 if (mb_width > 1 && BYTES_BY_CHAR_HEAD (*ptr) == mb_bytes)
+                   wide_column_end_hpos = hpos + mb_width;
+                 hpos += mb_width;
                }
              else if (VECTORP (charvec))
                ++hpos;
@@ -1722,8 +1680,6 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
     val_compute_motion.prevhpos = contin_hpos;
   else
     val_compute_motion.prevhpos = prev_hpos;
-  /* We alalways handle all of them here; none of them remain to do.  */
-  val_compute_motion.ovstring_chars_done = 0;
 
   /* Nonzero if have just continued a line */
   val_compute_motion.contin = (contin_hpos && prev_hpos == 0);
@@ -1775,14 +1731,13 @@ of a certain window, pass the window's starting location as FROM
 and the window's upper-left coordinates as FROMPOS.
 Pass the buffer's (point-max) as TO, to limit the scan to the end of the
 visible section of the buffer, and pass LINE and COL as TOPOS.  */)
-     (from, frompos, to, topos, width, offsets, window)
-     Lisp_Object from, frompos, to, topos;
-     Lisp_Object width, offsets, window;
+  (Lisp_Object from, Lisp_Object frompos, Lisp_Object to, Lisp_Object topos, Lisp_Object width, Lisp_Object offsets, Lisp_Object window)
 {
   struct window *w;
   Lisp_Object bufpos, hpos, vpos, prevhpos;
   struct position *pos;
-  int hscroll, tab_offset;
+  ptrdiff_t hscroll;
+  int tab_offset;
 
   CHECK_NUMBER_COERCE_MARKER (from);
   CHECK_CONS (frompos);
@@ -1803,6 +1758,9 @@ visible section of the buffer, and pass LINE and COL as TOPOS.  */)
       CHECK_CONS (offsets);
       CHECK_NUMBER_CAR (offsets);
       CHECK_NUMBER_CDR (offsets);
+      if (! (0 <= XINT (XCAR (offsets)) && XINT (XCAR (offsets)) <= PTRDIFF_MAX
+            && 0 <= XINT (XCDR (offsets)) && XINT (XCDR (offsets)) <= INT_MAX))
+       args_out_of_range (XCAR (offsets), XCDR (offsets));
       hscroll = XINT (XCAR (offsets));
       tab_offset = XINT (XCDR (offsets));
     }
@@ -1827,7 +1785,7 @@ visible section of the buffer, and pass LINE and COL as TOPOS.  */)
                         ? window_internal_height (w)
                         : XINT (XCDR (topos))),
                        (NILP (topos)
-                        ? (window_box_text_cols (w)
+                        ? (window_body_cols (w)
                            - (
 #ifdef HAVE_WINDOW_SYSTEM
                               FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
@@ -1853,28 +1811,26 @@ visible section of the buffer, and pass LINE and COL as TOPOS.  */)
 \f
 /* Fvertical_motion and vmotion */
 
-struct position val_vmotion;
+static struct position val_vmotion;
 
 struct position *
-vmotion (from, vtarget, w)
-     register EMACS_INT from, vtarget;
-     struct window *w;
+vmotion (register ptrdiff_t from, register EMACS_INT vtarget, struct window *w)
 {
-  EMACS_INT hscroll = XINT (w->hscroll);
+  ptrdiff_t hscroll = w->hscroll;
   struct position pos;
   /* vpos is cumulative vertical position, changed as from is changed */
-  register int vpos = 0;
-  EMACS_INT prevline;
-  register EMACS_INT first;
-  EMACS_INT from_byte;
-  EMACS_INT lmargin = hscroll > 0 ? 1 - hscroll : 0;
-  int selective
-    = (INTEGERP (current_buffer->selective_display)
-       ? XINT (current_buffer->selective_display)
-       : !NILP (current_buffer->selective_display) ? -1 : 0);
+  register EMACS_INT vpos = 0;
+  ptrdiff_t prevline;
+  register ptrdiff_t first;
+  ptrdiff_t from_byte;
+  ptrdiff_t lmargin = hscroll > 0 ? 1 - hscroll : 0;
+  ptrdiff_t selective
+    = (INTEGERP (BVAR (current_buffer, selective_display))
+       ? clip_to_bounds (-1, XINT (BVAR (current_buffer, selective_display)),
+                        PTRDIFF_MAX)
+       : !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
   Lisp_Object window;
-  EMACS_INT start_hpos = 0;
-  int did_motion;
+  bool did_motion;
   /* This is the object we use for fetching character properties.  */
   Lisp_Object text_prop_object;
 
@@ -1903,7 +1859,7 @@ vmotion (from, vtarget, w)
                 && ((selective > 0
                      && indented_beyond_p (prevline,
                                            CHAR_TO_BYTE (prevline),
-                                           (double) selective)) /* iftc */
+                                           selective))
                     /* Watch out for newlines with `invisible' property.
                        When moving upward, check the newline before.  */
                     || (propval = Fget_char_property (make_number (prevline - 1),
@@ -1912,7 +1868,7 @@ vmotion (from, vtarget, w)
                         TEXT_PROP_MEANS_INVISIBLE (propval))))
            prevline = find_next_newline_no_quit (prevline - 1, -1);
          pos = *compute_motion (prevline, 0,
-                                lmargin + (prevline == BEG ? start_hpos : 0),
+                                lmargin,
                                 0,
                                 from,
                                 /* Don't care for VPOS...  */
@@ -1920,10 +1876,7 @@ vmotion (from, vtarget, w)
                                 /* ... nor HPOS.  */
                                 1 << (BITS_PER_SHORT - 1),
                                 -1, hscroll,
-                                /* This compensates for start_hpos
-                                   so that a tab as first character
-                                   still occupies 8 columns.  */
-                                (prevline == BEG ? -start_hpos : 0),
+                                0,
                                 w);
          vpos -= pos.vpos;
          first = 0;
@@ -1941,8 +1894,6 @@ vmotion (from, vtarget, w)
          val_vmotion.hpos = lmargin;
          val_vmotion.contin = 0;
          val_vmotion.prevhpos = 0;
-         val_vmotion.ovstring_chars_done = 0;
-         val_vmotion.tab_offset = 0; /* For accumulating tab offset.  */
          return &val_vmotion;
        }
 
@@ -1960,7 +1911,7 @@ vmotion (from, vtarget, w)
             && ((selective > 0
                  && indented_beyond_p (prevline,
                                        CHAR_TO_BYTE (prevline),
-                                       (double) selective)) /* iftc */
+                                       selective))
                 /* Watch out for newlines with `invisible' property.
                    When moving downward, check the newline after.  */
                 || (propval = Fget_char_property (make_number (prevline),
@@ -1969,8 +1920,7 @@ vmotion (from, vtarget, w)
                     TEXT_PROP_MEANS_INVISIBLE (propval))))
        prevline = find_next_newline_no_quit (prevline - 1, -1);
       pos = *compute_motion (prevline, 0,
-                            lmargin + (prevline == BEG
-                                       ? start_hpos : 0),
+                            lmargin,
                             0,
                             from,
                             /* Don't care for VPOS...  */
@@ -1978,21 +1928,20 @@ vmotion (from, vtarget, w)
                             /* ... nor HPOS.  */
                             1 << (BITS_PER_SHORT - 1),
                             -1, hscroll,
-                            (prevline == BEG ? -start_hpos : 0),
+                            0,
                             w);
       did_motion = 1;
     }
   else
     {
-      pos.hpos = lmargin + (from == BEG ? start_hpos : 0);
+      pos.hpos = lmargin;
       pos.vpos = 0;
-      pos.tab_offset = 0;
       did_motion = 0;
     }
   return compute_motion (from, vpos, pos.hpos, did_motion,
                         ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)),
                         -1, hscroll,
-                        pos.tab_offset - (from == BEG ? start_hpos : 0),
+                        0,
                         w);
 }
 
@@ -2021,16 +1970,17 @@ regardless of which buffer is displayed in WINDOW.
 This is consistent with other cursor motion functions
 and makes it possible to use `vertical-motion' in any buffer,
 whether or not it is currently displayed in some window.  */)
-     (lines, window)
-     Lisp_Object lines, window;
+  (Lisp_Object lines, Lisp_Object window)
 {
   struct it it;
   struct text_pos pt;
   struct window *w;
   Lisp_Object old_buffer;
-  struct gcpro gcpro1;
+  EMACS_INT old_charpos IF_LINT (= 0), old_bytepos IF_LINT (= 0);
+  struct gcpro gcpro1, gcpro2, gcpro3;
   Lisp_Object lcols = Qnil;
-  double cols;
+  double cols IF_LINT (= 0);
+  void *itdata = NULL;
 
   /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES).  */
   if (CONSP (lines) && (NUMBERP (XCAR (lines))))
@@ -2048,12 +1998,16 @@ whether or not it is currently displayed in some window.  */)
   w = XWINDOW (window);
 
   old_buffer = Qnil;
-  GCPRO1 (old_buffer);
+  GCPRO3 (old_buffer, old_charpos, old_bytepos);
   if (XBUFFER (w->buffer) != current_buffer)
     {
       /* Set the window's buffer temporarily to the current buffer.  */
       old_buffer = w->buffer;
-      XSETBUFFER (w->buffer, current_buffer);
+      old_charpos = XMARKER (w->pointm)->charpos;
+      old_bytepos = XMARKER (w->pointm)->bytepos;
+      wset_buffer (w, Fcurrent_buffer ());
+      set_marker_both (w->pointm, w->buffer,
+                      BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer));
     }
 
   if (noninteractive)
@@ -2064,30 +2018,37 @@ whether or not it is currently displayed in some window.  */)
     }
   else
     {
-      int it_start, first_x, it_overshoot_expected;
+      ptrdiff_t it_start, it_overshoot_count = 0;
+      int first_x;
+      bool overshoot_handled = 0;
+      bool disp_string_at_start_p = 0;
 
+      itdata = bidi_shelve_cache ();
       SET_TEXT_POS (pt, PT, PT_BYTE);
       start_display (&it, w, pt);
       first_x = it.first_visible_x;
       it_start = IT_CHARPOS (it);
 
       /* See comments below for why we calculate this.  */
-      if (XINT (lines) > 0)
+      if (it.cmp_it.id >= 0)
+       it_overshoot_count = 0;
+      else if (it.method == GET_FROM_STRING)
        {
-         if (it.cmp_it.id >= 0)
-           it_overshoot_expected = 1;
-         else if (it.method == GET_FROM_STRING)
+         const char *s = SSDATA (it.string);
+         const char *e = s + SBYTES (it.string);
+
+         disp_string_at_start_p = it.string_from_display_prop_p;
+         while (s < e)
            {
-             const char *s = SDATA (it.string);
-             const char *e = s + SBYTES (it.string);
-             while (s < e && *s != '\n')
-               ++s;
-             it_overshoot_expected = (s == e) ? -1 : 0;
+             if (*s++ == '\n')
+               it_overshoot_count++;
            }
-         else
-           it_overshoot_expected = (it.method == GET_FROM_IMAGE
-                                    || it.method == GET_FROM_STRETCH);
+         if (!it_overshoot_count)
+           it_overshoot_count = -1;
        }
+      else
+       it_overshoot_count =
+         !(it.method == GET_FROM_IMAGE || it.method == GET_FROM_STRETCH);
 
       /* Scan from the start of the line containing PT.  If we don't
         do this, we start moving with IT->current_x == 0, while PT is
@@ -2101,55 +2062,67 @@ whether or not it is currently displayed in some window.  */)
           tell, and it causes Bug#2694 .  -- cyd */
        move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
 
+      /* IT may move too far if truncate-lines is on and PT lies
+        beyond the right margin.  IT may also move too far if the
+        starting point is on a Lisp string that has embedded
+        newlines, or spans several screen lines.  In these cases,
+        backtrack.  */
+      if (IT_CHARPOS (it) > it_start)
+       {
+         /* We need to backtrack also if the Lisp string contains no
+            newlines, but there is a newline right after it.  In this
+            case, IT overshoots if there is an after-string just
+            before the newline.  */
+         if (it_overshoot_count < 0
+             && it.method == GET_FROM_BUFFER
+             && it.c == '\n')
+           it_overshoot_count = 1;
+         else if (disp_string_at_start_p && it.vpos > 0)
+           {
+             /* This is the case of a display string that spans
+                several screen lines.  In that case, we end up at the
+                end of the string, and it.vpos tells us how many
+                screen lines we need to backtrack.  */
+             it_overshoot_count = it.vpos;
+           }
+         if (it_overshoot_count > 0)
+           move_it_by_lines (&it, -it_overshoot_count);
+
+         overshoot_handled = 1;
+       }
       if (XINT (lines) <= 0)
        {
          it.vpos = 0;
          /* Do this even if LINES is 0, so that we move back to the
             beginning of the current line as we ought.  */
          if (XINT (lines) == 0 || IT_CHARPOS (it) > 0)
-           move_it_by_lines (&it, XINT (lines), 0);
+           move_it_by_lines (&it, max (PTRDIFF_MIN, XINT (lines)));
+       }
+      else if (overshoot_handled)
+       {
+         it.vpos = 0;
+         move_it_by_lines (&it, min (PTRDIFF_MAX, XINT (lines)));
        }
       else
        {
-         if (IT_CHARPOS (it) > it_start)
+         /* Otherwise, we are at the first row occupied by PT, which
+            might span multiple screen lines (e.g., if it's on a
+            multi-line display string).  We want to start from the
+            last line that it occupies.  */
+         if (it_start < ZV)
            {
-             /* IT may move too far if truncate-lines is on and PT
-                lies beyond the right margin.  In that case,
-                backtrack unless the starting point is on an image,
-                stretch glyph, composition, or Lisp string.  */
-             if (!it_overshoot_expected
-                 /* Also, backtrack if the Lisp string contains no
-                    newline, but there is a newline right after it.
-                    In this case, IT overshoots if there is an
-                    after-string just before the newline.  */
-                 || (it_overshoot_expected < 0
-                     && it.method == GET_FROM_BUFFER
-                     && it.c == '\n'))
-               move_it_by_lines (&it, -1, 0);
-             it.vpos = 0;
-             move_it_by_lines (&it, XINT (lines), 0);
-           }
-         else
-           {
-             /* Otherwise, we are at the first row occupied by PT,
-                which might span multiple screen lines (e.g., if it's
-                on a multi-line display string).  We want to start
-                from the last line that it occupies.  */
-             if (it_start < ZV)
-               {
-                 while (IT_CHARPOS (it) <= it_start)
-                   {
-                     it.vpos = 0;
-                     move_it_by_lines (&it, 1, 0);
-                   }
-                 if (XINT (lines) > 1)
-                   move_it_by_lines (&it, XINT (lines) - 1, 0);
-               }
-             else
+             while (IT_CHARPOS (it) <= it_start)
                {
                  it.vpos = 0;
-                 move_it_by_lines (&it, XINT (lines), 0);
+                 move_it_by_lines (&it, 1);
                }
+             if (XINT (lines) > 1)
+               move_it_by_lines (&it, min (PTRDIFF_MAX, XINT (lines) - 1));
+           }
+         else
+           {
+             it.vpos = 0;
+             move_it_by_lines (&it, min (PTRDIFF_MAX, XINT (lines)));
            }
        }
 
@@ -2170,10 +2143,15 @@ whether or not it is currently displayed in some window.  */)
        }
 
       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+      bidi_unshelve_cache (itdata, 0);
     }
 
   if (BUFFERP (old_buffer))
-    w->buffer = old_buffer;
+    {
+      wset_buffer (w, old_buffer);
+      set_marker_both (w->pointm, w->buffer,
+                      old_charpos, old_bytepos);
+    }
 
   RETURN_UNGCPRO (make_number (it.vpos));
 }
@@ -2183,10 +2161,10 @@ whether or not it is currently displayed in some window.  */)
 /* File's initialization.  */
 
 void
-syms_of_indent ()
+syms_of_indent (void)
 {
-  DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
-              doc: /* *Indentation can insert tabs if this is non-nil.  */);
+  DEFVAR_BOOL ("indent-tabs-mode", indent_tabs_mode,
+              doc: /* Indentation can insert tabs if this is non-nil.  */);
   indent_tabs_mode = 1;
 
   defsubr (&Scurrent_indentation);
@@ -2196,6 +2174,3 @@ syms_of_indent ()
   defsubr (&Svertical_motion);
   defsubr (&Scompute_motion);
 }
-
-/* arch-tag: 9adfea44-71f7-4988-8ee3-96da15c502cc
-   (do not change this comment) */