Minor fixes for signed vs unsigned integers.
[bpt/emacs.git] / src / composite.c
index 0b0602b..ab9ec3f 100644 (file)
@@ -152,13 +152,14 @@ int n_compositions;
    COMPOSITION-ID.  */
 Lisp_Object composition_hash_table;
 
-Lisp_Object Qauto_composed;
-Lisp_Object Qauto_composition_function;
+static Lisp_Object Qauto_composed;
+static Lisp_Object Qauto_composition_function;
 /* Maximum number of characters to look back for
    auto-compositions.  */
 #define MAX_AUTO_COMPOSITION_LOOKBACK 3
 
-EXFUN (Fremove_list_of_text_properties, 4);
+static Lisp_Object Fcomposition_get_gstring (Lisp_Object, Lisp_Object,
+                                            Lisp_Object, Lisp_Object);
 
 /* Temporary variable used in macros COMPOSITION_XXX.  */
 Lisp_Object composition_temp;
@@ -178,8 +179,8 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars,
   Lisp_Object id, length, components, key, *key_contents;
   int glyph_len;
   struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table);
-  int hash_index;
-  unsigned hash_code;
+  EMACS_INT hash_index;
+  EMACS_UINT hash_code;
   struct composition *cmp;
   EMACS_INT i;
   int ch;
@@ -292,7 +293,7 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars,
     }
   else if (VECTORP (components) || CONSP (components))
     {
-      EMACS_UINT len = XVECTOR (key)->size;
+      EMACS_UINT len = ASIZE (key);
 
       /* The number of elements should be odd.  */
       if ((len % 2) == 0)
@@ -325,8 +326,8 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars,
                    : COMPOSITION_WITH_RULE_ALTCHARS));
   cmp->hash_index = hash_index;
   glyph_len = (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS
-              ? (XVECTOR (key)->size + 1) / 2
-              : XVECTOR (key)->size);
+              ? (ASIZE (key) + 1) / 2
+              : ASIZE (key));
   cmp->glyph_len = glyph_len;
   cmp->offsets = (short *) xmalloc (sizeof (short) * glyph_len * 2);
   cmp->font = NULL;
