aboutsummaryrefslogtreecommitdiffstats
path: root/src/editfns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/editfns.c')
-rw-r--r--src/editfns.c415
1 files changed, 202 insertions, 213 deletions
diff --git a/src/editfns.c b/src/editfns.c
index 8122ffdd0d4..d0cca6f3d7b 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -1,6 +1,6 @@
1/* Lisp functions pertaining to editing. 1/* Lisp functions pertaining to editing.
2 2
3Copyright (C) 1985-1987, 1989, 1993-2012 Free Software Foundation, Inc. 3Copyright (C) 1985-1987, 1989, 1993-2013 Free Software Foundation, Inc.
4 4
5This file is part of GNU Emacs. 5This file is part of GNU Emacs.
6 6
@@ -24,6 +24,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
24 24
25#ifdef HAVE_PWD_H 25#ifdef HAVE_PWD_H
26#include <pwd.h> 26#include <pwd.h>
27#include <grp.h>
27#endif 28#endif
28 29
29#include <unistd.h> 30#include <unistd.h>
@@ -78,6 +79,15 @@ Lisp_Object Qfield;
78 79
79static Lisp_Object Qboundary; 80static Lisp_Object Qboundary;
80 81
82/* The startup value of the TZ environment variable so it can be
83 restored if the user calls set-time-zone-rule with a nil
84 argument. If null, the TZ environment variable was unset. */
85static char const *initial_tz;
86
87/* True if the static variable tzvalbuf (defined in
88 set_time_zone_rule) is part of 'environ'. */
89static bool tzvalbuf_in_environ;
90
81 91
82void 92void
83init_editfns (void) 93init_editfns (void)
@@ -96,6 +106,9 @@ init_editfns (void)
96 return; 106 return;
97#endif /* not CANNOT_DUMP */ 107#endif /* not CANNOT_DUMP */
98 108
109 initial_tz = getenv ("TZ");
110 tzvalbuf_in_environ = 0;
111
99 pw = getpwuid (getuid ()); 112 pw = getpwuid (getuid ());
100#ifdef MSDOS 113#ifdef MSDOS
101 /* We let the real user name default to "root" because that's quite 114 /* We let the real user name default to "root" because that's quite
@@ -360,7 +373,7 @@ get_pos_property (Lisp_Object position, register Lisp_Object prop, Lisp_Object o
360 if (NILP (object)) 373 if (NILP (object))
361 XSETBUFFER (object, current_buffer); 374 XSETBUFFER (object, current_buffer);
362 else if (WINDOWP (object)) 375 else if (WINDOWP (object))
363 object = XWINDOW (object)->buffer; 376 object = XWINDOW (object)->contents;
364 377
365 if (!BUFFERP (object)) 378 if (!BUFFERP (object))
366 /* pos-property only makes sense in buffers right now, since strings 379 /* pos-property only makes sense in buffers right now, since strings
@@ -373,6 +386,7 @@ get_pos_property (Lisp_Object position, register Lisp_Object prop, Lisp_Object o
373 ptrdiff_t noverlays; 386 ptrdiff_t noverlays;
374 Lisp_Object *overlay_vec, tem; 387 Lisp_Object *overlay_vec, tem;
375 struct buffer *obuf = current_buffer; 388 struct buffer *obuf = current_buffer;
389 USE_SAFE_ALLOCA;
376 390
377 set_buffer_temp (XBUFFER (object)); 391 set_buffer_temp (XBUFFER (object));
378 392
@@ -385,7 +399,7 @@ get_pos_property (Lisp_Object position, register Lisp_Object prop, Lisp_Object o
385 make enough space for all, and try again. */ 399 make enough space for all, and try again. */
386 if (noverlays > 40) 400 if (noverlays > 40)
387 { 401 {
388 overlay_vec = alloca (noverlays * sizeof *overlay_vec); 402 SAFE_ALLOCA_LISP (overlay_vec, noverlays);
389 noverlays = overlays_around (posn, overlay_vec, noverlays); 403 noverlays = overlays_around (posn, overlay_vec, noverlays);
390 } 404 }
391 noverlays = sort_overlays (overlay_vec, noverlays, NULL); 405 noverlays = sort_overlays (overlay_vec, noverlays, NULL);
@@ -408,10 +422,12 @@ get_pos_property (Lisp_Object position, register Lisp_Object prop, Lisp_Object o
408 ; /* The overlay will not cover a char inserted at point. */ 422 ; /* The overlay will not cover a char inserted at point. */
409 else 423 else
410 { 424 {
425 SAFE_FREE ();
411 return tem; 426 return tem;
412 } 427 }
413 } 428 }
414 } 429 }
430 SAFE_FREE ();
415 431
416 { /* Now check the text properties. */ 432 { /* Now check the text properties. */
417 int stickiness = text_property_stickiness (prop, position, object); 433 int stickiness = text_property_stickiness (prop, position, object);
@@ -653,7 +669,8 @@ If the optional argument INHIBIT-CAPTURE-PROPERTY is non-nil, and OLD-POS has
653a non-nil property of that name, then any field boundaries are ignored. 669a non-nil property of that name, then any field boundaries are ignored.
654 670
655Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */) 671Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
656 (Lisp_Object new_pos, Lisp_Object old_pos, Lisp_Object escape_from_edge, Lisp_Object only_in_line, Lisp_Object inhibit_capture_property) 672 (Lisp_Object new_pos, Lisp_Object old_pos, Lisp_Object escape_from_edge,
673 Lisp_Object only_in_line, Lisp_Object inhibit_capture_property)
657{ 674{
658 /* If non-zero, then the original point, before re-positioning. */ 675 /* If non-zero, then the original point, before re-positioning. */
659 ptrdiff_t orig_point = 0; 676 ptrdiff_t orig_point = 0;
@@ -719,9 +736,9 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
719 /* This is the ONLY_IN_LINE case, check that NEW_POS and 736 /* This is the ONLY_IN_LINE case, check that NEW_POS and
720 FIELD_BOUND are on the same line by seeing whether 737 FIELD_BOUND are on the same line by seeing whether
721 there's an intervening newline or not. */ 738 there's an intervening newline or not. */
722 || (scan_buffer ('\n', 739 || (find_newline (XFASTINT (new_pos), -1,
723 XFASTINT (new_pos), XFASTINT (field_bound), 740 XFASTINT (field_bound), -1,
724 fwd ? -1 : 1, &shortage, 1), 741 fwd ? -1 : 1, &shortage, NULL, 1),
725 shortage != 0))) 742 shortage != 0)))
726 /* Constrain NEW_POS to FIELD_BOUND. */ 743 /* Constrain NEW_POS to FIELD_BOUND. */
727 new_pos = field_bound; 744 new_pos = field_bound;
@@ -806,45 +823,47 @@ This function does not move point. */)
806 CHECK_NUMBER (n); 823 CHECK_NUMBER (n);
807 824
808 clipped_n = clip_to_bounds (PTRDIFF_MIN + 1, XINT (n), PTRDIFF_MAX); 825 clipped_n = clip_to_bounds (PTRDIFF_MIN + 1, XINT (n), PTRDIFF_MAX);
809 end_pos = find_before_next_newline (orig, 0, clipped_n - (clipped_n <= 0)); 826 end_pos = find_before_next_newline (orig, 0, clipped_n - (clipped_n <= 0),
827 NULL);
810 828
811 /* Return END_POS constrained to the current input field. */ 829 /* Return END_POS constrained to the current input field. */
812 return Fconstrain_to_field (make_number (end_pos), make_number (orig), 830 return Fconstrain_to_field (make_number (end_pos), make_number (orig),
813 Qnil, Qt, Qnil); 831 Qnil, Qt, Qnil);
814} 832}
815 833
816 834/* Save current buffer state for `save-excursion' special form.
835 We (ab)use Lisp_Misc_Save_Value to allow explicit free and so
836 offload some work from GC. */
837
817Lisp_Object 838Lisp_Object
818save_excursion_save (void) 839save_excursion_save (void)
819{ 840{
820 bool visible = (XBUFFER (XWINDOW (selected_window)->buffer) 841 return make_save_value
821 == current_buffer); 842 (SAVE_TYPE_OBJ_OBJ_OBJ_OBJ,
822 /* Do not copy the mark if it points to nowhere. */ 843 Fpoint_marker (),
823 Lisp_Object mark = (XMARKER (BVAR (current_buffer, mark))->buffer 844 /* Do not copy the mark if it points to nowhere. */
824 ? Fcopy_marker (BVAR (current_buffer, mark), Qnil) 845 (XMARKER (BVAR (current_buffer, mark))->buffer
825 : Qnil); 846 ? Fcopy_marker (BVAR (current_buffer, mark), Qnil)
826 847 : Qnil),
827 return Fcons (Fpoint_marker (), 848 /* Selected window if current buffer is shown in it, nil otherwise. */
828 Fcons (mark, 849 (EQ (XWINDOW (selected_window)->contents, Fcurrent_buffer ())
829 Fcons (visible ? Qt : Qnil, 850 ? selected_window : Qnil),
830 Fcons (BVAR (current_buffer, mark_active), 851 BVAR (current_buffer, mark_active));
831 selected_window))));
832} 852}
833 853
854/* Restore saved buffer before leaving `save-excursion' special form. */
855
834Lisp_Object 856Lisp_Object
835save_excursion_restore (Lisp_Object info) 857save_excursion_restore (Lisp_Object info)
836{ 858{
837 Lisp_Object tem, tem1, omark, nmark; 859 Lisp_Object tem, tem1, omark, nmark;
838 struct gcpro gcpro1, gcpro2, gcpro3; 860 struct gcpro gcpro1, gcpro2, gcpro3;
839 bool visible_p;
840 861
841 tem = Fmarker_buffer (XCAR (info)); 862 tem = Fmarker_buffer (XSAVE_OBJECT (info, 0));
842 /* If buffer being returned to is now deleted, avoid error */ 863 /* If we're unwinding to top level, saved buffer may be deleted. This
843 /* Otherwise could get error here while unwinding to top level 864 means that all of its markers are unchained and so tem is nil. */
844 and crash */
845 /* In that case, Fmarker_buffer returns nil now. */
846 if (NILP (tem)) 865 if (NILP (tem))
847 return Qnil; 866 goto out;
848 867
849 omark = nmark = Qnil; 868 omark = nmark = Qnil;
850 GCPRO3 (info, omark, nmark); 869 GCPRO3 (info, omark, nmark);
@@ -852,13 +871,12 @@ save_excursion_restore (Lisp_Object info)
852 Fset_buffer (tem); 871 Fset_buffer (tem);
853 872
854 /* Point marker. */ 873 /* Point marker. */
855 tem = XCAR (info); 874 tem = XSAVE_OBJECT (info, 0);
856 Fgoto_char (tem); 875 Fgoto_char (tem);
857 unchain_marker (XMARKER (tem)); 876 unchain_marker (XMARKER (tem));
858 877
859 /* Mark marker. */ 878 /* Mark marker. */
860 info = XCDR (info); 879 tem = XSAVE_OBJECT (info, 1);
861 tem = XCAR (info);
862 omark = Fmarker_position (BVAR (current_buffer, mark)); 880 omark = Fmarker_position (BVAR (current_buffer, mark));
863 if (NILP (tem)) 881 if (NILP (tem))
864 unchain_marker (XMARKER (BVAR (current_buffer, mark))); 882 unchain_marker (XMARKER (BVAR (current_buffer, mark)));
@@ -869,23 +887,8 @@ save_excursion_restore (Lisp_Object info)
869 unchain_marker (XMARKER (tem)); 887 unchain_marker (XMARKER (tem));
870 } 888 }
871 889
872 /* visible */ 890 /* Mark active. */
873 info = XCDR (info); 891 tem = XSAVE_OBJECT (info, 3);
874 visible_p = !NILP (XCAR (info));
875
876#if 0 /* We used to make the current buffer visible in the selected window
877 if that was true previously. That avoids some anomalies.
878 But it creates others, and it wasn't documented, and it is simpler
879 and cleaner never to alter the window/buffer connections. */
880 tem1 = Fcar (tem);
881 if (!NILP (tem1)
882 && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
883 Fswitch_to_buffer (Fcurrent_buffer (), Qnil);
884#endif /* 0 */
885
886 /* Mark active */
887 info = XCDR (info);
888 tem = XCAR (info);
889 tem1 = BVAR (current_buffer, mark_active); 892 tem1 = BVAR (current_buffer, mark_active);
890 bset_mark_active (current_buffer, tem); 893 bset_mark_active (current_buffer, tem);
891 894
@@ -909,10 +912,10 @@ save_excursion_restore (Lisp_Object info)
909 /* If buffer was visible in a window, and a different window was 912 /* If buffer was visible in a window, and a different window was
910 selected, and the old selected window is still showing this 913 selected, and the old selected window is still showing this
911 buffer, restore point in that window. */ 914 buffer, restore point in that window. */
912 tem = XCDR (info); 915 tem = XSAVE_OBJECT (info, 2);
913 if (visible_p 916 if (WINDOWP (tem)
914 && !EQ (tem, selected_window) 917 && !EQ (tem, selected_window)
915 && (tem1 = XWINDOW (tem)->buffer, 918 && (tem1 = XWINDOW (tem)->contents,
916 (/* Window is live... */ 919 (/* Window is live... */
917 BUFFERP (tem1) 920 BUFFERP (tem1)
918 /* ...and it shows the current buffer. */ 921 /* ...and it shows the current buffer. */
@@ -920,6 +923,10 @@ save_excursion_restore (Lisp_Object info)
920 Fset_window_point (tem, make_number (PT)); 923 Fset_window_point (tem, make_number (PT));
921 924
922 UNGCPRO; 925 UNGCPRO;
926
927 out:
928
929 free_misc (info);
923 return Qnil; 930 return Qnil;
924} 931}
925 932
@@ -962,7 +969,7 @@ usage: (save-current-buffer &rest BODY) */)
962 return unbind_to (count, Fprogn (args)); 969 return unbind_to (count, Fprogn (args));
963} 970}
964 971
965DEFUN ("buffer-size", Fbufsize, Sbufsize, 0, 1, 0, 972DEFUN ("buffer-size", Fbuffer_size, Sbuffer_size, 0, 1, 0,
966 doc: /* Return the number of characters in the current buffer. 973 doc: /* Return the number of characters in the current buffer.
967If BUFFER, return the number of characters in that buffer instead. */) 974If BUFFER, return the number of characters in that buffer instead. */)
968 (Lisp_Object buffer) 975 (Lisp_Object buffer)
@@ -1267,6 +1274,24 @@ Value is an integer or a float, depending on the value. */)
1267 return make_fixnum_or_float (uid); 1274 return make_fixnum_or_float (uid);
1268} 1275}
1269 1276
1277DEFUN ("group-gid", Fgroup_gid, Sgroup_gid, 0, 0, 0,
1278 doc: /* Return the effective gid of Emacs.
1279Value is an integer or a float, depending on the value. */)
1280 (void)
1281{
1282 gid_t egid = getegid ();
1283 return make_fixnum_or_float (egid);
1284}
1285
1286DEFUN ("group-real-gid", Fgroup_real_gid, Sgroup_real_gid, 0, 0, 0,
1287 doc: /* Return the real gid of Emacs.
1288Value is an integer or a float, depending on the value. */)
1289 (void)
1290{
1291 gid_t gid = getgid ();
1292 return make_fixnum_or_float (gid);
1293}
1294
1270DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0, 1295DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0,
1271 doc: /* Return the full name of the user logged in, as a string. 1296 doc: /* Return the full name of the user logged in, as a string.
1272If the full name corresponding to Emacs's userid is not known, 1297If the full name corresponding to Emacs's userid is not known,
@@ -1373,8 +1398,8 @@ hi_time (time_t t)
1373 no runtime check is needed, and taking care not to convert 1398 no runtime check is needed, and taking care not to convert
1374 negative numbers to unsigned before comparing them. */ 1399 negative numbers to unsigned before comparing them. */
1375 if (! ((! TYPE_SIGNED (time_t) 1400 if (! ((! TYPE_SIGNED (time_t)
1376 || MOST_NEGATIVE_FIXNUM <= TIME_T_MIN >> 16 1401 || TIME_T_MIN >> 16 >= MOST_NEGATIVE_FIXNUM
1377 || MOST_NEGATIVE_FIXNUM <= hi) 1402 || hi >= MOST_NEGATIVE_FIXNUM)
1378 && (TIME_T_MAX >> 16 <= MOST_POSITIVE_FIXNUM 1403 && (TIME_T_MAX >> 16 <= MOST_POSITIVE_FIXNUM
1379 || hi <= MOST_POSITIVE_FIXNUM))) 1404 || hi <= MOST_POSITIVE_FIXNUM)))
1380 time_overflow (); 1405 time_overflow ();
@@ -1461,9 +1486,7 @@ Lisp_Object
1461make_lisp_time (EMACS_TIME t) 1486make_lisp_time (EMACS_TIME t)
1462{ 1487{
1463 int ns = EMACS_NSECS (t); 1488 int ns = EMACS_NSECS (t);
1464 return make_time_tail (EMACS_SECS (t), 1489 return make_time_tail (EMACS_SECS (t), list2i (ns / 1000, ns % 1000 * 1000));
1465 list2 (make_number (ns / 1000),
1466 make_number (ns % 1000 * 1000)));
1467} 1490}
1468 1491
1469/* Decode a Lisp list SPECIFIED_TIME that represents a time. 1492/* Decode a Lisp list SPECIFIED_TIME that represents a time.
@@ -1538,7 +1561,7 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec,
1538 1561
1539 if (result) 1562 if (result)
1540 { 1563 {
1541 if ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> 16 <= hi : 0 <= hi) 1564 if (hi >= (TYPE_SIGNED (time_t) ? TIME_T_MIN >> 16 : 0)
1542 && hi <= TIME_T_MAX >> 16) 1565 && hi <= TIME_T_MAX >> 16)
1543 { 1566 {
1544 /* Return the greatest representable time that is not greater 1567 /* Return the greatest representable time that is not greater
@@ -1907,9 +1930,11 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1907 } 1930 }
1908 else 1931 else
1909 { 1932 {
1910 char tzbuf[100]; 1933 static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d";
1934 char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)];
1935 char *old_tzstring;
1911 const char *tzstring; 1936 const char *tzstring;
1912 char **oldenv = environ, **newenv; 1937 USE_SAFE_ALLOCA;
1913 1938
1914 if (EQ (zone, Qt)) 1939 if (EQ (zone, Qt))
1915 tzstring = "UTC0"; 1940 tzstring = "UTC0";
@@ -1921,13 +1946,20 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1921 EMACS_INT zone_hr = abszone / (60*60); 1946 EMACS_INT zone_hr = abszone / (60*60);
1922 int zone_min = (abszone/60) % 60; 1947 int zone_min = (abszone/60) % 60;
1923 int zone_sec = abszone % 60; 1948 int zone_sec = abszone % 60;
1924 sprintf (tzbuf, "XXX%s%"pI"d:%02d:%02d", "-" + (XINT (zone) < 0), 1949 sprintf (tzbuf, tzbuf_format, "-" + (XINT (zone) < 0),
1925 zone_hr, zone_min, zone_sec); 1950 zone_hr, zone_min, zone_sec);
1926 tzstring = tzbuf; 1951 tzstring = tzbuf;
1927 } 1952 }
1928 else 1953 else
1929 error ("Invalid time zone specification"); 1954 error ("Invalid time zone specification");
1930 1955
1956 old_tzstring = getenv ("TZ");
1957 if (old_tzstring)
1958 {
1959 char *buf = SAFE_ALLOCA (strlen (old_tzstring) + 1);
1960 old_tzstring = strcpy (buf, old_tzstring);
1961 }
1962
1931 block_input (); 1963 block_input ();
1932 1964
1933 /* Set TZ before calling mktime; merely adjusting mktime's returned 1965 /* Set TZ before calling mktime; merely adjusting mktime's returned
@@ -1936,15 +1968,12 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1936 1968
1937 value = mktime (&tm); 1969 value = mktime (&tm);
1938 1970
1939 /* Restore TZ to previous value. */ 1971 set_time_zone_rule (old_tzstring);
1940 newenv = environ;
1941 environ = oldenv;
1942#ifdef LOCALTIME_CACHE 1972#ifdef LOCALTIME_CACHE
1943 tzset (); 1973 tzset ();
1944#endif 1974#endif
1945 unblock_input (); 1975 unblock_input ();
1946 1976 SAFE_FREE ();
1947 xfree (newenv);
1948 } 1977 }
1949 1978
1950 if (value == (time_t) -1) 1979 if (value == (time_t) -1)
@@ -2074,16 +2103,6 @@ the data it can't find. */)
2074 return list2 (zone_offset, zone_name); 2103 return list2 (zone_offset, zone_name);
2075} 2104}
2076 2105
2077/* This holds the value of `environ' produced by the previous
2078 call to Fset_time_zone_rule, or 0 if Fset_time_zone_rule
2079 has never been called. */
2080static char **environbuf;
2081
2082/* This holds the startup value of the TZ environment variable so it
2083 can be restored if the user calls set-time-zone-rule with a nil
2084 argument. */
2085static char *initial_tz;
2086
2087DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0, 2106DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
2088 doc: /* Set the local time zone using TZ, a string specifying a time zone rule. 2107 doc: /* Set the local time zone using TZ, a string specifying a time zone rule.
2089If TZ is nil, use implementation-defined default time zone information. 2108If TZ is nil, use implementation-defined default time zone information.
@@ -2096,18 +2115,10 @@ only the former. */)
2096 (Lisp_Object tz) 2115 (Lisp_Object tz)
2097{ 2116{
2098 const char *tzstring; 2117 const char *tzstring;
2099 char **old_environbuf;
2100 2118
2101 if (! (NILP (tz) || EQ (tz, Qt))) 2119 if (! (NILP (tz) || EQ (tz, Qt)))
2102 CHECK_STRING (tz); 2120 CHECK_STRING (tz);
2103 2121
2104 block_input ();
2105
2106 /* When called for the first time, save the original TZ. */
2107 old_environbuf = environbuf;
2108 if (!old_environbuf)
2109 initial_tz = (char *) getenv ("TZ");
2110
2111 if (NILP (tz)) 2122 if (NILP (tz))
2112 tzstring = initial_tz; 2123 tzstring = initial_tz;
2113 else if (EQ (tz, Qt)) 2124 else if (EQ (tz, Qt))
@@ -2115,106 +2126,98 @@ only the former. */)
2115 else 2126 else
2116 tzstring = SSDATA (tz); 2127 tzstring = SSDATA (tz);
2117 2128
2129 block_input ();
2118 set_time_zone_rule (tzstring); 2130 set_time_zone_rule (tzstring);
2119 environbuf = environ;
2120
2121 unblock_input (); 2131 unblock_input ();
2122 2132
2123 xfree (old_environbuf);
2124 return Qnil; 2133 return Qnil;
2125} 2134}
2126 2135
2127#ifdef LOCALTIME_CACHE
2128
2129/* These two values are known to load tz files in buggy implementations,
2130 i.e. Solaris 1 executables running under either Solaris 1 or Solaris 2.
2131 Their values shouldn't matter in non-buggy implementations.
2132 We don't use string literals for these strings,
2133 since if a string in the environment is in readonly
2134 storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
2135 See Sun bugs 1113095 and 1114114, ``Timezone routines
2136 improperly modify environment''. */
2137
2138static char set_time_zone_rule_tz1[] = "TZ=GMT+0";
2139static char set_time_zone_rule_tz2[] = "TZ=GMT+1";
2140
2141#endif
2142
2143/* Set the local time zone rule to TZSTRING. 2136/* Set the local time zone rule to TZSTRING.
2144 This allocates memory into `environ', which it is the caller's 2137
2145 responsibility to free. */ 2138 This function is not thread-safe, partly because putenv, unsetenv
2139 and tzset are not, and partly because of the static storage it
2140 updates. Other threads that invoke localtime etc. may be adversely
2141 affected while this function is executing. */
2146 2142
2147void 2143void
2148set_time_zone_rule (const char *tzstring) 2144set_time_zone_rule (const char *tzstring)
2149{ 2145{
2150 ptrdiff_t envptrs; 2146 /* A buffer holding a string of the form "TZ=value", intended
2151 char **from, **to, **newenv; 2147 to be part of the environment. */
2148 static char *tzvalbuf;
2149 static ptrdiff_t tzvalbufsize;
2152 2150
2153 /* Make the ENVIRON vector longer with room for TZSTRING. */ 2151 int tzeqlen = sizeof "TZ=" - 1;
2154 for (from = environ; *from; from++) 2152
2155 continue; 2153#ifdef LOCALTIME_CACHE
2156 envptrs = from - environ + 2; 2154 /* These two values are known to load tz files in buggy implementations,
2157 newenv = to = xmalloc (envptrs * sizeof *newenv 2155 i.e., Solaris 1 executables running under either Solaris 1 or Solaris 2.
2158 + (tzstring ? strlen (tzstring) + 4 : 0)); 2156 Their values shouldn't matter in non-buggy implementations.
2157 We don't use string literals for these strings,
2158 since if a string in the environment is in readonly
2159 storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
2160 See Sun bugs 1113095 and 1114114, ``Timezone routines
2161 improperly modify environment''. */
2162
2163 static char set_time_zone_rule_tz[][sizeof "TZ=GMT+0"]
2164 = { "TZ=GMT+0", "TZ=GMT+1" };
2165
2166 /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
2167 "US/Pacific" that loads a tz file, then changes to a value like
2168 "XXX0" that does not load a tz file, and then changes back to
2169 its original value, the last change is (incorrectly) ignored.
2170 Also, if TZ changes twice in succession to values that do
2171 not load a tz file, tzset can dump core (see Sun bug#1225179).
2172 The following code works around these bugs. */
2159 2173
2160 /* Add TZSTRING to the end of environ, as a value for TZ. */
2161 if (tzstring) 2174 if (tzstring)
2162 { 2175 {
2163 char *t = (char *) (to + envptrs); 2176 /* Temporarily set TZ to a value that loads a tz file
2164 strcpy (t, "TZ="); 2177 and that differs from tzstring. */
2165 strcat (t, tzstring); 2178 bool eq0 = strcmp (tzstring, set_time_zone_rule_tz[0] + tzeqlen) == 0;
2166 *to++ = t; 2179 xputenv (set_time_zone_rule_tz[eq0]);
2180 }
2181 else
2182 {
2183 /* The implied tzstring is unknown, so temporarily set TZ to
2184 two different values that each load a tz file. */
2185 xputenv (set_time_zone_rule_tz[0]);
2186 tzset ();
2187 xputenv (set_time_zone_rule_tz[1]);
2167 } 2188 }
2189 tzset ();
2190 tzvalbuf_in_environ = 0;
2191#endif
2168 2192
2169 /* Copy the old environ vector elements into NEWENV, 2193 if (!tzstring)
2170 but don't copy the TZ variable. 2194 {
2171 So we have only one definition of TZ, which came from TZSTRING. */ 2195 unsetenv ("TZ");
2172 for (from = environ; *from; from++) 2196 tzvalbuf_in_environ = 0;
2173 if (strncmp (*from, "TZ=", 3) != 0) 2197 }
2174 *to++ = *from; 2198 else
2175 *to = 0; 2199 {
2200 ptrdiff_t tzstringlen = strlen (tzstring);
2176 2201
2177 environ = newenv; 2202 if (tzvalbufsize <= tzeqlen + tzstringlen)
2203 {
2204 unsetenv ("TZ");
2205 tzvalbuf_in_environ = 0;
2206 tzvalbuf = xpalloc (tzvalbuf, &tzvalbufsize,
2207 tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1);
2208 memcpy (tzvalbuf, "TZ=", tzeqlen);
2209 }
2178 2210
2179 /* If we do have a TZSTRING, NEWENV points to the vector slot where 2211 strcpy (tzvalbuf + tzeqlen, tzstring);
2180 the TZ variable is stored. If we do not have a TZSTRING,
2181 TO points to the vector slot which has the terminating null. */
2182 2212
2183#ifdef LOCALTIME_CACHE 2213 if (!tzvalbuf_in_environ)
2184 { 2214 {
2185 /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like 2215 xputenv (tzvalbuf);
2186 "US/Pacific" that loads a tz file, then changes to a value like 2216 tzvalbuf_in_environ = 1;
2187 "XXX0" that does not load a tz file, and then changes back to 2217 }
2188 its original value, the last change is (incorrectly) ignored. 2218 }
2189 Also, if TZ changes twice in succession to values that do
2190 not load a tz file, tzset can dump core (see Sun bug#1225179).
2191 The following code works around these bugs. */
2192
2193 if (tzstring)
2194 {
2195 /* Temporarily set TZ to a value that loads a tz file
2196 and that differs from tzstring. */
2197 char *tz = *newenv;
2198 *newenv = (strcmp (tzstring, set_time_zone_rule_tz1 + 3) == 0
2199 ? set_time_zone_rule_tz2 : set_time_zone_rule_tz1);
2200 tzset ();
2201 *newenv = tz;
2202 }
2203 else
2204 {
2205 /* The implied tzstring is unknown, so temporarily set TZ to
2206 two different values that each load a tz file. */
2207 *to = set_time_zone_rule_tz1;
2208 to[1] = 0;
2209 tzset ();
2210 *to = set_time_zone_rule_tz2;
2211 tzset ();
2212 *to = 0;
2213 }
2214
2215 /* Now TZ has the desired value, and tzset can be invoked safely. */
2216 }
2217 2219
2220#ifdef LOCALTIME_CACHE
2218 tzset (); 2221 tzset ();
2219#endif 2222#endif
2220} 2223}
@@ -2359,8 +2362,8 @@ usage: (insert-before-markers-and-inherit &rest ARGS) */)
2359 2362
2360DEFUN ("insert-char", Finsert_char, Sinsert_char, 1, 3, 2363DEFUN ("insert-char", Finsert_char, Sinsert_char, 1, 3,
2361 "(list (read-char-by-name \"Insert character (Unicode name or hex): \")\ 2364 "(list (read-char-by-name \"Insert character (Unicode name or hex): \")\
2362 (prefix-numeric-value current-prefix-arg)\ 2365 (prefix-numeric-value current-prefix-arg)\
2363 t))", 2366 t))",
2364 doc: /* Insert COUNT copies of CHARACTER. 2367 doc: /* Insert COUNT copies of CHARACTER.
2365Interactively, prompt for CHARACTER. You can specify CHARACTER in one 2368Interactively, prompt for CHARACTER. You can specify CHARACTER in one
2366of these ways: 2369of these ways:
@@ -2497,7 +2500,7 @@ make_buffer_string_both (ptrdiff_t start, ptrdiff_t start_byte,
2497 Lisp_Object result, tem, tem1; 2500 Lisp_Object result, tem, tem1;
2498 2501
2499 if (start < GPT && GPT < end) 2502 if (start < GPT && GPT < end)
2500 move_gap (start); 2503 move_gap_both (start, start_byte);
2501 2504
2502 if (! NILP (BVAR (current_buffer, enable_multibyte_characters))) 2505 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
2503 result = make_uninit_multibyte_string (end - start, end_byte - start_byte); 2506 result = make_uninit_multibyte_string (end - start, end_byte - start_byte);
@@ -2595,7 +2598,7 @@ If narrowing is in effect, this function returns only the visible part
2595of the buffer. */) 2598of the buffer. */)
2596 (void) 2599 (void)
2597{ 2600{
2598 return make_buffer_string (BEGV, ZV, 1); 2601 return make_buffer_string_both (BEGV, BEGV_BYTE, ZV, ZV_BYTE, 1);
2599} 2602}
2600 2603
2601DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring, 2604DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
@@ -2650,10 +2653,10 @@ They default to the values of (point-min) and (point-max) in BUFFER. */)
2650DEFUN ("compare-buffer-substrings", Fcompare_buffer_substrings, Scompare_buffer_substrings, 2653DEFUN ("compare-buffer-substrings", Fcompare_buffer_substrings, Scompare_buffer_substrings,
2651 6, 6, 0, 2654 6, 6, 0,
2652 doc: /* Compare two substrings of two buffers; return result as number. 2655 doc: /* Compare two substrings of two buffers; return result as number.
2653the value is -N if first string is less after N-1 chars, 2656Return -N if first string is less after N-1 chars, +N if first string is
2654+N if first string is greater after N-1 chars, or 0 if strings match. 2657greater after N-1 chars, or 0 if strings match. Each substring is
2655Each substring is represented as three arguments: BUFFER, START and END. 2658represented as three arguments: BUFFER, START and END. That makes six
2656That makes six args in all, three for each substring. 2659args in all, three for each substring.
2657 2660
2658The value of `case-fold-search' in the current buffer 2661The value of `case-fold-search' in the current buffer
2659determines whether case is significant or ignored. */) 2662determines whether case is significant or ignored. */)
@@ -2929,7 +2932,7 @@ Both characters must have the same length of multi-byte form. */)
2929 else if (!changed) 2932 else if (!changed)
2930 { 2933 {
2931 changed = -1; 2934 changed = -1;
2932 modify_region (current_buffer, pos, XINT (end), 0); 2935 modify_region_1 (pos, XINT (end), false);
2933 2936
2934 if (! NILP (noundo)) 2937 if (! NILP (noundo))
2935 { 2938 {
@@ -3105,7 +3108,7 @@ It returns the number of characters changed. */)
3105 pos = XINT (start); 3108 pos = XINT (start);
3106 pos_byte = CHAR_TO_BYTE (pos); 3109 pos_byte = CHAR_TO_BYTE (pos);
3107 end_pos = XINT (end); 3110 end_pos = XINT (end);
3108 modify_region (current_buffer, pos, end_pos, 0); 3111 modify_region_1 (pos, end_pos, false);
3109 3112
3110 cnt = 0; 3113 cnt = 0;
3111 for (; pos < end_pos; ) 3114 for (; pos < end_pos; )
@@ -3426,12 +3429,6 @@ usage: (save-restriction &rest BODY) */)
3426 return unbind_to (count, val); 3429 return unbind_to (count, val);
3427} 3430}
3428 3431
3429/* Buffer for the most recent text displayed by Fmessage_box. */
3430static char *message_text;
3431
3432/* Allocated length of that buffer. */
3433static ptrdiff_t message_length;
3434
3435DEFUN ("message", Fmessage, Smessage, 1, MANY, 0, 3432DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
3436 doc: /* Display a message at the bottom of the screen. 3433 doc: /* Display a message at the bottom of the screen.
3437The message also goes into the `*Messages*' buffer, if `message-log-max' 3434The message also goes into the `*Messages*' buffer, if `message-log-max'
@@ -3455,14 +3452,14 @@ usage: (message FORMAT-STRING &rest ARGS) */)
3455 || (STRINGP (args[0]) 3452 || (STRINGP (args[0])
3456 && SBYTES (args[0]) == 0)) 3453 && SBYTES (args[0]) == 0))
3457 { 3454 {
3458 message (0); 3455 message1 (0);
3459 return args[0]; 3456 return args[0];
3460 } 3457 }
3461 else 3458 else
3462 { 3459 {
3463 register Lisp_Object val; 3460 register Lisp_Object val;
3464 val = Fformat (nargs, args); 3461 val = Fformat (nargs, args);
3465 message3 (val, SBYTES (val), STRING_MULTIBYTE (val)); 3462 message3 (val);
3466 return val; 3463 return val;
3467 } 3464 }
3468} 3465}
@@ -3481,13 +3478,12 @@ usage: (message-box FORMAT-STRING &rest ARGS) */)
3481{ 3478{
3482 if (NILP (args[0])) 3479 if (NILP (args[0]))
3483 { 3480 {
3484 message (0); 3481 message1 (0);
3485 return Qnil; 3482 return Qnil;
3486 } 3483 }
3487 else 3484 else
3488 { 3485 {
3489 register Lisp_Object val; 3486 Lisp_Object val = Fformat (nargs, args);
3490 val = Fformat (nargs, args);
3491#ifdef HAVE_MENUS 3487#ifdef HAVE_MENUS
3492 /* The MS-DOS frames support popup menus even though they are 3488 /* The MS-DOS frames support popup menus even though they are
3493 not FRAME_WINDOW_P. */ 3489 not FRAME_WINDOW_P. */
@@ -3504,16 +3500,7 @@ usage: (message-box FORMAT-STRING &rest ARGS) */)
3504 return val; 3500 return val;
3505 } 3501 }
3506#endif /* HAVE_MENUS */ 3502#endif /* HAVE_MENUS */
3507 /* Copy the data so that it won't move when we GC. */ 3503 message3 (val);
3508 if (SBYTES (val) > message_length)
3509 {
3510 ptrdiff_t new_length = SBYTES (val) + 80;
3511 message_text = xrealloc (message_text, new_length);
3512 message_length = new_length;
3513 }
3514 memcpy (message_text, SDATA (val), SBYTES (val));
3515 message2 (message_text, SBYTES (val),
3516 STRING_MULTIBYTE (val));
3517 return val; 3504 return val;
3518 } 3505 }
3519} 3506}
@@ -3971,7 +3958,7 @@ usage: (format STRING &rest OBJECTS) */)
3971 trailing "d"). */ 3958 trailing "d"). */
3972 pMlen = sizeof pMd - 2 3959 pMlen = sizeof pMd - 2
3973 }; 3960 };
3974 verify (0 < USEFUL_PRECISION_MAX); 3961 verify (USEFUL_PRECISION_MAX > 0);
3975 3962
3976 int prec; 3963 int prec;
3977 ptrdiff_t padding, sprintf_bytes; 3964 ptrdiff_t padding, sprintf_bytes;
@@ -4249,12 +4236,15 @@ usage: (format STRING &rest OBJECTS) */)
4249 { 4236 {
4250 buf = xmalloc (bufsize); 4237 buf = xmalloc (bufsize);
4251 sa_must_free = 1; 4238 sa_must_free = 1;
4252 buf_save_value = make_save_value (buf, 0); 4239 buf_save_value = make_save_pointer (buf);
4253 record_unwind_protect (safe_alloca_unwind, buf_save_value); 4240 record_unwind_protect (safe_alloca_unwind, buf_save_value);
4254 memcpy (buf, initial_buffer, used); 4241 memcpy (buf, initial_buffer, used);
4255 } 4242 }
4256 else 4243 else
4257 XSAVE_VALUE (buf_save_value)->pointer = buf = xrealloc (buf, bufsize); 4244 {
4245 buf = xrealloc (buf, bufsize);
4246 set_save_pointer (buf_save_value, 0, buf);
4247 }
4258 4248
4259 p = buf + used; 4249 p = buf + used;
4260 } 4250 }
@@ -4519,7 +4509,7 @@ Transposing beyond buffer boundaries is an error. */)
4519 (Lisp_Object startr1, Lisp_Object endr1, Lisp_Object startr2, Lisp_Object endr2, Lisp_Object leave_markers) 4509 (Lisp_Object startr1, Lisp_Object endr1, Lisp_Object startr2, Lisp_Object endr2, Lisp_Object leave_markers)
4520{ 4510{
4521 register ptrdiff_t start1, end1, start2, end2; 4511 register ptrdiff_t start1, end1, start2, end2;
4522 ptrdiff_t start1_byte, start2_byte, len1_byte, len2_byte; 4512 ptrdiff_t start1_byte, start2_byte, len1_byte, len2_byte, end2_byte;
4523 ptrdiff_t gap, len1, len_mid, len2; 4513 ptrdiff_t gap, len1, len_mid, len2;
4524 unsigned char *start1_addr, *start2_addr, *temp; 4514 unsigned char *start1_addr, *start2_addr, *temp;
4525 4515
@@ -4580,20 +4570,22 @@ Transposing beyond buffer boundaries is an error. */)
4580 the gap the minimum distance to get it out of the way, and then 4570 the gap the minimum distance to get it out of the way, and then
4581 deal with an unbroken array. */ 4571 deal with an unbroken array. */
4582 4572
4573 start1_byte = CHAR_TO_BYTE (start1);
4574 end2_byte = CHAR_TO_BYTE (end2);
4575
4583 /* Make sure the gap won't interfere, by moving it out of the text 4576 /* Make sure the gap won't interfere, by moving it out of the text
4584 we will operate on. */ 4577 we will operate on. */
4585 if (start1 < gap && gap < end2) 4578 if (start1 < gap && gap < end2)
4586 { 4579 {
4587 if (gap - start1 < end2 - gap) 4580 if (gap - start1 < end2 - gap)
4588 move_gap (start1); 4581 move_gap_both (start1, start1_byte);
4589 else 4582 else
4590 move_gap (end2); 4583 move_gap_both (end2, end2_byte);
4591 } 4584 }
4592 4585
4593 start1_byte = CHAR_TO_BYTE (start1);
4594 start2_byte = CHAR_TO_BYTE (start2); 4586 start2_byte = CHAR_TO_BYTE (start2);
4595 len1_byte = CHAR_TO_BYTE (end1) - start1_byte; 4587 len1_byte = CHAR_TO_BYTE (end1) - start1_byte;
4596 len2_byte = CHAR_TO_BYTE (end2) - start2_byte; 4588 len2_byte = end2_byte - start2_byte;
4597 4589
4598#ifdef BYTE_COMBINING_DEBUG 4590#ifdef BYTE_COMBINING_DEBUG
4599 if (end1 == start2) 4591 if (end1 == start2)
@@ -4629,7 +4621,7 @@ Transposing beyond buffer boundaries is an error. */)
4629 4621
4630 if (end1 == start2) /* adjacent regions */ 4622 if (end1 == start2) /* adjacent regions */
4631 { 4623 {
4632 modify_region (current_buffer, start1, end2, 0); 4624 modify_region_1 (start1, end2, false);
4633 record_change (start1, len1 + len2); 4625 record_change (start1, len1 + len2);
4634 4626
4635 tmp_interval1 = copy_intervals (cur_intv, start1, len1); 4627 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
@@ -4688,8 +4680,8 @@ Transposing beyond buffer boundaries is an error. */)
4688 { 4680 {
4689 USE_SAFE_ALLOCA; 4681 USE_SAFE_ALLOCA;
4690 4682
4691 modify_region (current_buffer, start1, end1, 0); 4683 modify_region_1 (start1, end1, false);
4692 modify_region (current_buffer, start2, end2, 0); 4684 modify_region_1 (start2, end2, false);
4693 record_change (start1, len1); 4685 record_change (start1, len1);
4694 record_change (start2, len2); 4686 record_change (start2, len2);
4695 tmp_interval1 = copy_intervals (cur_intv, start1, len1); 4687 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
@@ -4722,7 +4714,7 @@ Transposing beyond buffer boundaries is an error. */)
4722 { 4714 {
4723 USE_SAFE_ALLOCA; 4715 USE_SAFE_ALLOCA;
4724 4716
4725 modify_region (current_buffer, start1, end2, 0); 4717 modify_region_1 (start1, end2, false);
4726 record_change (start1, (end2 - start1)); 4718 record_change (start1, (end2 - start1));
4727 tmp_interval1 = copy_intervals (cur_intv, start1, len1); 4719 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
4728 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid); 4720 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
@@ -4755,7 +4747,7 @@ Transposing beyond buffer boundaries is an error. */)
4755 USE_SAFE_ALLOCA; 4747 USE_SAFE_ALLOCA;
4756 4748
4757 record_change (start1, (end2 - start1)); 4749 record_change (start1, (end2 - start1));
4758 modify_region (current_buffer, start1, end2, 0); 4750 modify_region_1 (start1, end2, false);
4759 4751
4760 tmp_interval1 = copy_intervals (cur_intv, start1, len1); 4752 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
4761 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid); 4753 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
@@ -4806,9 +4798,6 @@ Transposing beyond buffer boundaries is an error. */)
4806void 4798void
4807syms_of_editfns (void) 4799syms_of_editfns (void)
4808{ 4800{
4809 environbuf = 0;
4810 initial_tz = 0;
4811
4812 DEFSYM (Qbuffer_access_fontify_functions, "buffer-access-fontify-functions"); 4801 DEFSYM (Qbuffer_access_fontify_functions, "buffer-access-fontify-functions");
4813 4802
4814 DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion, 4803 DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion,
@@ -4883,12 +4872,10 @@ functions if all the text being accessed has this property. */);
4883 defsubr (&Sline_beginning_position); 4872 defsubr (&Sline_beginning_position);
4884 defsubr (&Sline_end_position); 4873 defsubr (&Sline_end_position);
4885 4874
4886/* defsubr (&Smark); */
4887/* defsubr (&Sset_mark); */
4888 defsubr (&Ssave_excursion); 4875 defsubr (&Ssave_excursion);
4889 defsubr (&Ssave_current_buffer); 4876 defsubr (&Ssave_current_buffer);
4890 4877
4891 defsubr (&Sbufsize); 4878 defsubr (&Sbuffer_size);
4892 defsubr (&Spoint_max); 4879 defsubr (&Spoint_max);
4893 defsubr (&Spoint_min); 4880 defsubr (&Spoint_min);
4894 defsubr (&Spoint_min_marker); 4881 defsubr (&Spoint_min_marker);
@@ -4917,6 +4904,8 @@ functions if all the text being accessed has this property. */);
4917 defsubr (&Suser_real_login_name); 4904 defsubr (&Suser_real_login_name);
4918 defsubr (&Suser_uid); 4905 defsubr (&Suser_uid);
4919 defsubr (&Suser_real_uid); 4906 defsubr (&Suser_real_uid);
4907 defsubr (&Sgroup_gid);
4908 defsubr (&Sgroup_real_gid);
4920 defsubr (&Suser_full_name); 4909 defsubr (&Suser_full_name);
4921 defsubr (&Semacs_pid); 4910 defsubr (&Semacs_pid);
4922 defsubr (&Scurrent_time); 4911 defsubr (&Scurrent_time);