Convert (most) functions in src to standard C.
[bpt/emacs.git] / src / indent.c
index fdc042b..66f1f4c 100644 (file)
@@ -1,6 +1,6 @@
 /* Indentation functions.
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1998, 2000, 2001,
-                 2002, 2003, 2004, 2005, 2006, 2007, 2008
+                 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -20,11 +20,13 @@ 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 "category.h"
+#include "composite.h"
 #include "indent.h"
 #include "keyboard.h"
 #include "frame.h"
@@ -33,6 +35,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "termopts.h"
 #include "disptab.h"
 #include "intervals.h"
+#include "dispextern.h"
 #include "region-cache.h"
 
 /* Indentation can insert tabs if this is non-zero;
@@ -58,8 +61,8 @@ EMACS_INT last_known_column_point;
 
 static int last_known_column_modified;
 
-static double current_column_1 P_ ((void));
-static double position_indentation P_ ((int));
+static double current_column_1 (void);
+static double position_indentation (int);
 
 /* Cache of beginning of line found by the last call of
    current_column. */
@@ -69,7 +72,7 @@ static EMACS_INT 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;
 
@@ -86,9 +89,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;
 
@@ -122,9 +123,7 @@ character_width (c, dp)
    invalidate the buffer's width_run_cache.  */
 
 int
-disptab_matches_widthtab (disptab, widthtab)
-     struct Lisp_Char_Table *disptab;
-     struct Lisp_Vector *widthtab;
+disptab_matches_widthtab (struct Lisp_Char_Table *disptab, struct Lisp_Vector *widthtab)
 {
   int i;
 
@@ -142,9 +141,7 @@ 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;
@@ -163,7 +160,7 @@ 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)
       /* And, for the moment, this feature doesn't work on multibyte
@@ -214,11 +211,7 @@ width_run_cache_on_off ()
    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;
+skip_invisible (EMACS_INT pos, EMACS_INT *next_boundary_p, EMACS_INT to, Lisp_Object window)
 {
   Lisp_Object prop, position, overlay_limit, proplimit;
   Lisp_Object buffer, tmp;
@@ -250,7 +243,7 @@ skip_invisible (pos, next_boundary_p, to, window)
     {
       /* Don't scan terribly far.  */
       XSETFASTINT (proplimit, min (pos + 100, to));
-      /* No matter what. don't go past next overlay change.  */
+      /* No matter what, don't go past next overlay change.  */
       if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
        proplimit = overlay_limit;
       tmp = Fnext_single_property_change (position, Qinvisible,
@@ -280,32 +273,6 @@ skip_invisible (pos, next_boundary_p, to, window)
   return pos;
 }
 \f
-/* If a composition starts at POS/POS_BYTE and it doesn't stride over
-   POINT, set *LEN / *LEN_BYTE to the character and byte lengths, *WIDTH
-   to the width, and return 1.  Otherwise, return 0.  */
-
-static int
-check_composition (pos, pos_byte, point, len, len_byte, width)
-     int pos, pos_byte, point;
-     int *len, *len_byte, *width;
-{
-  Lisp_Object prop;
-  EMACS_INT start, end;
-  int id;
-
-  if (! find_composition (pos, -1, &start, &end, &prop, Qnil)
-      || pos != start || point < end
-      || !COMPOSITION_VALID_P (start, end, prop))
-    return 0;
-  if ((id = get_composition_id (pos, pos_byte, end - pos, prop, Qnil)) < 0)
-    return 0;
-
-  *len = COMPOSITION_LENGTH (prop);
-  *len_byte = CHAR_TO_BYTE (end) - pos_byte;
-  *width = composition_table[id]->width;
-  return 1;
-}
-\f
 /* Set variables WIDTH and BYTES for a multibyte sequence starting at P.
 
    DP is a display table or NULL.
@@ -318,7 +285,7 @@ check_composition (pos, pos_byte, point, len, len_byte, width)
     int c;                                                             \
                                                                        \
     wide_column = 0;                                                   \
-    c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, bytes);       \
+    c = STRING_CHAR_AND_LENGTH (p, bytes);                             \
     if (BYTES_BY_CHAR_HEAD (*p) != bytes)                              \
       width = bytes * 4;                                               \
     else                                                               \
@@ -355,13 +322,13 @@ Text that has an invisible property is considered as having width 0, unless
 /* Cancel any recorded value of the horizontal position.  */
 
 void
