(solar-sunrises-buffer): New constant.
[bpt/emacs.git] / src / editfns.c
index 98ab2f9..192277e 100644 (file)
@@ -1,14 +1,14 @@
 /* Lisp functions pertaining to editing.
    Copyright (C) 1985, 1986, 1987, 1989, 1993, 1994, 1995, 1996,
                  1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007 Free Software Foundation, Inc.
+                 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,9 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 #include <config.h>
@@ -52,7 +50,7 @@ Boston, MA 02110-1301, USA.  */
 
 #include "intervals.h"
 #include "buffer.h"
-#include "charset.h"
+#include "character.h"
 #include "coding.h"
 #include "frame.h"
 #include "window.h"
@@ -210,11 +208,9 @@ usage: (char-to-string CHAR)  */)
   int len;
   unsigned char str[MAX_MULTIBYTE_LENGTH];
 
-  CHECK_NUMBER (character);
+  CHECK_CHARACTER (character);
 
-  len = (SINGLE_BYTE_CHAR_P (XFASTINT (character))
-        ? (*str = (unsigned char)(XFASTINT (character)), 1)
-        : char_to_string (XFASTINT (character), str));
+  len = CHAR_STRING (XFASTINT (character), str);
   return make_string_from_bytes (str, 1, len);
 }
 
@@ -484,7 +480,7 @@ get_pos_property (position, prop, object)
            }
        }
 
-      { /* Now check the text-properties.  */
+      { /* Now check the text properties.  */
        int stickiness = text_property_stickiness (prop, position, object);
        if (stickiness > 0)
          return Fget_text_property (position, prop, object);
@@ -660,7 +656,7 @@ If POS is nil, the value of point is used for POS.  */)
 }
 
 DEFUN ("field-string-no-properties", Ffield_string_no_properties, Sfield_string_no_properties, 0, 1, 0,
-       doc: /* Return the contents of the field around POS, without text-properties.
+       doc: /* Return the contents of the field around POS, without text properties.
 A field is a region of text with the same `field' property.
 If POS is nil, the value of point is used for POS.  */)
      (pos)
@@ -2013,6 +2009,11 @@ the data it can't find.  */)
    has never been called.  */
 static char **environbuf;
 
+/* This holds the startup value of the TZ environment variable so it
+   can be restored if the user calls set-time-zone-rule with a nil
+   argument.  */
+static char *initial_tz;
+
 DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
        doc: /* Set the local time zone using TZ, a string specifying a time zone rule.
 If TZ is nil, use implementation-defined default time zone information.
@@ -2022,8 +2023,12 @@ If TZ is t, use Universal Time.  */)
 {
   char *tzstring;
 
+  /* When called for the first time, save the original TZ.  */
+  if (!environbuf)
+    initial_tz = (char *) getenv ("TZ");
+
   if (NILP (tz))
-    tzstring = 0;
+    tzstring = initial_tz;
   else if (EQ (tz, Qt))
     tzstring = "UTC0";
   else
@@ -2033,8 +2038,7 @@ If TZ is t, use Universal Time.  */)
     }
 
   set_time_zone_rule (tzstring);
-  if (environbuf)
-    free (environbuf);
+  free (environbuf);
   environbuf = environ;
 
   return Qnil;
