(adjust_frame_glyphs): Remove reference to
[bpt/emacs.git] / src / editfns.c
index 0e4f7ce..a12954a 100644 (file)
@@ -154,7 +154,12 @@ A multibyte character is handled correctly.")
   CHECK_STRING (string, 0);
   p = XSTRING (string);
   if (p->size)
-    XSETFASTINT (val, STRING_CHAR (p->data, STRING_BYTES (p)));
+    {
+      if (STRING_MULTIBYTE (string))
+       XSETFASTINT (val, STRING_CHAR (p->data, STRING_BYTES (p)));
+      else
+       XSETFASTINT (val, p->data[0]);
+    }
   else
     XSETFASTINT (val, 0);
   return val;
@@ -603,7 +608,7 @@ If POS is out of range, the value is nil.")
   if (NILP (pos))
     {
       pos_byte = PT_BYTE;
-      pos = PT;
+      XSETFASTINT (pos, PT);
     }
 
   if (MARKERP (pos))
@@ -637,7 +642,7 @@ If POS is out of range, the value is nil.")
   if (NILP (pos))
     {
       pos_byte = PT_BYTE;
-      pos = PT;
+      XSETFASTINT (pos, PT);
     }
 
   if (MARKERP (pos))
@@ -727,10 +732,13 @@ DEFUN ("user-real-uid", Fuser_real_uid, Suser_real_uid, 0, 0, 0,
 
 DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0,
   "Return the full name of the user logged in, as a string.\n\
+If the full name corresponding to Emacs's userid is not known,\n\
+return \"unknown\".\n\
+\n\
 If optional argument UID is an integer, return the full name of the user\n\
-with that uid, or \"unknown\" if there is no such user.\n\
+with that uid, or nil if there is no such user.\n\
 If UID is a string, return the full name of the user with that login\n\
-name, or \"unknown\" if no such user could be found.")
+name, or nil if there is no such user.")
   (uid)
      Lisp_Object uid;
 {
@@ -847,6 +855,58 @@ lisp_time_argument (specified_time, result)
     }
 }
 
+/* Write information into buffer S of size MAXSIZE, according to the
+   FORMAT of length FORMAT_LEN, using time information taken from *TP.
+   Return the number of bytes written, not including the terminating
+   '\0'.  If S is NULL, nothing will be written anywhere; so to
+   determine how many bytes would be written, use NULL for S and
+   ((size_t) -1) for MAXSIZE.
+
+   This function behaves like emacs_strftime, except it allows null
+   bytes in FORMAT.  */
+static size_t
+emacs_memftime (s, maxsize, format, format_len, tp)
+      char *s;
+      size_t maxsize;
+      const char *format;
+      size_t format_len;
+      const struct tm *tp;
+{
+  size_t total = 0;
+
+  /* Loop through all the null-terminated strings in the format
+     argument.  Normally there's just one null-terminated string, but
+     there can be arbitrarily many, concatenated together, if the
+     format contains '\0' bytes.  emacs_strftime stops at the first
+     '\0' byte so we must invoke it separately for each such string.  */
+  for (;;)
+    {
+      size_t len;
+      size_t result;
+
+      if (s)
+       s[0] = '\1';
+
+      result = emacs_strftime (s, maxsize, format, tp);
+
+      if (s)
+       {
+         if (result == 0 && s[0] != '\0')
+           return 0;
+         s += result + 1;
+       }
+
+      maxsize -= result + 1;
+      total += result;
+      len = strlen (format);
+      if (len == format_len)
+       return total;
+      total++;
+      format += len + 1;
+      format_len -= len + 1;
+    }
+}
+
 /*
 DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
   "Use FORMAT-STRING to format the time TIME, or now if omitted.\n\
@@ -925,13 +985,16 @@ DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
       int result;
 
       buf[0] = '\1';
-      result = emacs_strftime (buf, size, XSTRING (format_string)->data,
+      result = emacs_memftime (buf, size, XSTRING (format_string)->data,
+                              STRING_BYTES (XSTRING (format_string)),
                               tm);
       if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0'))
-       return build_string (buf);
+       return make_string (buf, result);
 
       /* If buffer was too small, make it bigger and try again.  */
