(Fformat, Ftranspose_regions): Use SAFE_ALLOCA.
[bpt/emacs.git] / src / editfns.c
index d3039ca..9fbdc03 100644 (file)
@@ -1,5 +1,5 @@
 /* Lisp functions pertaining to editing.
-   Copyright (C) 1985,86,87,89,93,94,95,96,97,98, 1999, 2000, 2001, 02, 2003
+   Copyright (C) 1985,86,87,89,93,94,95,96,97,98,1999,2000,01,02,03,2004
        Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -73,7 +73,7 @@ static int tm_diff P_ ((struct tm *, struct tm *));
 static void find_field P_ ((Lisp_Object, Lisp_Object, Lisp_Object, int *, Lisp_Object, int *));
 static void update_buffer_properties P_ ((int, int));
 static Lisp_Object region_limit P_ ((int));
-static int lisp_time_argument P_ ((Lisp_Object, time_t *, int *));
+int lisp_time_argument P_ ((Lisp_Object, time_t *, int *));
 static size_t emacs_memftimeu P_ ((char *, size_t, const char *,
                                   size_t, const struct tm *, int));
 static void general_insert_function P_ ((void (*) (const unsigned char *, int),
@@ -1138,7 +1138,7 @@ DEFUN ("eolp", Feolp, Seolp, 0, 0, 0,
 
 DEFUN ("char-after", Fchar_after, Schar_after, 0, 1, 0,
        doc: /* Return character in current buffer at position POS.
-POS is an integer or a marker.
+POS is an integer or a marker and defaults to point.
 If POS is out of range, the value is nil.  */)
      (pos)
      Lisp_Object pos;
@@ -1171,7 +1171,7 @@ If POS is out of range, the value is nil.  */)
 
 DEFUN ("char-before", Fchar_before, Schar_before, 0, 1, 0,
        doc: /* Return character in current buffer preceding position POS.
-POS is an integer or a marker.
+POS is an integer or a marker and defaults to point.
 If POS is out of range, the value is nil.  */)
      (pos)
      Lisp_Object pos;
@@ -1218,7 +1218,7 @@ If POS is out of range, the value is nil.  */)
 DEFUN ("user-login-name", Fuser_login_name, Suser_login_name, 0, 1, 0,
        doc: /* Return the name under which the user logged in, as a string.
 This is based on the effective uid, not the real uid.
-Also, if the environment variable LOGNAME or USER is set,
+Also, if the environment variables LOGNAME or USER are set,
 that determines the value of this function.
 
 If optional argument UID is an integer, return the login name of the user
@@ -1377,7 +1377,7 @@ resolution finer than a second.  */)
 }
 \f
 
-static int
+int
 lisp_time_argument (specified_time, result, usec)
      Lisp_Object specified_time;
      time_t *result;
@@ -1430,7 +1430,7 @@ lisp_time_argument (specified_time, result, usec)
 
 DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0,
        doc: /* Return the current time, as a float number of seconds since the epoch.
-If an argument is given, it specifies a time to convert to float
+If SPECIFIED-TIME is given, it is the time to convert to float
 instead of the current time.  The argument should have the forms:
  (HIGH . LOW) or (HIGH LOW USEC) or (HIGH LOW . USEC).
 Thus, you can use times obtained from `current-time'
@@ -1660,7 +1660,7 @@ are used as SECOND through YEAR, and the *last* argument is used as ZONE.
 The intervening arguments are ignored.
 This feature lets (apply 'encode-time (decode-time ...)) work.
 
-Out-of-range values for SEC, MINUTE, HOUR, DAY, or MONTH are allowed;
+Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed;
 for example, a DAY of 0 means the day preceding the given month.
 Year numbers less than 100 are treated just like other year numbers.
 If you want them to stand for years in this century, you must do that yourself.
@@ -1745,8 +1745,8 @@ The format is `Sun Sep 16 01:03:52 1973'.
 However, see also the functions `decode-time' and `format-time-string'
 which provide a much more powerful and general facility.
 
-If an argument is given, it specifies a time to format
-instead of the current time.  The argument should have the form:
+If SPECIFIED-TIME is given, it is a time to format instead
+of the current time.  The argument should have the form:
   (HIGH . LOW)
 or the form:
   (HIGH LOW . IGNORED).
@@ -1801,7 +1801,7 @@ This returns a list of the form (OFFSET NAME).
 OFFSET is an integer number of seconds ahead of UTC (east of Greenwich).
     A negative value means west of Greenwich.
 NAME is a string giving the name of the time zone.
-If an argument is given, it specifies when the time zone offset is determined
+If SPECIFIED-TIME is given, the time zone offset is determined from it
 instead of using the current time.  The argument should have the form:
   (HIGH . LOW)
 or the form:
@@ -2347,21 +2347,21 @@ of the buffer.  */)
 
 DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
        1, 3, 0,