@@ -2155,7 +2159,7 @@ general_insert_function (insert_func, insert_from_string_func,
   for (argnum = 0; argnum < nargs; argnum++)
     {
       val = args[argnum];
-      if (INTEGERP (val))
+      if (CHARACTERP (val))
        {
          unsigned char str[MAX_MULTIBYTE_LENGTH];
          int len;
@@ -2164,7 +2168,7 @@ general_insert_function (insert_func, insert_from_string_func,
            len = CHAR_STRING (XFASTINT (val), str);
          else
            {
-             str[0] = (SINGLE_BYTE_CHAR_P (XINT (val))
+             str[0] = (ASCII_CHAR_P (XINT (val))
                        ? XINT (val)
                        : multibyte_char_to_unibyte (XINT (val), Qnil));
              len = 1;
@@ -2331,6 +2335,29 @@ from adjoining text, if those properties are sticky.  */)
   return Qnil;
 }
 
+DEFUN ("insert-byte", Finsert_byte, Sinsert_byte, 2, 3, 0,
+       doc: /* Insert COUNT (second arg) copies of BYTE (first arg).
+Both arguments are required.
+BYTE is a number of the range 0..255.
+
+If BYTE is 128..255 and the current buffer is multibyte, the
+corresponding eight-bit character is inserted.
+
+Point, and before-insertion markers, are relocated as in the function `insert'.
+The optional third arg INHERIT, if non-nil, says to inherit text properties
+from adjoining text, if those properties are sticky.  */)
+     (byte, count, inherit)
+       Lisp_Object byte, count, inherit;
+{
+  CHECK_NUMBER (byte);
+  if (XINT (byte) < 0 || XINT (byte) > 255)
+    args_out_of_range_3 (byte, make_number (0), make_number (255));
+  if (XINT (byte) >= 128
+      && ! NILP (current_buffer->enable_multibyte_characters))
+    XSETFASTINT (byte, BYTE8_TO_CHAR (XINT (byte)));
+  return Finsert_char (byte, count, inherit);
+}
+
 \f
 /* Making strings from buffer contents.  */
 
@@ -2892,12 +2919,73 @@ Both characters must have the same length of multi-byte form.  */)
   return Qnil;
 }
 
+
+static Lisp_Object check_translation P_ ((int, int, int, Lisp_Object));
+
+/* Helper function for Ftranslate_region_internal.
+
+   Check if a character sequence at POS (POS_BYTE) matches an element
+   of VAL.  VAL is a list (([FROM-CHAR ...] . TO) ...).  If a matching
+   element is found, return it.  Otherwise return Qnil.  */
+
+static Lisp_Object
+check_translation (pos, pos_byte, end, val)
+     int pos, pos_byte, end;
+     Lisp_Object val;
+{
+  int buf_size = 16, buf_used = 0;
+  int *buf = alloca (sizeof (int) * buf_size);
+
+  for (; CONSP (val); val = XCDR (val))
+    {
+      Lisp_Object elt;
+      int len, i;
+
+      elt = XCAR (val);
+      if (! CONSP (elt))
+       continue;
+      elt = XCAR (elt);
+      if (! VECTORP (elt))
+       continue;
+      len = ASIZE (elt);
+      if (len <= end - pos)
+       {
+         for (i = 0; i < len; i++)
+           {
+             if (buf_used <= i)
+               {
+                 unsigned char *p = BYTE_POS_ADDR (pos_byte);
+                 int len;
+
+                 if (buf_used == buf_size)
+                   {
+                     int *newbuf;
+
+                     buf_size += 16;
+                     newbuf = alloca (sizeof (int) * buf_size);
+                     memcpy (newbuf, buf, sizeof (int) * buf_used);
+                     buf = newbuf;
+                   }
+                 buf[buf_used++] = STRING_CHAR_AND_LENGTH (p, 0, len);
+                 pos_byte += len;
+               }
+             if (XINT (AREF (elt, i)) != buf[i])
+               break;
+           }
+         if (i == len)
+           return XCAR (val);
+       }
+    }
+  return Qnil;
+}
+
+
 DEFUN ("translate-region-internal", Ftranslate_region_internal,
        Stranslate_region_internal, 3, 3, 0,
        doc: /* Internal use only.
 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.
+TABLE is a string or a char-table; the Nth character in it is the
+mapping for the character with code N.
 It returns the number of characters changed.  */)
      (start, end, table)
      Lisp_Object start;
@@ -2911,10 +2999,13 @@ It returns the number of characters changed.  */)
   int pos, pos_byte, end_pos;
   int multibyte = !NILP (current_buffer->enable_multibyte_characters);
   int string_multibyte;
+  Lisp_Object val;
 
   validate_region (&start, &end);
   if (CHAR_TABLE_P (table))
     {
+      if (! EQ (XCHAR_TABLE (table)->purpose, Qtranslation_table))
+       error ("Not a translation table");
       size = MAX_CHAR;
       tt = NULL;
     }
@@ -2925,14 +3016,14 @@ It returns the number of characters changed.  */)
       if (! multibyte && (SCHARS (table) < SBYTES (table)))
        table = string_make_unibyte (table);
       string_multibyte = SCHARS (table) < SBYTES (table);