-      result = emacs_strftime (NULL, 0x7fffffff, XSTRING (format_string)->data,
+      result = emacs_memftime (NULL, (size_t) -1,
+                              XSTRING (format_string)->data,
+                              STRING_BYTES (XSTRING (format_string)),
                               tm);
       size = result + 1;
     }
@@ -1543,6 +1606,13 @@ make_buffer_string_both (start, start_byte, end, end_byte, props)
 {
   Lisp_Object result, tem, tem1;
 
+  if (INTEGERP (current_buffer->minibuffer_prompt_length))
+    {
+      int len = XFASTINT (current_buffer->minibuffer_prompt_length);
+      start = min (end, max (len, start));
+      start_byte = CHAR_TO_BYTE (start);
+    }
+
   if (start < GPT && GPT < end)
     move_gap (start);
 
@@ -1883,6 +1953,11 @@ Both characters must have the same length of multi-byte form.")
   int changed = 0;
   unsigned char fromwork[4], *fromstr, towork[4], *tostr, *p;
   int count = specpdl_ptr - specpdl;
+#define COMBINING_NO    0
+#define COMBINING_BEFORE 1
+#define COMBINING_AFTER  2
+#define COMBINING_BOTH (COMBINING_BEFORE | COMBINING_AFTER)
+  int maybe_byte_combining = COMBINING_NO;
 
   validate_region (&start, &end);
   CHECK_NUMBER (fromchar, 2);
@@ -1893,6 +1968,17 @@ Both characters must have the same length of multi-byte form.")
       len = CHAR_STRING (XFASTINT (fromchar), fromwork, fromstr);
       if (CHAR_STRING (XFASTINT (tochar), towork, tostr) != len)
        error ("Characters in subst-char-in-region have different byte-lengths");
+      if (!ASCII_BYTE_P (*tostr))
+       {
+         /* If *TOSTR is in the range 0x80..0x9F and TOCHAR is not a
+            complete multibyte character, it may be combined with the
+            after bytes.  If it is in the range 0xA0..0xFF, it may be
+            combined with the before and after bytes.  */
+         if (!CHAR_HEAD_P (*tostr))
+           maybe_byte_combining = COMBINING_BOTH;
+         else if (BYTES_BY_CHAR_HEAD (*tostr) > len)
+           maybe_byte_combining = COMBINING_AFTER;
+       }
     }
   else
     {
@@ -1925,13 +2011,17 @@ Both characters must have the same length of multi-byte form.")
     stop = min (stop, GPT_BYTE);
   while (1)
     {
+      int pos_byte_next = pos_byte;
+
       if (pos_byte >= stop)
        {
          if (pos_byte >= end_byte) break;
          stop = end_byte;
        }
       p = BYTE_POS_ADDR (pos_byte);
-      if (p[0] == fromstr[0]
+      INC_POS (pos_byte_next);
+      if (pos_byte_next - pos_byte == len
+         && p[0] == fromstr[0]
          && (len == 1
              || (p[1] == fromstr[1]
                  && (len == 2 || (p[2] == fromstr[2]
@@ -1954,14 +2044,14 @@ Both characters must have the same length of multi-byte form.")
 
          /* Take care of the case where the new character
             combines with neighboring bytes.  */ 
-         if (len == 1
-             && ((! CHAR_HEAD_P (tostr[0])
-                  && pos_byte > BEGV_BYTE
-                  && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))
-                 ||
-                 (! ASCII_BYTE_P (tostr[0])
-                  && pos_byte + 1 < ZV_BYTE
-                  && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1)))))
+         if (maybe_byte_combining
+             && (maybe_byte_combining == COMBINING_AFTER
+                 ? (pos_byte_next < Z_BYTE
+                    && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
+                 : ((pos_byte_next < Z_BYTE
+                     && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
+                    || (pos_byte > BEG_BYTE
+                        && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))))))
            {
              Lisp_Object tem, string;
 
@@ -1970,15 +2060,21 @@ Both characters must have the same length of multi-byte form.")
              tem = current_buffer->undo_list;
              GCPRO1 (tem);
 
-             /* Make a multibyte string containing this
-                single-byte character.  */
-             string = Fmake_string (make_number (1),
-                                    make_number (tochar));
-             SET_STRING_BYTES (XSTRING (string), 1);
+             /* Make a multibyte string containing this single character.  */
+             string = make_multibyte_string (tostr, 1, len);
              /* replace_range is less efficient, because it moves the gap,
                 but it handles combining correctly.  */
              replace_range (pos, pos + 1, string,
-                            0, 0, 0);
+                            0, 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,
+                  decrease it now.  */
+               pos--;
+             else
+               INC_POS (pos_byte_next);
+               
              if (! NILP (noundo))
                current_buffer->undo_list = tem;
 
@@ -1991,7 +2087,8 @@ Both characters must have the same length of multi-byte form.")
              for (i = 0; i < len; i++) *p++ = tostr[i];
            }
        }
-      INC_BOTH (pos, pos_byte);
+      pos_byte = pos_byte_next;
+      pos++;
     }
 
   if (changed)
@@ -2037,8 +2134,10 @@ It returns the number of characters changed.")
       register unsigned char *p = BYTE_POS_ADDR (pos_byte);
       int len;
       int oc;
+      int pos_byte_next;
 
       oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
+      pos_byte_next = pos_byte + len;
       if (oc < size && len == 1)
        {
          nc = tt[oc];
@@ -2046,24 +2145,27 @@ It returns the number of characters changed.")
            {
              /* Take care of the case where the new character
                 combines with neighboring bytes.  */ 
-             if ((! CHAR_HEAD_P (nc)
-                  && pos_byte > BEGV_BYTE
-                  && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))
-                 ||
-                 (! ASCII_BYTE_P (nc)
-                  && pos_byte + 1 < ZV_BYTE
-                  && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))))
+             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)))))
                {
                  Lisp_Object string;
 
-                 string = Fmake_string (make_number (1),
-                                        make_number (nc));
-                 SET_STRING_BYTES (XSTRING (string), 1);
-
+                 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, 0);
+                                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);
                }
              else
                {
@@ -2074,7 +2176,7 @@ It returns the number of characters changed.")
              ++cnt;
            }
        }