-       doc: /* Insert before point a substring of the contents of buffer BUFFER.
+       doc: /* Insert before point a substring of the contents of BUFFER.
 BUFFER may be a buffer or a buffer name.
-Arguments START and END are character numbers specifying the substring.
-They default to the beginning and the end of BUFFER.  */)
-     (buf, start, end)
-     Lisp_Object buf, start, end;
+Arguments START and END are character positions specifying the substring.
+They default to the values of (point-min) and (point-max) in BUFFER.  */)
+     (buffer, start, end)
+     Lisp_Object buffer, start, end;
 {
   register int b, e, temp;
   register struct buffer *bp, *obuf;
-  Lisp_Object buffer;
+  Lisp_Object buf;
 
-  buffer = Fget_buffer (buf);
-  if (NILP (buffer))
-    nsberror (buf);
-  bp = XBUFFER (buffer);
+  buf = Fget_buffer (buffer);
+  if (NILP (buf))
+    nsberror (buffer);
+  bp = XBUFFER (buf);
   if (NILP (bp->name))
     error ("Selecting deleted buffer");
 
@@ -2741,85 +2741,84 @@ DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
        doc: /* From START to END, translate characters according to TABLE.
 TABLE is a string; the Nth character in it is the mapping
 for the character with code N.
-This function does not alter multibyte characters.
 It returns the number of characters changed.  */)
      (start, end, table)
      Lisp_Object start;
      Lisp_Object end;
      register Lisp_Object table;
 {
-  register int pos_byte, stop; /* Limits of the region. */
   register unsigned char *tt;  /* Trans table. */
   register int nc;             /* New character. */
   int cnt;                     /* Number of changes made. */
   int size;                    /* Size of translate table. */
-  int pos;
+  int pos, pos_byte;
   int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  int string_multibyte;
 
   validate_region (&start, &end);
   CHECK_STRING (table);
 
-  size = SBYTES (table);
+  if (multibyte != (SCHARS (table) < SBYTES (table)))
+    table = (multibyte
+            ? string_make_multibyte (table)
+            : string_make_unibyte (table));
+  string_multibyte = SCHARS (table) < SBYTES (table);
+
+  size = SCHARS (table);
   tt = SDATA (table);
 
-  pos_byte = CHAR_TO_BYTE (XINT (start));
-  stop = CHAR_TO_BYTE (XINT (end));
-  modify_region (current_buffer, XINT (start), XINT (end));
   pos = XINT (start);
+  pos_byte = CHAR_TO_BYTE (pos);
+  modify_region (current_buffer, pos, XINT (end));
 
   cnt = 0;
-  for (; pos_byte < stop; )
+  for (; pos < XINT (end); )
     {
       register unsigned char *p = BYTE_POS_ADDR (pos_byte);
-      int len;
+      unsigned char *str;
+      int len, str_len;
       int oc;
-      int pos_byte_next;
 
       if (multibyte)
-       oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
+       oc = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, len);
       else
        oc = *p, len = 1;
-      pos_byte_next = pos_byte + len;
-      if (oc < size && len == 1)
+      if (oc < size)
        {
-         nc = tt[oc];
+         if (string_multibyte)
+           {
+             str = tt + string_char_to_byte (table, oc);
+             nc = STRING_CHAR_AND_LENGTH (str, MAX_MULTIBYTE_LENGTH, str_len);
+           }
+         else
+           {
+             str = tt + oc;
+             nc = tt[oc], str_len = 1;
+           }
          if (nc != oc)
            {
-             /* Take care of the case where the new character
-                combines with neighboring bytes.  */
-             if (!ASCII_BYTE_P (nc)
-                 && (CHAR_HEAD_P (nc)
-                     ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))
-                     : (pos_byte > BEG_BYTE
-                        && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))))
+             if (len != str_len)
                {
                  Lisp_Object string;
 
-                 string = make_multibyte_string (tt + oc, 1, 1);
                  /* This is less efficient, because it moves the gap,
-                    but it handles combining correctly.  */
-                 replace_range (pos, pos + 1, string,
-                                1, 0, 1);
-                 pos_byte_next = CHAR_TO_BYTE (pos);
-                 if (pos_byte_next > pos_byte)
-                   /* Before combining happened.  We should not
-                      increment POS.  So, to cancel the later
-                      increment of POS, we decrease it now.  */
-                   pos--;
-                 else
-                   INC_POS (pos_byte_next);
+                    but it should multibyte characters correctly.  */
+                 string = make_multibyte_string (str, 1, str_len);
+                 replace_range (pos, pos + 1, string, 1, 0, 1);
+                 len = str_len;
                }
              else
                {
                  record_change (pos, 1);
-                 *p = nc;
+                 while (str_len-- > 0)
+                   *p++ = *str++;
                  signal_after_change (pos, 1, 1);
                  update_compositions (pos, pos + 1, CHECK_BORDER);
                }
              ++cnt;
            }
        }