-      size = SCHARS (table);
+      size = SBYTES (table);
       tt = SDATA (table);
     }
 
   pos = XINT (start);
   pos_byte = CHAR_TO_BYTE (pos);
   end_pos = XINT (end);
-  modify_region (current_buffer, pos, XINT (end), 0);
+  modify_region (current_buffer, pos, end_pos, 0);
 
   cnt = 0;
   for (; pos < end_pos; )
@@ -2941,6 +3032,7 @@ It returns the number of characters changed.  */)
       unsigned char *str, buf[MAX_MULTIBYTE_LENGTH];
       int len, str_len;
       int oc;
+      Lisp_Object val;
 
       if (multibyte)
        oc = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, len);
@@ -2963,7 +3055,7 @@ It returns the number of characters changed.  */)
                  nc = tt[oc];
                  if (! ASCII_BYTE_P (nc) && multibyte)
                    {
-                     str_len = CHAR_STRING (nc, buf);
+                     str_len = BYTE8_STRING (nc, buf);
                      str = buf;
                    }
                  else
@@ -2975,28 +3067,34 @@ It returns the number of characters changed.  */)
            }
          else
            {
-             Lisp_Object val;
              int c;
 
              nc = oc;
              val = CHAR_TABLE_REF (table, oc);
-             if (INTEGERP (val)
+             if (CHARACTERP (val)
                  && (c = XINT (val), CHAR_VALID_P (c, 0)))
                {
                  nc = c;
                  str_len = CHAR_STRING (nc, buf);
                  str = buf;
                }
+             else if (VECTORP (val) || (CONSP (val)))
+               {
+                 /* VAL is [TO_CHAR ...] or (([FROM-CHAR ...] .  TO) ...)
+                    where TO is TO-CHAR or [TO-CHAR ...].  */
+                 nc = -1;
+               }
            }
 
-         if (nc != oc)
+         if (nc != oc && nc >= 0)
            {
+             /* Simple one char to one char translation.  */
              if (len != str_len)
                {
                  Lisp_Object string;
 
                  /* This is less efficient, because it moves the gap,
-                    but it should multibyte characters correctly.  */
+                    but it should handle multibyte characters correctly.  */
                  string = make_multibyte_string (str, 1, str_len);
                  replace_range (pos, pos + 1, string, 1, 0, 1);
                  len = str_len;
@@ -3011,6 +3109,46 @@ It returns the number of characters changed.  */)
                }
              ++cnt;
            }
+         else if (nc < 0)
+           {
+             Lisp_Object string;
+
+             if (CONSP (val))
+               {
+                 val = check_translation (pos, pos_byte, end_pos, val);
+                 if (NILP (val))
+                   {
+                     pos_byte += len;
+                     pos++;
+                     continue;
+                   }
+                 /* VAL is ([FROM-CHAR ...] . TO).  */
+                 len = ASIZE (XCAR (val));
+                 val = XCDR (val);
+               }
+             else
+               len = 1;
+
+             if (VECTORP (val))
+               {
+                 int i;
+
+                 string = Fmake_string (make_number (ASIZE (val)),
+                                        AREF (val, 0));
+                 for (i = 1; i < ASIZE (val); i++)
+                   Faset (string, make_number (i), AREF (val, i));
+               }
+             else
+               {
+                 string = Fmake_string (make_number (1), val);
+               }
+             replace_range (pos, pos + len, string, 1, 0, 1);
+             pos_byte += SBYTES (string);
+             pos += SCHARS (string);
+             cnt += SCHARS (string);
+             end_pos += SCHARS (string) - len;
+             continue;
+           }
        }
       pos_byte += len;
       pos++;