@@ -354,7 +355,7 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars,
 
       for (i = 1; i < glyph_len; i += 2)
        {
-         int rule, gref, nref, xoff, yoff;
+         int rule, gref, nref;
          int this_width;
          float this_left;
 
@@ -376,7 +377,7 @@ get_composition_id (EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT nchars,
                |       |
                6---7---8 -- descent
          */
-         COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff);
+         COMPOSITION_DECODE_REFS (rule, gref, nref);
          this_left = (leftmost
                       + (gref % 3) * (rightmost - leftmost) / 2.0
                       - (nref % 3) * this_width / 2.0);
@@ -655,28 +656,28 @@ static Lisp_Object
 gstring_lookup_cache (Lisp_Object header)
 {
   struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
-  int i = hash_lookup (h, header, NULL);
+  EMACS_INT i = hash_lookup (h, header, NULL);
 
   return (i >= 0 ? HASH_VALUE (h, i) : Qnil);
 }
 
 Lisp_Object
-composition_gstring_put_cache (Lisp_Object gstring, int len)
+composition_gstring_put_cache (Lisp_Object gstring, EMACS_INT len)
 {
   struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
-  unsigned hash;
+  EMACS_UINT hash;
   Lisp_Object header, copy;
-  int i;
+  EMACS_INT i;
 
   header = LGSTRING_HEADER (gstring);
   hash = h->hashfn (h, header);
   if (len < 0)
     {
-      len = LGSTRING_GLYPH_LEN (gstring);
-      for (i = 0; i < len; i++)
-       if (NILP (LGSTRING_GLYPH (gstring, i)))
+      EMACS_UINT j, glyph_len = LGSTRING_GLYPH_LEN (gstring);
+      for (j = 0; j < glyph_len; j++)
+       if (NILP (LGSTRING_GLYPH (gstring, j)))
          break;
-      len = i;
+      len = j;
     }
 
   copy = Fmake_vector (make_number (len + 2), Qnil);
@@ -971,11 +972,12 @@ static int _work_char;
    category Z? or C? are not composable except for ZWNJ and ZWJ. */
 
 #define CHAR_COMPOSABLE_P(C)                                           \
-  ((C) == 0x200C || (C) == 0x200D                                      \
-   || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)),      \
-       (SYMBOLP (_work_val)                                            \
-       && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C'     \
-       && _work_char != 'Z')))
+  ((C) > ' '                                                           \
+   && ((C) == 0x200C || (C) == 0x200D                                  \
+       || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)),  \
+          (SYMBOLP (_work_val)                                         \
+           && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C' \
+           && _work_char != 'Z'))))
 
 /* Update cmp_it->stop_pos to the next position after CHARPOS (and
    BYTEPOS) where character composition may happen.  If BYTEPOS is
@@ -1115,7 +1117,7 @@ composition_compute_stop_pos (struct composition_it *cmp_it, EMACS_INT charpos,
          if (! NILP (val))
            {
              Lisp_Object elt;
-             int ridx, back, len;
+             int ridx, back, blen;
 
              for (ridx = 0; CONSP (val); val = XCDR (val), ridx++)
                {
@@ -1132,17 +1134,17 @@ composition_compute_stop_pos (struct composition_it *cmp_it, EMACS_INT charpos,
                        bpos = (NILP (string) ? CHAR_TO_BYTE (cpos)
                                : string_char_to_byte (string, cpos));
                      if (STRINGP (AREF (elt, 0)))
-                       len = fast_looking_at (AREF (elt, 0), cpos, bpos,
-                                              start + 1, limit, string);
+                       blen = fast_looking_at (AREF (elt, 0), cpos, bpos,
+                                               start + 1, limit, string);
                      else
-                       len = 1;
-                     if (len > 0)
+                       blen = 1;
+                     if (blen > 0)
                        {
                          /* Make CPOS point to the last character of
-                            match.  Note that LEN is byte-length.  */
-                         if (len > 1)
+                            match.  Note that BLEN is byte-length.  */
+                         if (blen > 1)
                            {
-                             bpos += len;
+                             bpos += blen;
                              if (NILP (string))
                                cpos = BYTE_TO_CHAR (bpos) - 1;
                              else
@@ -1248,8 +1250,8 @@ composition_reseat_it (struct composition_it *cmp_it, EMACS_INT charpos, EMACS_I
   else if (w)
     {
       Lisp_Object lgstring = Qnil;
-      Lisp_Object val, elt, re;
-      int len, i;
+      Lisp_Object val, elt;
+      int i;
 
       val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
       for (i = 0; i < cmp_it->rule_idx; i++, val = XCDR (val));
@@ -1364,7 +1366,7 @@ composition_reseat_it (struct composition_it *cmp_it, EMACS_INT charpos, EMACS_I
 int
 composition_update_it (struct composition_it *cmp_it, EMACS_INT charpos, EMACS_INT bytepos, Lisp_Object string)
 {
-  int i, c;
+  int i, c IF_LINT (= 0);
 
   if (cmp_it->ch < 0)
     {
@@ -1470,7 +1472,7 @@ struct position_record
 /* Update the members of POSITION to the previous character boundary.  */
 #define BACKWARD_CHAR(POSITION, STOP)          \
   do {                                         \
-    if ((POSITION).pos == STOP)                        \
+    if ((POSITION).pos == (STOP))              \
       (POSITION).p = GPT_ADDR;                 \
     do {                                       \
       (POSITION).pos_byte--;                   \
@@ -1480,173 +1482,198 @@ struct position_record
   } while (0)
 
 /* This is like find_composition, but find an automatic composition
-   instead.  If found, set *GSTRING to the glyph-string representing
-   the composition, and return 1.  Otherwise, return 0.  */
+   instead.  It is assured that POS is not within a static
+   composition.  If found, set *GSTRING to the glyph-string
+   representing the composition, and return 1.  Otherwise, *GSTRING to
+   Qnil, and return 0.  */
 
 static int
-find_automatic_composition (EMACS_INT pos, EMACS_INT limit, EMACS_INT *start, EMACS_INT *end, Lisp_Object *gstring, Lisp_Object string)
+find_automatic_composition (EMACS_INT pos, EMACS_INT limit,
+                           EMACS_INT *start, EMACS_INT *end,
+                           Lisp_Object *gstring, Lisp_Object string)
 {
   EMACS_INT head, tail, stop;
-  /* Limit to check a composition after POS.  */
+  /* Forward limit position of checking a composition taking a
+     looking-back count into account.  */
   EMACS_INT fore_check_limit;
-  struct position_record orig, cur, check, prev;
-  Lisp_Object check_val, val, elt;
-  int check_lookback;
+  struct position_record cur, prev;
   int c;
   Lisp_Object window;
   struct window *w;
+  int need_adjustment = 0;
 
   window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
   if (NILP (window))
     return 0;
   w = XWINDOW (window);
 
-  orig.pos = pos;
+  cur.pos = pos;
   if (NILP (string))
     {
       head = BEGV, tail = ZV, stop = GPT;
-      orig.pos_byte = CHAR_TO_BYTE (orig.pos);
-      orig.p = BYTE_POS_ADDR (orig.pos_byte);
+      cur.pos_byte = CHAR_TO_BYTE (cur.pos);
+      cur.p = BYTE_POS_ADDR (cur.pos_byte);
     }
   else
     {
       head = 0, tail = SCHARS (string), stop = -1;
-      orig.pos_byte = string_char_to_byte (string, orig.pos);
-      orig.p = SDATA (string) + orig.pos_byte;
+      cur.pos_byte = string_char_to_byte (string, cur.pos);
+      cur.p = SDATA (string) + cur.pos_byte;
     }
-  if (limit < pos)
-    fore_check_limit = min (tail, pos + MAX_AUTO_COMPOSITION_LOOKBACK);
+  if (limit < 0)
+    /* Finding a composition covering the character after POS is the
+       same as setting LIMIT to POS.  */
+    limit = pos;
+  if (limit <= pos)
+    fore_check_limit = min (tail, pos + 1 + MAX_AUTO_COMPOSITION_LOOKBACK);
   else
     fore_check_limit = min (tail, limit + MAX_AUTO_COMPOSITION_LOOKBACK);
-  cur = orig;
 
- retry:
-  check_val = Qnil;
-  /* At first, check if POS is composable.  */
-  c = STRING_CHAR (cur.p);
-  if (! CHAR_COMPOSABLE_P (c))
-    {
-      if (limit < 0)
-       return 0;
-      if (limit >= cur.pos)
-       goto search_forward;
-    }
-  else
-    {
-      val = CHAR_TABLE_REF (Vcomposition_function_table, c);
-      if (! NILP (val))
-       check_val = val, check = cur;
-      else
-       while (cur.pos + 1 < fore_check_limit)
-         {
-           EMACS_INT b, e;
+  /* Provided that we have these possible compositions now:
 
-           FORWARD_CHAR (cur, stop);
-           if (get_property_and_range (cur.pos, Qcomposition, &val, &b, &e,
-                                       Qnil)
-               && COMPOSITION_VALID_P (b, e, val))
-             {
-               fore_check_limit = cur.pos;
-               break;
-             }
-           c = STRING_CHAR (cur.p);
-           if (! CHAR_COMPOSABLE_P (c))
-             break;
-           val = CHAR_TABLE_REF (Vcomposition_function_table, c);
-           if (NILP (val))
-             continue;
-           check_val = val, check = cur;
-           break;
-         }
-      cur = orig;
-    }
-  /* Rewind back to the position where we can safely search forward
-     for compositions.  */
-  while (cur.pos > head)
-    {
-      EMACS_INT b, e;
+          POS: 1 2 3 4 5 6 7 8 9
+                       |-A-|
+                 |-B-|-C-|--D--|
 
-      BACKWARD_CHAR (cur, stop);
-      if (get_property_and_range (cur.pos, Qcomposition, &val, &b, &e, Qnil)
-         && COMPOSITION_VALID_P (b, e, val))
-       break;
+     Here, it is known that characters after positions 1 and 9 can
+     never be composed (i.e. ! CHAR_COMPOSABLE_P (CH)), and
+     composition A is an invalid one because it's partially covered by
+     the valid composition C.  And to know whether a composition is
+     valid or not, the only way is to start searching forward from a
+     position that can not be a tail part of composition (it's 2 in
+     the above case).
+
+     Now we have these cases (1 through 4):
+
+                   -- character after POS is ... --
+                   not composable         composable
+     LIMIT <= POS  (1)                    (3)
+     POS < LIMIT   (2)                    (4)
+
+     Among them, in case (2), we simply search forward from POS.
+
+     In the other cases, we at first rewind back to the position where
+     the previous character is not composable or the beginning of
+     buffer (string), then search compositions forward.  In case (1)
+     and (3) we repeat this process until a composition is found.  */
+
+  while (1)
+    {
       c = STRING_CHAR (cur.p);
       if (! CHAR_COMPOSABLE_P (c))
-       break;
-      val = CHAR_TABLE_REF (Vcomposition_function_table, c);
-      if (! NILP (val))
-       check_val = val, check = cur;
-    }
-  prev = cur;
-  /* Now search forward.  */
- search_forward:
-  *gstring = Qnil;
-  if (! NILP (check_val) || limit >= orig.pos)
-    {
-      if (NILP (check_val))
-       cur = orig;
-      else
-       cur = check;
-      while (cur.pos < fore_check_limit)
        {
-         int need_adjustment = 0;
+         if (limit <= pos)     /* case (1)  */
+           {
+             do {
+               if (cur.pos <= limit)
+                 return 0;
+               BACKWARD_CHAR (cur, stop);
+               c = STRING_CHAR (cur.p);
+             } while (! CHAR_COMPOSABLE_P (c));
+             fore_check_limit = cur.pos + 1;
+           }
+         else                  /* case (2) */
+           /* No need of rewinding back.  */
+           goto search_forward;
+       }
 
-         if (NILP (check_val))
+      /* Rewind back to the position where we can safely search
+        forward for compositions.  It is assured that the character
+        at cur.pos is composable.  */
+      while (head < cur.pos)
+       {
+         prev = cur;
+         BACKWARD_CHAR (cur, stop);
+         c = STRING_CHAR (cur.p);
+         if (! CHAR_COMPOSABLE_P (c))
            {
-             c = STRING_CHAR (cur.p);
-             check_val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+             cur = prev;
+             break;
            }
-         for (; CONSP (check_val); check_val = XCDR (check_val))
+       }
+
+    search_forward:
+      /* Now search forward. */
+      *gstring = Qnil;
+      prev = cur;      /* remember the start of searching position. */
+      while (cur.pos < fore_check_limit)
+       {
+         Lisp_Object val;
+
+         c = STRING_CHAR (cur.p);
+         for (val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+              CONSP (val); val = XCDR (val))
            {
-             elt = XCAR (check_val);
-             if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1))
-                 && cur.pos - XFASTINT (AREF (elt, 1)) >= head)
+             Lisp_Object elt = XCAR (val);
+
+             if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1)))
                {
-                 check.pos = cur.pos - XFASTINT (AREF (elt, 1));
-                 if (check.pos == cur.pos)
-                   check.pos_byte = cur.pos_byte;
-                 else
-                   check.pos_byte = CHAR_TO_BYTE (check.pos);
-                 val = autocmp_chars (elt, check.pos, check.pos_byte,
-                                      tail, w, NULL, string);
+                 EMACS_INT check_pos = cur.pos - XFASTINT (AREF (elt, 1));
+                 struct position_record check;
+
+                 if (check_pos < head
+                     || (limit <= pos ? pos < check_pos
+                         : limit <= check_pos))
+                   continue;
+                 for (check = cur; check_pos < check.pos; )
+                   BACKWARD_CHAR (check, stop);
+                 *gstring = autocmp_chars (elt, check.pos, check.pos_byte,
+                                           tail, w, NULL, string);
                  need_adjustment = 1;
-                 if (! NILP (val))
+                 if (NILP (*gstring))
+                   {
+                     /* As we have called Lisp, there's a possibility
+                        that buffer/string is relocated.  */
+                     if (NILP (string))
+                       cur.p  = BYTE_POS_ADDR (cur.pos_byte);
+                     else
+                       cur.p = SDATA (string) + cur.pos_byte;
+                   }
+                 else
                    {
-                     *gstring = val;
+                     /* We found a candidate of a target composition.  */
                      *start = check.pos;
                      *end = check.pos + LGSTRING_CHAR_LEN (*gstring);
-                     if (*start <= orig.pos ? *end > orig.pos
-                         : limit >= orig.pos)
+                     if (pos < limit
+                         ? pos < *end
+                         : *start <= pos && pos < *end)
+                       /* This is the target composition. */
                        return 1;
                      cur.pos = *end;
-                     cur.pos_byte = CHAR_TO_BYTE (cur.pos);
+                     if (NILP (string))
+                       {
+                         cur.pos_byte = CHAR_TO_BYTE (cur.pos);
+                         cur.p  = BYTE_POS_ADDR (cur.pos_byte);
+                       }
+                     else
+                       {
+                         cur.pos_byte = string_char_to_byte (string, cur.pos);
+                         cur.p = SDATA (string) + cur.pos_byte;
+                       }
                      break;
                    }
                }
            }
-         if (need_adjustment)
-           {
-             /* As we have called Lisp, there's a possibility that
-                buffer/string is relocated.  */
-             if (NILP (string))
-               cur.p  = BYTE_POS_ADDR (cur.pos_byte);
-             else
-               cur.p = SDATA (string) + cur.pos_byte;
-           }
-         if (! CONSP (check_val))
+         if (! CONSP (val))
+           /* We found no composition here.  */
            FORWARD_CHAR (cur, stop);
-         check_val = Qnil;
        }
-    }
-  if (! NILP (*gstring))
-    return (limit >= 0 || (*start <= orig.pos && *end > orig.pos));
-  if (limit >= 0 && limit < orig.pos && prev.pos > head)
-    {
+
+      if (pos < limit)         /* case (2) and (4)*/
+       return 0;
+      if (! NILP (*gstring))
+       return 1;
+      if (prev.pos == head)
+       return 0;
       cur = prev;
+      if (need_adjustment)
+       {
+         if (NILP (string))
+           cur.p  = BYTE_POS_ADDR (cur.pos_byte);
+         else
+           cur.p = SDATA (string) + cur.pos_byte;
+       }
       BACKWARD_CHAR (cur, stop);
-      orig = cur;
-      fore_check_limit = orig.pos;
-      goto retry;
     }
   return 0;
 }
@@ -1657,7 +1684,7 @@ find_automatic_composition (EMACS_INT pos, EMACS_INT limit, EMACS_INT *start, EM
 EMACS_INT
 composition_adjust_point (EMACS_INT last_pt, EMACS_INT new_pt)
 {
-  EMACS_INT charpos, bytepos, startpos, beg, end, pos;
+  EMACS_INT beg, end;
   Lisp_Object val;
   int i;
 
@@ -2032,4 +2059,3 @@ See also the documentation of `auto-composition-mode'.  */);
   defsubr (&Sfind_composition_internal);
   defsubr (&Scomposition_get_gstring);
 }
-