-      pos_byte = pos_byte_next;
+      pos_byte += len;
       pos++;
     }
 
@@ -2828,6 +2827,7 @@ It returns the number of characters changed.  */)
 
 DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r",
        doc: /* Delete the text between point and mark.
+
 When called from a program, expects two arguments,
 positions (integers or markers) specifying the stretch to be deleted.  */)
      (start, end)
@@ -3221,10 +3221,11 @@ usage: (format STRING &rest OBJECTS)  */)
      string itself, will not be used.  Element NARGS, corresponding to
      no argument, *will* be assigned to in the case that a `%' and `.'
      occur after the final format specifier.  */
-  int *precision = (int *) (alloca(nargs * sizeof (int)));
+  int *precision = (int *) (alloca((nargs + 1) * sizeof (int)));
   int longest_format;
   Lisp_Object val;
   int arg_intervals = 0;
+  USE_SAFE_ALLOCA;
 
   /* discarded[I] is 1 if byte I of the format
      string was not copied into the output.
@@ -3273,15 +3274,15 @@ usage: (format STRING &rest OBJECTS)  */)
   longest_format = 0;
 
   /* Make room in result for all the non-%-codes in the control string.  */
-  total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]);
+  total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]) + 1;
 
-  /* Allocate the info and discarded tables.  */ 
+  /* Allocate the info and discarded tables.  */
   {
     int nbytes = nargs * sizeof *info;
     int i;
     info = (struct info *) alloca (nbytes);
     bzero (info, nbytes);
-    for (i = 0; i <= nargs; i++)
+    for (i = 0; i < nargs; i++)
       info[i].start = -1;
     discarded = (char *) alloca (SBYTES (args[0]));
     bzero (discarded, SBYTES (args[0]));
@@ -3466,10 +3467,7 @@ usage: (format STRING &rest OBJECTS)  */)
 
   /* Allocate the space for the result.
      Note that TOTAL is an overestimate.  */