@@ -3381,7 +3519,10 @@ DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
        doc: /* Format a string out of a format-string and arguments.
 The first argument is a format control string.
 The other arguments are substituted into it to make the result, a string.
-It may contain %-sequences meaning to substitute the next argument.
+
+The format control string may contain %-sequences meaning to substitute
+the next available argument:
+
 %s means print a string argument.  Actually, prints any object, with `princ'.
 %d means print as number in decimal (%o octal, %x hex).
 %X is like %x, but uses upper case.
@@ -3391,12 +3532,34 @@ It may contain %-sequences meaning to substitute the next argument.
   or decimal-point notation, whichever uses fewer characters.
 %c means print a number as a single character.
 %S means print any object as an s-expression (using `prin1').
-  The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.
+
+The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.
 Use %% to put a single % into the output.
 
-The basic structure of a %-sequence is
-  % <flags> <width> <precision> character
-where flags is [-+ #0]+, width is [0-9]+, and precision is .[0-9]+
+A %-sequence may contain optional flag, width, and precision
+specifiers, as follows:
+
+  %<flags><width><precision>character
+
+where flags is [+ #-0]+, width is [0-9]+, and precision is .[0-9]+
+
+The + flag character inserts a + before any positive number, while a
+space inserts a space before any positive number; these flags only
+affect %d, %e, %f, and %g sequences, and the + flag takes precedence.
+The # flag means to use an alternate display form for %o, %x, %X, %e,
+%f, and %g sequences.  The - and 0 flags affect the width specifier,
+as described below.
+
+The width specifier supplies a lower limit for the length of the
+printed representation.  The padding, if any, normally goes on the
+left, but it goes on the right if the - flag is present.  The padding
+character is normally a space, but it is 0 if the 0 flag is present.
+The - flag takes precedence over the 0 flag.
+
+For %e, %f, and %g sequences, the number after the "." in the
+precision specifier says how many decimal places to show; if zero, the
+decimal point itself is omitted.  For %s and %S, the precision
+specifier truncates the string to the given width.
 
 usage: (format STRING &rest OBJECTS)  */)
      (nargs, args)
@@ -3541,8 +3704,10 @@ usage: (format STRING &rest OBJECTS)  */)
              precision[n+1] = 10 * precision[n+1] + *format - '0';
          }
 
-       if (format - this_format_start + 1 > longest_format)
-         longest_format = format - this_format_start + 1;
+       /* Extra +1 for 'l' that we may need to insert into the
+          format.  */
+       if (format - this_format_start + 2 > longest_format)
+         longest_format = format - this_format_start + 2;
 
        if (format == end)
          error ("Format string ends in middle of format specifier");
@@ -3603,11 +3768,11 @@ usage: (format STRING &rest OBJECTS)  */)
                  && *format != 'i' && *format != 'X' && *format != 'c')
                error ("Invalid format operation %%%c", *format);
 
-           thissize = 30;
+           thissize = 30 + (precision[n] > 0 ? precision[n] : 0);
            if (*format == 'c')
              {
-               if (! SINGLE_BYTE_CHAR_P (XINT (args[n]))
-                   /* Note: No one can remember why we have to treat
+               if (! ASCII_CHAR_P (XINT (args[n]))
+                   /* Note: No one can remeber why we have to treat
                       the character 0 as a multibyte character here.
                       But, until it causes a real problem, let's
                       don't change it.  */
@@ -3801,23 +3966,40 @@ usage: (format STRING &rest OBJECTS)  */)
                     format - this_format_start);
              this_format[format - this_format_start] = 0;
 