-invalidate_current_column ()
+invalidate_current_column (void)
 {
   last_known_column_point = 0;
 }
 
 double
-current_column ()
+current_column (void)
 {
   register int col;
   register unsigned char *ptr, *stop;
@@ -529,7 +496,7 @@ check_display_width (EMACS_INT pos, EMACS_INT col, EMACS_INT *endpos)
        width = XINT (prop) - col;
       else if (FLOATP (prop))
        width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
-           
+
       if (width >= 0)
        {
          EMACS_INT start;
@@ -556,6 +523,9 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
   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);
+  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;
@@ -572,7 +542,13 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
   next_boundary = scan;
   }
 
+  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);
+  cmp_it.id = -1;
+  composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
 
   /* Scan forward to the target position.  */
   while (scan < end)
@@ -599,20 +575,6 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
        break;
       prev_col = col;
 
-      { /* Check composition sequence.  */
-       int len, len_byte, width;
-
-       if (check_composition (scan, scan_byte, end,
-                              &len, &len_byte, &width))
-         {
-           scan += len;
-           scan_byte += len_byte;
-           if (scan <= end)
-             col += width;
-           continue;
-         }
-      }
-
       { /* Check display property.  */
        EMACS_INT end;
        int width = check_display_width (scan, col, &end);
@@ -627,13 +589,36 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
          }
       }
 
+      /* Check composition sequence.  */
+      if (cmp_it.id >= 0
+         || (scan == cmp_it.stop_pos
+             && composition_reseat_it (&cmp_it, scan, scan_byte, end,
+                                       w, NULL, Qnil)))
+       composition_update_it (&cmp_it, scan, scan_byte, Qnil);
+      if (cmp_it.id >= 0)
+       {
+         scan += cmp_it.nchars;
+         scan_byte += cmp_it.nbytes;
+         if (scan <= end)
+           col += cmp_it.width;
+         if (cmp_it.to == cmp_it.nglyphs)
+           {
+             cmp_it.id = -1;
+             composition_compute_stop_pos (&cmp_it, scan, scan_byte, end,
+                                           Qnil);
+           }
+         else
+           cmp_it.from = cmp_it.to;
+         continue;
+       }
+
       c = FETCH_BYTE (scan_byte);
 
       /* See if there is a display table and it relates
         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;
@@ -684,7 +669,7 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
              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;
@@ -728,7 +713,7 @@ scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
    due to text properties or overlays.  */
 
 static double
-current_column_1 ()
+current_column_1 (void)
 {
   EMACS_INT col = MOST_POSITIVE_FIXNUM;
   EMACS_INT opoint = PT;
@@ -872,7 +857,7 @@ The return value is COLUMN.  */)
 }
 
 \f
-static double position_indentation P_ ((int));
+static double position_indentation (int);
 
 DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
        0, 0, 0,
@@ -892,8 +877,7 @@ following any initial whitespace.  */)
 }
 
 static double