-  if (total < 1000)
-    buf = (char *) alloca (total + 1);
-  else
-    buf = (char *) xmalloc (total + 1);
+  SAFE_ALLOCA (buf, char *, total);
 
   p = buf;
   nchars = 0;
@@ -3602,7 +3600,7 @@ usage: (format STRING &rest OBJECTS)  */)
                maybe_combine_byte = 1;
              this_nchars = strlen (p);
              if (multibyte)
-               p += str_to_multibyte (p, buf + total - p, this_nchars);
+               p += str_to_multibyte (p, buf + total - 1 - p, this_nchars);
              else
                p += this_nchars;
              nchars += this_nchars;
@@ -3639,7 +3637,7 @@ usage: (format STRING &rest OBJECTS)  */)
        *p++ = *format++, nchars++;
     }
 
-  if (p > buf + total + 1)
+  if (p > buf + total)
     abort ();
 
   if (maybe_combine_byte)
@@ -3647,8 +3645,7 @@ usage: (format STRING &rest OBJECTS)  */)
   val = make_specified_string (buf, nchars, p - buf, multibyte);
 
   /* If we allocated BUF with malloc, free it too.  */
-  if (total >= 1000)
-    xfree (buf);
+  SAFE_FREE (total);
 
   /* If the format string has text properties, or any of the string
      arguments has text properties, set up text properties of the
@@ -3876,11 +3873,11 @@ transpose_markers (start1, end1, start2, end2,
 }
 
 DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5, 0,
-       doc: /* Transpose region START1 to END1 with START2 to END2.
+       doc: /* Transpose region STARTR1 to ENDR1 with STARTR2 to ENDR2.
 The regions may not be overlapping, because the size of the buffer is
 never changed in a transposition.
 
-Optional fifth arg LEAVE_MARKERS, if non-nil, means don't update
+Optional fifth arg LEAVE-MARKERS, if non-nil, means don't update
 any markers that happen to be located in the regions.
 
 Transposing beyond buffer boundaries is an error.  */)
@@ -4005,12 +4002,9 @@ Transposing beyond buffer boundaries is an error.  */)
       /* First region smaller than second.  */
       if (len1_byte < len2_byte)
         {
-         /* We use alloca only if it is small,
-            because we want to avoid stack overflow.  */
-         if (len2_byte > 20000)
-           temp = (unsigned char *) xmalloc (len2_byte);
-         else
-           temp = (unsigned char *) alloca (len2_byte);
+         USE_SAFE_ALLOCA;
+
+         SAFE_ALLOCA (temp, unsigned char *, len2_byte);
 
          /* Don't precompute these addresses.  We have to compute them
             at the last minute, because the relocating allocator might
@@ -4021,23 +4015,20 @@ Transposing beyond buffer boundaries is an error.  */)
           bcopy (start2_addr, temp, len2_byte);
           bcopy (start1_addr, start1_addr + len2_byte, len1_byte);
           bcopy (temp, start1_addr, len2_byte);
-         if (len2_byte > 20000)
-           xfree (temp);
+         SAFE_FREE (len2_byte);
         }
       else
        /* First region not smaller than second.  */
         {
-         if (len1_byte > 20000)
-           temp = (unsigned char *) xmalloc (len1_byte);
-         else
-           temp = (unsigned char *) alloca (len1_byte);
+         USE_SAFE_ALLOCA;
+
+         SAFE_ALLOCA (temp, unsigned char *, len1_byte);
          start1_addr = BYTE_POS_ADDR (start1_byte);
          start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start1_addr, temp, len1_byte);
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (temp, start1_addr + len2_byte, len1_byte);
-         if (len1_byte > 20000)
-           xfree (temp);
+         SAFE_FREE (len1_byte);
         }
       graft_intervals_into_buffer (tmp_interval1, start1 + len2,
                                    len1, current_buffer, 0);