-      pos_byte += len;
+      pos_byte = pos_byte_next;
       pos++;
     }
 
@@ -2214,6 +2316,7 @@ The value returned is the value of the last form in BODY.\n\
 \n\
 `save-restriction' can get confused if, within the BODY, you widen\n\
 and then make changes outside the area within the saved restrictions.\n\
+See Info node `(elisp)Narrowing' for details and an appropriate technique.\n\
 \n\
 Note: if you are using both `save-excursion' and `save-restriction',\n\
 use `save-excursion' outermost:\n\
@@ -2255,20 +2358,7 @@ minibuffer contents show.")
     {
       register Lisp_Object val;
       val = Fformat (nargs, args);
-      /* Copy the data so that it won't move when we GC.  */
-      if (! message_text)
-       {
-         message_text = (char *)xmalloc (80);
-         message_length = 80;
-       }
-      if (STRING_BYTES (XSTRING (val)) > message_length)
-       {
-         message_length = STRING_BYTES (XSTRING (val));
-         message_text = (char *)xrealloc (message_text, message_length);
-       }
-      bcopy (XSTRING (val)->data, message_text, STRING_BYTES (XSTRING (val)));
-      message2 (message_text, STRING_BYTES (XSTRING (val)),
-               STRING_MULTIBYTE (val));
+      message3 (val, STRING_BYTES (XSTRING (val)), STRING_MULTIBYTE (val));
       return val;
     }
 }