-             if (INTEGERP (args[n]))
+             if (format[-1] == 'e' || format[-1] == 'f' || format[-1] == 'g')
+               sprintf (p, this_format, XFLOAT_DATA (args[n]));
+             else
                {
-                 if (format[-1] == 'd')
-                   sprintf (p, this_format, XINT (args[n]));
-                 /* Don't sign-extend for octal or hex printing.  */
+                 if (sizeof (EMACS_INT) > sizeof (int)
+                     && format[-1] != 'c')
+                   {
+                     /* Insert 'l' before format spec.  */
+                     this_format[format - this_format_start]
+                       = this_format[format - this_format_start - 1];
+                     this_format[format - this_format_start - 1] = 'l';
+                     this_format[format - this_format_start + 1] = 0;
+                   }
+
+                 if (INTEGERP (args[n]))
+                   {
+                     if (format[-1] == 'c')
+                       sprintf (p, this_format, (int) XINT (args[n]));
+                     else if (format[-1] == 'd')
+                       sprintf (p, this_format, XINT (args[n]));
+                     /* Don't sign-extend for octal or hex printing.  */
+                     else
+                       sprintf (p, this_format, XUINT (args[n]));
+                   }
+                 else if (format[-1] == 'c')
+                   sprintf (p, this_format, (int) XFLOAT_DATA (args[n]));
+                 else if (format[-1] == 'd')
+                   /* Maybe we should use "%1.0f" instead so it also works
+                      for values larger than MAXINT.  */
+                   sprintf (p, this_format, (EMACS_INT) XFLOAT_DATA (args[n]));
                  else
-                   sprintf (p, this_format, XUINT (args[n]));
+                   /* Don't sign-extend for octal or hex printing.  */
+                   sprintf (p, this_format, (EMACS_UINT) XFLOAT_DATA (args[n]));
                }
-             else if (format[-1] == 'e' || format[-1] == 'f' || format[-1] == 'g')
-               sprintf (p, this_format, XFLOAT_DATA (args[n]));
-             else if (format[-1] == 'd')
-               /* Maybe we should use "%1.0f" instead so it also works
-                  for values larger than MAXINT.  */
-               sprintf (p, this_format, (EMACS_INT) XFLOAT_DATA (args[n]));
-             else
-               /* Don't sign-extend for octal or hex printing.  */
-               sprintf (p, this_format, (EMACS_UINT) XFLOAT_DATA (args[n]));
 
              if (p > buf
                  && multibyte
@@ -4000,8 +4182,10 @@ Case is ignored if `case-fold-search' is non-nil in the current buffer.  */)
      register Lisp_Object c1, c2;
 {
   int i1, i2;
-  CHECK_NUMBER (c1);
-  CHECK_NUMBER (c2);
+  /* Check they're chars, not just integers, otherwise we could get array
+     bounds violations in DOWNCASE.  */
+  CHECK_CHARACTER (c1);
+  CHECK_CHARACTER (c2);
 
   if (XINT (c1) == XINT (c2))
     return Qt;
@@ -4011,8 +4195,20 @@ Case is ignored if `case-fold-search' is non-nil in the current buffer.  */)
   /* Do these in separate statements,
      then compare the variables.
      because of the way DOWNCASE uses temp variables.  */
-  i1 = DOWNCASE (XFASTINT (c1));
-  i2 = DOWNCASE (XFASTINT (c2));
+  i1 = XFASTINT (c1);
+  if (NILP (current_buffer->enable_multibyte_characters)
+      && ! ASCII_CHAR_P (i1))
+    {
+      MAKE_CHAR_MULTIBYTE (i1);
+    }
+  i2 = XFASTINT (c2);
+  if (NILP (current_buffer->enable_multibyte_characters)
+      && ! ASCII_CHAR_P (i2))
+    {
+      MAKE_CHAR_MULTIBYTE (i2);
+    }
+  i1 = DOWNCASE (i1);
+  i2 = DOWNCASE (i2);
   return (i1 == i2 ? Qt :  Qnil);
 }
 \f
@@ -4400,6 +4596,7 @@ void
 syms_of_editfns ()
 {
   environbuf = 0;
+  initial_tz = 0;
 
   Qbuffer_access_fontify_functions
     = intern ("buffer-access-fontify-functions");
@@ -4507,6 +4704,7 @@ functions if all the text being accessed has this property.  */);
   defsubr (&Sinsert_and_inherit);
   defsubr (&Sinsert_and_inherit_before_markers);
   defsubr (&Sinsert_char);
+  defsubr (&Sinsert_byte);
 
   defsubr (&Suser_login_name);
   defsubr (&Suser_real_login_name);