@@ -4054,6 +4045,8 @@ Transposing beyond buffer boundaries is an error.  */)
       if (len1_byte == len2_byte)
        /* Regions are same size, though, how nice.  */
         {
+         USE_SAFE_ALLOCA;
+
           modify_region (current_buffer, start1, end1);
           modify_region (current_buffer, start2, end2);
           record_change (start1, len1);
@@ -4065,17 +4058,14 @@ Transposing beyond buffer boundaries is an error.  */)
           Fset_text_properties (make_number (start2), make_number (end2),
                                Qnil, Qnil);
 
-         if (len1_byte > 20000)
-           temp = (unsigned char *) xmalloc (len1_byte);
-         else
-           temp = (unsigned char *) alloca (len1_byte);
+         SAFE_ALLOCA (temp, unsigned char *, len1_byte);
          start1_addr = BYTE_POS_ADDR (start1_byte);
          start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start1_addr, temp, len1_byte);
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (temp, start2_addr, len1_byte);
-         if (len1_byte > 20000)
-           xfree (temp);
+         SAFE_FREE (len1_byte);
+
           graft_intervals_into_buffer (tmp_interval1, start2,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval2, start1,
@@ -4085,6 +4075,8 @@ Transposing beyond buffer boundaries is an error.  */)
       else if (len1_byte < len2_byte)  /* Second region larger than first */
         /* Non-adjacent & unequal size, area between must also be shifted.  */
         {
+         USE_SAFE_ALLOCA;
+
           modify_region (current_buffer, start1, end2);
           record_change (start1, (end2 - start1));
           tmp_interval1 = copy_intervals (cur_intv, start1, len1);
@@ -4094,18 +4086,15 @@ Transposing beyond buffer boundaries is an error.  */)
                                Qnil, Qnil);
 
          /* holds region 2 */
-         if (len2_byte > 20000)
-           temp = (unsigned char *) xmalloc (len2_byte);
-         else
-           temp = (unsigned char *) alloca (len2_byte);
+         SAFE_ALLOCA (temp, unsigned char *, len2_byte);
          start1_addr = BYTE_POS_ADDR (start1_byte);
          start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start2_addr, temp, len2_byte);
           bcopy (start1_addr, start1_addr + len_mid + len2_byte, len1_byte);
           safe_bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
           bcopy (temp, start1_addr, len2_byte);
-         if (len2_byte > 20000)
-           xfree (temp);
+         SAFE_FREE (len2_byte);
+
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
@@ -4116,6 +4105,8 @@ Transposing beyond buffer boundaries is an error.  */)
       else
        /* Second region smaller than first.  */
         {
+         USE_SAFE_ALLOCA;
+
           record_change (start1, (end2 - start1));
           modify_region (current_buffer, start1, end2);
 
@@ -4126,18 +4117,15 @@ Transposing beyond buffer boundaries is an error.  */)
                                Qnil, Qnil);
 
          /* holds region 1 */
-         if (len1_byte > 20000)
-           temp = (unsigned char *) xmalloc (len1_byte);
-         else
-           temp = (unsigned char *) alloca (len1_byte);
+         SAFE_ALLOCA (temp, unsigned char *, len1_byte);
          start1_addr = BYTE_POS_ADDR (start1_byte);
          start2_addr = BYTE_POS_ADDR (start2_byte);
           bcopy (start1_addr, temp, len1_byte);
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
           bcopy (temp, start1_addr + len2_byte + len_mid, len1_byte);
-         if (len1_byte > 20000)
-           xfree (temp);
+         SAFE_FREE (len1_byte);
+
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
@@ -4158,7 +4146,7 @@ Transposing beyond buffer boundaries is an error.  */)
       transpose_markers (start1, end1, start2, end2,
                         start1_byte, start1_byte + len1_byte,
                         start2_byte, start2_byte + len2_byte);
-      fix_overlays_in_range (start1, end2);
+      fix_start_end_in_overlays (start1, end2);
     }
 
   return Qnil;