@@ -2352,9 +2442,7 @@ DEFUN ("current-message", Fcurrent_message, Scurrent_message, 0, 0, 0,
   "Return the string currently displayed in the echo area, or nil if none.")
   ()
 {
-  return (echo_area_glyphs
-         ? make_string (echo_area_glyphs, echo_area_glyphs_length)
-         : Qnil);
+  return current_message ();
 }
 
 /* Number of bytes that STRING will occupy when put into the result.
@@ -2378,7 +2466,7 @@ It may contain %-sequences meaning to substitute the next argument.\n\
 %g means print a number in exponential notation\n\
   or decimal-point notation, whichever uses fewer characters.\n\
 %c means print a number as a single character.\n\
-%S means print any object as an s-expression (using prin1).\n\
+%S means print any object as an s-expression (using `prin1').\n\
   The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.\n\
 Use %% to put a single % into the output.")
   (nargs, args)
@@ -2401,6 +2489,10 @@ Use %% to put a single % into the output.")
   unsigned char *this_format;
   int longest_format;
   Lisp_Object val;
+  struct info
+  {
+    int start, end;
+  } *info = 0;
 
   extern char *index ();
 
@@ -2495,7 +2587,12 @@ Use %% to put a single % into the output.")
               be a double.  */
            if (*format == 'e' || *format == 'f' || *format == 'g')
              args[n] = Ffloat (args[n]);
+           else
 #endif
+             if (*format != 'd' && *format != 'o' && *format != 'x'
+                 && *format != 'i' && *format != 'X' && *format != 'c')
+               error ("Invalid format operation %%%c", *format);
+
            thissize = 30;      
            if (*format == 'c'
                && (! SINGLE_BYTE_CHAR_P (XINT (args[n]))
@@ -2515,7 +2612,7 @@ Use %% to put a single % into the output.")
          {
            if (! (*format == 'e' || *format == 'f' || *format == 'g'))
              args[n] = Ftruncate (args[n], Qnil);
-           thissize = 60;
+           thissize = 200;
          }
 #endif
        else
@@ -2590,6 +2687,7 @@ Use %% to put a single % into the output.")
              int padding, nbytes;
              int width = strwidth (XSTRING (args[n])->data,
                                    STRING_BYTES (XSTRING (args[n])));
+             int start = nchars;
 
              /* If spec requires it, pad on right with spaces.  */
              padding = minlen - width;
@@ -2618,6 +2716,21 @@ Use %% to put a single % into the output.")
                    *p++ = ' ';
                    nchars++;
                  }
+
+             /* If this argument has text properties, record where
+                in the result string it appears.  */
+             if (XSTRING (args[n])->intervals)
+               {
+                 if (!info)
+                   {
+                     int nbytes = nargs * sizeof *info;
+                     info = (struct info *) alloca (nbytes);
+                     bzero (info, nbytes);
+                   }
+                 
+                 info[n].start = start;
+                 info[n].end = nchars;
+               }
            }
          else if (INTEGERP (args[n]) || FLOATP (args[n]))
            {
@@ -2675,6 +2788,43 @@ Use %% to put a single % into the output.")
   if (total >= 1000)
     xfree (buf);
 
+  /* If the format string has text properties, or any of the string
+     arguments has text properties, set up text properties of the
+     result string.  */
+  
+  if (XSTRING (args[0])->intervals || info)
+    {
+      Lisp_Object len, new_len, props;
+      struct gcpro gcpro1;
+      
+      /* Add text properties from the format string.  */
+      len = make_number (XSTRING (args[0])->size);
+      props = text_property_list (args[0], make_number (0), len, Qnil);
+      GCPRO1 (props);
+      
+      if (CONSP (props))
+       {
+         new_len = make_number (XSTRING (val)->size);
+         extend_property_ranges (props, len, new_len);
+         add_text_properties_from_list (val, props, make_number (0));
+       }
+
+      /* Add text properties from arguments.  */
+      if (info)
+       for (n = 1; n < nargs; ++n)
+         if (info[n].end)
+           {
+             len = make_number (XSTRING (args[n])->size);
+             new_len = make_number (info[n].end - info[n].start);
+             props = text_property_list (args[n], make_number (0), len, Qnil);
+             extend_property_ranges (props, len, new_len);
+             add_text_properties_from_list (val, props,
+                                            make_number (info[n].start));
+           }
+
+      UNGCPRO;
+    }
+
   return val;
 }