-position_indentation (pos_byte)
-     register int pos_byte;
+position_indentation (register int pos_byte)
 {
   register EMACS_INT column = 0;
   register EMACS_INT tab_width = XINT (current_buffer->tab_width);
@@ -982,9 +966,7 @@ position_indentation (pos_byte)
    preceding line.  */
 
 int
-indented_beyond_p (pos, pos_byte, column)
-     int pos, pos_byte;
-     double column;
+indented_beyond_p (int pos, int pos_byte, double column)
 {
   double val;
   int opoint = PT, opoint_byte = PT_BYTE;
@@ -1142,12 +1124,7 @@ struct position val_compute_motion;
    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 (EMACS_INT from, EMACS_INT fromvpos, EMACS_INT fromhpos, int did_motion, EMACS_INT to, EMACS_INT tovpos, EMACS_INT tohpos, EMACS_INT width, EMACS_INT hscroll, EMACS_INT tab_offset, struct window *win)
 {
   register EMACS_INT hpos = fromhpos;
   register EMACS_INT vpos = fromvpos;
@@ -1195,6 +1172,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
   EMACS_INT prev_tab_offset;   /* Previous tab offset.  */
   EMACS_INT continuation_glyph_width;
 
+  struct composition_it cmp_it;
+
   XSETBUFFER (buffer, current_buffer);
   XSETWINDOW (window, win);
 
@@ -1235,6 +1214,10 @@ 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);
+  cmp_it.id = -1;
+  composition_compute_stop_pos (&cmp_it, pos, pos_byte, to, Qnil);
+
   while (1)
     {
       while (pos == next_boundary)
@@ -1349,10 +1332,20 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
 
       if (hpos > width)
        {
-         if (hscroll
-             || (truncate_partial_width_windows
-                 && ((width + continuation_glyph_width)
-                     < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
+         int total_width = width + continuation_glyph_width;
+         int truncate = 0;
+
+         if (!NILP (Vtruncate_partial_width_windows)
+             && (total_width < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
+           {
+             if (INTEGERP (Vtruncate_partial_width_windows))
+               truncate
+                 = total_width < XFASTINT (Vtruncate_partial_width_windows);
+             else
+               truncate = 1;
+           }
+
+         if (hscroll || truncate
              || !NILP (current_buffer->truncate_lines))
            {
              /* Truncating: skip to newline, unless we are already past
@@ -1512,21 +1505,29 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
          EMACS_INT i, n;
          Lisp_Object charvec;
 
-         c = FETCH_BYTE (pos_byte);
-
          /* Check composition sequence.  */
-         {
-           int len, len_byte, width;
-
-           if (check_composition (pos, pos_byte, to, &len, &len_byte, &width))
-             {
-               pos += len;
-               pos_byte += len_byte;
-               hpos += width;
-               continue;
-             }
-         }
+         if (cmp_it.id >= 0
+             || (pos == cmp_it.stop_pos
+                 && composition_reseat_it (&cmp_it, pos, pos_byte, to, win,
+                                           NULL, Qnil)))
+           composition_update_it (&cmp_it, pos, pos_byte, Qnil);
+         if (cmp_it.id >= 0)
+           {
+             pos += cmp_it.nchars;
+             pos_byte += cmp_it.nbytes;
+             hpos += cmp_it.width;
+             if (cmp_it.to == cmp_it.nglyphs)
+               {
+                 cmp_it.id = -1;
+                 composition_compute_stop_pos (&cmp_it, pos, pos_byte, to,
+                                               Qnil);
+               }
+             else
+               cmp_it.from = cmp_it.to;
+             continue;
+           }
 
+         c = FETCH_BYTE (pos_byte);
          pos++, pos_byte++;
 
          /* Perhaps add some info to the width_run_cache.  */
@@ -1558,7 +1559,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);
@@ -1664,7 +1665,7 @@ 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;
@@ -1837,9 +1838,7 @@ visible section of the buffer, and pass LINE and COL as TOPOS.  */)
 struct position val_vmotion;
 
 struct position *
-vmotion (from, vtarget, w)
-     register EMACS_INT from, vtarget;
-     struct window *w;
+vmotion (register EMACS_INT from, register EMACS_INT vtarget, struct window *w)
 {
   EMACS_INT hscroll = XINT (w->hscroll);
   struct position pos;
@@ -2010,12 +2009,14 @@ whether or not it is currently displayed in some window.  */)
   struct window *w;
   Lisp_Object old_buffer;
   struct gcpro gcpro1;
-  int cols = 0;
+  Lisp_Object lcols = Qnil;
+  double cols;
 
   /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES).  */
   if (CONSP (lines) && (NUMBERP (XCAR (lines))))
     {
-      cols = XINT (XCAR (lines));
+      lcols = XCAR (lines);
+      cols = INTEGERP (lcols) ? (double) XINT (lcols) : XFLOAT_DATA (lcols);
       lines = XCDR (lines);
     }
 
@@ -2043,73 +2044,110 @@ whether or not it is currently displayed in some window.  */)
     }
   else
     {
-      int it_start;
-      int oselective;
-      int it_overshoot_expected;
+      int it_start, first_x, it_overshoot_expected;
 
       SET_TEXT_POS (pt, PT, PT_BYTE);
       start_display (&it, w, pt);
-
-      /* 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
-        really at some x > 0.  The effect is, in continuation lines, that
-        we end up with the iterator placed at where it thinks X is 0,
-        while the end position is really at some X > 0, the same X that
-        PT had.  */
+      first_x = it.first_visible_x;
       it_start = IT_CHARPOS (it);
 
-      /* We expect the call to move_it_to, further down, to overshoot
-        if the starting point is on an image, stretch glyph,
-        composition, or Lisp string.  We won't need to backtrack in
-        this situation, except for one corner case: when the Lisp
-        string contains a newline.  */
-      if (it.method == GET_FROM_STRING)
+      /* See comments below for why we calculate this.  */
+      if (XINT (lines) > 0)
        {
-         const char *s = SDATA (it.string);
-         const char *e = s + SBYTES (it.string);
-
-         while (s < e && *s != '\n')
-           ++s;
-
-         /* If there is no newline in the string, we need to check
-            whether there is a newline immediately after the string
-            in move_it_to below.  This may happen if there is an
-            overlay with an after-string just before the newline.  */
-         it_overshoot_expected = (s == e) ? -1 : 0;
+         if (it.cmp_it.id >= 0)
+           it_overshoot_expected = 1;
+         else if (it.method == GET_FROM_STRING)
+           {
+             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;
+           }
+         else
+           it_overshoot_expected = (it.method == GET_FROM_IMAGE
+                                    || it.method == GET_FROM_STRETCH);
        }
-      else
-       it_overshoot_expected = (it.method == GET_FROM_IMAGE
-                                || it.method == GET_FROM_STRETCH
-                                || it.method == GET_FROM_COMPOSITION);
 
+      /* 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
+        really at some x > 0.  */
       reseat_at_previous_visible_line_start (&it);
       it.current_x = it.hpos = 0;
-      /* Temporarily disable selective display so we don't move too far */
-      oselective = it.selective;
-      it.selective = 0;
-      move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
-      it.selective = oselective;
-
-      /* Move back if we got too far.  This may happen if
-        truncate-lines is on and PT is beyond right margin.
-        Don't go back if the overshoot is expected (see above).  */
-      if (IT_CHARPOS (it) > it_start && XINT (lines) > 0
-         && (!it_overshoot_expected
-             || (it_overshoot_expected < 0
-                 && it.method == GET_FROM_BUFFER
-                 && it.c == '\n')))
-       move_it_by_lines (&it, -1, 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);
-
-      if (cols)
-       move_it_in_display_line (&it, ZV,
-                                cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)),
-                                MOVE_TO_X);
+      if (IT_CHARPOS (it) != PT)
+       /* We used to temporarily disable selective display here; the
+          comment said this is "so we don't move too far" (2005-01-19
+          checkin by kfs).  But this does nothing useful that I can
+          tell, and it causes Bug#2694 .  -- cyd */
+       move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+
+      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);
+       }
+      else
+       {
+         if (IT_CHARPOS (it) > it_start)
+           {
+             /* 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
+               {
+                 it.vpos = 0;
+                 move_it_by_lines (&it, XINT (lines), 0);
+               }
+           }
+       }
+
+      /* Move to the goal column, if one was specified.  */
+      if (!NILP (lcols))
+       {
+         /* If the window was originally hscrolled, move forward by
+            the hscrolled amount first.  */
+         if (first_x > 0)
+           {
+             move_it_in_display_line (&it, ZV, first_x, MOVE_TO_X);
+             it.current_x = 0;
+           }
+         move_it_in_display_line
+           (&it, ZV,
+            (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5),
+            MOVE_TO_X);
+       }
 
       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
     }
@@ -2125,7 +2163,7 @@ 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.  */);