Assume C89 or later.
[bpt/emacs.git] / src / editfns.c
CommitLineData
35692fe0 1/* Lisp functions pertaining to editing.
64c60c2f 2
acaf905b 3Copyright (C) 1985-1987, 1989, 1993-2012 Free Software Foundation, Inc.
35692fe0
JB
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
35692fe0 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
35692fe0
JB
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
35692fe0
JB
19
20
18160b98 21#include <config.h>
68c45bf0 22#include <sys/types.h>
3c14598c 23#include <stdio.h>
d7306fe6 24#include <setjmp.h>
bfb61299 25
5b9c0a1d 26#ifdef HAVE_PWD_H
35692fe0 27#include <pwd.h>
bfb61299
JB
28#endif
29
dfcf069d 30#include <unistd.h>
dfcf069d 31
3bb9abc8
ST
32#ifdef HAVE_SYS_UTSNAME_H
33#include <sys/utsname.h>
34#endif
35
b17f9379
DN
36#include "lisp.h"
37
3c14598c
EZ
38/* systime.h includes <sys/time.h> which, on some systems, is required
39 for <sys/resource.h>; thus systime.h must be included before
40 <sys/resource.h> */
41#include "systime.h"
21acf124
ST
42
43#if defined HAVE_SYS_RESOURCE_H
4211ee7d 44#include <sys/resource.h>
e0f712ba
AC
45#endif
46
409847a1 47#include <ctype.h>
37910ab2 48#include <float.h>
b8d9bd41
PE
49#include <limits.h>
50#include <intprops.h>
16c3e636 51#include <strftime.h>
37910ab2 52#include <verify.h>
409847a1 53
74d6d8c5 54#include "intervals.h"
35692fe0 55#include "buffer.h"
40fbd254 56#include "character.h"
68c45bf0 57#include "coding.h"
0ae83348 58#include "frame.h"
35692fe0 59#include "window.h"
b91834c3 60#include "blockinput.h"
35692fe0 61
d823c26b
EZ
62#ifndef USER_FULL_NAME
63#define USER_FULL_NAME pw->pw_gecos
64#endif
65
f12ef5eb 66#ifndef USE_CRT_DLL
c59b5089 67extern char **environ;
f12ef5eb
AI
68#endif
69
aac18aa4
PE
70#define TM_YEAR_BASE 1900
71
c433c134 72#ifdef WINDOWSNT
361358ea 73extern Lisp_Object w32_get_internal_run_time (void);
c433c134
JR
74#endif
75
fe31d94c 76static void time_overflow (void) NO_RETURN;
7da0b018 77static Lisp_Object format_time_string (char const *, ptrdiff_t, Lisp_Object,
7ed806a7 78 int, time_t *, struct tm *);
f57e2426 79static int tm_diff (struct tm *, struct tm *);
29cdc13e 80static void update_buffer_properties (EMACS_INT, EMACS_INT);
260e2e2a 81
955cbe7b 82static Lisp_Object Qbuffer_access_fontify_functions;
cd64ea1d 83static Lisp_Object Fuser_full_name (Lisp_Object);
e3ed8469 84
acb7cc89
GM
85/* Symbol for the text property used to mark fields. */
86
87Lisp_Object Qfield;
88
89/* A special value for Qfield properties. */
90
955cbe7b 91static Lisp_Object Qboundary;
acb7cc89
GM
92
93
35692fe0 94void
971de7fb 95init_editfns (void)
35692fe0 96{
63c5d10b 97 const char *user_name;
e7f8264d 98 register char *p;
35692fe0 99 struct passwd *pw; /* password entry for the current user */
35692fe0
JB
100 Lisp_Object tem;
101
102 /* Set up system_name even when dumping. */
ac988277 103 init_system_name ();
35692fe0
JB
104
105#ifndef CANNOT_DUMP
106 /* Don't bother with this on initial start when just dumping out */
107 if (!initialized)
108 return;
109#endif /* not CANNOT_DUMP */
110
63c5d10b 111 pw = getpwuid (getuid ());
87485d6f
MW
112#ifdef MSDOS
113 /* We let the real user name default to "root" because that's quite
114 accurate on MSDOG and because it lets Emacs find the init file.
115 (The DVX libraries override the Djgpp libraries here.) */
35b34f72 116 Vuser_real_login_name = build_string (pw ? pw->pw_name : "root");
87485d6f 117#else
35b34f72 118 Vuser_real_login_name = build_string (pw ? pw->pw_name : "unknown");
87485d6f 119#endif
35692fe0 120
52b14ac0
JB
121 /* Get the effective user name, by consulting environment variables,
122 or the effective uid if those are unset. */
63c5d10b 123 user_name = getenv ("LOGNAME");
35692fe0 124 if (!user_name)
4691c06d 125#ifdef WINDOWSNT
63c5d10b 126 user_name = getenv ("USERNAME"); /* it's USERNAME on NT */
4691c06d 127#else /* WINDOWSNT */
63c5d10b 128 user_name = getenv ("USER");
4691c06d 129#endif /* WINDOWSNT */
52b14ac0
JB
130 if (!user_name)
131 {
63c5d10b
PE
132 pw = getpwuid (geteuid ());
133 user_name = pw ? pw->pw_name : "unknown";
52b14ac0 134 }
35b34f72 135 Vuser_login_name = build_string (user_name);
35692fe0 136
52b14ac0
JB
137 /* If the user name claimed in the environment vars differs from
138 the real uid, use the claimed name to find the full name. */
35b34f72 139 tem = Fstring_equal (Vuser_login_name, Vuser_real_login_name);
5e617bc2 140 Vuser_full_name = Fuser_full_name (NILP (tem)? make_number (geteuid ())
3415b0e9 141 : Vuser_login_name);
34a7a267 142
e7f8264d 143 p = getenv ("NAME");
9d36d071
RS
144 if (p)
145 Vuser_full_name = build_string (p);
3347526c
RS
146 else if (NILP (Vuser_full_name))
147 Vuser_full_name = build_string ("unknown");
3bb9abc8
ST
148
149#ifdef HAVE_SYS_UTSNAME_H
150 {
151 struct utsname uts;
152 uname (&uts);
153 Voperating_system_release = build_string (uts.release);
154 }
155#else
156 Voperating_system_release = Qnil;
157#endif
35692fe0
JB
158}
159\f
a7ca3326 160DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
06283081
PJ
161 doc: /* Convert arg CHAR to a string containing that character.
162usage: (char-to-string CHAR) */)
5842a27b 163 (Lisp_Object character)
35692fe0 164{
13bdea59 165 int c, len;
d5c2c403 166 unsigned char str[MAX_MULTIBYTE_LENGTH];
fb8106e8 167
1b9c91ed 168 CHECK_CHARACTER (character);
13bdea59 169 c = XFASTINT (character);
35692fe0 170
13bdea59 171 len = CHAR_STRING (c, str);
e7f8264d 172 return make_string_from_bytes ((char *) str, 1, len);
35692fe0
JB
173}
174
c3bb441d 175DEFUN ("byte-to-string", Fbyte_to_string, Sbyte_to_string, 1, 1, 0,
35f1de62 176 doc: /* Convert arg BYTE to a unibyte string containing that byte. */)
5842a27b 177 (Lisp_Object byte)
c3bb441d 178{
64c60c2f 179 unsigned char b;
c3bb441d 180 CHECK_NUMBER (byte);
35f1de62
CY
181 if (XINT (byte) < 0 || XINT (byte) > 255)
182 error ("Invalid byte");
64c60c2f 183 b = XINT (byte);
e7f8264d 184 return make_string_from_bytes ((char *) &b, 1, 1);
c3bb441d
SM
185}
186
35692fe0 187DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0,
da4adb04 188 doc: /* Return the first character in STRING. */)
5842a27b 189 (register Lisp_Object string)
35692fe0
JB
190{
191 register Lisp_Object val;
b7826503 192 CHECK_STRING (string);
4e491f8d 193 if (SCHARS (string))
d9d851ea
KH
194 {
195 if (STRING_MULTIBYTE (string))
62a6e103 196 XSETFASTINT (val, STRING_CHAR (SDATA (string)));
d9d851ea 197 else
4e491f8d 198 XSETFASTINT (val, SREF (string, 0));
d9d851ea 199 }
35692fe0 200 else
55561c63 201 XSETFASTINT (val, 0);
35692fe0
JB
202 return val;
203}
204\f
205static Lisp_Object
29cdc13e 206buildmark (EMACS_INT charpos, EMACS_INT bytepos)
35692fe0
JB
207{
208 register Lisp_Object mark;
209 mark = Fmake_marker ();
ec1c14f6 210 set_marker_both (mark, Qnil, charpos, bytepos);
35692fe0
JB
211 return mark;
212}
213
a7ca3326 214DEFUN ("point", Fpoint, Spoint, 0, 0, 0,
7ee72033
MB
215 doc: /* Return value of point, as an integer.
216Beginning of buffer is position (point-min). */)
5842a27b 217 (void)
35692fe0
JB
218{
219 Lisp_Object temp;
6ec8bbd2 220 XSETFASTINT (temp, PT);
35692fe0
JB
221 return temp;
222}
223
a7ca3326 224DEFUN ("point-marker", Fpoint_marker, Spoint_marker, 0, 0, 0,
7ee72033 225 doc: /* Return value of point, as a marker object. */)
5842a27b 226 (void)
35692fe0 227{
ec1c14f6 228 return buildmark (PT, PT_BYTE);
35692fe0
JB
229}
230
fe3537c3 231EMACS_INT
29cdc13e 232clip_to_bounds (EMACS_INT lower, EMACS_INT num, EMACS_INT upper)
35692fe0
JB
233{
234 if (num < lower)
235 return lower;
236 else if (num > upper)
237 return upper;
238 else
239 return num;
240}
241
a7ca3326 242DEFUN ("goto-char", Fgoto_char, Sgoto_char, 1, 1, "NGoto char: ",
7ee72033 243 doc: /* Set point to POSITION, a number or marker.
8696b557
EZ
244Beginning of buffer is position (point-min), end is (point-max).
245
246The return value is POSITION. */)
5842a27b 247 (register Lisp_Object position)
35692fe0 248{
29cdc13e 249 EMACS_INT pos;
fb8106e8 250
72ef82ec
RS
251 if (MARKERP (position)
252 && current_buffer == XMARKER (position)->buffer)
ec1c14f6
RS
253 {
254 pos = marker_position (position);
255 if (pos < BEGV)
256 SET_PT_BOTH (BEGV, BEGV_BYTE);
257 else if (pos > ZV)
258 SET_PT_BOTH (ZV, ZV_BYTE);
259 else
260 SET_PT_BOTH (pos, marker_byte_position (position));
261
262 return position;
263 }
264
b7826503 265 CHECK_NUMBER_COERCE_MARKER (position);
35692fe0 266
fb8106e8 267 pos = clip_to_bounds (BEGV, XINT (position), ZV);
fb8106e8 268 SET_PT (pos);
2591ec64 269 return position;
35692fe0
JB
270}
271
acb7cc89
GM
272
273/* Return the start or end position of the region.
274 BEGINNINGP non-zero means return the start.
275 If there is no region active, signal an error. */
276
35692fe0 277static Lisp_Object
971de7fb 278region_limit (int beginningp)
35692fe0 279{
acb7cc89 280 Lisp_Object m;
177c0ea7 281
acb7cc89
GM
282 if (!NILP (Vtransient_mark_mode)
283 && NILP (Vmark_even_if_inactive)
4b4deea2 284 && NILP (BVAR (current_buffer, mark_active)))
8a0ff744 285 xsignal0 (Qmark_inactive);
177c0ea7 286
4b4deea2 287 m = Fmarker_position (BVAR (current_buffer, mark));
acb7cc89 288 if (NILP (m))
7b5ad687 289 error ("The mark is not set now, so there is no region");
177c0ea7 290
f555f8cf 291 if ((PT < XFASTINT (m)) == (beginningp != 0))
acb7cc89
GM
292 m = make_number (PT);
293 return m;
35692fe0
JB
294}
295
296DEFUN ("region-beginning", Fregion_beginning, Sregion_beginning, 0, 0, 0,
7b0815ba 297 doc: /* Return the integer value of point or mark, whichever is smaller. */)
5842a27b 298 (void)
35692fe0 299{
acb7cc89 300 return region_limit (1);
35692fe0
JB
301}
302
303DEFUN ("region-end", Fregion_end, Sregion_end, 0, 0, 0,
7b0815ba 304 doc: /* Return the integer value of point or mark, whichever is larger. */)
5842a27b 305 (void)
35692fe0 306{
acb7cc89 307 return region_limit (0);
35692fe0
JB
308}
309
35692fe0 310DEFUN ("mark-marker", Fmark_marker, Smark_marker, 0, 0, 0,
7ee72033 311 doc: /* Return this buffer's mark, as a marker object.
a1f17501 312Watch out! Moving this marker changes the mark position.
7ee72033 313If you set the marker not to point anywhere, the buffer will have no mark. */)
5842a27b 314 (void)
35692fe0 315{
4b4deea2 316 return BVAR (current_buffer, mark);
35692fe0 317}
acb7cc89 318
c9ed721d 319\f
58401a34
SM
320/* Find all the overlays in the current buffer that touch position POS.
321 Return the number found, and store them in a vector in VEC
322 of length LEN. */
323
b081724f
PE
324static ptrdiff_t
325overlays_around (EMACS_INT pos, Lisp_Object *vec, ptrdiff_t len)
58401a34 326{
88006f77
SM
327 Lisp_Object overlay, start, end;
328 struct Lisp_Overlay *tail;
29cdc13e 329 EMACS_INT startpos, endpos;
b081724f 330 ptrdiff_t idx = 0;
58401a34 331
88006f77 332 for (tail = current_buffer->overlays_before; tail; tail = tail->next)
58401a34 333 {
88006f77 334 XSETMISC (overlay, tail);
58401a34
SM
335
336 end = OVERLAY_END (overlay);
337 endpos = OVERLAY_POSITION (end);
338 if (endpos < pos)
339 break;
340 start = OVERLAY_START (overlay);
341 startpos = OVERLAY_POSITION (start);
342 if (startpos <= pos)
343 {
344 if (idx < len)
345 vec[idx] = overlay;
346 /* Keep counting overlays even if we can't return them all. */
347 idx++;
348 }
349 }
350
88006f77 351 for (tail = current_buffer->overlays_after; tail; tail = tail->next)
58401a34 352 {
88006f77 353 XSETMISC (overlay, tail);
58401a34
SM
354
355 start = OVERLAY_START (overlay);
356 startpos = OVERLAY_POSITION (start);
357 if (pos < startpos)
358 break;
359 end = OVERLAY_END (overlay);
360 endpos = OVERLAY_POSITION (end);
361 if (pos <= endpos)
362 {
363 if (idx < len)
364 vec[idx] = overlay;
365 idx++;
366 }
367 }
368
369 return idx;
370}
371
372/* Return the value of property PROP, in OBJECT at POSITION.
373 It's the value of PROP that a char inserted at POSITION would get.
374 OBJECT is optional and defaults to the current buffer.
375 If OBJECT is a buffer, then overlay properties are considered as well as
376 text properties.
377 If OBJECT is a window, then that window's buffer is used, but
378 window-specific overlays are considered only if they are associated
379 with OBJECT. */
538f9462 380Lisp_Object
971de7fb 381get_pos_property (Lisp_Object position, register Lisp_Object prop, Lisp_Object object)
58401a34 382{
58401a34
SM
383 CHECK_NUMBER_COERCE_MARKER (position);
384
385 if (NILP (object))
386 XSETBUFFER (object, current_buffer);
dfe6cbf8
SM
387 else if (WINDOWP (object))
388 object = XWINDOW (object)->buffer;
389
390 if (!BUFFERP (object))
391 /* pos-property only makes sense in buffers right now, since strings
392 have no overlays and no notion of insertion for which stickiness
393 could be obeyed. */
394 return Fget_text_property (position, prop, object);
395 else
58401a34 396 {
29cdc13e 397 EMACS_INT posn = XINT (position);
b081724f 398 ptrdiff_t noverlays;
58401a34
SM
399 Lisp_Object *overlay_vec, tem;
400 struct buffer *obuf = current_buffer;
401
402 set_buffer_temp (XBUFFER (object));
403
404 /* First try with room for 40 overlays. */
405 noverlays = 40;
406 overlay_vec = (Lisp_Object *) alloca (noverlays * sizeof (Lisp_Object));
407 noverlays = overlays_around (posn, overlay_vec, noverlays);
408
409 /* If there are more than 40,
410 make enough space for all, and try again. */
411 if (noverlays > 40)
412 {
413 overlay_vec = (Lisp_Object *) alloca (noverlays * sizeof (Lisp_Object));
414 noverlays = overlays_around (posn, overlay_vec, noverlays);
415 }
416 noverlays = sort_overlays (overlay_vec, noverlays, NULL);
417
418 set_buffer_temp (obuf);
419
420 /* Now check the overlays in order of decreasing priority. */
421 while (--noverlays >= 0)
422 {
423 Lisp_Object ol = overlay_vec[noverlays];
424 tem = Foverlay_get (ol, prop);
425 if (!NILP (tem))
426 {
427 /* Check the overlay is indeed active at point. */
428 Lisp_Object start = OVERLAY_START (ol), finish = OVERLAY_END (ol);
429 if ((OVERLAY_POSITION (start) == posn
430 && XMARKER (start)->insertion_type == 1)
431 || (OVERLAY_POSITION (finish) == posn
432 && XMARKER (finish)->insertion_type == 0))
433 ; /* The overlay will not cover a char inserted at point. */
434 else
435 {
436 return tem;
437 }
438 }
439 }
177c0ea7 440
7a6a86ad 441 { /* Now check the text properties. */
dfe6cbf8
SM
442 int stickiness = text_property_stickiness (prop, position, object);
443 if (stickiness > 0)
444 return Fget_text_property (position, prop, object);
445 else if (stickiness < 0
446 && XINT (position) > BUF_BEGV (XBUFFER (object)))
447 return Fget_text_property (make_number (XINT (position) - 1),
448 prop, object);
449 else
450 return Qnil;
451 }
58401a34 452 }
58401a34
SM
453}
454
a3caef99 455/* Find the field surrounding POS in *BEG and *END. If POS is nil,
59062dce 456 the value of point is used instead. If BEG or END is null,
acb7cc89 457 means don't store the beginning or end of the field.
a3caef99 458
9ac741c5
MB
459 BEG_LIMIT and END_LIMIT serve to limit the ranged of the returned
460 results; they do not effect boundary behavior.
461
a3caef99 462 If MERGE_AT_BOUNDARY is nonzero, then if POS is at the very first
ee547125
MB
463 position of a field, then the beginning of the previous field is
464 returned instead of the beginning of POS's field (since the end of a
465 field is actually also the beginning of the next input field, this
466 behavior is sometimes useful). Additionally in the MERGE_AT_BOUNDARY
467 true case, if two fields are separated by a field with the special
468 value `boundary', and POS lies within it, then the two separated
469 fields are considered to be adjacent, and POS between them, when
470 finding the beginning and ending of the "merged" field.
a3caef99
RS
471
472 Either BEG or END may be 0, in which case the corresponding value
473 is not stored. */
474
acb7cc89 475static void
413d18e7
EZ
476find_field (Lisp_Object pos, Lisp_Object merge_at_boundary,
477 Lisp_Object beg_limit,
478 EMACS_INT *beg, Lisp_Object end_limit, EMACS_INT *end)
0daf6e8d 479{
ee547125
MB
480 /* Fields right before and after the point. */
481 Lisp_Object before_field, after_field;
a3caef99
RS
482 /* 1 if POS counts as the start of a field. */
483 int at_field_start = 0;
484 /* 1 if POS counts as the end of a field. */
485 int at_field_end = 0;
ee547125 486
0daf6e8d
GM
487 if (NILP (pos))
488 XSETFASTINT (pos, PT);
489 else
b7826503 490 CHECK_NUMBER_COERCE_MARKER (pos);
0daf6e8d 491
acb7cc89 492 after_field
58401a34 493 = get_char_property_and_overlay (pos, Qfield, Qnil, NULL);
acb7cc89
GM
494 before_field
495 = (XFASTINT (pos) > BEGV
7ae1c032 496 ? get_char_property_and_overlay (make_number (XINT (pos) - 1),
58401a34 497 Qfield, Qnil, NULL)
e477bb04
KL
498 /* Using nil here would be a more obvious choice, but it would
499 fail when the buffer starts with a non-sticky field. */
500 : after_field);
ee547125
MB
501
502 /* See if we need to handle the case where MERGE_AT_BOUNDARY is nil
503 and POS is at beginning of a field, which can also be interpreted
504 as the end of the previous field. Note that the case where if
505 MERGE_AT_BOUNDARY is non-nil (see function comment) is actually the
506 more natural one; then we avoid treating the beginning of a field
507 specially. */
58401a34 508 if (NILP (merge_at_boundary))
ee547125 509 {
58401a34
SM
510 Lisp_Object field = get_pos_property (pos, Qfield, Qnil);
511 if (!EQ (field, after_field))
ee547125 512 at_field_end = 1;
58401a34
SM
513 if (!EQ (field, before_field))
514 at_field_start = 1;
2db1186a
SM
515 if (NILP (field) && at_field_start && at_field_end)
516 /* If an inserted char would have a nil field while the surrounding
517 text is non-nil, we're probably not looking at a
518 zero-length field, but instead at a non-nil field that's
519 not intended for editing (such as comint's prompts). */
520 at_field_end = at_field_start = 0;
0daf6e8d
GM
521 }
522
ee547125
MB
523 /* Note about special `boundary' fields:
524
525 Consider the case where the point (`.') is between the fields `x' and `y':
526
527 xxxx.yyyy
528
529 In this situation, if merge_at_boundary is true, we consider the
530 `x' and `y' fields as forming one big merged field, and so the end
531 of the field is the end of `y'.
532
533 However, if `x' and `y' are separated by a special `boundary' field
534 (a field with a `field' char-property of 'boundary), then we ignore
535 this special field when merging adjacent fields. Here's the same
536 situation, but with a `boundary' field between the `x' and `y' fields:
537
538 xxx.BBBByyyy
539
540 Here, if point is at the end of `x', the beginning of `y', or
541 anywhere in-between (within the `boundary' field), we merge all
542 three fields and consider the beginning as being the beginning of
543 the `x' field, and the end as being the end of the `y' field. */
544
0daf6e8d 545 if (beg)
acb7cc89
GM
546 {
547 if (at_field_start)
548 /* POS is at the edge of a field, and we should consider it as
549 the beginning of the following field. */
550 *beg = XFASTINT (pos);
551 else
552 /* Find the previous field boundary. */
553 {
58401a34 554 Lisp_Object p = pos;
acb7cc89
GM
555 if (!NILP (merge_at_boundary) && EQ (before_field, Qboundary))
556 /* Skip a `boundary' field. */
58401a34 557 p = Fprevious_single_char_property_change (p, Qfield, Qnil,
9ac741c5 558 beg_limit);
58401a34
SM
559
560 p = Fprevious_single_char_property_change (p, Qfield, Qnil,
561 beg_limit);
562 *beg = NILP (p) ? BEGV : XFASTINT (p);
acb7cc89
GM
563 }
564 }
0daf6e8d
GM
565
566 if (end)
acb7cc89
GM
567 {
568 if (at_field_end)
569 /* POS is at the edge of a field, and we should consider it as
570 the end of the previous field. */
571 *end = XFASTINT (pos);
572 else
573 /* Find the next field boundary. */
574 {
575 if (!NILP (merge_at_boundary) && EQ (after_field, Qboundary))
576 /* Skip a `boundary' field. */
9ac741c5
MB
577 pos = Fnext_single_char_property_change (pos, Qfield, Qnil,
578 end_limit);
ee547125 579
9ac741c5
MB
580 pos = Fnext_single_char_property_change (pos, Qfield, Qnil,
581 end_limit);
acb7cc89
GM
582 *end = NILP (pos) ? ZV : XFASTINT (pos);
583 }
584 }
0daf6e8d 585}
acb7cc89 586
0daf6e8d 587\f
d01f3570 588DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0,
7ee72033 589 doc: /* Delete the field surrounding POS.
a1f17501 590A field is a region of text with the same `field' property.
f554db0f 591If POS is nil, the value of point is used for POS. */)
5842a27b 592 (Lisp_Object pos)
0daf6e8d 593{
413d18e7 594 EMACS_INT beg, end;
9ac741c5 595 find_field (pos, Qnil, Qnil, &beg, Qnil, &end);
0daf6e8d
GM
596 if (beg != end)
597 del_range (beg, end);
d01f3570 598 return Qnil;
0daf6e8d
GM
599}
600
601DEFUN ("field-string", Ffield_string, Sfield_string, 0, 1, 0,
7ee72033 602 doc: /* Return the contents of the field surrounding POS as a string.
a1f17501 603A field is a region of text with the same `field' property.
f554db0f 604If POS is nil, the value of point is used for POS. */)
5842a27b 605 (Lisp_Object pos)
0daf6e8d 606{
413d18e7 607 EMACS_INT beg, end;
9ac741c5 608 find_field (pos, Qnil, Qnil, &beg, Qnil, &end);
0daf6e8d
GM
609 return make_buffer_string (beg, end, 1);
610}
611
612DEFUN ("field-string-no-properties", Ffield_string_no_properties, Sfield_string_no_properties, 0, 1, 0,
7a6a86ad 613 doc: /* Return the contents of the field around POS, without text properties.
a1f17501 614A field is a region of text with the same `field' property.
f554db0f 615If POS is nil, the value of point is used for POS. */)
5842a27b 616 (Lisp_Object pos)
0daf6e8d 617{
413d18e7 618 EMACS_INT beg, end;
9ac741c5 619 find_field (pos, Qnil, Qnil, &beg, Qnil, &end);
0daf6e8d
GM
620 return make_buffer_string (beg, end, 0);
621}
622
9ac741c5 623DEFUN ("field-beginning", Ffield_beginning, Sfield_beginning, 0, 3, 0,
7ee72033 624 doc: /* Return the beginning of the field surrounding POS.
a1f17501
PJ
625A field is a region of text with the same `field' property.
626If POS is nil, the value of point is used for POS.
627If ESCAPE-FROM-EDGE is non-nil and POS is at the beginning of its
9ac741c5
MB
628field, then the beginning of the *previous* field is returned.
629If LIMIT is non-nil, it is a buffer position; if the beginning of the field
f554db0f 630is before LIMIT, then LIMIT will be returned instead. */)
5842a27b 631 (Lisp_Object pos, Lisp_Object escape_from_edge, Lisp_Object limit)
0daf6e8d 632{
413d18e7 633 EMACS_INT beg;
9ac741c5 634 find_field (pos, escape_from_edge, limit, &beg, Qnil, 0);
0daf6e8d
GM
635 return make_number (beg);
636}
637
a7ca3326 638DEFUN ("field-end", Ffield_end, Sfield_end, 0, 3, 0,
7ee72033 639 doc: /* Return the end of the field surrounding POS.
a1f17501
PJ
640A field is a region of text with the same `field' property.
641If POS is nil, the value of point is used for POS.
642If ESCAPE-FROM-EDGE is non-nil and POS is at the end of its field,
9ac741c5
MB
643then the end of the *following* field is returned.
644If LIMIT is non-nil, it is a buffer position; if the end of the field
f554db0f 645is after LIMIT, then LIMIT will be returned instead. */)
5842a27b 646 (Lisp_Object pos, Lisp_Object escape_from_edge, Lisp_Object limit)
0daf6e8d 647{
413d18e7 648 EMACS_INT end;
9ac741c5 649 find_field (pos, escape_from_edge, Qnil, 0, limit, &end);
0daf6e8d
GM
650 return make_number (end);
651}
652
a7ca3326 653DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 5, 0,
7ee72033 654 doc: /* Return the position closest to NEW-POS that is in the same field as OLD-POS.
a1f17501 655A field is a region of text with the same `field' property.
66c5eebd
CY
656
657If NEW-POS is nil, then use the current point instead, and move point
658to the resulting constrained position, in addition to returning that
659position.
a1f17501
PJ
660
661If OLD-POS is at the boundary of two fields, then the allowable
662positions for NEW-POS depends on the value of the optional argument
663ESCAPE-FROM-EDGE: If ESCAPE-FROM-EDGE is nil, then NEW-POS is
664constrained to the field that has the same `field' char-property
665as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE
666is non-nil, NEW-POS is constrained to the union of the two adjacent
667fields. Additionally, if two fields are separated by another field with
668the special value `boundary', then any point within this special field is
669also considered to be `on the boundary'.
670
671If the optional argument ONLY-IN-LINE is non-nil and constraining
672NEW-POS would move it to a different line, NEW-POS is returned
673unconstrained. This useful for commands that move by line, like
674\\[next-line] or \\[beginning-of-line], which should generally respect field boundaries
675only in the case where they can still move to the right line.
676
677If the optional argument INHIBIT-CAPTURE-PROPERTY is non-nil, and OLD-POS has
678a non-nil property of that name, then any field boundaries are ignored.
679
7ee72033 680Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
5842a27b 681 (Lisp_Object new_pos, Lisp_Object old_pos, Lisp_Object escape_from_edge, Lisp_Object only_in_line, Lisp_Object inhibit_capture_property)
0daf6e8d
GM
682{
683 /* If non-zero, then the original point, before re-positioning. */
29cdc13e 684 EMACS_INT orig_point = 0;
d63b4018
KR
685 int fwd;
686 Lisp_Object prev_old, prev_new;
aac18aa4 687
0daf6e8d
GM
688 if (NILP (new_pos))
689 /* Use the current point, and afterwards, set it. */
690 {
691 orig_point = PT;
692 XSETFASTINT (new_pos, PT);
693 }
694
e477bb04
KL
695 CHECK_NUMBER_COERCE_MARKER (new_pos);
696 CHECK_NUMBER_COERCE_MARKER (old_pos);
697
698 fwd = (XFASTINT (new_pos) > XFASTINT (old_pos));
699
700 prev_old = make_number (XFASTINT (old_pos) - 1);
701 prev_new = make_number (XFASTINT (new_pos) - 1);
aac18aa4 702
ee5cd4db
GM
703 if (NILP (Vinhibit_field_text_motion)
704 && !EQ (new_pos, old_pos)
42ab8e36
MB
705 && (!NILP (Fget_char_property (new_pos, Qfield, Qnil))
706 || !NILP (Fget_char_property (old_pos, Qfield, Qnil))
e477bb04
KL
707 /* To recognize field boundaries, we must also look at the
708 previous positions; we could use `get_pos_property'
709 instead, but in itself that would fail inside non-sticky
710 fields (like comint prompts). */
711 || (XFASTINT (new_pos) > BEGV
42ab8e36 712 && !NILP (Fget_char_property (prev_new, Qfield, Qnil)))
e477bb04 713 || (XFASTINT (old_pos) > BEGV
42ab8e36 714 && !NILP (Fget_char_property (prev_old, Qfield, Qnil))))
ee547125 715 && (NILP (inhibit_capture_property)
e477bb04
KL
716 /* Field boundaries are again a problem; but now we must
717 decide the case exactly, so we need to call
718 `get_pos_property' as well. */
719 || (NILP (get_pos_property (old_pos, inhibit_capture_property, Qnil))
720 && (XFASTINT (old_pos) <= BEGV
42ab8e36
MB
721 || NILP (Fget_char_property (old_pos, inhibit_capture_property, Qnil))
722 || NILP (Fget_char_property (prev_old, inhibit_capture_property, Qnil))))))
2cb3aec4
KL
723 /* It is possible that NEW_POS is not within the same field as
724 OLD_POS; try to move NEW_POS so that it is. */
0daf6e8d 725 {
a53e2e89 726 EMACS_INT shortage;
0daf6e8d
GM
727 Lisp_Object field_bound;
728
0daf6e8d 729 if (fwd)
9ac741c5 730 field_bound = Ffield_end (old_pos, escape_from_edge, new_pos);
0daf6e8d 731 else
9ac741c5 732 field_bound = Ffield_beginning (old_pos, escape_from_edge, new_pos);
0daf6e8d 733
10b0f752
MB
734 if (/* See if ESCAPE_FROM_EDGE caused FIELD_BOUND to jump to the
735 other side of NEW_POS, which would mean that NEW_POS is
736 already acceptable, and it's not necessary to constrain it
737 to FIELD_BOUND. */
738 ((XFASTINT (field_bound) < XFASTINT (new_pos)) ? fwd : !fwd)
739 /* NEW_POS should be constrained, but only if either
740 ONLY_IN_LINE is nil (in which case any constraint is OK),
741 or NEW_POS and FIELD_BOUND are on the same line (in which
742 case the constraint is OK even if ONLY_IN_LINE is non-nil). */
743 && (NILP (only_in_line)
744 /* This is the ONLY_IN_LINE case, check that NEW_POS and
745 FIELD_BOUND are on the same line by seeing whether
746 there's an intervening newline or not. */
747 || (scan_buffer ('\n',
748 XFASTINT (new_pos), XFASTINT (field_bound),
749 fwd ? -1 : 1, &shortage, 1),
750 shortage != 0)))
0daf6e8d
GM
751 /* Constrain NEW_POS to FIELD_BOUND. */
752 new_pos = field_bound;
753
754 if (orig_point && XFASTINT (new_pos) != orig_point)
755 /* The NEW_POS argument was originally nil, so automatically set PT. */
756 SET_PT (XFASTINT (new_pos));
757 }
758
759 return new_pos;
760}
acb7cc89 761
0daf6e8d 762\f
a7ca3326 763DEFUN ("line-beginning-position",
6d57c318 764 Fline_beginning_position, Sline_beginning_position, 0, 1, 0,
7ee72033 765 doc: /* Return the character position of the first character on the current line.
a1f17501
PJ
766With argument N not nil or 1, move forward N - 1 lines first.
767If scan reaches end of buffer, return that position.
6d57c318 768
cd21226d
EZ
769The returned position is of the first character in the logical order,
770i.e. the one that has the smallest character position.
771
2cb3aec4
KL
772This function constrains the returned position to the current field
773unless that would be on a different line than the original,
774unconstrained result. If N is nil or 1, and a front-sticky field
775starts at point, the scan stops as soon as it starts. To ignore field
6d57c318 776boundaries bind `inhibit-field-text-motion' to t.
a1f17501 777
7ee72033 778This function does not move point. */)
5842a27b 779 (Lisp_Object n)
c9ed721d 780{
29cdc13e 781 EMACS_INT orig, orig_byte, end;
4e8f005c
CY
782 int count = SPECPDL_INDEX ();
783 specbind (Qinhibit_point_motion_hooks, Qt);
c9ed721d
RS
784
785 if (NILP (n))
786 XSETFASTINT (n, 1);
787 else
b7826503 788 CHECK_NUMBER (n);
c9ed721d
RS
789
790 orig = PT;
ec1c14f6 791 orig_byte = PT_BYTE;
c9ed721d
RS
792 Fforward_line (make_number (XINT (n) - 1));
793 end = PT;
e2dae3f2 794
ec1c14f6 795 SET_PT_BOTH (orig, orig_byte);
35692fe0 796
4e8f005c
CY
797 unbind_to (count, Qnil);
798
0daf6e8d 799 /* Return END constrained to the current input field. */
ee5cd4db
GM
800 return Fconstrain_to_field (make_number (end), make_number (orig),
801 XINT (n) != 1 ? Qt : Qnil,
ee547125 802 Qt, Qnil);
c9ed721d
RS
803}
804
a7ca3326 805DEFUN ("line-end-position", Fline_end_position, Sline_end_position, 0, 1, 0,
7ee72033 806 doc: /* Return the character position of the last character on the current line.
a1f17501
PJ
807With argument N not nil or 1, move forward N - 1 lines first.
808If scan reaches end of buffer, return that position.
6d57c318 809
cd21226d
EZ
810The returned position is of the last character in the logical order,
811i.e. the character whose buffer position is the largest one.
812
2cb3aec4
KL
813This function constrains the returned position to the current field
814unless that would be on a different line than the original,
815unconstrained result. If N is nil or 1, and a rear-sticky field ends
816at point, the scan stops as soon as it starts. To ignore field
6d57c318
MB
817boundaries bind `inhibit-field-text-motion' to t.
818
7ee72033 819This function does not move point. */)
5842a27b 820 (Lisp_Object n)
c9ed721d 821{
29cdc13e
EZ
822 EMACS_INT end_pos;
823 EMACS_INT orig = PT;
0daf6e8d 824
c9ed721d
RS
825 if (NILP (n))
826 XSETFASTINT (n, 1);
827 else
b7826503 828 CHECK_NUMBER (n);
c9ed721d 829
0daf6e8d
GM
830 end_pos = find_before_next_newline (orig, 0, XINT (n) - (XINT (n) <= 0));
831
832 /* Return END_POS constrained to the current input field. */
ee5cd4db 833 return Fconstrain_to_field (make_number (end_pos), make_number (orig),
ee547125 834 Qnil, Qt, Qnil);
c9ed721d 835}
6d57c318 836
c9ed721d 837\f
35692fe0 838Lisp_Object
971de7fb 839save_excursion_save (void)
35692fe0 840{
acb7cc89
GM
841 int visible = (XBUFFER (XWINDOW (selected_window)->buffer)
842 == current_buffer);
35692fe0
JB
843
844 return Fcons (Fpoint_marker (),
4b4deea2 845 Fcons (Fcopy_marker (BVAR (current_buffer, mark), Qnil),
9772455e 846 Fcons (visible ? Qt : Qnil,
4b4deea2 847 Fcons (BVAR (current_buffer, mark_active),
2483cf58 848 selected_window))));
35692fe0
JB
849}
850
851Lisp_Object
971de7fb 852save_excursion_restore (Lisp_Object info)
35692fe0 853{
4ad8681a
RS
854 Lisp_Object tem, tem1, omark, nmark;
855 struct gcpro gcpro1, gcpro2, gcpro3;
2483cf58 856 int visible_p;
35692fe0 857
2483cf58 858 tem = Fmarker_buffer (XCAR (info));
35692fe0
JB
859 /* If buffer being returned to is now deleted, avoid error */
860 /* Otherwise could get error here while unwinding to top level
861 and crash */
862 /* In that case, Fmarker_buffer returns nil now. */
56a98455 863 if (NILP (tem))
35692fe0 864 return Qnil;
4ad8681a
RS
865
866 omark = nmark = Qnil;
867 GCPRO3 (info, omark, nmark);
868
35692fe0 869 Fset_buffer (tem);
2483cf58
GM
870
871 /* Point marker. */
872 tem = XCAR (info);
35692fe0 873 Fgoto_char (tem);
12038f9f 874 unchain_marker (XMARKER (tem));
2483cf58
GM
875
876 /* Mark marker. */
877 info = XCDR (info);
878 tem = XCAR (info);
4b4deea2
TT
879 omark = Fmarker_position (BVAR (current_buffer, mark));
880 Fset_marker (BVAR (current_buffer, mark), tem, Fcurrent_buffer ());
03d18690 881 nmark = Fmarker_position (tem);
12038f9f 882 unchain_marker (XMARKER (tem));
2483cf58
GM
883
884 /* visible */
885 info = XCDR (info);
886 visible_p = !NILP (XCAR (info));
177c0ea7 887
ef580991
RS
888#if 0 /* We used to make the current buffer visible in the selected window
889 if that was true previously. That avoids some anomalies.
890 But it creates others, and it wasn't documented, and it is simpler
891 and cleaner never to alter the window/buffer connections. */
9772455e
RS
892 tem1 = Fcar (tem);
893 if (!NILP (tem1)
0e2c9c70 894 && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
35692fe0 895 Fswitch_to_buffer (Fcurrent_buffer (), Qnil);
ef580991 896#endif /* 0 */
9772455e 897
2483cf58
GM
898 /* Mark active */
899 info = XCDR (info);
900 tem = XCAR (info);
4b4deea2
TT
901 tem1 = BVAR (current_buffer, mark_active);
902 BVAR (current_buffer, mark_active) = tem;
2483cf58 903
dee091a3
JD
904 /* If mark is active now, and either was not active
905 or was at a different place, run the activate hook. */
906 if (! NILP (tem))
9fed2b18 907 {
dee091a3
JD
908 if (! EQ (omark, nmark))
909 {
910 tem = intern ("activate-mark-hook");
911 Frun_hooks (1, &tem);
912 }
913 }
914 /* If mark has ceased to be active, run deactivate hook. */
915 else if (! NILP (tem1))
916 {
917 tem = intern ("deactivate-mark-hook");
918 Frun_hooks (1, &tem);
9fed2b18 919 }
2483cf58
GM
920
921 /* If buffer was visible in a window, and a different window was
793cd2c8
GM
922 selected, and the old selected window is still showing this
923 buffer, restore point in that window. */
2483cf58
GM
924 tem = XCDR (info);
925 if (visible_p
926 && !EQ (tem, selected_window)
ba973f7a
GM
927 && (tem1 = XWINDOW (tem)->buffer,
928 (/* Window is live... */
929 BUFFERP (tem1)
930 /* ...and it shows the current buffer. */
931 && XBUFFER (tem1) == current_buffer)))
2483cf58
GM
932 Fset_window_point (tem, make_number (PT));
933
4ad8681a 934 UNGCPRO;
35692fe0
JB
935 return Qnil;
936}
937
938DEFUN ("save-excursion", Fsave_excursion, Ssave_excursion, 0, UNEVALLED, 0,
7ee72033 939 doc: /* Save point, mark, and current buffer; execute BODY; restore those things.
a1f17501
PJ
940Executes BODY just like `progn'.
941The values of point, mark and the current buffer are restored
942even in case of abnormal exit (throw or error).
943The state of activation of the mark is also restored.
944
945This construct does not save `deactivate-mark', and therefore
946functions that change the buffer will still cause deactivation
947of the mark at the end of the command. To prevent that, bind
33c2d29f
MB
948`deactivate-mark' with `let'.
949
7450fd36
SM
950If you only want to save the current buffer but not point nor mark,
951then just use `save-current-buffer', or even `with-current-buffer'.
952
33c2d29f 953usage: (save-excursion &rest BODY) */)
5842a27b 954 (Lisp_Object args)
35692fe0
JB
955{
956 register Lisp_Object val;
aed13378 957 int count = SPECPDL_INDEX ();
35692fe0
JB
958
959 record_unwind_protect (save_excursion_restore, save_excursion_save ());
4bc8c7d2
RS
960
961 val = Fprogn (args);
962 return unbind_to (count, val);
963}
964
965DEFUN ("save-current-buffer", Fsave_current_buffer, Ssave_current_buffer, 0, UNEVALLED, 0,
7ee72033 966 doc: /* Save the current buffer; execute BODY; restore the current buffer.
33c2d29f
MB
967Executes BODY just like `progn'.
968usage: (save-current-buffer &rest BODY) */)
5842a27b 969 (Lisp_Object args)
4bc8c7d2 970{
acb7cc89 971 Lisp_Object val;
aed13378 972 int count = SPECPDL_INDEX ();
4bc8c7d2 973
cb5e5f74 974 record_unwind_protect (set_buffer_if_live, Fcurrent_buffer ());
4bc8c7d2 975
35692fe0
JB
976 val = Fprogn (args);
977 return unbind_to (count, val);
978}
979\f
95dccf75 980DEFUN ("buffer-size", Fbufsize, Sbufsize, 0, 1, 0,
7ee72033
MB
981 doc: /* Return the number of characters in the current buffer.
982If BUFFER, return the number of characters in that buffer instead. */)
5842a27b 983 (Lisp_Object buffer)
35692fe0 984{
95dccf75
RS
985 if (NILP (buffer))
986 return make_number (Z - BEG);
02050596
RS
987 else
988 {
b7826503 989 CHECK_BUFFER (buffer);
02050596
RS
990 return make_number (BUF_Z (XBUFFER (buffer))
991 - BUF_BEG (XBUFFER (buffer)));
992 }
35692fe0
JB
993}
994
995DEFUN ("point-min", Fpoint_min, Spoint_min, 0, 0, 0,
7ee72033
MB
996 doc: /* Return the minimum permissible value of point in the current buffer.
997This is 1, unless narrowing (a buffer restriction) is in effect. */)
5842a27b 998 (void)
35692fe0
JB
999{
1000 Lisp_Object temp;
55561c63 1001 XSETFASTINT (temp, BEGV);
35692fe0
JB
1002 return temp;
1003}
1004
1005DEFUN ("point-min-marker", Fpoint_min_marker, Spoint_min_marker, 0, 0, 0,
7ee72033
MB
1006 doc: /* Return a marker to the minimum permissible value of point in this buffer.
1007This is the beginning, unless narrowing (a buffer restriction) is in effect. */)
5842a27b 1008 (void)
35692fe0 1009{
ec1c14f6 1010 return buildmark (BEGV, BEGV_BYTE);
35692fe0
JB
1011}
1012
1013DEFUN ("point-max", Fpoint_max, Spoint_max, 0, 0, 0,
7ee72033 1014 doc: /* Return the maximum permissible value of point in the current buffer.
a1f17501 1015This is (1+ (buffer-size)), unless narrowing (a buffer restriction)
7ee72033 1016is in effect, in which case it is less. */)
5842a27b 1017 (void)
35692fe0
JB
1018{
1019 Lisp_Object temp;
55561c63 1020 XSETFASTINT (temp, ZV);
35692fe0
JB
1021 return temp;
1022}
1023
a7ca3326 1024DEFUN ("point-max-marker", Fpoint_max_marker, Spoint_max_marker, 0, 0, 0,
7ee72033 1025 doc: /* Return a marker to the maximum permissible value of point in this buffer.
a1f17501 1026This is (1+ (buffer-size)), unless narrowing (a buffer restriction)
7ee72033 1027is in effect, in which case it is less. */)
5842a27b 1028 (void)
35692fe0 1029{
ec1c14f6 1030 return buildmark (ZV, ZV_BYTE);
35692fe0
JB
1031}
1032
c86212b9 1033DEFUN ("gap-position", Fgap_position, Sgap_position, 0, 0, 0,
7ee72033
MB
1034 doc: /* Return the position of the gap, in the current buffer.
1035See also `gap-size'. */)
5842a27b 1036 (void)
c86212b9
RS
1037{
1038 Lisp_Object temp;
1039 XSETFASTINT (temp, GPT);
1040 return temp;
1041}
1042
1043DEFUN ("gap-size", Fgap_size, Sgap_size, 0, 0, 0,
7ee72033
MB
1044 doc: /* Return the size of the current buffer's gap.
1045See also `gap-position'. */)
5842a27b 1046 (void)
c86212b9
RS
1047{
1048 Lisp_Object temp;
1049 XSETFASTINT (temp, GAP_SIZE);
1050 return temp;
1051}
1052
7df74da6 1053DEFUN ("position-bytes", Fposition_bytes, Sposition_bytes, 1, 1, 0,
7ee72033
MB
1054 doc: /* Return the byte position for character position POSITION.
1055If POSITION is out of range, the value is nil. */)
5842a27b 1056 (Lisp_Object position)
7df74da6 1057{
b7826503 1058 CHECK_NUMBER_COERCE_MARKER (position);
fcf9683e
KH
1059 if (XINT (position) < BEG || XINT (position) > Z)
1060 return Qnil;
fa8a5a15 1061 return make_number (CHAR_TO_BYTE (XINT (position)));
7df74da6 1062}
3ab0732d
RS
1063
1064DEFUN ("byte-to-position", Fbyte_to_position, Sbyte_to_position, 1, 1, 0,
7ee72033
MB
1065 doc: /* Return the character position for byte position BYTEPOS.
1066If BYTEPOS is out of range, the value is nil. */)
5842a27b 1067 (Lisp_Object bytepos)
3ab0732d 1068{
b7826503 1069 CHECK_NUMBER (bytepos);
fcf9683e
KH
1070 if (XINT (bytepos) < BEG_BYTE || XINT (bytepos) > Z_BYTE)
1071 return Qnil;
3ab0732d
RS
1072 return make_number (BYTE_TO_CHAR (XINT (bytepos)));
1073}
7df74da6 1074\f
a7ca3326 1075DEFUN ("following-char", Ffollowing_char, Sfollowing_char, 0, 0, 0,
7ee72033
MB
1076 doc: /* Return the character following point, as a number.
1077At the end of the buffer or accessible region, return 0. */)
5842a27b 1078 (void)
35692fe0
JB
1079{
1080 Lisp_Object temp;
6ec8bbd2 1081 if (PT >= ZV)
55561c63 1082 XSETFASTINT (temp, 0);
850a8179 1083 else
ec1c14f6 1084 XSETFASTINT (temp, FETCH_CHAR (PT_BYTE));
35692fe0
JB
1085 return temp;
1086}
1087
a7ca3326 1088DEFUN ("preceding-char", Fprevious_char, Sprevious_char, 0, 0, 0,
7ee72033
MB
1089 doc: /* Return the character preceding point, as a number.
1090At the beginning of the buffer or accessible region, return 0. */)
5842a27b 1091 (void)
35692fe0
JB
1092{
1093 Lisp_Object temp;
6ec8bbd2 1094 if (PT <= BEGV)
55561c63 1095 XSETFASTINT (temp, 0);
4b4deea2 1096 else if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
fb8106e8 1097 {
29cdc13e 1098 EMACS_INT pos = PT_BYTE;
fb8106e8
KH
1099 DEC_POS (pos);
1100 XSETFASTINT (temp, FETCH_CHAR (pos));
1101 }
35692fe0 1102 else
ec1c14f6 1103 XSETFASTINT (temp, FETCH_BYTE (PT_BYTE - 1));
35692fe0
JB
1104 return temp;
1105}
1106
a7ca3326 1107DEFUN ("bobp", Fbobp, Sbobp, 0, 0, 0,
7ee72033
MB
1108 doc: /* Return t if point is at the beginning of the buffer.
1109If the buffer is narrowed, this means the beginning of the narrowed part. */)
5842a27b 1110 (void)
35692fe0 1111{
6ec8bbd2 1112 if (PT == BEGV)
35692fe0
JB
1113 return Qt;
1114 return Qnil;
1115}
1116
a7ca3326 1117DEFUN ("eobp", Feobp, Seobp, 0, 0, 0,
7ee72033
MB
1118 doc: /* Return t if point is at the end of the buffer.
1119If the buffer is narrowed, this means the end of the narrowed part. */)
5842a27b 1120 (void)
35692fe0 1121{
6ec8bbd2 1122 if (PT == ZV)
35692fe0
JB
1123 return Qt;
1124 return Qnil;
1125}
1126
a7ca3326 1127DEFUN ("bolp", Fbolp, Sbolp, 0, 0, 0,
7ee72033 1128 doc: /* Return t if point is at the beginning of a line. */)
5842a27b 1129 (void)
35692fe0 1130{
ec1c14f6 1131 if (PT == BEGV || FETCH_BYTE (PT_BYTE - 1) == '\n')
35692fe0
JB
1132 return Qt;
1133 return Qnil;
1134}
1135
a7ca3326 1136DEFUN ("eolp", Feolp, Seolp, 0, 0, 0,
7ee72033
MB
1137 doc: /* Return t if point is at the end of a line.
1138`End of a line' includes point being at the end of the buffer. */)
5842a27b 1139 (void)
35692fe0 1140{
ec1c14f6 1141 if (PT == ZV || FETCH_BYTE (PT_BYTE) == '\n')
35692fe0
JB
1142 return Qt;
1143 return Qnil;
1144}
1145
a7ca3326 1146DEFUN ("char-after", Fchar_after, Schar_after, 0, 1, 0,
7ee72033 1147 doc: /* Return character in current buffer at position POS.
f555f8cf 1148POS is an integer or a marker and defaults to point.
7ee72033 1149If POS is out of range, the value is nil. */)
5842a27b 1150 (Lisp_Object pos)
35692fe0 1151{
29cdc13e 1152 register EMACS_INT pos_byte;
35692fe0 1153
fa1d3816 1154 if (NILP (pos))
39a4c932
RS
1155 {
1156 pos_byte = PT_BYTE;
3c52e568 1157 XSETFASTINT (pos, PT);
39a4c932
RS
1158 }
1159
1160 if (MARKERP (pos))
85cac557
RS
1161 {
1162 pos_byte = marker_byte_position (pos);
1163 if (pos_byte < BEGV_BYTE || pos_byte >= ZV_BYTE)
1164 return Qnil;
1165 }
fa1d3816
RS
1166 else
1167 {
b7826503 1168 CHECK_NUMBER_COERCE_MARKER (pos);
b98ef0dc 1169 if (XINT (pos) < BEGV || XINT (pos) >= ZV)
85cac557 1170 return Qnil;
34a7a267 1171
ec1c14f6 1172 pos_byte = CHAR_TO_BYTE (XINT (pos));
fa1d3816 1173 }
35692fe0 1174
ec1c14f6 1175 return make_number (FETCH_CHAR (pos_byte));
35692fe0 1176}
fb8106e8 1177
fa1d3816 1178DEFUN ("char-before", Fchar_before, Schar_before, 0, 1, 0,
7ee72033 1179 doc: /* Return character in current buffer preceding position POS.
f555f8cf 1180POS is an integer or a marker and defaults to point.
7ee72033 1181If POS is out of range, the value is nil. */)
5842a27b 1182 (Lisp_Object pos)
fb8106e8
KH
1183{
1184 register Lisp_Object val;
29cdc13e 1185 register EMACS_INT pos_byte;
fb8106e8 1186
fa1d3816 1187 if (NILP (pos))
39a4c932
RS
1188 {
1189 pos_byte = PT_BYTE;
3c52e568 1190 XSETFASTINT (pos, PT);
39a4c932
RS
1191 }
1192
1193 if (MARKERP (pos))
85cac557
RS
1194 {
1195 pos_byte = marker_byte_position (pos);
1196
1197 if (pos_byte <= BEGV_BYTE || pos_byte > ZV_BYTE)
1198 return Qnil;
1199 }
fa1d3816
RS
1200 else
1201 {
b7826503 1202 CHECK_NUMBER_COERCE_MARKER (pos);
fb8106e8 1203
b98ef0dc 1204 if (XINT (pos) <= BEGV || XINT (pos) > ZV)
85cac557
RS
1205 return Qnil;
1206
ec1c14f6 1207 pos_byte = CHAR_TO_BYTE (XINT (pos));
fa1d3816 1208 }
fb8106e8 1209
4b4deea2 1210 if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
fb8106e8 1211 {
ec1c14f6
RS
1212 DEC_POS (pos_byte);
1213 XSETFASTINT (val, FETCH_CHAR (pos_byte));
fb8106e8
KH
1214 }
1215 else
1216 {
ec1c14f6
RS
1217 pos_byte--;
1218 XSETFASTINT (val, FETCH_BYTE (pos_byte));
fb8106e8
KH
1219 }
1220 return val;
1221}
35692fe0 1222\f
a7ca3326 1223DEFUN ("user-login-name", Fuser_login_name, Suser_login_name, 0, 1, 0,
7ee72033 1224 doc: /* Return the name under which the user logged in, as a string.
a1f17501 1225This is based on the effective uid, not the real uid.
412f1fab 1226Also, if the environment variables LOGNAME or USER are set,
a1f17501
PJ
1227that determines the value of this function.
1228
7b1c38a4
EZ
1229If optional argument UID is an integer or a float, return the login name
1230of the user with that uid, or nil if there is no such user. */)
5842a27b 1231 (Lisp_Object uid)
35692fe0 1232{
87485d6f 1233 struct passwd *pw;
7b1c38a4 1234 uid_t id;
87485d6f 1235
f8a0e364
RS
1236 /* Set up the user name info if we didn't do it before.
1237 (That can happen if Emacs is dumpable
1238 but you decide to run `temacs -l loadup' and not dump. */
35b34f72 1239 if (INTEGERP (Vuser_login_name))
f8a0e364 1240 init_editfns ();
87485d6f
MW
1241
1242 if (NILP (uid))
35b34f72 1243 return Vuser_login_name;
87485d6f 1244
63c5d10b 1245 id = XFLOATINT (uid);
b91834c3 1246 BLOCK_INPUT;
63c5d10b 1247 pw = getpwuid (id);
b91834c3 1248 UNBLOCK_INPUT;
87485d6f 1249 return (pw ? build_string (pw->pw_name) : Qnil);
35692fe0
JB
1250}
1251
1252DEFUN ("user-real-login-name", Fuser_real_login_name, Suser_real_login_name,
deb8e082 1253 0, 0, 0,
7ee72033 1254 doc: /* Return the name of the user's real uid, as a string.
a1f17501 1255This ignores the environment variables LOGNAME and USER, so it differs from
7ee72033 1256`user-login-name' when running under `su'. */)
5842a27b 1257 (void)
35692fe0 1258{
f8a0e364
RS
1259 /* Set up the user name info if we didn't do it before.
1260 (That can happen if Emacs is dumpable
1261 but you decide to run `temacs -l loadup' and not dump. */
35b34f72 1262 if (INTEGERP (Vuser_login_name))
f8a0e364 1263 init_editfns ();
35b34f72 1264 return Vuser_real_login_name;
35692fe0
JB
1265}
1266
1267DEFUN ("user-uid", Fuser_uid, Suser_uid, 0, 0, 0,
7ee72033 1268 doc: /* Return the effective uid of Emacs.
e00553bf 1269Value is an integer or a float, depending on the value. */)
5842a27b 1270 (void)
35692fe0 1271{
3aef3c0a
EZ
1272 /* Assignment to EMACS_INT stops GCC whining about limited range of
1273 data type. */
1274 EMACS_INT euid = geteuid ();
e00553bf
EZ
1275
1276 /* Make sure we don't produce a negative UID due to signed integer
1277 overflow. */
1278 if (euid < 0)
63c5d10b 1279 return make_float (geteuid ());
3aef3c0a 1280 return make_fixnum_or_float (euid);
35692fe0
JB
1281}
1282
1283DEFUN ("user-real-uid", Fuser_real_uid, Suser_real_uid, 0, 0, 0,
7ee72033 1284 doc: /* Return the real uid of Emacs.
e00553bf 1285Value is an integer or a float, depending on the value. */)
5842a27b 1286 (void)
35692fe0 1287{
3aef3c0a
EZ
1288 /* Assignment to EMACS_INT stops GCC whining about limited range of
1289 data type. */
1290 EMACS_INT uid = getuid ();
e00553bf
EZ
1291
1292 /* Make sure we don't produce a negative UID due to signed integer
1293 overflow. */
1294 if (uid < 0)
63c5d10b 1295 return make_float (getuid ());
3aef3c0a 1296 return make_fixnum_or_float (uid);
35692fe0
JB
1297}
1298
c9ed721d 1299DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0,
7ee72033 1300 doc: /* Return the full name of the user logged in, as a string.
a1f17501
PJ
1301If the full name corresponding to Emacs's userid is not known,
1302return "unknown".
1303
1304If optional argument UID is an integer or float, return the full name
1305of the user with that uid, or nil if there is no such user.
1306If UID is a string, return the full name of the user with that login
7ee72033 1307name, or nil if there is no such user. */)
5842a27b 1308 (Lisp_Object uid)
35692fe0 1309{
c9ed721d 1310 struct passwd *pw;
e7f8264d 1311 register char *p, *q;
3415b0e9 1312 Lisp_Object full;
c9ed721d
RS
1313
1314 if (NILP (uid))
34a7a267 1315 return Vuser_full_name;
3415b0e9 1316 else if (NUMBERP (uid))
b91834c3 1317 {
63c5d10b 1318 uid_t u = XFLOATINT (uid);
b91834c3 1319 BLOCK_INPUT;
63c5d10b 1320 pw = getpwuid (u);
b91834c3
YM
1321 UNBLOCK_INPUT;
1322 }
34a7a267 1323 else if (STRINGP (uid))
b91834c3
YM
1324 {
1325 BLOCK_INPUT;
63c5d10b 1326 pw = getpwnam (SSDATA (uid));
b91834c3
YM
1327 UNBLOCK_INPUT;
1328 }
3415b0e9
RS
1329 else
1330 error ("Invalid UID specification");
c9ed721d 1331
3415b0e9 1332 if (!pw)
3347526c 1333 return Qnil;
34a7a267 1334
e7f8264d 1335 p = USER_FULL_NAME;
3415b0e9 1336 /* Chop off everything after the first comma. */
e7f8264d 1337 q = strchr (p, ',');
3415b0e9 1338 full = make_string (p, q ? q - p : strlen (p));
34a7a267 1339
3415b0e9 1340#ifdef AMPERSAND_FULL_NAME
e7f8264d
PE
1341 p = SSDATA (full);
1342 q = strchr (p, '&');
3415b0e9
RS
1343 /* Substitute the login name for the &, upcasing the first character. */
1344 if (q)
1345 {
e7f8264d 1346 register char *r;
3415b0e9
RS
1347 Lisp_Object login;
1348
1349 login = Fuser_login_name (make_number (pw->pw_uid));
e7f8264d 1350 r = (char *) alloca (strlen (p) + SCHARS (login) + 1);
72af86bd 1351 memcpy (r, p, q - p);
3415b0e9 1352 r[q - p] = 0;
42a5b22f 1353 strcat (r, SSDATA (login));
5da9919f 1354 r[q - p] = upcase ((unsigned char) r[q - p]);
3415b0e9
RS
1355 strcat (r, q + 1);
1356 full = build_string (r);
1357 }
1358#endif /* AMPERSAND_FULL_NAME */
1359
1360 return full;
35692fe0
JB
1361}
1362
a7ca3326 1363DEFUN ("system-name", Fsystem_name, Ssystem_name, 0, 0, 0,
1a7e0117 1364 doc: /* Return the host name of the machine you are running on, as a string. */)
5842a27b 1365 (void)
35692fe0
JB
1366{
1367 return Vsystem_name;
1368}
1369
8ea90aa3 1370const char *
971de7fb 1371get_system_name (void)
ac988277 1372{
3d976a9a 1373 if (STRINGP (Vsystem_name))
51b59d79 1374 return SSDATA (Vsystem_name);
3d976a9a
RS
1375 else
1376 return "";
ac988277
KH
1377}
1378
7fd233b3 1379DEFUN ("emacs-pid", Femacs_pid, Semacs_pid, 0, 0, 0,
7ee72033 1380 doc: /* Return the process ID of Emacs, as an integer. */)
5842a27b 1381 (void)
7fd233b3
RS
1382{
1383 return make_number (getpid ());
1384}
1385
b8d9bd41
PE
1386\f
1387
1388#ifndef TIME_T_MIN
1389# define TIME_T_MIN TYPE_MINIMUM (time_t)
1390#endif
1391#ifndef TIME_T_MAX
1392# define TIME_T_MAX TYPE_MAXIMUM (time_t)
1393#endif
1394
1395/* Report that a time value is out of range for Emacs. */
1396static void
1397time_overflow (void)
1398{
1399 error ("Specified time is not representable");
1400}
1401
1402/* Return the upper part of the time T (everything but the bottom 16 bits),
1403 making sure that it is representable. */
1404static EMACS_INT
1405hi_time (time_t t)
1406{
1407 time_t hi = t >> 16;
313c1e54
PE
1408
1409 /* Check for overflow, helping the compiler for common cases where
1410 no runtime check is needed, and taking care not to convert
1411 negative numbers to unsigned before comparing them. */
1412 if (! ((! TYPE_SIGNED (time_t)
1413 || MOST_NEGATIVE_FIXNUM <= TIME_T_MIN >> 16
1414 || MOST_NEGATIVE_FIXNUM <= hi)
1415 && (TIME_T_MAX >> 16 <= MOST_POSITIVE_FIXNUM
1416 || hi <= MOST_POSITIVE_FIXNUM)))
b8d9bd41 1417 time_overflow ();
313c1e54 1418
b8d9bd41
PE
1419 return hi;
1420}
1421
1422/* Return the bottom 16 bits of the time T. */
1423static EMACS_INT
1424lo_time (time_t t)
1425{
1426 return t & ((1 << 16) - 1);
1427}
1428
a7ca3326 1429DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0,
7ee72033 1430 doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00.
a1f17501
PJ
1431The time is returned as a list of three integers. The first has the
1432most significant 16 bits of the seconds, while the second has the
1433least significant 16 bits. The third integer gives the microsecond
1434count.
1435
1436The microsecond count is zero on systems that do not provide
7ee72033 1437resolution finer than a second. */)
5842a27b 1438 (void)
d940e0e4 1439{
956ace37 1440 EMACS_TIME t;
956ace37
JB
1441
1442 EMACS_GET_TIME (t);
b8d9bd41
PE
1443 return list3 (make_number (hi_time (EMACS_SECS (t))),
1444 make_number (lo_time (EMACS_SECS (t))),
799734b0 1445 make_number (EMACS_USECS (t)));
d940e0e4 1446}
4211ee7d 1447
a7ca3326 1448DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time,
4211ee7d
EZ
1449 0, 0, 0,
1450 doc: /* Return the current run time used by Emacs.
1451The time is returned as a list of three integers. The first has the
1452most significant 16 bits of the seconds, while the second has the
1453least significant 16 bits. The third integer gives the microsecond
1454count.
1455
9671c13a
JB
1456On systems that can't determine the run time, `get-internal-run-time'
1457does the same thing as `current-time'. The microsecond count is zero
1458on systems that do not provide resolution finer than a second. */)
5842a27b 1459 (void)
4211ee7d
EZ
1460{
1461#ifdef HAVE_GETRUSAGE
1462 struct rusage usage;
b8d9bd41
PE
1463 time_t secs;
1464 int usecs;
4211ee7d
EZ
1465
1466 if (getrusage (RUSAGE_SELF, &usage) < 0)
1467 /* This shouldn't happen. What action is appropriate? */
8a0ff744 1468 xsignal0 (Qerror);
4211ee7d
EZ
1469
1470 /* Sum up user time and system time. */
1471 secs = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
1472 usecs = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
1473 if (usecs >= 1000000)
1474 {
1475 usecs -= 1000000;
1476 secs++;
1477 }
1478
b8d9bd41
PE
1479 return list3 (make_number (hi_time (secs)),
1480 make_number (lo_time (secs)),
799734b0 1481 make_number (usecs));
c433c134 1482#else /* ! HAVE_GETRUSAGE */
43db14bb 1483#ifdef WINDOWSNT
c433c134
JR
1484 return w32_get_internal_run_time ();
1485#else /* ! WINDOWSNT */
4211ee7d 1486 return Fcurrent_time ();
c433c134
JR
1487#endif /* WINDOWSNT */
1488#endif /* HAVE_GETRUSAGE */
4211ee7d 1489}
d940e0e4
JB
1490\f
1491
8be6f318
PE
1492/* Make a Lisp list that represents the time T. */
1493Lisp_Object
1494make_time (time_t t)
1495{
b8d9bd41
PE
1496 return list2 (make_number (hi_time (t)),
1497 make_number (lo_time (t)));
8be6f318
PE
1498}
1499
1500/* Decode a Lisp list SPECIFIED_TIME that represents a time.
1501 If SPECIFIED_TIME is nil, use the current time.
1502 Set *RESULT to seconds since the Epoch.
1503 If USEC is not null, set *USEC to the microseconds component.
1504 Return nonzero if successful. */
5c5718b6 1505int
971de7fb 1506lisp_time_argument (Lisp_Object specified_time, time_t *result, int *usec)
e3120ab5
JB
1507{
1508 if (NILP (specified_time))
34a7a267
SS
1509 {
1510 if (usec)
1511 {
1512 EMACS_TIME t;
1513
c0261b5e 1514 EMACS_GET_TIME (t);
34a7a267
SS
1515 *usec = EMACS_USECS (t);
1516 *result = EMACS_SECS (t);
1517 return 1;
1518 }
1519 else
1520 return time (result) != -1;
1521 }
e3120ab5
JB
1522 else
1523 {
1524 Lisp_Object high, low;
313c1e54 1525 EMACS_INT hi;
e3120ab5 1526 high = Fcar (specified_time);
b7826503 1527 CHECK_NUMBER (high);
e3120ab5 1528 low = Fcdr (specified_time);
ae683129 1529 if (CONSP (low))
34a7a267
SS
1530 {
1531 if (usec)
1532 {
1533 Lisp_Object usec_l = Fcdr (low);
1534 if (CONSP (usec_l))
1535 usec_l = Fcar (usec_l);
1536 if (NILP (usec_l))
1537 *usec = 0;
1538 else
1539 {
b7826503 1540 CHECK_NUMBER (usec_l);
34a7a267
SS
1541 *usec = XINT (usec_l);
1542 }
1543 }
1544 low = Fcar (low);
1545 }
1546 else if (usec)
1547 *usec = 0;
b7826503 1548 CHECK_NUMBER (low);
313c1e54
PE
1549 hi = XINT (high);
1550
1551 /* Check for overflow, helping the compiler for common cases
1552 where no runtime check is needed, and taking care not to
1553 convert negative numbers to unsigned before comparing them. */
1554 if (! ((TYPE_SIGNED (time_t)
1555 ? (TIME_T_MIN >> 16 <= MOST_NEGATIVE_FIXNUM
1556 || TIME_T_MIN >> 16 <= hi)
1557 : 0 <= hi)
1558 && (MOST_POSITIVE_FIXNUM <= TIME_T_MAX >> 16
1559 || hi <= TIME_T_MAX >> 16)))
1560 return 0;
1561
1562 *result = (hi << 16) + (XINT (low) & 0xffff);
1563 return 1;
e3120ab5
JB
1564 }
1565}
1566
34a7a267 1567DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0,
7ee72033 1568 doc: /* Return the current time, as a float number of seconds since the epoch.
412f1fab 1569If SPECIFIED-TIME is given, it is the time to convert to float
5668fbb8 1570instead of the current time. The argument should have the form
c6493cdd 1571(HIGH LOW) or (HIGH LOW USEC). Thus, you can use times obtained from
5668fbb8
LT
1572`current-time' and from `file-attributes'. SPECIFIED-TIME can also
1573have the form (HIGH . LOW), but this is considered obsolete.
a1f17501
PJ
1574
1575WARNING: Since the result is floating point, it may not be exact.
d427a9fa
EZ
1576If precise time stamps are required, use either `current-time',
1577or (if you need time as a string) `format-time-string'. */)
5842a27b 1578 (Lisp_Object specified_time)
34a7a267
SS
1579{
1580 time_t sec;
1581 int usec;
1582
1583 if (! lisp_time_argument (specified_time, &sec, &usec))
1584 error ("Invalid time specification");
1585
26fad6e5 1586 return make_float ((sec * 1e6 + usec) / 1e6);
34a7a267
SS
1587}
1588
70ebbe5f
PE
1589/* Write information into buffer S of size MAXSIZE, according to the
1590 FORMAT of length FORMAT_LEN, using time information taken from *TP.
68c45bf0 1591 Default to Universal Time if UT is nonzero, local time otherwise.
a4180391 1592 Use NS as the number of nanoseconds in the %N directive.
70ebbe5f
PE
1593 Return the number of bytes written, not including the terminating
1594 '\0'. If S is NULL, nothing will be written anywhere; so to
1595 determine how many bytes would be written, use NULL for S and
1596 ((size_t) -1) for MAXSIZE.
1597
16c3e636
PE
1598 This function behaves like nstrftime, except it allows null
1599 bytes in FORMAT and it does not support nanoseconds. */
70ebbe5f 1600static size_t
a4180391
PE
1601emacs_nmemftime (char *s, size_t maxsize, const char *format,
1602 size_t format_len, const struct tm *tp, int ut, int ns)
70ebbe5f
PE
1603{
1604 size_t total = 0;
1605
be09e6e6
PE
1606 /* Loop through all the null-terminated strings in the format
1607 argument. Normally there's just one null-terminated string, but
1608 there can be arbitrarily many, concatenated together, if the
16c3e636 1609 format contains '\0' bytes. nstrftime stops at the first
be09e6e6 1610 '\0' byte so we must invoke it separately for each such string. */
70ebbe5f
PE
1611 for (;;)
1612 {
1613 size_t len;
1614 size_t result;
1615
1616 if (s)
1617 s[0] = '\1';
1618
a4180391 1619 result = nstrftime (s, maxsize, format, tp, ut, ns);
70ebbe5f
PE
1620
1621 if (s)
1622 {
1623 if (result == 0 && s[0] != '\0')
1624 return 0;
1625 s += result + 1;
1626 }
1627
1628 maxsize -= result + 1;
1629 total += result;
1630 len = strlen (format);
1631 if (len == format_len)
1632 return total;
1633 total++;
1634 format += len + 1;
1635 format_len -= len + 1;
1636 }
1637}
1638
3efcc98a 1639DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
7ee72033 1640 doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted.
5668fbb8
LT
1641TIME is specified as (HIGH LOW . IGNORED), as returned by
1642`current-time' or `file-attributes'. The obsolete form (HIGH . LOW)
1643is also still accepted.
a1f17501
PJ
1644The third, optional, argument UNIVERSAL, if non-nil, means describe TIME
1645as Universal Time; nil means describe TIME in the local time zone.
1646The value is a copy of FORMAT-STRING, but with certain constructs replaced
1647by text that describes the specified date and time in TIME:
1648
1649%Y is the year, %y within the century, %C the century.
1650%G is the year corresponding to the ISO week, %g within the century.
1651%m is the numeric month.
1652%b and %h are the locale's abbreviated month name, %B the full name.
1653%d is the day of the month, zero-padded, %e is blank-padded.
1654%u is the numeric day of week from 1 (Monday) to 7, %w from 0 (Sunday) to 6.
1655%a is the locale's abbreviated name of the day of week, %A the full name.
1656%U is the week number starting on Sunday, %W starting on Monday,
1657 %V according to ISO 8601.
1658%j is the day of the year.
1659
1660%H is the hour on a 24-hour clock, %I is on a 12-hour clock, %k is like %H
1661 only blank-padded, %l is like %I blank-padded.
1662%p is the locale's equivalent of either AM or PM.
1663%M is the minute.
1664%S is the second.
a4180391 1665%N is the nanosecond, %6N the microsecond, %3N the millisecond, etc.
a1f17501
PJ
1666%Z is the time zone name, %z is the numeric form.
1667%s is the number of seconds since 1970-01-01 00:00:00 +0000.
1668
1669%c is the locale's date and time format.
1670%x is the locale's "preferred" date format.
1671%D is like "%m/%d/%y".
1672
1673%R is like "%H:%M", %T is like "%H:%M:%S", %r is like "%I:%M:%S %p".
1674%X is the locale's "preferred" time format.
1675
1676Finally, %n is a newline, %t is a tab, %% is a literal %.
1677
1678Certain flags and modifiers are available with some format controls.
1679The flags are `_', `-', `^' and `#'. For certain characters X,
1680%_X is like %X, but padded with blanks; %-X is like %X,
a67a233b
MR
1681but without padding. %^X is like %X, but with all textual
1682characters up-cased; %#X is like %X, but with letter-case of
a1f17501
PJ
1683all textual characters reversed.
1684%NX (where N stands for an integer) is like %X,
1685but takes up at least N (a number) positions.
1686The modifiers are `E' and `O'. For certain characters X,
1687%EX is a locale's alternative version of %X;
1688%OX is like %X, but uses the locale's number symbols.
1689
75bfc667
JL
1690For example, to produce full ISO 8601 format, use "%Y-%m-%dT%T%z".
1691
1692usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL) */)
545b49b4 1693 (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object universal)
a82d387c 1694{
7da0b018 1695 time_t t;
7ed806a7 1696 struct tm tm;
7da0b018
PE
1697
1698 CHECK_STRING (format_string);
1699 format_string = code_convert_string_norecord (format_string,
1700 Vlocale_coding_system, 1);
1701 return format_time_string (SSDATA (format_string), SBYTES (format_string),
1702 timeval, ! NILP (universal), &t, &tm);
1703}
1704
1705static Lisp_Object
1706format_time_string (char const *format, ptrdiff_t formatlen,
7ed806a7 1707 Lisp_Object timeval, int ut, time_t *tval, struct tm *tmp)
7da0b018 1708{
7ed806a7
PE
1709 char buffer[4000];
1710 char *buf = buffer;
1711 size_t size = sizeof buffer;
1712 size_t len;
1713 Lisp_Object bufstring;
a4180391
PE
1714 int usec;
1715 int ns;
177ea5f1 1716 struct tm *tm;
7ed806a7 1717 USE_SAFE_ALLOCA;
a82d387c 1718
7da0b018 1719 if (! (lisp_time_argument (timeval, tval, &usec)
a4180391 1720 && 0 <= usec && usec < 1000000))
a82d387c 1721 error ("Invalid time specification");
a4180391 1722 ns = usec * 1000;
a82d387c 1723
a82d387c
RS
1724 while (1)
1725 {
7ed806a7
PE
1726 BLOCK_INPUT;
1727
1728 synchronize_system_time_locale ();
1729
1730 tm = ut ? gmtime (tval) : localtime (tval);
1731 if (! tm)
1732 {
1733 UNBLOCK_INPUT;
1734 time_overflow ();
1735 }
1736 *tmp = *tm;
b48382a0 1737
bfbcc5ee 1738 buf[0] = '\1';
7ed806a7
PE
1739 len = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns);
1740 if ((0 < len && len < size) || (len == 0 && buf[0] == '\0'))
1741 break;
b48382a0 1742
7ed806a7
PE
1743 /* Buffer was too small, so make it bigger and try again. */
1744 len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tm, ut, ns);
bcda42c8 1745 UNBLOCK_INPUT;
7ed806a7 1746 if (STRING_BYTES_BOUND <= len)
da64016e 1747 string_overflow ();
7ed806a7
PE
1748 size = len + 1;
1749 SAFE_ALLOCA (buf, char *, size);
a82d387c 1750 }
7ed806a7
PE
1751
1752 UNBLOCK_INPUT;
1753 bufstring = make_unibyte_string (buf, len);
1754 SAFE_FREE ();
1755 return code_convert_string_norecord (bufstring, Vlocale_coding_system, 0);
a82d387c
RS
1756}
1757
4691c06d 1758DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 1, 0,
7ee72033 1759 doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST ZONE).
5668fbb8 1760The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED),
9671c13a 1761as from `current-time' and `file-attributes', or nil to use the
5668fbb8
LT
1762current time. The obsolete form (HIGH . LOW) is also still accepted.
1763The list has the following nine members: SEC is an integer between 0
1764and 60; SEC is 60 for a leap second, which only some operating systems
1765support. MINUTE is an integer between 0 and 59. HOUR is an integer
1766between 0 and 23. DAY is an integer between 1 and 31. MONTH is an
1767integer between 1 and 12. YEAR is an integer indicating the
1768four-digit year. DOW is the day of week, an integer between 0 and 6,
f1767e2b 1769where 0 is Sunday. DST is t if daylight saving time is in effect,
5668fbb8
LT
1770otherwise nil. ZONE is an integer indicating the number of seconds
1771east of Greenwich. (Note that Common Lisp has different meanings for
1772DOW and ZONE.) */)
5842a27b 1773 (Lisp_Object specified_time)
4691c06d
RS
1774{
1775 time_t time_spec;
3c887943 1776 struct tm save_tm;
4691c06d
RS
1777 struct tm *decoded_time;
1778 Lisp_Object list_args[9];
34a7a267
SS
1779
1780 if (! lisp_time_argument (specified_time, &time_spec, NULL))
4691c06d
RS
1781 error ("Invalid time specification");
1782
bcda42c8 1783 BLOCK_INPUT;
4691c06d 1784 decoded_time = localtime (&time_spec);
7ed806a7
PE
1785 /* Make a copy, in case a signal handler modifies TZ or the struct. */
1786 if (decoded_time)
1787 save_tm = *decoded_time;
bcda42c8 1788 UNBLOCK_INPUT;
b8d9bd41 1789 if (! (decoded_time
7ed806a7
PE
1790 && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= save_tm.tm_year
1791 && save_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE))
fe31d94c 1792 time_overflow ();
7ed806a7
PE
1793 XSETFASTINT (list_args[0], save_tm.tm_sec);
1794 XSETFASTINT (list_args[1], save_tm.tm_min);
1795 XSETFASTINT (list_args[2], save_tm.tm_hour);
1796 XSETFASTINT (list_args[3], save_tm.tm_mday);
1797 XSETFASTINT (list_args[4], save_tm.tm_mon + 1);
71c3f28f
EZ
1798 /* On 64-bit machines an int is narrower than EMACS_INT, thus the
1799 cast below avoids overflow in int arithmetics. */
7ed806a7
PE
1800 XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) save_tm.tm_year);
1801 XSETFASTINT (list_args[6], save_tm.tm_wday);
1802 list_args[7] = save_tm.tm_isdst ? Qt : Qnil;
3c887943 1803
bcda42c8 1804 BLOCK_INPUT;
3c887943
KH
1805 decoded_time = gmtime (&time_spec);
1806 if (decoded_time == 0)
1807 list_args[8] = Qnil;
1808 else
94751666 1809 XSETINT (list_args[8], tm_diff (&save_tm, decoded_time));
7ed806a7 1810 UNBLOCK_INPUT;
4691c06d
RS
1811 return Flist (9, list_args);
1812}
1813
b8d9bd41
PE
1814/* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that
1815 the result is representable as an int. Assume OFFSET is small and
1816 nonnegative. */
1817static int
1818check_tm_member (Lisp_Object obj, int offset)
1819{
1820 EMACS_INT n;
1821 CHECK_NUMBER (obj);
1822 n = XINT (obj);
1823 if (! (INT_MIN + offset <= n && n - offset <= INT_MAX))
1824 time_overflow ();
1825 return n - offset;
1826}
1827
6ee9061c 1828DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0,
7ee72033 1829 doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time.
a1f17501
PJ
1830This is the reverse operation of `decode-time', which see.
1831ZONE defaults to the current time zone rule. This can
1832be a string or t (as from `set-time-zone-rule'), or it can be a list
b57c2708 1833\(as from `current-time-zone') or an integer (as from `decode-time')
9c279ddf 1834applied without consideration for daylight saving time.
a1f17501
PJ
1835
1836You can pass more than 7 arguments; then the first six arguments
1837are used as SECOND through YEAR, and the *last* argument is used as ZONE.
1838The intervening arguments are ignored.
1839This feature lets (apply 'encode-time (decode-time ...)) work.
1840
412f1fab 1841Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed;
a1f17501
PJ
1842for example, a DAY of 0 means the day preceding the given month.
1843Year numbers less than 100 are treated just like other year numbers.
4bfbe194
MB
1844If you want them to stand for years in this century, you must do that yourself.
1845
f555f8cf
KH
1846Years before 1970 are not guaranteed to work. On some systems,
1847year values as low as 1901 do work.
1848
4bfbe194 1849usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
f66c7cf8 1850 (ptrdiff_t nargs, Lisp_Object *args)
cce7b8a0 1851{
545b49b4 1852 time_t value;
c59b5089 1853 struct tm tm;
60653898 1854 Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil);
6ee9061c 1855
b8d9bd41
PE
1856 tm.tm_sec = check_tm_member (args[0], 0);
1857 tm.tm_min = check_tm_member (args[1], 0);
1858 tm.tm_hour = check_tm_member (args[2], 0);
1859 tm.tm_mday = check_tm_member (args[3], 0);
1860 tm.tm_mon = check_tm_member (args[4], 1);
1861 tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE);
c59b5089
PE
1862 tm.tm_isdst = -1;
1863
1864 if (CONSP (zone))
1865 zone = Fcar (zone);
1b8fa736 1866 if (NILP (zone))
bcda42c8
YM
1867 {
1868 BLOCK_INPUT;
545b49b4 1869 value = mktime (&tm);
bcda42c8
YM
1870 UNBLOCK_INPUT;
1871 }
c59b5089 1872 else
1b8fa736 1873 {
c59b5089 1874 char tzbuf[100];
8ea90aa3 1875 const char *tzstring;
c59b5089 1876 char **oldenv = environ, **newenv;
34a7a267 1877
2e34157c 1878 if (EQ (zone, Qt))
085e9fcb
EN
1879 tzstring = "UTC0";
1880 else if (STRINGP (zone))
51b59d79 1881 tzstring = SSDATA (zone);
c59b5089 1882 else if (INTEGERP (zone))
1b8fa736 1883 {
1ea40aa2 1884 int abszone = eabs (XINT (zone));
c59b5089
PE
1885 sprintf (tzbuf, "XXX%s%d:%02d:%02d", "-" + (XINT (zone) < 0),
1886 abszone / (60*60), (abszone/60) % 60, abszone % 60);
1887 tzstring = tzbuf;
1b8fa736 1888 }
c59b5089
PE
1889 else
1890 error ("Invalid time zone specification");
1891
7ed806a7
PE
1892 BLOCK_INPUT;
1893
34a7a267 1894 /* Set TZ before calling mktime; merely adjusting mktime's returned
c59b5089
PE
1895 value doesn't suffice, since that would mishandle leap seconds. */
1896 set_time_zone_rule (tzstring);
1897
545b49b4 1898 value = mktime (&tm);
c59b5089
PE
1899
1900 /* Restore TZ to previous value. */
1901 newenv = environ;
1902 environ = oldenv;
c59b5089
PE
1903#ifdef LOCALTIME_CACHE
1904 tzset ();
1905#endif
7ed806a7
PE
1906 UNBLOCK_INPUT;
1907
1908 xfree (newenv);
1b8fa736 1909 }
1b8fa736 1910
545b49b4 1911 if (value == (time_t) -1)
fe31d94c 1912 time_overflow ();
c59b5089 1913
545b49b4 1914 return make_time (value);
cce7b8a0
RS
1915}
1916
2148f2b4 1917DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 1, 0,
244b023e 1918 doc: /* Return the current local time, as a human-readable string.
a1f17501 1919Programs can use this function to decode a time,
d65b4235
PE
1920since the number of columns in each field is fixed
1921if the year is in the range 1000-9999.
a1f17501
PJ
1922The format is `Sun Sep 16 01:03:52 1973'.
1923However, see also the functions `decode-time' and `format-time-string'
1924which provide a much more powerful and general facility.
1925
5668fbb8
LT
1926If SPECIFIED-TIME is given, it is a time to format instead of the
1927current time. The argument should have the form (HIGH LOW . IGNORED).
1928Thus, you can use times obtained from `current-time' and from
1929`file-attributes'. SPECIFIED-TIME can also have the form (HIGH . LOW),
1930but this is considered obsolete. */)
5842a27b 1931 (Lisp_Object specified_time)
2148f2b4 1932{
e3120ab5 1933 time_t value;
aac18aa4 1934 struct tm *tm;
ab0fa4e4
PE
1935 char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1];
1936 int len IF_LINT (= 0);
2148f2b4 1937
34a7a267 1938 if (! lisp_time_argument (specified_time, &value, NULL))
aac18aa4 1939 error ("Invalid time specification");
d65b4235 1940
ab0fa4e4
PE
1941 /* Convert to a string in ctime format, except without the trailing
1942 newline, and without the 4-digit year limit. Don't use asctime
1943 or ctime, as they might dump core if the year is outside the
1944 range -999 .. 9999. */
bcda42c8 1945 BLOCK_INPUT;
aac18aa4 1946 tm = localtime (&value);
ab0fa4e4 1947 if (tm)
7ed806a7 1948 {
ab0fa4e4
PE
1949 static char const wday_name[][4] =
1950 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1951 static char const mon_name[][4] =
1952 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1953 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1954 printmax_t year_base = TM_YEAR_BASE;
1955
1956 len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd,
1957 wday_name[tm->tm_wday], mon_name[tm->tm_mon], tm->tm_mday,
1958 tm->tm_hour, tm->tm_min, tm->tm_sec,
1959 tm->tm_year + year_base);
7ed806a7 1960 }
bcda42c8 1961 UNBLOCK_INPUT;
ab0fa4e4 1962 if (! tm)
fe31d94c 1963 time_overflow ();
35692fe0 1964
ab0fa4e4 1965 return make_unibyte_string (buf, len);
35692fe0 1966}
c2662aea 1967
94751666
PE
1968/* Yield A - B, measured in seconds.
1969 This function is copied from the GNU C Library. */
1970static int
971de7fb 1971tm_diff (struct tm *a, struct tm *b)
e3120ab5 1972{
94751666
PE
1973 /* Compute intervening leap days correctly even if year is negative.
1974 Take care to avoid int overflow in leap day calculations,
1975 but it's OK to assume that A and B are close to each other. */
1976 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
1977 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
1978 int a100 = a4 / 25 - (a4 % 25 < 0);
1979 int b100 = b4 / 25 - (b4 % 25 < 0);
1980 int a400 = a100 >> 2;
1981 int b400 = b100 >> 2;
1982 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
1983 int years = a->tm_year - b->tm_year;
1984 int days = (365 * years + intervening_leap_days
1985 + (a->tm_yday - b->tm_yday));
1986 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
1987 + (a->tm_min - b->tm_min))
8e718b4e 1988 + (a->tm_sec - b->tm_sec));
e3120ab5
JB
1989}
1990
1991DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0,
7ee72033 1992 doc: /* Return the offset and name for the local time zone.
a1f17501
PJ
1993This returns a list of the form (OFFSET NAME).
1994OFFSET is an integer number of seconds ahead of UTC (east of Greenwich).
1995 A negative value means west of Greenwich.
1996NAME is a string giving the name of the time zone.
412f1fab 1997If SPECIFIED-TIME is given, the time zone offset is determined from it
5668fbb8
LT
1998instead of using the current time. The argument should have the form
1999(HIGH LOW . IGNORED). Thus, you can use times obtained from
2000`current-time' and from `file-attributes'. SPECIFIED-TIME can also
2001have the form (HIGH . LOW), but this is considered obsolete.
a1f17501
PJ
2002
2003Some operating systems cannot provide all this information to Emacs;
2004in this case, `current-time-zone' returns a list containing nil for
7ee72033 2005the data it can't find. */)
5842a27b 2006 (Lisp_Object specified_time)
c2662aea 2007{
e3120ab5 2008 time_t value;
7ed806a7 2009 int offset;
e3120ab5 2010 struct tm *t;
7da0b018 2011 struct tm localtm;
7da0b018
PE
2012 Lisp_Object zone_offset, zone_name;
2013
2014 zone_offset = Qnil;
2015 zone_name = format_time_string ("%Z", sizeof "%Z" - 1, specified_time,
7ed806a7 2016 0, &value, &localtm);
7da0b018
PE
2017 BLOCK_INPUT;
2018 t = gmtime (&value);
7ed806a7
PE
2019 if (t)
2020 offset = tm_diff (&localtm, t);
7da0b018 2021 UNBLOCK_INPUT;
bcda42c8
YM
2022
2023 if (t)
e3120ab5 2024 {
7da0b018
PE
2025 zone_offset = make_number (offset);
2026 if (SCHARS (zone_name) == 0)
e3120ab5
JB
2027 {
2028 /* No local time zone name is available; use "+-NNNN" instead. */
33ef5c64
PE
2029 int m = offset / 60;
2030 int am = offset < 0 ? - m : m;
7da0b018 2031 char buf[sizeof "+00" + INT_STRLEN_BOUND (int)];
e3120ab5 2032 sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60);
7da0b018 2033 zone_name = build_string (buf);
e3120ab5 2034 }
e3120ab5 2035 }
7da0b018
PE
2036
2037 return list2 (zone_offset, zone_name);
c2662aea
JB
2038}
2039
260e2e2a
KH
2040/* This holds the value of `environ' produced by the previous
2041 call to Fset_time_zone_rule, or 0 if Fset_time_zone_rule
2042 has never been called. */
2043static char **environbuf;
2044
a03fc5a6
JR
2045/* This holds the startup value of the TZ environment variable so it
2046 can be restored if the user calls set-time-zone-rule with a nil
2047 argument. */
2048static char *initial_tz;
2049
143cb9a9 2050DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
7ee72033 2051 doc: /* Set the local time zone using TZ, a string specifying a time zone rule.
a1f17501 2052If TZ is nil, use implementation-defined default time zone information.
37e11a63
CY
2053If TZ is t, use Universal Time.
2054
2055Instead of calling this function, you typically want (setenv "TZ" TZ).
2056That changes both the environment of the Emacs process and the
2057variable `process-environment', whereas `set-time-zone-rule' affects
2058only the former. */)
5842a27b 2059 (Lisp_Object tz)
143cb9a9 2060{
8ea90aa3 2061 const char *tzstring;
7ed806a7
PE
2062 char **old_environbuf;
2063
2064 if (! (NILP (tz) || EQ (tz, Qt)))
2065 CHECK_STRING (tz);
2066
2067 BLOCK_INPUT;
143cb9a9 2068
a03fc5a6 2069 /* When called for the first time, save the original TZ. */
7ed806a7
PE
2070 old_environbuf = environbuf;
2071 if (!old_environbuf)
a03fc5a6
JR
2072 initial_tz = (char *) getenv ("TZ");
2073
143cb9a9 2074 if (NILP (tz))
a03fc5a6 2075 tzstring = initial_tz;
2e34157c 2076 else if (EQ (tz, Qt))
085e9fcb 2077 tzstring = "UTC0";
143cb9a9 2078 else
7ed806a7 2079 tzstring = SSDATA (tz);
143cb9a9 2080
c59b5089 2081 set_time_zone_rule (tzstring);
c59b5089
PE
2082 environbuf = environ;
2083
7ed806a7
PE
2084 UNBLOCK_INPUT;
2085
2086 xfree (old_environbuf);
c59b5089
PE
2087 return Qnil;
2088}
2089
e0bf9faf
PE
2090#ifdef LOCALTIME_CACHE
2091
2092/* These two values are known to load tz files in buggy implementations,
2093 i.e. Solaris 1 executables running under either Solaris 1 or Solaris 2.
1155c453 2094 Their values shouldn't matter in non-buggy implementations.
34a7a267 2095 We don't use string literals for these strings,
1155c453
RS
2096 since if a string in the environment is in readonly
2097 storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
2098 See Sun bugs 1113095 and 1114114, ``Timezone routines
2099 improperly modify environment''. */
2100
e0bf9faf
PE
2101static char set_time_zone_rule_tz1[] = "TZ=GMT+0";
2102static char set_time_zone_rule_tz2[] = "TZ=GMT+1";
2103
2104#endif
1155c453 2105
c59b5089
PE
2106/* Set the local time zone rule to TZSTRING.
2107 This allocates memory into `environ', which it is the caller's
2108 responsibility to free. */
acb7cc89 2109
a92ae0ce 2110void
a8fe7202 2111set_time_zone_rule (const char *tzstring)
c59b5089 2112{
c9f8d652 2113 ptrdiff_t envptrs;
c59b5089
PE
2114 char **from, **to, **newenv;
2115
aafe5147 2116 /* Make the ENVIRON vector longer with room for TZSTRING. */
143cb9a9
RS
2117 for (from = environ; *from; from++)
2118 continue;
2119 envptrs = from - environ + 2;
2120 newenv = to = (char **) xmalloc (envptrs * sizeof (char *)
2121 + (tzstring ? strlen (tzstring) + 4 : 0));
aafe5147
RS
2122
2123 /* Add TZSTRING to the end of environ, as a value for TZ. */
143cb9a9
RS
2124 if (tzstring)
2125 {
2126 char *t = (char *) (to + envptrs);
2127 strcpy (t, "TZ=");
2128 strcat (t, tzstring);
2129 *to++ = t;
2130 }
2131
aafe5147
RS
2132 /* Copy the old environ vector elements into NEWENV,
2133 but don't copy the TZ variable.
2134 So we have only one definition of TZ, which came from TZSTRING. */
143cb9a9
RS
2135 for (from = environ; *from; from++)
2136 if (strncmp (*from, "TZ=", 3) != 0)
2137 *to++ = *from;
2138 *to = 0;
2139
2140 environ = newenv;
143cb9a9 2141
aafe5147
RS
2142 /* If we do have a TZSTRING, NEWENV points to the vector slot where
2143 the TZ variable is stored. If we do not have a TZSTRING,
2144 TO points to the vector slot which has the terminating null. */
2145
143cb9a9 2146#ifdef LOCALTIME_CACHE
aafe5147
RS
2147 {
2148 /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
2149 "US/Pacific" that loads a tz file, then changes to a value like
2150 "XXX0" that does not load a tz file, and then changes back to
2151 its original value, the last change is (incorrectly) ignored.
2152 Also, if TZ changes twice in succession to values that do
2153 not load a tz file, tzset can dump core (see Sun bug#1225179).
2154 The following code works around these bugs. */
2155
aafe5147
RS
2156 if (tzstring)
2157 {
2158 /* Temporarily set TZ to a value that loads a tz file
2159 and that differs from tzstring. */
2160 char *tz = *newenv;
1155c453
RS
2161 *newenv = (strcmp (tzstring, set_time_zone_rule_tz1 + 3) == 0
2162 ? set_time_zone_rule_tz2 : set_time_zone_rule_tz1);
aafe5147
RS
2163 tzset ();
2164 *newenv = tz;
2165 }
2166 else
2167 {
2168 /* The implied tzstring is unknown, so temporarily set TZ to
2169 two different values that each load a tz file. */
1155c453 2170 *to = set_time_zone_rule_tz1;
aafe5147
RS
2171 to[1] = 0;
2172 tzset ();
1155c453 2173 *to = set_time_zone_rule_tz2;
aafe5147
RS
2174 tzset ();
2175 *to = 0;
2176 }
2177
2178 /* Now TZ has the desired value, and tzset can be invoked safely. */
2179 }
2180
143cb9a9
RS
2181 tzset ();
2182#endif
143cb9a9 2183}
35692fe0 2184\f
fb8106e8
KH
2185/* Insert NARGS Lisp objects in the array ARGS by calling INSERT_FUNC
2186 (if a type of object is Lisp_Int) or INSERT_FROM_STRING_FUNC (if a
2187 type of object is Lisp_String). INHERIT is passed to
2188 INSERT_FROM_STRING_FUNC as the last argument. */
2189
acb7cc89 2190static void
9628fed7 2191general_insert_function (void (*insert_func)
b68864e5 2192 (const char *, EMACS_INT),
9628fed7
SM
2193 void (*insert_from_string_func)
2194 (Lisp_Object, EMACS_INT, EMACS_INT,
2195 EMACS_INT, EMACS_INT, int),
f66c7cf8 2196 int inherit, ptrdiff_t nargs, Lisp_Object *args)
fb8106e8 2197{
f66c7cf8 2198 ptrdiff_t argnum;
fb8106e8
KH
2199 register Lisp_Object val;
2200
2201 for (argnum = 0; argnum < nargs; argnum++)
2202 {
2203 val = args[argnum];
1b9c91ed 2204 if (CHARACTERP (val))
fb8106e8 2205 {
13bdea59 2206 int c = XFASTINT (val);
d5c2c403 2207 unsigned char str[MAX_MULTIBYTE_LENGTH];
fb8106e8
KH
2208 int len;
2209
4b4deea2 2210 if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
13bdea59 2211 len = CHAR_STRING (c, str);
fb8106e8 2212 else
13c148b8 2213 {
abbd3d23 2214 str[0] = ASCII_CHAR_P (c) ? c : multibyte_char_to_unibyte (c);
13c148b8
KH
2215 len = 1;
2216 }
b68864e5 2217 (*insert_func) ((char *) str, len);
fb8106e8
KH
2218 }
2219 else if (STRINGP (val))
2220 {
1f24f4fd 2221 (*insert_from_string_func) (val, 0, 0,
d5db4077
KR
2222 SCHARS (val),
2223 SBYTES (val),
1f24f4fd 2224 inherit);
fb8106e8
KH
2225 }
2226 else
b7f34213 2227 wrong_type_argument (Qchar_or_string_p, val);
fb8106e8
KH
2228 }
2229}
2230
35692fe0 2231void
971de7fb 2232insert1 (Lisp_Object arg)
35692fe0
JB
2233{
2234 Finsert (1, &arg);
2235}
2236
52b14ac0
JB
2237
2238/* Callers passing one argument to Finsert need not gcpro the
2239 argument "array", since the only element of the array will
2240 not be used after calling insert or insert_from_string, so
2241 we don't care if it gets trashed. */
2242
a7ca3326 2243DEFUN ("insert", Finsert, Sinsert, 0, MANY, 0,
7ee72033 2244 doc: /* Insert the arguments, either strings or characters, at point.
a1f17501
PJ
2245Point and before-insertion markers move forward to end up
2246 after the inserted text.
2247Any other markers at the point of insertion remain before the text.
2248
2249If the current buffer is multibyte, unibyte strings are converted
72bb55c6 2250to multibyte for insertion (see `string-make-multibyte').
a1f17501 2251If the current buffer is unibyte, multibyte strings are converted
72bb55c6
KS
2252to unibyte for insertion (see `string-make-unibyte').
2253
2254When operating on binary data, it may be necessary to preserve the
2255original bytes of a unibyte string when inserting it into a multibyte
2256buffer; to accomplish this, apply `string-as-multibyte' to the string
2257and insert the result.
4bfbe194
MB
2258
2259usage: (insert &rest ARGS) */)
f66c7cf8 2260 (ptrdiff_t nargs, Lisp_Object *args)
35692fe0 2261{
fb8106e8 2262 general_insert_function (insert, insert_from_string, 0, nargs, args);
be91036a
RS
2263 return Qnil;
2264}
2265
2266DEFUN ("insert-and-inherit", Finsert_and_inherit, Sinsert_and_inherit,
2267 0, MANY, 0,
7ee72033 2268 doc: /* Insert the arguments at point, inheriting properties from adjoining text.
a1f17501
PJ
2269Point and before-insertion markers move forward to end up
2270 after the inserted text.
2271Any other markers at the point of insertion remain before the text.
2272
2273If the current buffer is multibyte, unibyte strings are converted
2274to multibyte for insertion (see `unibyte-char-to-multibyte').
2275If the current buffer is unibyte, multibyte strings are converted
4bfbe194
MB
2276to unibyte for insertion.
2277
2278usage: (insert-and-inherit &rest ARGS) */)
f66c7cf8 2279 (ptrdiff_t nargs, Lisp_Object *args)
be91036a 2280{
fb8106e8
KH
2281 general_insert_function (insert_and_inherit, insert_from_string, 1,
2282 nargs, args);
35692fe0
JB
2283 return Qnil;
2284}
2285
2286DEFUN ("insert-before-markers", Finsert_before_markers, Sinsert_before_markers, 0, MANY, 0,
7ee72033 2287 doc: /* Insert strings or characters at point, relocating markers after the text.
a1f17501
PJ
2288Point and markers move forward to end up after the inserted text.
2289
2290If the current buffer is multibyte, unibyte strings are converted
2291to multibyte for insertion (see `unibyte-char-to-multibyte').
2292If the current buffer is unibyte, multibyte strings are converted
4bfbe194
MB
2293to unibyte for insertion.
2294
2295usage: (insert-before-markers &rest ARGS) */)
f66c7cf8 2296 (ptrdiff_t nargs, Lisp_Object *args)
35692fe0 2297{
fb8106e8
KH
2298 general_insert_function (insert_before_markers,
2299 insert_from_string_before_markers, 0,
2300 nargs, args);
be91036a
RS
2301 return Qnil;
2302}
2303
a0d76c27
EN
2304DEFUN ("insert-before-markers-and-inherit", Finsert_and_inherit_before_markers,
2305 Sinsert_and_inherit_before_markers, 0, MANY, 0,
7ee72033 2306 doc: /* Insert text at point, relocating markers and inheriting properties.
a1f17501
PJ
2307Point and markers move forward to end up after the inserted text.
2308
2309If the current buffer is multibyte, unibyte strings are converted
2310to multibyte for insertion (see `unibyte-char-to-multibyte').
2311If the current buffer is unibyte, multibyte strings are converted
4bfbe194
MB
2312to unibyte for insertion.
2313
2314usage: (insert-before-markers-and-inherit &rest ARGS) */)
f66c7cf8 2315 (ptrdiff_t nargs, Lisp_Object *args)
be91036a 2316{
fb8106e8
KH
2317 general_insert_function (insert_before_markers_and_inherit,
2318 insert_from_string_before_markers, 1,
2319 nargs, args);
35692fe0
JB
2320 return Qnil;
2321}
2322\f
a7ca3326 2323DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0,
9671c13a 2324 doc: /* Insert COUNT copies of CHARACTER.
a1f17501
PJ
2325Point, and before-insertion markers, are relocated as in the function `insert'.
2326The optional third arg INHERIT, if non-nil, says to inherit text properties
7ee72033 2327from adjoining text, if those properties are sticky. */)
5842a27b 2328 (Lisp_Object character, Lisp_Object count, Lisp_Object inherit)
35692fe0 2329{
21d890a4 2330 int i, stringlen;
29cdc13e 2331 register EMACS_INT n;
13bdea59 2332 int c, len;
d5c2c403 2333 unsigned char str[MAX_MULTIBYTE_LENGTH];
21d890a4 2334 char string[4000];
35692fe0 2335
13bdea59 2336 CHECK_CHARACTER (character);
b7826503 2337 CHECK_NUMBER (count);
13bdea59 2338 c = XFASTINT (character);
35692fe0 2339
4b4deea2 2340 if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
13bdea59 2341 len = CHAR_STRING (c, str);
fb8106e8 2342 else
13bdea59 2343 str[0] = c, len = 1;
2e6813b0
PE
2344 if (XINT (count) <= 0)
2345 return Qnil;
d1f3d2af 2346 if (BUF_BYTES_MAX / len < XINT (count))
99561444 2347 buffer_overflow ();
fb8106e8 2348 n = XINT (count) * len;
21d890a4 2349 stringlen = min (n, sizeof string - sizeof string % len);
545b49b4 2350 for (i = 0; i < stringlen; i++)
fb8106e8 2351 string[i] = str[i % len];
21d890a4 2352 while (n > stringlen)
35692fe0 2353 {
54e42e2d 2354 QUIT;
e2eeabbb 2355 if (!NILP (inherit))
545b49b4 2356 insert_and_inherit (string, stringlen);
e2eeabbb 2357 else
545b49b4
PE
2358 insert (string, stringlen);
2359 n -= stringlen;
35692fe0 2360 }
21d890a4
PE
2361 if (!NILP (inherit))
2362 insert_and_inherit (string, n);
2363 else
2364 insert (string, n);
35692fe0
JB
2365 return Qnil;
2366}
2367
48ef988f
KH
2368DEFUN ("insert-byte", Finsert_byte, Sinsert_byte, 2, 3, 0,
2369 doc: /* Insert COUNT (second arg) copies of BYTE (first arg).
2370Both arguments are required.
2371BYTE is a number of the range 0..255.
2372
2373If BYTE is 128..255 and the current buffer is multibyte, the
2374corresponding eight-bit character is inserted.
2375
2376Point, and before-insertion markers, are relocated as in the function `insert'.
2377The optional third arg INHERIT, if non-nil, says to inherit text properties
2378from adjoining text, if those properties are sticky. */)
5842a27b 2379 (Lisp_Object byte, Lisp_Object count, Lisp_Object inherit)
48ef988f
KH
2380{
2381 CHECK_NUMBER (byte);
2382 if (XINT (byte) < 0 || XINT (byte) > 255)
2383 args_out_of_range_3 (byte, make_number (0), make_number (255));
2384 if (XINT (byte) >= 128
4b4deea2 2385 && ! NILP (BVAR (current_buffer, enable_multibyte_characters)))
48ef988f 2386 XSETFASTINT (byte, BYTE8_TO_CHAR (XINT (byte)));
ed398b0a 2387 return Finsert_char (byte, count, inherit);
48ef988f
KH
2388}
2389
35692fe0 2390\f
ffd56f97
JB
2391/* Making strings from buffer contents. */
2392
2393/* Return a Lisp_String containing the text of the current buffer from
74d6d8c5 2394 START to END. If text properties are in use and the current buffer
eb8c3be9 2395 has properties in the range specified, the resulting string will also
260e2e2a 2396 have them, if PROPS is nonzero.
ffd56f97
JB
2397
2398 We don't want to use plain old make_string here, because it calls
2399 make_uninit_string, which can cause the buffer arena to be
2400 compacted. make_string has no way of knowing that the data has
2401 been moved, and thus copies the wrong data into the string. This
2402 doesn't effect most of the other users of make_string, so it should
2403 be left as is. But we should use this function when conjuring
2404 buffer substrings. */
74d6d8c5 2405
ffd56f97 2406Lisp_Object
413d18e7 2407make_buffer_string (EMACS_INT start, EMACS_INT end, int props)
ffd56f97 2408{
413d18e7
EZ
2409 EMACS_INT start_byte = CHAR_TO_BYTE (start);
2410 EMACS_INT end_byte = CHAR_TO_BYTE (end);
ffd56f97 2411
88441c8e
RS
2412 return make_buffer_string_both (start, start_byte, end, end_byte, props);
2413}
2414
2415/* Return a Lisp_String containing the text of the current buffer from
2416 START / START_BYTE to END / END_BYTE.
2417
2418 If text properties are in use and the current buffer
2419 has properties in the range specified, the resulting string will also
2420 have them, if PROPS is nonzero.
2421
2422 We don't want to use plain old make_string here, because it calls
2423 make_uninit_string, which can cause the buffer arena to be
2424 compacted. make_string has no way of knowing that the data has
2425 been moved, and thus copies the wrong data into the string. This
2426 doesn't effect most of the other users of make_string, so it should
2427 be left as is. But we should use this function when conjuring
2428 buffer substrings. */
2429
2430Lisp_Object
413d18e7
EZ
2431make_buffer_string_both (EMACS_INT start, EMACS_INT start_byte,
2432 EMACS_INT end, EMACS_INT end_byte, int props)
88441c8e
RS
2433{
2434 Lisp_Object result, tem, tem1;
2435
ffd56f97
JB
2436 if (start < GPT && GPT < end)
2437 move_gap (start);
2438
4b4deea2 2439 if (! NILP (BVAR (current_buffer, enable_multibyte_characters)))
5f75e666
RS
2440 result = make_uninit_multibyte_string (end - start, end_byte - start_byte);
2441 else
2442 result = make_uninit_string (end - start);
72af86bd 2443 memcpy (SDATA (result), BYTE_POS_ADDR (start_byte), end_byte - start_byte);
ffd56f97 2444
260e2e2a 2445 /* If desired, update and copy the text properties. */
260e2e2a
KH
2446 if (props)
2447 {
2448 update_buffer_properties (start, end);
2449
2450 tem = Fnext_property_change (make_number (start), Qnil, make_number (end));
2451 tem1 = Ftext_properties_at (make_number (start), Qnil);
2452
2453 if (XINT (tem) != end || !NILP (tem1))
ec1c14f6
RS
2454 copy_intervals_to_string (result, current_buffer, start,
2455 end - start);
260e2e2a 2456 }
74d6d8c5 2457
ffd56f97
JB
2458 return result;
2459}
35692fe0 2460
260e2e2a
KH
2461/* Call Vbuffer_access_fontify_functions for the range START ... END
2462 in the current buffer, if necessary. */
2463
2464static void
29cdc13e 2465update_buffer_properties (EMACS_INT start, EMACS_INT end)
260e2e2a 2466{
260e2e2a
KH
2467 /* If this buffer has some access functions,
2468 call them, specifying the range of the buffer being accessed. */
2469 if (!NILP (Vbuffer_access_fontify_functions))
2470 {
2471 Lisp_Object args[3];
2472 Lisp_Object tem;
2473
2474 args[0] = Qbuffer_access_fontify_functions;
2475 XSETINT (args[1], start);
2476 XSETINT (args[2], end);
2477
2478 /* But don't call them if we can tell that the work
2479 has already been done. */
2480 if (!NILP (Vbuffer_access_fontified_property))
2481 {
2482 tem = Ftext_property_any (args[1], args[2],
2483 Vbuffer_access_fontified_property,
2484 Qnil, Qnil);
2485 if (! NILP (tem))
ced1d19a 2486 Frun_hook_with_args (3, args);
260e2e2a
KH
2487 }
2488 else
ced1d19a 2489 Frun_hook_with_args (3, args);
260e2e2a 2490 }
260e2e2a
KH
2491}
2492
a7ca3326 2493DEFUN ("buffer-substring", Fbuffer_substring, Sbuffer_substring, 2, 2, 0,
7ee72033 2494 doc: /* Return the contents of part of the current buffer as a string.
a1f17501
PJ
2495The two arguments START and END are character positions;
2496they can be in either order.
2497The string returned is multibyte if the buffer is multibyte.
2498
2499This function copies the text properties of that part of the buffer
2500into the result string; if you don't want the text properties,
7ee72033 2501use `buffer-substring-no-properties' instead. */)
5842a27b 2502 (Lisp_Object start, Lisp_Object end)
35692fe0 2503{
413d18e7 2504 register EMACS_INT b, e;
35692fe0 2505
2591ec64
EN
2506 validate_region (&start, &end);
2507 b = XINT (start);
2508 e = XINT (end);
35692fe0 2509
2591ec64 2510 return make_buffer_string (b, e, 1);
260e2e2a
KH
2511}
2512
2513DEFUN ("buffer-substring-no-properties", Fbuffer_substring_no_properties,
2514 Sbuffer_substring_no_properties, 2, 2, 0,
7ee72033 2515 doc: /* Return the characters of part of the buffer, without the text properties.
a1f17501 2516The two arguments START and END are character positions;
7ee72033 2517they can be in either order. */)
5842a27b 2518 (Lisp_Object start, Lisp_Object end)
260e2e2a 2519{
413d18e7 2520 register EMACS_INT b, e;
260e2e2a 2521
2591ec64
EN
2522 validate_region (&start, &end);
2523 b = XINT (start);
2524 e = XINT (end);
260e2e2a 2525
2591ec64 2526 return make_buffer_string (b, e, 0);
35692fe0
JB
2527}
2528
a7ca3326 2529DEFUN ("buffer-string", Fbuffer_string, Sbuffer_string, 0, 0, 0,
7ee72033 2530 doc: /* Return the contents of the current buffer as a string.
a1f17501 2531If narrowing is in effect, this function returns only the visible part
7ee72033 2532of the buffer. */)
5842a27b 2533 (void)
35692fe0 2534{
0daf6e8d 2535 return make_buffer_string (BEGV, ZV, 1);
35692fe0
JB
2536}
2537
2538DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
deb8e082 2539 1, 3, 0,
658ec670 2540 doc: /* Insert before point a substring of the contents of BUFFER.
a1f17501 2541BUFFER may be a buffer or a buffer name.
412f1fab
JB
2542Arguments START and END are character positions specifying the substring.
2543They default to the values of (point-min) and (point-max) in BUFFER. */)
5842a27b 2544 (Lisp_Object buffer, Lisp_Object start, Lisp_Object end)
35692fe0 2545{
29cdc13e 2546 register EMACS_INT b, e, temp;
260e2e2a 2547 register struct buffer *bp, *obuf;
658ec670 2548 Lisp_Object buf;
35692fe0 2549
658ec670
JB
2550 buf = Fget_buffer (buffer);
2551 if (NILP (buf))
2552 nsberror (buffer);
2553 bp = XBUFFER (buf);
4b4deea2 2554 if (NILP (BVAR (bp, name)))
93b62e82 2555 error ("Selecting deleted buffer");
35692fe0 2556
2591ec64
EN
2557 if (NILP (start))
2558 b = BUF_BEGV (bp);
35692fe0
JB
2559 else
2560 {
b7826503 2561 CHECK_NUMBER_COERCE_MARKER (start);
2591ec64 2562 b = XINT (start);
35692fe0 2563 }
2591ec64
EN
2564 if (NILP (end))
2565 e = BUF_ZV (bp);
35692fe0
JB
2566 else
2567 {
b7826503 2568 CHECK_NUMBER_COERCE_MARKER (end);
2591ec64 2569 e = XINT (end);
35692fe0
JB
2570 }
2571
2591ec64
EN
2572 if (b > e)
2573 temp = b, b = e, e = temp;
35692fe0 2574
2591ec64
EN
2575 if (!(BUF_BEGV (bp) <= b && e <= BUF_ZV (bp)))
2576 args_out_of_range (start, end);
35692fe0 2577
260e2e2a
KH
2578 obuf = current_buffer;
2579 set_buffer_internal_1 (bp);
2591ec64 2580 update_buffer_properties (b, e);
260e2e2a
KH
2581 set_buffer_internal_1 (obuf);
2582
2591ec64 2583 insert_from_buffer (bp, b, e - b, 0);
35692fe0
JB
2584 return Qnil;
2585}
e9cf2084
RS
2586
2587DEFUN ("compare-buffer-substrings", Fcompare_buffer_substrings, Scompare_buffer_substrings,
deb8e082 2588 6, 6, 0,
7ee72033 2589 doc: /* Compare two substrings of two buffers; return result as number.
a1f17501
PJ
2590the value is -N if first string is less after N-1 chars,
2591+N if first string is greater after N-1 chars, or 0 if strings match.
2592Each substring is represented as three arguments: BUFFER, START and END.
2593That makes six args in all, three for each substring.
2594
2595The value of `case-fold-search' in the current buffer
7ee72033 2596determines whether case is significant or ignored. */)
5842a27b 2597 (Lisp_Object buffer1, Lisp_Object start1, Lisp_Object end1, Lisp_Object buffer2, Lisp_Object start2, Lisp_Object end2)
e9cf2084 2598{
29cdc13e 2599 register EMACS_INT begp1, endp1, begp2, endp2, temp;
e9cf2084 2600 register struct buffer *bp1, *bp2;
1149fd6f 2601 register Lisp_Object trt
4b4deea2
TT
2602 = (!NILP (BVAR (current_buffer, case_fold_search))
2603 ? BVAR (current_buffer, case_canon_table) : Qnil);
29cdc13e
EZ
2604 EMACS_INT chars = 0;
2605 EMACS_INT i1, i2, i1_byte, i2_byte;
e9cf2084
RS
2606
2607 /* Find the first buffer and its substring. */
2608
2609 if (NILP (buffer1))
2610 bp1 = current_buffer;
2611 else
2612 {
3fff2dfa
RS
2613 Lisp_Object buf1;
2614 buf1 = Fget_buffer (buffer1);
2615 if (NILP (buf1))
2616 nsberror (buffer1);
2617 bp1 = XBUFFER (buf1);
4b4deea2 2618 if (NILP (BVAR (bp1, name)))
93b62e82 2619 error ("Selecting deleted buffer");
e9cf2084
RS
2620 }
2621
2622 if (NILP (start1))
2623 begp1 = BUF_BEGV (bp1);
2624 else
2625 {
b7826503 2626 CHECK_NUMBER_COERCE_MARKER (start1);
e9cf2084
RS
2627 begp1 = XINT (start1);
2628 }
2629 if (NILP (end1))
2630 endp1 = BUF_ZV (bp1);
2631 else
2632 {
b7826503 2633 CHECK_NUMBER_COERCE_MARKER (end1);
e9cf2084
RS
2634 endp1 = XINT (end1);
2635 }
2636
2637 if (begp1 > endp1)
2638 temp = begp1, begp1 = endp1, endp1 = temp;
2639
2640 if (!(BUF_BEGV (bp1) <= begp1
2641 && begp1 <= endp1
2642 && endp1 <= BUF_ZV (bp1)))
2643 args_out_of_range (start1, end1);
2644
2645 /* Likewise for second substring. */
2646
2647 if (NILP (buffer2))
2648 bp2 = current_buffer;
2649 else
2650 {
3fff2dfa
RS
2651 Lisp_Object buf2;
2652 buf2 = Fget_buffer (buffer2);
2653 if (NILP (buf2))
2654 nsberror (buffer2);
3b1fdd85 2655 bp2 = XBUFFER (buf2);
4b4deea2 2656 if (NILP (BVAR (bp2, name)))
93b62e82 2657 error ("Selecting deleted buffer");
e9cf2084
RS
2658 }
2659
2660 if (NILP (start2))
2661 begp2 = BUF_BEGV (bp2);
2662 else
2663 {
b7826503 2664 CHECK_NUMBER_COERCE_MARKER (start2);
e9cf2084
RS
2665 begp2 = XINT (start2);
2666 }
2667 if (NILP (end2))
2668 endp2 = BUF_ZV (bp2);
2669 else
2670 {
b7826503 2671 CHECK_NUMBER_COERCE_MARKER (end2);
e9cf2084
RS
2672 endp2 = XINT (end2);
2673 }
2674
2675 if (begp2 > endp2)
2676 temp = begp2, begp2 = endp2, endp2 = temp;
2677
2678 if (!(BUF_BEGV (bp2) <= begp2
2679 && begp2 <= endp2
2680 && endp2 <= BUF_ZV (bp2)))
2681 args_out_of_range (start2, end2);
2682
07422a12
RS
2683 i1 = begp1;
2684 i2 = begp2;
2685 i1_byte = buf_charpos_to_bytepos (bp1, i1);
2686 i2_byte = buf_charpos_to_bytepos (bp2, i2);
e9cf2084 2687
07422a12 2688 while (i1 < endp1 && i2 < endp2)
e9cf2084 2689 {
07422a12
RS
2690 /* When we find a mismatch, we must compare the
2691 characters, not just the bytes. */
2692 int c1, c2;
ec1c14f6 2693
2221451f
RS
2694 QUIT;
2695
4b4deea2 2696 if (! NILP (BVAR (bp1, enable_multibyte_characters)))
07422a12
RS
2697 {
2698 c1 = BUF_FETCH_MULTIBYTE_CHAR (bp1, i1_byte);
2699 BUF_INC_POS (bp1, i1_byte);
2700 i1++;
2701 }
2702 else
2703 {
2704 c1 = BUF_FETCH_BYTE (bp1, i1);
4c0354d7 2705 MAKE_CHAR_MULTIBYTE (c1);
07422a12
RS
2706 i1++;
2707 }
2708
4b4deea2 2709 if (! NILP (BVAR (bp2, enable_multibyte_characters)))
07422a12
RS
2710 {
2711 c2 = BUF_FETCH_MULTIBYTE_CHAR (bp2, i2_byte);
2712 BUF_INC_POS (bp2, i2_byte);
2713 i2++;
2714 }
2715 else
2716 {
2717 c2 = BUF_FETCH_BYTE (bp2, i2);
4c0354d7 2718 MAKE_CHAR_MULTIBYTE (c2);
07422a12
RS
2719 i2++;
2720 }
ec1c14f6 2721
1149fd6f 2722 if (!NILP (trt))
e9cf2084 2723 {
1149fd6f
SM
2724 c1 = CHAR_TABLE_TRANSLATE (trt, c1);
2725 c2 = CHAR_TABLE_TRANSLATE (trt, c2);
e9cf2084
RS
2726 }
2727 if (c1 < c2)
ec1c14f6 2728 return make_number (- 1 - chars);
e9cf2084 2729 if (c1 > c2)
ec1c14f6 2730 return make_number (chars + 1);
07422a12
RS
2731
2732 chars++;
e9cf2084
RS
2733 }
2734
2735 /* The strings match as far as they go.
2736 If one is shorter, that one is less. */
07422a12 2737 if (chars < endp1 - begp1)
ec1c14f6 2738 return make_number (chars + 1);
07422a12 2739 else if (chars < endp2 - begp2)
ec1c14f6 2740 return make_number (- chars - 1);
e9cf2084
RS
2741
2742 /* Same length too => they are equal. */
2743 return make_number (0);
2744}
35692fe0 2745\f
d5a539cd 2746static Lisp_Object
971de7fb 2747subst_char_in_region_unwind (Lisp_Object arg)
d5a539cd 2748{
4b4deea2 2749 return BVAR (current_buffer, undo_list) = arg;
d5a539cd
RS
2750}
2751
c8e76b47 2752static Lisp_Object
971de7fb 2753subst_char_in_region_unwind_1 (Lisp_Object arg)
c8e76b47 2754{
4b4deea2 2755 return BVAR (current_buffer, filename) = arg;
c8e76b47
RS
2756}
2757
35692fe0 2758DEFUN ("subst-char-in-region", Fsubst_char_in_region,
deb8e082 2759 Ssubst_char_in_region, 4, 5, 0,
7ee72033 2760 doc: /* From START to END, replace FROMCHAR with TOCHAR each time it occurs.
a1f17501
PJ
2761If optional arg NOUNDO is non-nil, don't record this change for undo
2762and don't mark the buffer as really changed.
7ee72033 2763Both characters must have the same length of multi-byte form. */)
5842a27b 2764 (Lisp_Object start, Lisp_Object end, Lisp_Object fromchar, Lisp_Object tochar, Lisp_Object noundo)
35692fe0 2765{
c8a66ab8 2766 register EMACS_INT pos, pos_byte, stop, i, len, end_byte;
0f2e2a3b
SM
2767 /* Keep track of the first change in the buffer:
2768 if 0 we haven't found it yet.
2769 if < 0 we've found it and we've run the before-change-function.
2770 if > 0 we've actually performed it and the value is its position. */
29cdc13e 2771 EMACS_INT changed = 0;
d5c2c403
KH
2772 unsigned char fromstr[MAX_MULTIBYTE_LENGTH], tostr[MAX_MULTIBYTE_LENGTH];
2773 unsigned char *p;
aed13378 2774 int count = SPECPDL_INDEX ();
aa801467
KH
2775#define COMBINING_NO 0
2776#define COMBINING_BEFORE 1
2777#define COMBINING_AFTER 2
2778#define COMBINING_BOTH (COMBINING_BEFORE | COMBINING_AFTER)
2779 int maybe_byte_combining = COMBINING_NO;
29cdc13e 2780 EMACS_INT last_changed = 0;
4b4deea2 2781 int multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
13bdea59 2782 int fromc, toc;
35692fe0 2783
0f2e2a3b
SM
2784 restart:
2785
35692fe0 2786 validate_region (&start, &end);
13bdea59
PE
2787 CHECK_CHARACTER (fromchar);
2788 CHECK_CHARACTER (tochar);
2789 fromc = XFASTINT (fromchar);
2790 toc = XFASTINT (tochar);
35692fe0 2791
7439e5b9 2792 if (multibyte_p)
fb8106e8 2793 {
13bdea59
PE
2794 len = CHAR_STRING (fromc, fromstr);
2795 if (CHAR_STRING (toc, tostr) != len)
fdd6025e 2796 error ("Characters in `subst-char-in-region' have different byte-lengths");
aa801467
KH
2797 if (!ASCII_BYTE_P (*tostr))
2798 {
2799 /* If *TOSTR is in the range 0x80..0x9F and TOCHAR is not a
2800 complete multibyte character, it may be combined with the
2801 after bytes. If it is in the range 0xA0..0xFF, it may be
2802 combined with the before and after bytes. */
2803 if (!CHAR_HEAD_P (*tostr))
2804 maybe_byte_combining = COMBINING_BOTH;
2805 else if (BYTES_BY_CHAR_HEAD (*tostr) > len)
2806 maybe_byte_combining = COMBINING_AFTER;
2807 }
fb8106e8
KH
2808 }
2809 else
2810 {
2811 len = 1;
13bdea59
PE
2812 fromstr[0] = fromc;
2813 tostr[0] = toc;
fb8106e8
KH
2814 }
2815
84246b95
KH
2816 pos = XINT (start);
2817 pos_byte = CHAR_TO_BYTE (pos);
ec1c14f6
RS
2818 stop = CHAR_TO_BYTE (XINT (end));
2819 end_byte = stop;
35692fe0 2820
d5a539cd
RS
2821 /* If we don't want undo, turn off putting stuff on the list.
2822 That's faster than getting rid of things,
c8e76b47
RS
2823 and it prevents even the entry for a first change.
2824 Also inhibit locking the file. */
0f2e2a3b 2825 if (!changed && !NILP (noundo))
d5a539cd
RS
2826 {
2827 record_unwind_protect (subst_char_in_region_unwind,
4b4deea2
TT
2828 BVAR (current_buffer, undo_list));
2829 BVAR (current_buffer, undo_list) = Qt;
c8e76b47
RS
2830 /* Don't do file-locking. */
2831 record_unwind_protect (subst_char_in_region_unwind_1,
4b4deea2
TT
2832 BVAR (current_buffer, filename));
2833 BVAR (current_buffer, filename) = Qnil;
d5a539cd
RS
2834 }
2835
84246b95 2836 if (pos_byte < GPT_BYTE)
ec1c14f6 2837 stop = min (stop, GPT_BYTE);
fb8106e8 2838 while (1)
35692fe0 2839 {
c8a66ab8 2840 EMACS_INT pos_byte_next = pos_byte;
a3360ff9 2841
84246b95 2842 if (pos_byte >= stop)
fb8106e8 2843 {
84246b95 2844 if (pos_byte >= end_byte) break;
ec1c14f6 2845 stop = end_byte;
fb8106e8 2846 }
84246b95 2847 p = BYTE_POS_ADDR (pos_byte);
7439e5b9
GM
2848 if (multibyte_p)
2849 INC_POS (pos_byte_next);
2850 else
2851 ++pos_byte_next;
a3360ff9
KH
2852 if (pos_byte_next - pos_byte == len
2853 && p[0] == fromstr[0]
fb8106e8
KH
2854 && (len == 1
2855 || (p[1] == fromstr[1]
2856 && (len == 2 || (p[2] == fromstr[2]
2857 && (len == 3 || p[3] == fromstr[3]))))))
35692fe0 2858 {
0f2e2a3b
SM
2859 if (changed < 0)
2860 /* We've already seen this and run the before-change-function;
2861 this time we only need to record the actual position. */
2862 changed = pos;
2863 else if (!changed)
60b96ee7 2864 {
0f2e2a3b 2865 changed = -1;
3e145152 2866 modify_region (current_buffer, pos, XINT (end), 0);
7653d030
RS
2867
2868 if (! NILP (noundo))
2869 {
1e158d25
RS
2870 if (MODIFF - 1 == SAVE_MODIFF)
2871 SAVE_MODIFF++;
0b5397c2
SM
2872 if (MODIFF - 1 == BUF_AUTOSAVE_MODIFF (current_buffer))
2873 BUF_AUTOSAVE_MODIFF (current_buffer)++;
7653d030 2874 }
0f2e2a3b
SM
2875
2876 /* The before-change-function may have moved the gap
2877 or even modified the buffer so we should start over. */
2878 goto restart;
60b96ee7
RS
2879 }
2880
0c1e3b85 2881 /* Take care of the case where the new character
34a7a267 2882 combines with neighboring bytes. */
a3360ff9 2883 if (maybe_byte_combining
aa801467
KH
2884 && (maybe_byte_combining == COMBINING_AFTER
2885 ? (pos_byte_next < Z_BYTE
2886 && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
2887 : ((pos_byte_next < Z_BYTE
2888 && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
2889 || (pos_byte > BEG_BYTE
2890 && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))))))
0c1e3b85
RS
2891 {
2892 Lisp_Object tem, string;
2893
2894 struct gcpro gcpro1;
2895
4b4deea2 2896 tem = BVAR (current_buffer, undo_list);
0c1e3b85
RS
2897 GCPRO1 (tem);
2898
aa801467 2899 /* Make a multibyte string containing this single character. */
e7f8264d 2900 string = make_multibyte_string ((char *) tostr, 1, len);
0c1e3b85
RS
2901 /* replace_range is less efficient, because it moves the gap,
2902 but it handles combining correctly. */
2903 replace_range (pos, pos + 1, string,
9869520f 2904 0, 0, 1);
a3360ff9
KH
2905 pos_byte_next = CHAR_TO_BYTE (pos);
2906 if (pos_byte_next > pos_byte)
2907 /* Before combining happened. We should not increment
3f5409d3
KH
2908 POS. So, to cancel the later increment of POS,
2909 decrease it now. */
2910 pos--;
a3360ff9 2911 else
3f5409d3 2912 INC_POS (pos_byte_next);
34a7a267 2913
0c1e3b85 2914 if (! NILP (noundo))
4b4deea2 2915 BVAR (current_buffer, undo_list) = tem;
0c1e3b85
RS
2916
2917 UNGCPRO;
2918 }
2919 else
2920 {
2921 if (NILP (noundo))
2922 record_change (pos, 1);
2923 for (i = 0; i < len; i++) *p++ = tostr[i];
2924 }
d5c2c403 2925 last_changed = pos + 1;
35692fe0 2926 }
3f5409d3
KH
2927 pos_byte = pos_byte_next;
2928 pos++;
35692fe0
JB
2929 }
2930
0f2e2a3b 2931 if (changed > 0)
d5c2c403
KH
2932 {
2933 signal_after_change (changed,
2934 last_changed - changed, last_changed - changed);
2935 update_compositions (changed, last_changed, CHECK_ALL);
2936 }
60b96ee7 2937
d5a539cd 2938 unbind_to (count, Qnil);
35692fe0
JB
2939 return Qnil;
2940}
2941
f555f8cf 2942
c8a66ab8
EZ
2943static Lisp_Object check_translation (EMACS_INT, EMACS_INT, EMACS_INT,
2944 Lisp_Object);
f555f8cf
KH
2945
2946/* Helper function for Ftranslate_region_internal.
2947
2948 Check if a character sequence at POS (POS_BYTE) matches an element
2949 of VAL. VAL is a list (([FROM-CHAR ...] . TO) ...). If a matching
2950 element is found, return it. Otherwise return Qnil. */
2951
2952static Lisp_Object
c8a66ab8
EZ
2953check_translation (EMACS_INT pos, EMACS_INT pos_byte, EMACS_INT end,
2954 Lisp_Object val)
f555f8cf
KH
2955{
2956 int buf_size = 16, buf_used = 0;
2957 int *buf = alloca (sizeof (int) * buf_size);
2958
2959 for (; CONSP (val); val = XCDR (val))
2960 {
2961 Lisp_Object elt;
c8a66ab8 2962 EMACS_INT len, i;
f555f8cf
KH
2963
2964 elt = XCAR (val);
2965 if (! CONSP (elt))
2966 continue;
2967 elt = XCAR (elt);
2968 if (! VECTORP (elt))
2969 continue;
2970 len = ASIZE (elt);
2971 if (len <= end - pos)
2972 {
2973 for (i = 0; i < len; i++)
2974 {
2975 if (buf_used <= i)
2976 {
2977 unsigned char *p = BYTE_POS_ADDR (pos_byte);
c8a66ab8 2978 int len1;
f555f8cf
KH
2979
2980 if (buf_used == buf_size)
2981 {
2982 int *newbuf;
2983
2984 buf_size += 16;
2985 newbuf = alloca (sizeof (int) * buf_size);
2986 memcpy (newbuf, buf, sizeof (int) * buf_used);
2987 buf = newbuf;
2988 }
c8a66ab8
EZ
2989 buf[buf_used++] = STRING_CHAR_AND_LENGTH (p, len1);
2990 pos_byte += len1;
f555f8cf
KH
2991 }
2992 if (XINT (AREF (elt, i)) != buf[i])
2993 break;
2994 }
2995 if (i == len)
2996 return XCAR (val);
2997 }
2998 }
2999 return Qnil;
3000}
3001
3002
8583605b
KH
3003DEFUN ("translate-region-internal", Ftranslate_region_internal,
3004 Stranslate_region_internal, 3, 3, 0,
3005 doc: /* Internal use only.
3006From START to END, translate characters according to TABLE.
f555f8cf
KH
3007TABLE is a string or a char-table; the Nth character in it is the
3008mapping for the character with code N.
7ee72033 3009It returns the number of characters changed. */)
5842a27b 3010 (Lisp_Object start, Lisp_Object end, register Lisp_Object table)
35692fe0 3011{
35692fe0 3012 register unsigned char *tt; /* Trans table. */
35692fe0
JB
3013 register int nc; /* New character. */
3014 int cnt; /* Number of changes made. */
faf8b5bc 3015 EMACS_INT size; /* Size of translate table. */
c8a66ab8 3016 EMACS_INT pos, pos_byte, end_pos;
4b4deea2 3017 int multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
9710023e 3018 int string_multibyte IF_LINT (= 0);
35692fe0
JB
3019
3020 validate_region (&start, &end);
8583605b 3021 if (CHAR_TABLE_P (table))
f555f8cf
KH
3022 {
3023 if (! EQ (XCHAR_TABLE (table)->purpose, Qtranslation_table))
3024 error ("Not a translation table");
eb3d9ec7 3025 size = MAX_CHAR;
f555f8cf
KH
3026 tt = NULL;
3027 }
8583605b
KH
3028 else
3029 {
3030 CHECK_STRING (table);
3031
eb3d9ec7
KH
3032 if (! multibyte && (SCHARS (table) < SBYTES (table)))
3033 table = string_make_unibyte (table);
8583605b
KH
3034 string_multibyte = SCHARS (table) < SBYTES (table);
3035 size = SBYTES (table);
3036 tt = SDATA (table);
3037 }
35692fe0 3038
1f24f4fd 3039 pos = XINT (start);
8583605b 3040 pos_byte = CHAR_TO_BYTE (pos);
e65837df 3041 end_pos = XINT (end);
af6ea8ad 3042 modify_region (current_buffer, pos, end_pos, 0);
35692fe0
JB
3043
3044 cnt = 0;
f555f8cf 3045 for (; pos < end_pos; )
35692fe0 3046 {
ec1c14f6 3047 register unsigned char *p = BYTE_POS_ADDR (pos_byte);
8583605b
KH
3048 unsigned char *str, buf[MAX_MULTIBYTE_LENGTH];
3049 int len, str_len;
1f24f4fd 3050 int oc;
f555f8cf 3051 Lisp_Object val;
ec1c14f6 3052
e8cce5af 3053 if (multibyte)
62a6e103 3054 oc = STRING_CHAR_AND_LENGTH (p, len);
e8cce5af 3055 else
eb3d9ec7
KH
3056 oc = *p, len = 1;
3057 if (oc < size)
35692fe0 3058 {
eb3d9ec7 3059 if (tt)
35692fe0 3060 {
fa056b08
KS
3061 /* Reload as signal_after_change in last iteration may GC. */
3062 tt = SDATA (table);
8583605b 3063 if (string_multibyte)
0c1e3b85 3064 {
8583605b 3065 str = tt + string_char_to_byte (table, oc);
62a6e103 3066 nc = STRING_CHAR_AND_LENGTH (str, str_len);
0c1e3b85
RS
3067 }
3068 else
3069 {
eb3d9ec7
KH
3070 nc = tt[oc];
3071 if (! ASCII_BYTE_P (nc) && multibyte)
3072 {
3073 str_len = BYTE8_STRING (nc, buf);
3074 str = buf;
3075 }
3076 else
3077 {
3078 str_len = 1;
3079 str = tt + oc;
3080 }
0c1e3b85 3081 }
35692fe0 3082 }
eb3d9ec7 3083 else
f555f8cf 3084 {
eb3d9ec7
KH
3085 nc = oc;
3086 val = CHAR_TABLE_REF (table, oc);
045eb8d9 3087 if (CHARACTERP (val))
eb3d9ec7 3088 {
045eb8d9 3089 nc = XFASTINT (val);
eb3d9ec7
KH
3090 str_len = CHAR_STRING (nc, buf);
3091 str = buf;
3092 }
3093 else if (VECTORP (val) || (CONSP (val)))
3094 {
3095 /* VAL is [TO_CHAR ...] or (([FROM-CHAR ...] . TO) ...)
3096 where TO is TO-CHAR or [TO-CHAR ...]. */
3097 nc = -1;
3098 }
f555f8cf 3099 }
8583605b 3100
eb3d9ec7 3101 if (nc != oc && nc >= 0)
8583605b 3102 {
f555f8cf
KH
3103 /* Simple one char to one char translation. */
3104 if (len != str_len)
3105 {
3106 Lisp_Object string;
8583605b 3107
f555f8cf
KH
3108 /* This is less efficient, because it moves the gap,
3109 but it should handle multibyte characters correctly. */
e7f8264d 3110 string = make_multibyte_string ((char *) str, 1, str_len);
f555f8cf
KH
3111 replace_range (pos, pos + 1, string, 1, 0, 1);
3112 len = str_len;
3113 }
3114 else
3115 {
3116 record_change (pos, 1);
3117 while (str_len-- > 0)
3118 *p++ = *str++;
3119 signal_after_change (pos, 1, 1);
3120 update_compositions (pos, pos + 1, CHECK_BORDER);
3121 }
3122 ++cnt;
8583605b 3123 }
eb3d9ec7 3124 else if (nc < 0)
8583605b 3125 {
f555f8cf
KH
3126 Lisp_Object string;
3127
3128 if (CONSP (val))
3129 {
3130 val = check_translation (pos, pos_byte, end_pos, val);
3131 if (NILP (val))
3132 {
3133 pos_byte += len;
3134 pos++;
3135 continue;
3136 }
3137 /* VAL is ([FROM-CHAR ...] . TO). */
3138 len = ASIZE (XCAR (val));
3139 val = XCDR (val);
3140 }
3141 else
3142 len = 1;
3143
3144 if (VECTORP (val))
3145 {
bde25748 3146 string = Fconcat (1, &val);
f555f8cf
KH
3147 }
3148 else
3149 {
3150 string = Fmake_string (make_number (1), val);
3151 }
3152 replace_range (pos, pos + len, string, 1, 0, 1);
3153 pos_byte += SBYTES (string);
3154 pos += SCHARS (string);
3155 cnt += SCHARS (string);
3156 end_pos += SCHARS (string) - len;
3157 continue;
8583605b 3158 }
8583605b
KH
3159 }
3160 pos_byte += len;
3f5409d3 3161 pos++;
35692fe0
JB
3162 }
3163
ec1c14f6 3164 return make_number (cnt);
35692fe0
JB
3165}
3166
a7ca3326 3167DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r",
3bbd2265 3168 doc: /* Delete the text between START and END.
f0fcdf4b
LMI
3169If called interactively, delete the region between point and mark.
3170This command deletes buffer text without modifying the kill ring. */)
5842a27b 3171 (Lisp_Object start, Lisp_Object end)
35692fe0 3172{
2591ec64
EN
3173 validate_region (&start, &end);
3174 del_range (XINT (start), XINT (end));
35692fe0
JB
3175 return Qnil;
3176}
7dae4502
SM
3177
3178DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
3179 Sdelete_and_extract_region, 2, 2, 0,
7ee72033 3180 doc: /* Delete the text between START and END and return it. */)
5842a27b 3181 (Lisp_Object start, Lisp_Object end)
7dae4502
SM
3182{
3183 validate_region (&start, &end);
8550b998 3184 if (XINT (start) == XINT (end))
977f6cfb 3185 return empty_unibyte_string;
7dae4502
SM
3186 return del_range_1 (XINT (start), XINT (end), 1, 1);
3187}
35692fe0 3188\f
a7ca3326 3189DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
7ee72033
MB
3190 doc: /* Remove restrictions (narrowing) from current buffer.
3191This allows the buffer's full text to be seen and edited. */)
5842a27b 3192 (void)
35692fe0 3193{
2cad2e34
RS
3194 if (BEG != BEGV || Z != ZV)
3195 current_buffer->clip_changed = 1;
35692fe0 3196 BEGV = BEG;
ec1c14f6
RS
3197 BEGV_BYTE = BEG_BYTE;
3198 SET_BUF_ZV_BOTH (current_buffer, Z, Z_BYTE);
52b14ac0
JB
3199 /* Changing the buffer bounds invalidates any recorded current column. */
3200 invalidate_current_column ();
35692fe0
JB
3201 return Qnil;
3202}
3203
a7ca3326 3204DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
7ee72033 3205 doc: /* Restrict editing in this buffer to the current region.
a1f17501
PJ
3206The rest of the text becomes temporarily invisible and untouchable
3207but is not deleted; if you save the buffer in a file, the invisible
3208text is included in the file. \\[widen] makes all visible again.
3209See also `save-restriction'.
3210
3211When calling from a program, pass two arguments; positions (integers
7ee72033 3212or markers) bounding the text that should remain visible. */)
5842a27b 3213 (register Lisp_Object start, Lisp_Object end)
35692fe0 3214{
b7826503
PJ
3215 CHECK_NUMBER_COERCE_MARKER (start);
3216 CHECK_NUMBER_COERCE_MARKER (end);
35692fe0 3217
2591ec64 3218 if (XINT (start) > XINT (end))
35692fe0 3219 {
b5a6948e 3220 Lisp_Object tem;
2591ec64 3221 tem = start; start = end; end = tem;
35692fe0
JB
3222 }
3223
2591ec64
EN
3224 if (!(BEG <= XINT (start) && XINT (start) <= XINT (end) && XINT (end) <= Z))
3225 args_out_of_range (start, end);
35692fe0 3226
2cad2e34
RS
3227 if (BEGV != XFASTINT (start) || ZV != XFASTINT (end))
3228 current_buffer->clip_changed = 1;
3229
ec1c14f6 3230 SET_BUF_BEGV (current_buffer, XFASTINT (start));
2591ec64 3231 SET_BUF_ZV (current_buffer, XFASTINT (end));
6ec8bbd2 3232 if (PT < XFASTINT (start))
2591ec64 3233 SET_PT (XFASTINT (start));
6ec8bbd2 3234 if (PT > XFASTINT (end))
2591ec64 3235 SET_PT (XFASTINT (end));
52b14ac0
JB
3236 /* Changing the buffer bounds invalidates any recorded current column. */
3237 invalidate_current_column ();
35692fe0
JB
3238 return Qnil;
3239}
3240
3241Lisp_Object
971de7fb 3242save_restriction_save (void)
35692fe0 3243{
d6abb4c7
MB
3244 if (BEGV == BEG && ZV == Z)
3245 /* The common case that the buffer isn't narrowed.
3246 We return just the buffer object, which save_restriction_restore
3247 recognizes as meaning `no restriction'. */
3248 return Fcurrent_buffer ();
3249 else
3250 /* We have to save a restriction, so return a pair of markers, one
3251 for the beginning and one for the end. */
3252 {
3253 Lisp_Object beg, end;
3254
3255 beg = buildmark (BEGV, BEGV_BYTE);
3256 end = buildmark (ZV, ZV_BYTE);
35692fe0 3257
d6abb4c7 3258 /* END must move forward if text is inserted at its exact location. */
5e617bc2 3259 XMARKER (end)->insertion_type = 1;
d6abb4c7
MB
3260
3261 return Fcons (beg, end);
3262 }
35692fe0
JB
3263}
3264
3265Lisp_Object
971de7fb 3266save_restriction_restore (Lisp_Object data)
35692fe0 3267{
d528b1ce
SM
3268 struct buffer *cur = NULL;
3269 struct buffer *buf = (CONSP (data)
3270 ? XMARKER (XCAR (data))->buffer
3271 : XBUFFER (data));
3272
4b4deea2 3273 if (buf && buf != current_buffer && !NILP (BVAR (buf, pt_marker)))
d528b1ce
SM
3274 { /* If `buf' uses markers to keep track of PT, BEGV, and ZV (as
3275 is the case if it is or has an indirect buffer), then make
3276 sure it is current before we update BEGV, so
3277 set_buffer_internal takes care of managing those markers. */
3278 cur = current_buffer;
3279 set_buffer_internal (buf);
3280 }
3281
d6abb4c7
MB
3282 if (CONSP (data))
3283 /* A pair of marks bounding a saved restriction. */
35692fe0 3284 {
d6abb4c7
MB
3285 struct Lisp_Marker *beg = XMARKER (XCAR (data));
3286 struct Lisp_Marker *end = XMARKER (XCDR (data));
d528b1ce 3287 eassert (buf == end->buffer);
2cad2e34 3288
63884563
RS
3289 if (buf /* Verify marker still points to a buffer. */
3290 && (beg->charpos != BUF_BEGV (buf) || end->charpos != BUF_ZV (buf)))
d6abb4c7
MB
3291 /* The restriction has changed from the saved one, so restore
3292 the saved restriction. */
3293 {
faf8b5bc 3294 EMACS_INT pt = BUF_PT (buf);
d6abb4c7
MB
3295
3296 SET_BUF_BEGV_BOTH (buf, beg->charpos, beg->bytepos);
3297 SET_BUF_ZV_BOTH (buf, end->charpos, end->bytepos);
3298
3299 if (pt < beg->charpos || pt > end->charpos)
3300 /* The point is outside the new visible range, move it inside. */
3301 SET_BUF_PT_BOTH (buf,
3302 clip_to_bounds (beg->charpos, pt, end->charpos),
63884563 3303 clip_to_bounds (beg->bytepos, BUF_PT_BYTE (buf),
d6abb4c7 3304 end->bytepos));
177c0ea7 3305
d6abb4c7
MB
3306 buf->clip_changed = 1; /* Remember that the narrowing changed. */
3307 }
3308 }
3309 else
3310 /* A buffer, which means that there was no old restriction. */
3311 {
63884563
RS
3312 if (buf /* Verify marker still points to a buffer. */
3313 && (BUF_BEGV (buf) != BUF_BEG (buf) || BUF_ZV (buf) != BUF_Z (buf)))
d6abb4c7
MB
3314 /* The buffer has been narrowed, get rid of the narrowing. */
3315 {
63884563
RS
3316 SET_BUF_BEGV_BOTH (buf, BUF_BEG (buf), BUF_BEG_BYTE (buf));
3317 SET_BUF_ZV_BOTH (buf, BUF_Z (buf), BUF_Z_BYTE (buf));
35692fe0 3318
d6abb4c7
MB
3319 buf->clip_changed = 1; /* Remember that the narrowing changed. */
3320 }
3321 }
35692fe0 3322
aca092ac
SM
3323 /* Changing the buffer bounds invalidates any recorded current column. */
3324 invalidate_current_column ();
3325
d528b1ce
SM
3326 if (cur)
3327 set_buffer_internal (cur);
3328
35692fe0
JB
3329 return Qnil;
3330}
3331
3332DEFUN ("save-restriction", Fsave_restriction, Ssave_restriction, 0, UNEVALLED, 0,
7ee72033 3333 doc: /* Execute BODY, saving and restoring current buffer's restrictions.
a1f17501 3334The buffer's restrictions make parts of the beginning and end invisible.
9671c13a 3335\(They are set up with `narrow-to-region' and eliminated with `widen'.)
a1f17501
PJ
3336This special form, `save-restriction', saves the current buffer's restrictions
3337when it is entered, and restores them when it is exited.
3338So any `narrow-to-region' within BODY lasts only until the end of the form.
3339The old restrictions settings are restored
3340even in case of abnormal exit (throw or error).
3341
3342The value returned is the value of the last form in BODY.
3343
3344Note: if you are using both `save-excursion' and `save-restriction',
3345use `save-excursion' outermost:
33c2d29f
MB
3346 (save-excursion (save-restriction ...))
3347
3348usage: (save-restriction &rest BODY) */)
5842a27b 3349 (Lisp_Object body)
35692fe0
JB
3350{
3351 register Lisp_Object val;
aed13378 3352 int count = SPECPDL_INDEX ();
35692fe0
JB
3353
3354 record_unwind_protect (save_restriction_restore, save_restriction_save ());
3355 val = Fprogn (body);
3356 return unbind_to (count, val);
3357}
3358\f
0ae83348 3359/* Buffer for the most recent text displayed by Fmessage_box. */
671fbc4d
KH
3360static char *message_text;
3361
3362/* Allocated length of that buffer. */
c9f8d652 3363static ptrdiff_t message_length;
671fbc4d 3364
a7ca3326 3365DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
db18da59 3366 doc: /* Display a message at the bottom of the screen.
281c1721
RS
3367The message also goes into the `*Messages*' buffer.
3368\(In keyboard macros, that's all it does.)
db18da59 3369Return the message.
281c1721 3370
a1f17501
PJ
3371The first argument is a format control string, and the rest are data
3372to be formatted under control of the string. See `format' for details.
3373
7bd5bcfb
KS
3374Note: Use (message "%s" VALUE) to print the value of expressions and
3375variables to avoid accidentally interpreting `%' as format specifiers.
3376
fa056b08
KS
3377If the first argument is nil or the empty string, the function clears
3378any existing message; this lets the minibuffer contents show. See
3379also `current-message'.
4bfbe194 3380
867b9600 3381usage: (message FORMAT-STRING &rest ARGS) */)
f66c7cf8 3382 (ptrdiff_t nargs, Lisp_Object *args)
35692fe0 3383{
6076e561
RS
3384 if (NILP (args[0])
3385 || (STRINGP (args[0])
3386 && SBYTES (args[0]) == 0))
f0250249
JB
3387 {
3388 message (0);
674a954a 3389 return args[0];
f0250249 3390 }
ccdac5be
JB
3391 else
3392 {
3393 register Lisp_Object val;
304f1f12 3394 val = Fformat (nargs, args);
d5db4077 3395 message3 (val, SBYTES (val), STRING_MULTIBYTE (val));
ccdac5be
JB
3396 return val;
3397 }
35692fe0
JB
3398}
3399
cacc3e2c 3400DEFUN ("message-box", Fmessage_box, Smessage_box, 1, MANY, 0,
7ee72033 3401 doc: /* Display a message, in a dialog box if possible.
a1f17501
PJ
3402If a dialog box is not available, use the echo area.
3403The first argument is a format control string, and the rest are data
3404to be formatted under control of the string. See `format' for details.
3405
fa056b08
KS
3406If the first argument is nil or the empty string, clear any existing
3407message; let the minibuffer contents show.
4bfbe194 3408
867b9600 3409usage: (message-box FORMAT-STRING &rest ARGS) */)
f66c7cf8 3410 (ptrdiff_t nargs, Lisp_Object *args)
cacc3e2c
RS
3411{
3412 if (NILP (args[0]))
3413 {
3414 message (0);
3415 return Qnil;
3416 }
3417 else
3418 {
3419 register Lisp_Object val;
3420 val = Fformat (nargs, args);
f8250f01 3421#ifdef HAVE_MENUS
0ae83348
EZ
3422 /* The MS-DOS frames support popup menus even though they are
3423 not FRAME_WINDOW_P. */
3424 if (FRAME_WINDOW_P (XFRAME (selected_frame))
3425 || FRAME_MSDOS_P (XFRAME (selected_frame)))
cacc3e2c 3426 {
f838ed7b 3427 Lisp_Object pane, menu;
cacc3e2c
RS
3428 struct gcpro gcpro1;
3429 pane = Fcons (Fcons (build_string ("OK"), Qt), Qnil);
3430 GCPRO1 (pane);
3431 menu = Fcons (val, pane);
f838ed7b 3432 Fx_popup_dialog (Qt, menu, Qt);
cacc3e2c
RS
3433 UNGCPRO;
3434 return val;
3435 }
0ae83348 3436#endif /* HAVE_MENUS */
cacc3e2c
RS
3437 /* Copy the data so that it won't move when we GC. */
3438 if (! message_text)
3439 {
3440 message_text = (char *)xmalloc (80);
3441 message_length = 80;
3442 }
d5db4077 3443 if (SBYTES (val) > message_length)
cacc3e2c 3444 {
c9f8d652 3445 message_text = (char *) xrealloc (message_text, SBYTES (val));
d5db4077 3446 message_length = SBYTES (val);
cacc3e2c 3447 }
72af86bd 3448 memcpy (message_text, SDATA (val), SBYTES (val));
d5db4077 3449 message2 (message_text, SBYTES (val),
d13a8480 3450 STRING_MULTIBYTE (val));
cacc3e2c 3451 return val;
cacc3e2c
RS
3452 }
3453}
f8250f01 3454
cacc3e2c 3455DEFUN ("message-or-box", Fmessage_or_box, Smessage_or_box, 1, MANY, 0,
7ee72033 3456 doc: /* Display a message in a dialog box or in the echo area.
a1f17501
PJ
3457If this command was invoked with the mouse, use a dialog box if
3458`use-dialog-box' is non-nil.
3459Otherwise, use the echo area.
3460The first argument is a format control string, and the rest are data
3461to be formatted under control of the string. See `format' for details.
3462
fa056b08
KS
3463If the first argument is nil or the empty string, clear any existing
3464message; let the minibuffer contents show.
4bfbe194 3465
867b9600 3466usage: (message-or-box FORMAT-STRING &rest ARGS) */)
f66c7cf8 3467 (ptrdiff_t nargs, Lisp_Object *args)
cacc3e2c 3468{
f8250f01 3469#ifdef HAVE_MENUS
5920df33 3470 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
c01fbf95 3471 && use_dialog_box)
0a56ee6b 3472 return Fmessage_box (nargs, args);
cacc3e2c
RS
3473#endif
3474 return Fmessage (nargs, args);
3475}
3476
a7ca3326 3477DEFUN ("current-message", Fcurrent_message, Scurrent_message, 0, 0, 0,
7ee72033 3478 doc: /* Return the string currently displayed in the echo area, or nil if none. */)
5842a27b 3479 (void)
b14dda8a 3480{
0634a78e 3481 return current_message ();
b14dda8a
RS
3482}
3483
2d9811c4 3484
d2936d21 3485DEFUN ("propertize", Fpropertize, Spropertize, 1, MANY, 0,
7ee72033 3486 doc: /* Return a copy of STRING with text properties added.
a1f17501
PJ
3487First argument is the string to copy.
3488Remaining arguments form a sequence of PROPERTY VALUE pairs for text
4bfbe194
MB
3489properties to add to the result.
3490usage: (propertize STRING &rest PROPERTIES) */)
f66c7cf8 3491 (ptrdiff_t nargs, Lisp_Object *args)
2d9811c4
GM
3492{
3493 Lisp_Object properties, string;
3494 struct gcpro gcpro1, gcpro2;
f66c7cf8 3495 ptrdiff_t i;
2d9811c4
GM
3496
3497 /* Number of args must be odd. */
c5101a77 3498 if ((nargs & 1) == 0)
2d9811c4
GM
3499 error ("Wrong number of arguments");
3500
3501 properties = string = Qnil;
3502 GCPRO2 (properties, string);
34a7a267 3503
2d9811c4 3504 /* First argument must be a string. */
b7826503 3505 CHECK_STRING (args[0]);
2d9811c4
GM
3506 string = Fcopy_sequence (args[0]);
3507
3508 for (i = 1; i < nargs; i += 2)
9b7a2369 3509 properties = Fcons (args[i], Fcons (args[i + 1], properties));
2d9811c4
GM
3510
3511 Fadd_text_properties (make_number (0),
d5db4077 3512 make_number (SCHARS (string)),
2d9811c4
GM
3513 properties, string);
3514 RETURN_UNGCPRO (string);
3515}
3516
a7ca3326 3517DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
867b9600
JL
3518 doc: /* Format a string out of a format-string and arguments.
3519The first argument is a format control string.
a1f17501 3520The other arguments are substituted into it to make the result, a string.
575b782f
CY
3521
3522The format control string may contain %-sequences meaning to substitute
3523the next available argument:
3524
a1f17501
PJ
3525%s means print a string argument. Actually, prints any object, with `princ'.
3526%d means print as number in decimal (%o octal, %x hex).
3527%X is like %x, but uses upper case.
3528%e means print a number in exponential notation.
3529%f means print a number in decimal-point notation.
3530%g means print a number in exponential notation
3531 or decimal-point notation, whichever uses fewer characters.
3532%c means print a number as a single character.
3533%S means print any object as an s-expression (using `prin1').
575b782f
CY
3534
3535The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.
4bfbe194
MB
3536Use %% to put a single % into the output.
3537
575b782f
CY
3538A %-sequence may contain optional flag, width, and precision
3539specifiers, as follows:
3540
3541 %<flags><width><precision>character
3542
3543where flags is [+ #-0]+, width is [0-9]+, and precision is .[0-9]+
3544
3545The + flag character inserts a + before any positive number, while a
3546space inserts a space before any positive number; these flags only
3547affect %d, %e, %f, and %g sequences, and the + flag takes precedence.
3548The # flag means to use an alternate display form for %o, %x, %X, %e,
3549%f, and %g sequences. The - and 0 flags affect the width specifier,
3550as described below.
3551
3552The width specifier supplies a lower limit for the length of the
3553printed representation. The padding, if any, normally goes on the
3554left, but it goes on the right if the - flag is present. The padding
3555character is normally a space, but it is 0 if the 0 flag is present.
a9ab721e
LMI
3556The 0 flag is ignored if the - flag is present, or the format sequence
3557is something other than %d, %e, %f, and %g.
575b782f
CY
3558
3559For %e, %f, and %g sequences, the number after the "." in the
3560precision specifier says how many decimal places to show; if zero, the
3561decimal point itself is omitted. For %s and %S, the precision
3562specifier truncates the string to the given width.
f555f8cf 3563
4bfbe194 3564usage: (format STRING &rest OBJECTS) */)
f66c7cf8 3565 (ptrdiff_t nargs, Lisp_Object *args)
35692fe0 3566{
f66c7cf8 3567 ptrdiff_t n; /* The number of the next arg to substitute */
37910ab2
PE
3568 char initial_buffer[4000];
3569 char *buf = initial_buffer;
3570 EMACS_INT bufsize = sizeof initial_buffer;
c9d624c6 3571 EMACS_INT max_bufsize = STRING_BYTES_BOUND + 1;
37910ab2
PE
3572 char *p;
3573 Lisp_Object buf_save_value IF_LINT (= {0});
e7f8264d 3574 register char *format, *end, *format_start;
37910ab2
PE
3575 EMACS_INT formatlen, nchars;
3576 /* Nonzero if the format is multibyte. */
3577 int multibyte_format = 0;
1f24f4fd
RS
3578 /* Nonzero if the output should be a multibyte string,
3579 which is true if any of the inputs is one. */
3580 int multibyte = 0;
8f2917e4
KH
3581 /* When we make a multibyte string, we must pay attention to the
3582 byte combining problem, i.e., a byte may be combined with a
3b59c351 3583 multibyte character of the previous string. This flag tells if we
8f2917e4
KH
3584 must consider such a situation or not. */
3585 int maybe_combine_byte;
8d6179dc 3586 Lisp_Object val;
d147ee84 3587 int arg_intervals = 0;
7e2c051b 3588 USE_SAFE_ALLOCA;
d147ee84
RS
3589
3590 /* discarded[I] is 1 if byte I of the format
3591 string was not copied into the output.
3592 It is 2 if byte I was not the first byte of its character. */
37910ab2 3593 char *discarded;
d147ee84
RS
3594
3595 /* Each element records, for one argument,
3596 the start and end bytepos in the output string,
37910ab2 3597 whether the argument has been converted to string (e.g., due to "%S"),
d147ee84
RS
3598 and whether the argument is a string with intervals.
3599 info[0] is unused. Unused elements have -1 for start. */
5e6d5493
GM
3600 struct info
3601 {
37910ab2
PE
3602 EMACS_INT start, end;
3603 int converted_to_string;
3604 int intervals;
5e6d5493 3605 } *info = 0;
1f24f4fd 3606
35692fe0
JB
3607 /* It should not be necessary to GCPRO ARGS, because
3608 the caller in the interpreter should take care of that. */
3609
37910ab2
PE
3610 CHECK_STRING (args[0]);
3611 format_start = SSDATA (args[0]);
3612 formatlen = SBYTES (args[0]);
3613
3614 /* Allocate the info and discarded tables. */
3615 {
f66c7cf8 3616 ptrdiff_t i;
37910ab2 3617 if ((SIZE_MAX - formatlen) / sizeof (struct info) <= nargs)
531b0165 3618 memory_full (SIZE_MAX);
37910ab2
PE
3619 SAFE_ALLOCA (info, struct info *, (nargs + 1) * sizeof *info + formatlen);
3620 discarded = (char *) &info[nargs + 1];
3621 for (i = 0; i < nargs + 1; i++)
3622 {
3623 info[i].start = -1;
3624 info[i].intervals = info[i].converted_to_string = 0;
3625 }
3626 memset (discarded, 0, formatlen);
3627 }
3628
e781c49e
RS
3629 /* Try to determine whether the result should be multibyte.
3630 This is not always right; sometimes the result needs to be multibyte
3631 because of an object that we will pass through prin1,
3632 and in that case, we won't know it here. */
37910ab2
PE
3633 multibyte_format = STRING_MULTIBYTE (args[0]);
3634 multibyte = multibyte_format;
3635 for (n = 1; !multibyte && n < nargs; n++)
3636 if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
3637 multibyte = 1;
67965a98 3638
e781c49e 3639 /* If we start out planning a unibyte result,
37910ab2 3640 then discover it has to be multibyte, we jump back to retry. */
e781c49e
RS
3641 retry:
3642
37910ab2
PE
3643 p = buf;
3644 nchars = 0;
3645 n = 0;
d147ee84 3646
37910ab2
PE
3647 /* Scan the format and store result in BUF. */
3648 format = format_start;
3649 end = format + formatlen;
3650 maybe_combine_byte = 0;
35692fe0 3651
35692fe0 3652 while (format != end)
37910ab2
PE
3653 {
3654 /* The values of N and FORMAT when the loop body is entered. */
f66c7cf8 3655 ptrdiff_t n0 = n;
37910ab2 3656 char *format0 = format;
35692fe0 3657
37910ab2
PE
3658 /* Bytes needed to represent the output of this conversion. */
3659 EMACS_INT convbytes;
537dfb13 3660
37910ab2
PE
3661 if (*format == '%')
3662 {
3663 /* General format specifications look like
a432bfe5 3664
37910ab2 3665 '%' [flags] [field-width] [precision] format
a432bfe5 3666
37910ab2 3667 where
a432bfe5 3668
37910ab2
PE
3669 flags ::= [-+0# ]+
3670 field-width ::= [0-9]+
3671 precision ::= '.' [0-9]*
a432bfe5 3672
37910ab2
PE
3673 If a field-width is specified, it specifies to which width
3674 the output should be padded with blanks, if the output
3675 string is shorter than field-width.
a432bfe5 3676
37910ab2
PE
3677 If precision is specified, it specifies the number of
3678 digits to print after the '.' for floats, or the max.
3679 number of chars to print from a string. */
a432bfe5 3680
37910ab2
PE
3681 int minus_flag = 0;
3682 int plus_flag = 0;
3683 int space_flag = 0;
3684 int sharp_flag = 0;
3685 int zero_flag = 0;
3686 EMACS_INT field_width;
3687 int precision_given;
3688 uintmax_t precision = UINTMAX_MAX;
3689 char *num_end;
3690 char conversion;
a432bfe5 3691
37910ab2
PE
3692 while (1)
3693 {
3694 switch (*++format)
3695 {
3696 case '-': minus_flag = 1; continue;
3697 case '+': plus_flag = 1; continue;
3698 case ' ': space_flag = 1; continue;
3699 case '#': sharp_flag = 1; continue;
3700 case '0': zero_flag = 1; continue;
3701 }
3702 break;
3703 }
35692fe0 3704
37910ab2
PE
3705 /* Ignore flags when sprintf ignores them. */
3706 space_flag &= ~ plus_flag;
3707 zero_flag &= ~ minus_flag;
1f24f4fd 3708
35692fe0 3709 {
37910ab2
PE
3710 uintmax_t w = strtoumax (format, &num_end, 10);
3711 if (max_bufsize <= w)
3712 string_overflow ();
3713 field_width = w;
35692fe0 3714 }
37910ab2
PE
3715 precision_given = *num_end == '.';
3716 if (precision_given)
3717 precision = strtoumax (num_end + 1, &num_end, 10);
3718 format = num_end;
3719
3720 if (format == end)
3721 error ("Format string ends in middle of format specifier");
3722
3723 memset (&discarded[format0 - format_start], 1, format - format0);
3724 conversion = *format;
3725 if (conversion == '%')
7812ba2d 3726 goto copy_char;
d147ee84 3727 discarded[format - format_start] = 1;
1f24f4fd 3728 format++;
fb893977 3729
37910ab2
PE
3730 ++n;
3731 if (! (n < nargs))
3732 error ("Not enough arguments for format string");
3733
3734 /* For 'S', prin1 the argument, and then treat like 's'.
3735 For 's', princ any argument that is not a string or
3736 symbol. But don't do this conversion twice, which might
3737 happen after retrying. */
3738 if ((conversion == 'S'
3739 || (conversion == 's'
3740 && ! STRINGP (args[n]) && ! SYMBOLP (args[n]))))
f555f8cf 3741 {
37910ab2 3742 if (! info[n].converted_to_string)
f555f8cf 3743 {
37910ab2
PE
3744 Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
3745 args[n] = Fprin1_to_string (args[n], noescape);
3746 info[n].converted_to_string = 1;
3747 if (STRING_MULTIBYTE (args[n]) && ! multibyte)
3748 {
3749 multibyte = 1;
3750 goto retry;
3751 }
f555f8cf 3752 }
37910ab2 3753 conversion = 's';
f555f8cf 3754 }
37910ab2
PE
3755 else if (conversion == 'c')
3756 {
3757 if (FLOATP (args[n]))
3758 {
3759 double d = XFLOAT_DATA (args[n]);
3760 args[n] = make_number (FIXNUM_OVERFLOW_P (d) ? -1 : d);
3761 }
f555f8cf 3762
37910ab2
PE
3763 if (INTEGERP (args[n]) && ! ASCII_CHAR_P (XINT (args[n])))
3764 {
3765 if (!multibyte)
3766 {
3767 multibyte = 1;
3768 goto retry;
3769 }
3770 args[n] = Fchar_to_string (args[n]);
3771 info[n].converted_to_string = 1;
3772 }
f555f8cf 3773
37910ab2
PE
3774 if (info[n].converted_to_string)
3775 conversion = 's';
3776 zero_flag = 0;
d147ee84 3777 }
35692fe0 3778
37910ab2 3779 if (SYMBOLP (args[n]))
1f24f4fd 3780 {
37910ab2
PE
3781 args[n] = SYMBOL_NAME (args[n]);
3782 if (STRING_MULTIBYTE (args[n]) && ! multibyte)
3783 {
3784 multibyte = 1;
3785 goto retry;
3786 }
1f24f4fd
RS
3787 }
3788
37910ab2 3789 if (conversion == 's')
1f24f4fd 3790 {
ac42d7b9
KG
3791 /* handle case (precision[n] >= 0) */
3792
37910ab2 3793 EMACS_INT width, padding, nbytes;
579c18d0 3794 EMACS_INT nchars_string;
ac42d7b9 3795
37910ab2
PE
3796 EMACS_INT prec = -1;
3797 if (precision_given && precision <= TYPE_MAXIMUM (EMACS_INT))
3798 prec = precision;
3799
ac42d7b9
KG
3800 /* lisp_string_width ignores a precision of 0, but GNU
3801 libc functions print 0 characters when the precision
3802 is 0. Imitate libc behavior here. Changing
3803 lisp_string_width is the right thing, and will be
3804 done, but meanwhile we work with it. */
3805
37910ab2 3806 if (prec == 0)
ac42d7b9 3807 width = nchars_string = nbytes = 0;
ac42d7b9 3808 else
37910ab2
PE
3809 {
3810 EMACS_INT nch, nby;
3811 width = lisp_string_width (args[n], prec, &nch, &nby);
3812 if (prec < 0)
3813 {
3814 nchars_string = SCHARS (args[n]);
3815 nbytes = SBYTES (args[n]);
3816 }
3817 else
3818 {
3819 nchars_string = nch;
3820 nbytes = nby;
3821 }
ac42d7b9 3822 }
25c9e7fb 3823
37910ab2
PE
3824 convbytes = nbytes;
3825 if (convbytes && multibyte && ! STRING_MULTIBYTE (args[n]))
3826 convbytes = count_size_as_multibyte (SDATA (args[n]), nbytes);
1f24f4fd 3827
37910ab2 3828 padding = width < field_width ? field_width - width : 0;
ac42d7b9 3829
37910ab2
PE
3830 if (max_bufsize - padding <= convbytes)
3831 string_overflow ();
3832 convbytes += padding;
3833 if (convbytes <= buf + bufsize - p)
3834 {
3835 if (! minus_flag)
3836 {
3837 memset (p, ' ', padding);
3838 p += padding;
3839 nchars += padding;
3840 }
ac42d7b9 3841
37910ab2
PE
3842 if (p > buf
3843 && multibyte
3844 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
3845 && STRING_MULTIBYTE (args[n])
3846 && !CHAR_HEAD_P (SREF (args[n], 0)))
3847 maybe_combine_byte = 1;
1f24f4fd 3848
37910ab2
PE
3849 p += copy_text (SDATA (args[n]), (unsigned char *) p,
3850 nbytes,
3851 STRING_MULTIBYTE (args[n]), multibyte);
8f2c9ed8 3852
37910ab2
PE
3853 info[n].start = nchars;
3854 nchars += nchars_string;
3855 info[n].end = nchars;
3856
3857 if (minus_flag)
3858 {
3859 memset (p, ' ', padding);
3860 p += padding;
3861 nchars += padding;
3862 }
5e6d5493 3863
37910ab2
PE
3864 /* If this argument has text properties, record where
3865 in the result string it appears. */
3866 if (STRING_INTERVALS (args[n]))
3867 info[n].intervals = arg_intervals = 1;
3868
3869 continue;
3870 }
1f24f4fd 3871 }
37910ab2
PE
3872 else if (! (conversion == 'c' || conversion == 'd'
3873 || conversion == 'e' || conversion == 'f'
3874 || conversion == 'g' || conversion == 'i'
3875 || conversion == 'o' || conversion == 'x'
3876 || conversion == 'X'))
3877 error ("Invalid format operation %%%c",
3878 STRING_CHAR ((unsigned char *) format - 1));
3879 else if (! (INTEGERP (args[n]) || FLOATP (args[n])))
3880 error ("Format specifier doesn't match argument type");
3881 else
1f24f4fd 3882 {
37910ab2
PE
3883 enum
3884 {
3885 /* Maximum precision for a %f conversion such that the
333f9019 3886 trailing output digit might be nonzero. Any precision
37910ab2
PE
3887 larger than this will not yield useful information. */
3888 USEFUL_PRECISION_MAX =
3889 ((1 - DBL_MIN_EXP)
3890 * (FLT_RADIX == 2 || FLT_RADIX == 10 ? 1
3891 : FLT_RADIX == 16 ? 4
3892 : -1)),
3893
3894 /* Maximum number of bytes generated by any format, if
81f7c12e 3895 precision is no more than USEFUL_PRECISION_MAX.
37910ab2
PE
3896 On all practical hosts, %f is the worst case. */
3897 SPRINTF_BUFSIZE =
a81d11a3
PE
3898 sizeof "-." + (DBL_MAX_10_EXP + 1) + USEFUL_PRECISION_MAX,
3899
3900 /* Length of pM (that is, of pMd without the
3901 trailing "d"). */
3902 pMlen = sizeof pMd - 2
37910ab2
PE
3903 };
3904 verify (0 < USEFUL_PRECISION_MAX);
3905
3906 int prec;
3907 EMACS_INT padding, sprintf_bytes;
3908 uintmax_t excess_precision, numwidth;
3909 uintmax_t leading_zeros = 0, trailing_zeros = 0;
3910
3911 char sprintf_buf[SPRINTF_BUFSIZE];
3912
3913 /* Copy of conversion specification, modified somewhat.
3914 At most three flags F can be specified at once. */
a81d11a3 3915 char convspec[sizeof "%FFF.*d" + pMlen];
37910ab2
PE
3916
3917 /* Avoid undefined behavior in underlying sprintf. */
3918 if (conversion == 'd' || conversion == 'i')
3919 sharp_flag = 0;
3920
3921 /* Create the copy of the conversion specification, with
3922 any width and precision removed, with ".*" inserted,
a81d11a3 3923 and with pM inserted for integer formats. */
37910ab2
PE
3924 {
3925 char *f = convspec;
3926 *f++ = '%';
3927 *f = '-'; f += minus_flag;
3928 *f = '+'; f += plus_flag;
3929 *f = ' '; f += space_flag;
3930 *f = '#'; f += sharp_flag;
3931 *f = '0'; f += zero_flag;
3932 *f++ = '.';
3933 *f++ = '*';
3934 if (conversion == 'd' || conversion == 'i'
3935 || conversion == 'o' || conversion == 'x'
3936 || conversion == 'X')
3937 {
a81d11a3
PE
3938 memcpy (f, pMd, pMlen);
3939 f += pMlen;
37910ab2
PE
3940 zero_flag &= ~ precision_given;
3941 }
3942 *f++ = conversion;
3943 *f = '\0';
3944 }
1f24f4fd 3945
37910ab2
PE
3946 prec = -1;
3947 if (precision_given)
3948 prec = min (precision, USEFUL_PRECISION_MAX);
3949
3950 /* Use sprintf to format this number into sprintf_buf. Omit
3951 padding and excess precision, though, because sprintf limits
3952 output length to INT_MAX.
3953
3954 There are four types of conversion: double, unsigned
3955 char (passed as int), wide signed int, and wide
3956 unsigned int. Treat them separately because the
3957 sprintf ABI is sensitive to which type is passed. Be
3958 careful about integer overflow, NaNs, infinities, and
3959 conversions; for example, the min and max macros are
3960 not suitable here. */
3961 if (conversion == 'e' || conversion == 'f' || conversion == 'g')
3962 {
3963 double x = (INTEGERP (args[n])
3964 ? XINT (args[n])
3965 : XFLOAT_DATA (args[n]));
3966 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
3967 }
3968 else if (conversion == 'c')
3969 {
3970 /* Don't use sprintf here, as it might mishandle prec. */
3971 sprintf_buf[0] = XINT (args[n]);
3972 sprintf_bytes = prec != 0;
3973 }
3974 else if (conversion == 'd')
3975 {
3976 /* For float, maybe we should use "%1.0f"
3977 instead so it also works for values outside
3978 the integer range. */
a81d11a3 3979 printmax_t x;
37910ab2
PE
3980 if (INTEGERP (args[n]))
3981 x = XINT (args[n]);
3982 else
3983 {
3984 double d = XFLOAT_DATA (args[n]);
3985 if (d < 0)
3986 {
a81d11a3 3987 x = TYPE_MINIMUM (printmax_t);
37910ab2
PE
3988 if (x < d)
3989 x = d;
3990 }
3991 else
3992 {
a81d11a3 3993 x = TYPE_MAXIMUM (printmax_t);
37910ab2
PE
3994 if (d < x)
3995 x = d;
3996 }
3997 }
3998 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
3999 }
0f860bd7 4000 else
de92d4d4 4001 {
37910ab2 4002 /* Don't sign-extend for octal or hex printing. */
a81d11a3 4003 uprintmax_t x;
37910ab2
PE
4004 if (INTEGERP (args[n]))
4005 x = XUINT (args[n]);
4006 else
0f860bd7 4007 {
37910ab2
PE
4008 double d = XFLOAT_DATA (args[n]);
4009 if (d < 0)
4010 x = 0;
4011 else
4012 {
a81d11a3 4013 x = TYPE_MAXIMUM (uprintmax_t);
37910ab2
PE
4014 if (d < x)
4015 x = d;
4016 }
0f860bd7 4017 }
37910ab2
PE
4018 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
4019 }
0f860bd7 4020
37910ab2
PE
4021 /* Now the length of the formatted item is known, except it omits
4022 padding and excess precision. Deal with excess precision
4023 first. This happens only when the format specifies
4024 ridiculously large precision. */
4025 excess_precision = precision - prec;
4026 if (excess_precision)
4027 {
4028 if (conversion == 'e' || conversion == 'f'
4029 || conversion == 'g')
ff6e6ac8 4030 {
37910ab2
PE
4031 if ((conversion == 'g' && ! sharp_flag)
4032 || ! ('0' <= sprintf_buf[sprintf_bytes - 1]
4033 && sprintf_buf[sprintf_bytes - 1] <= '9'))
4034 excess_precision = 0;
ff6e6ac8 4035 else
37910ab2
PE
4036 {
4037 if (conversion == 'g')
4038 {
4039 char *dot = strchr (sprintf_buf, '.');
4040 if (!dot)
4041 excess_precision = 0;
4042 }
4043 }
4044 trailing_zeros = excess_precision;
ff6e6ac8 4045 }
de92d4d4 4046 else
37910ab2 4047 leading_zeros = excess_precision;
de92d4d4 4048 }
1f24f4fd 4049
37910ab2
PE
4050 /* Compute the total bytes needed for this item, including
4051 excess precision and padding. */
4052 numwidth = sprintf_bytes + excess_precision;
4053 padding = numwidth < field_width ? field_width - numwidth : 0;
4054 if (max_bufsize - sprintf_bytes <= excess_precision
4055 || max_bufsize - padding <= numwidth)
4056 string_overflow ();
4057 convbytes = numwidth + padding;
4058
4059 if (convbytes <= buf + bufsize - p)
4060 {
4061 /* Copy the formatted item from sprintf_buf into buf,
4062 inserting padding and excess-precision zeros. */
4063
4064 char *src = sprintf_buf;
4065 char src0 = src[0];
4066 int exponent_bytes = 0;
4067 int signedp = src0 == '-' || src0 == '+' || src0 == ' ';
4068 int significand_bytes;
172418ad
AS
4069 if (zero_flag
4070 && ((src[signedp] >= '0' && src[signedp] <= '9')
4071 || (src[signedp] >= 'a' && src[signedp] <= 'f')
4072 || (src[signedp] >= 'A' && src[signedp] <= 'F')))
37910ab2
PE
4073 {
4074 leading_zeros += padding;
4075 padding = 0;
4076 }
4077
4078 if (excess_precision
4079 && (conversion == 'e' || conversion == 'g'))
4080 {
4081 char *e = strchr (src, 'e');
4082 if (e)
4083 exponent_bytes = src + sprintf_bytes - e;
4084 }
4085
4086 if (! minus_flag)
4087 {
4088 memset (p, ' ', padding);
4089 p += padding;
4090 nchars += padding;
4091 }
4092
4093 *p = src0;
4094 src += signedp;
4095 p += signedp;
4096 memset (p, '0', leading_zeros);
4097 p += leading_zeros;
4098 significand_bytes = sprintf_bytes - signedp - exponent_bytes;
4099 memcpy (p, src, significand_bytes);
4100 p += significand_bytes;
4101 src += significand_bytes;
4102 memset (p, '0', trailing_zeros);
4103 p += trailing_zeros;
4104 memcpy (p, src, exponent_bytes);
4105 p += exponent_bytes;
4106
4107 info[n].start = nchars;
4108 nchars += leading_zeros + sprintf_bytes + trailing_zeros;
4109 info[n].end = nchars;
4110
4111 if (minus_flag)
4112 {
4113 memset (p, ' ', padding);
4114 p += padding;
4115 nchars += padding;
4116 }
4117
4118 continue;
4119 }
4120 }
4121 }
4122 else
4123 copy_char:
4124 {
4125 /* Copy a single character from format to buf. */
4126
4127 char *src = format;
4128 unsigned char str[MAX_MULTIBYTE_LENGTH];
4129
4130 if (multibyte_format)
4131 {
4132 /* Copy a whole multibyte character. */
8f2917e4 4133 if (p > buf
25aa5d64 4134 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
37910ab2 4135 && !CHAR_HEAD_P (*format))
8f2917e4 4136 maybe_combine_byte = 1;
37910ab2
PE
4137
4138 do
4139 format++;
4140 while (! CHAR_HEAD_P (*format));
4141
a02719a3 4142 convbytes = format - src;
7812ba2d 4143 memset (&discarded[src + 1 - format_start], 2, convbytes - 1);
37910ab2
PE
4144 }
4145 else
4146 {
4147 unsigned char uc = *format++;
4148 if (! multibyte || ASCII_BYTE_P (uc))
4149 convbytes = 1;
9a599130 4150 else
37910ab2
PE
4151 {
4152 int c = BYTE8_TO_CHAR (uc);
4153 convbytes = CHAR_STRING (c, str);
4154 src = (char *) str;
4155 }
1f24f4fd 4156 }
d147ee84 4157
37910ab2 4158 if (convbytes <= buf + bufsize - p)
d147ee84 4159 {
37910ab2
PE
4160 memcpy (p, src, convbytes);
4161 p += convbytes;
4162 nchars++;
4163 continue;
d147ee84 4164 }
7df74da6 4165 }
1f24f4fd 4166
37910ab2
PE
4167 /* There wasn't enough room to store this conversion or single
4168 character. CONVBYTES says how much room is needed. Allocate
4169 enough room (and then some) and do it again. */
4170 {
c9f8d652 4171 ptrdiff_t used = p - buf;
37910ab2
PE
4172
4173 if (max_bufsize - used < convbytes)
4174 string_overflow ();
4175 bufsize = used + convbytes;
4176 bufsize = bufsize < max_bufsize / 2 ? bufsize * 2 : max_bufsize;
4177
4178 if (buf == initial_buffer)
4179 {
4180 buf = xmalloc (bufsize);
4181 sa_must_free = 1;
4182 buf_save_value = make_save_value (buf, 0);
4183 record_unwind_protect (safe_alloca_unwind, buf_save_value);
4184 memcpy (buf, initial_buffer, used);
4185 }
4186 else
4187 XSAVE_VALUE (buf_save_value)->pointer = buf = xrealloc (buf, bufsize);
4188
4189 p = buf + used;
4190 }
4191
4192 format = format0;
4193 n = n0;
1f24f4fd
RS
4194 }
4195
37910ab2 4196 if (bufsize < p - buf)
a432bfe5
GM
4197 abort ();
4198
8f2917e4 4199 if (maybe_combine_byte)
e7f8264d 4200 nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf);
5f75e666 4201 val = make_specified_string (buf, nchars, p - buf, multibyte);
8d6179dc 4202
1f24f4fd 4203 /* If we allocated BUF with malloc, free it too. */
e65837df 4204 SAFE_FREE ();
35692fe0 4205
5e6d5493
GM
4206 /* If the format string has text properties, or any of the string
4207 arguments has text properties, set up text properties of the
4208 result string. */
34a7a267 4209
d147ee84 4210 if (STRING_INTERVALS (args[0]) || arg_intervals)
5e6d5493
GM
4211 {
4212 Lisp_Object len, new_len, props;
4213 struct gcpro gcpro1;
34a7a267 4214
5e6d5493 4215 /* Add text properties from the format string. */
d5db4077 4216 len = make_number (SCHARS (args[0]));
5e6d5493
GM
4217 props = text_property_list (args[0], make_number (0), len, Qnil);
4218 GCPRO1 (props);
34a7a267 4219
5e6d5493
GM
4220 if (CONSP (props))
4221 {
29cdc13e 4222 EMACS_INT bytepos = 0, position = 0, translated = 0;
37910ab2 4223 EMACS_INT argn = 1;
d147ee84
RS
4224 Lisp_Object list;
4225
4226 /* Adjust the bounds of each text property
4227 to the proper start and end in the output string. */
d147ee84 4228
15fad037
KS
4229 /* Put the positions in PROPS in increasing order, so that
4230 we can do (effectively) one scan through the position
4231 space of the format string. */
4232 props = Fnreverse (props);
4233
4234 /* BYTEPOS is the byte position in the format string,
d147ee84
RS
4235 POSITION is the untranslated char position in it,
4236 TRANSLATED is the translated char position in BUF,
4237 and ARGN is the number of the next arg we will come to. */
4238 for (list = props; CONSP (list); list = XCDR (list))
4239 {
f3ce1df8 4240 Lisp_Object item;
29cdc13e 4241 EMACS_INT pos;
d147ee84
RS
4242
4243 item = XCAR (list);
4244
4245 /* First adjust the property start position. */
4246 pos = XINT (XCAR (item));
4247
4248 /* Advance BYTEPOS, POSITION, TRANSLATED and ARGN
4249 up to this position. */
4250 for (; position < pos; bytepos++)
4251 {
4252 if (! discarded[bytepos])
4253 position++, translated++;
4254 else if (discarded[bytepos] == 1)
4255 {
4256 position++;
4257 if (translated == info[argn].start)
4258 {
4259 translated += info[argn].end - info[argn].start;
4260 argn++;
4261 }
4262 }
4263 }
4264
4265 XSETCAR (item, make_number (translated));
4266
4267 /* Likewise adjust the property end position. */
4268 pos = XINT (XCAR (XCDR (item)));
4269
d40ec4a0 4270 for (; position < pos; bytepos++)
d147ee84
RS
4271 {
4272 if (! discarded[bytepos])
4273 position++, translated++;
4274 else if (discarded[bytepos] == 1)
4275 {
4276 position++;
4277 if (translated == info[argn].start)
4278 {
4279 translated += info[argn].end - info[argn].start;
4280 argn++;
4281 }
4282 }
4283 }
4284
4285 XSETCAR (XCDR (item), make_number (translated));
4286 }
4287
5e6d5493
GM
4288 add_text_properties_from_list (val, props, make_number (0));
4289 }
4290
4291 /* Add text properties from arguments. */
d147ee84 4292 if (arg_intervals)
5e6d5493 4293 for (n = 1; n < nargs; ++n)
d147ee84 4294 if (info[n].intervals)
5e6d5493 4295 {
d5db4077 4296 len = make_number (SCHARS (args[n]));
5e6d5493
GM
4297 new_len = make_number (info[n].end - info[n].start);
4298 props = text_property_list (args[n], make_number (0), len, Qnil);
e398c61c
CY
4299 props = extend_property_ranges (props, new_len);
4300 /* If successive arguments have properties, be sure that
be17069b
KH
4301 the value of `composition' property be the copy. */
4302 if (n > 1 && info[n - 1].end)
4303 make_composition_value_copy (props);
5e6d5493
GM
4304 add_text_properties_from_list (val, props,
4305 make_number (info[n].start));
4306 }
4307
4308 UNGCPRO;
4309 }
4310
8d6179dc 4311 return val;
35692fe0
JB
4312}
4313
35692fe0 4314Lisp_Object
a8fe7202 4315format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1)
d40dc1d0
RS
4316{
4317 Lisp_Object args[3];
d40dc1d0
RS
4318 args[0] = build_string (string1);
4319 args[1] = arg0;
4320 args[2] = arg1;
4321 return Fformat (3, args);
35692fe0
JB
4322}
4323\f
4324DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
7ee72033 4325 doc: /* Return t if two characters match, optionally ignoring case.
a1f17501 4326Both arguments must be characters (i.e. integers).
7ee72033 4327Case is ignored if `case-fold-search' is non-nil in the current buffer. */)
5842a27b 4328 (register Lisp_Object c1, Lisp_Object c2)
35692fe0 4329{
1b5d98bb 4330 int i1, i2;
253c3c82 4331 /* Check they're chars, not just integers, otherwise we could get array
5da9919f 4332 bounds violations in downcase. */
253c3c82
SM
4333 CHECK_CHARACTER (c1);
4334 CHECK_CHARACTER (c2);
35692fe0 4335
1b5d98bb 4336 if (XINT (c1) == XINT (c2))
35692fe0 4337 return Qt;
4b4deea2 4338 if (NILP (BVAR (current_buffer, case_fold_search)))
1b5d98bb
RS
4339 return Qnil;
4340
e5112ecb 4341 i1 = XFASTINT (c1);
4b4deea2 4342 if (NILP (BVAR (current_buffer, enable_multibyte_characters))
e5112ecb
KH
4343 && ! ASCII_CHAR_P (i1))
4344 {
4345 MAKE_CHAR_MULTIBYTE (i1);
4346 }
4347 i2 = XFASTINT (c2);
4b4deea2 4348 if (NILP (BVAR (current_buffer, enable_multibyte_characters))
e5112ecb
KH
4349 && ! ASCII_CHAR_P (i2))
4350 {
4351 MAKE_CHAR_MULTIBYTE (i2);
4352 }
0da09c43 4353 return (downcase (i1) == downcase (i2) ? Qt : Qnil);
35692fe0 4354}
b229b8d1
RS
4355\f
4356/* Transpose the markers in two regions of the current buffer, and
4357 adjust the ones between them if necessary (i.e.: if the regions
4358 differ in size).
4359
ec1c14f6
RS
4360 START1, END1 are the character positions of the first region.
4361 START1_BYTE, END1_BYTE are the byte positions.
4362 START2, END2 are the character positions of the second region.
4363 START2_BYTE, END2_BYTE are the byte positions.
4364
b229b8d1
RS
4365 Traverses the entire marker list of the buffer to do so, adding an
4366 appropriate amount to some, subtracting from some, and leaving the
4367 rest untouched. Most of this is copied from adjust_markers in insdel.c.
34a7a267 4368
ec1c14f6 4369 It's the caller's job to ensure that START1 <= END1 <= START2 <= END2. */
b229b8d1 4370
acb7cc89 4371static void
29cdc13e
EZ
4372transpose_markers (EMACS_INT start1, EMACS_INT end1,
4373 EMACS_INT start2, EMACS_INT end2,
4374 EMACS_INT start1_byte, EMACS_INT end1_byte,
4375 EMACS_INT start2_byte, EMACS_INT end2_byte)
b229b8d1 4376{
29cdc13e 4377 register EMACS_INT amt1, amt1_byte, amt2, amt2_byte, diff, diff_byte, mpos;
12038f9f 4378 register struct Lisp_Marker *marker;
b229b8d1 4379
03240d11 4380 /* Update point as if it were a marker. */
8de1d5f0
KH
4381 if (PT < start1)
4382 ;
4383 else if (PT < end1)
ec1c14f6
RS
4384 TEMP_SET_PT_BOTH (PT + (end2 - end1),
4385 PT_BYTE + (end2_byte - end1_byte));
8de1d5f0 4386 else if (PT < start2)
ec1c14f6
RS
4387 TEMP_SET_PT_BOTH (PT + (end2 - start2) - (end1 - start1),
4388 (PT_BYTE + (end2_byte - start2_byte)
4389 - (end1_byte - start1_byte)));
8de1d5f0 4390 else if (PT < end2)
ec1c14f6
RS
4391 TEMP_SET_PT_BOTH (PT - (start2 - start1),
4392 PT_BYTE - (start2_byte - start1_byte));
8de1d5f0 4393
03240d11
KH
4394 /* We used to adjust the endpoints here to account for the gap, but that
4395 isn't good enough. Even if we assume the caller has tried to move the
4396 gap out of our way, it might still be at start1 exactly, for example;
4397 and that places it `inside' the interval, for our purposes. The amount
4398 of adjustment is nontrivial if there's a `denormalized' marker whose
4399 position is between GPT and GPT + GAP_SIZE, so it's simpler to leave
4400 the dirty work to Fmarker_position, below. */
b229b8d1
RS
4401
4402 /* The difference between the region's lengths */
4403 diff = (end2 - start2) - (end1 - start1);
ec1c14f6 4404 diff_byte = (end2_byte - start2_byte) - (end1_byte - start1_byte);
34a7a267 4405
b229b8d1 4406 /* For shifting each marker in a region by the length of the other
ec1c14f6 4407 region plus the distance between the regions. */
b229b8d1
RS
4408 amt1 = (end2 - start2) + (start2 - end1);
4409 amt2 = (end1 - start1) + (start2 - end1);
ec1c14f6
RS
4410 amt1_byte = (end2_byte - start2_byte) + (start2_byte - end1_byte);
4411 amt2_byte = (end1_byte - start1_byte) + (start2_byte - end1_byte);
b229b8d1 4412
12038f9f 4413 for (marker = BUF_MARKERS (current_buffer); marker; marker = marker->next)
b229b8d1 4414 {
12038f9f 4415 mpos = marker->bytepos;
ec1c14f6
RS
4416 if (mpos >= start1_byte && mpos < end2_byte)
4417 {
4418 if (mpos < end1_byte)
4419 mpos += amt1_byte;
4420 else if (mpos < start2_byte)
4421 mpos += diff_byte;
4422 else
4423 mpos -= amt2_byte;
12038f9f 4424 marker->bytepos = mpos;
ec1c14f6 4425 }
12038f9f 4426 mpos = marker->charpos;
03240d11
KH
4427 if (mpos >= start1 && mpos < end2)
4428 {
4429 if (mpos < end1)
4430 mpos += amt1;
4431 else if (mpos < start2)
4432 mpos += diff;
4433 else
4434 mpos -= amt2;
03240d11 4435 }
12038f9f 4436 marker->charpos = mpos;
b229b8d1
RS
4437 }
4438}
4439
4440DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5, 0,
412f1fab 4441 doc: /* Transpose region STARTR1 to ENDR1 with STARTR2 to ENDR2.
27a69fd9 4442The regions should not be overlapping, because the size of the buffer is
a1f17501
PJ
4443never changed in a transposition.
4444
412f1fab 4445Optional fifth arg LEAVE-MARKERS, if non-nil, means don't update
a1f17501
PJ
4446any markers that happen to be located in the regions.
4447
7ee72033 4448Transposing beyond buffer boundaries is an error. */)
5842a27b 4449 (Lisp_Object startr1, Lisp_Object endr1, Lisp_Object startr2, Lisp_Object endr2, Lisp_Object leave_markers)
b229b8d1 4450{
d47ecf8b
SM
4451 register EMACS_INT start1, end1, start2, end2;
4452 EMACS_INT start1_byte, start2_byte, len1_byte, len2_byte;
4453 EMACS_INT gap, len1, len_mid, len2;
3c6bc7d0 4454 unsigned char *start1_addr, *start2_addr, *temp;
b229b8d1 4455
6cd0f478 4456 INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2, tmp_interval3;
916480c4
CY
4457 Lisp_Object buf;
4458
4459 XSETBUFFER (buf, current_buffer);
1e158d25 4460 cur_intv = BUF_INTERVALS (current_buffer);
b229b8d1
RS
4461
4462 validate_region (&startr1, &endr1);
4463 validate_region (&startr2, &endr2);
4464
4465 start1 = XFASTINT (startr1);
4466 end1 = XFASTINT (endr1);
4467 start2 = XFASTINT (startr2);
4468 end2 = XFASTINT (endr2);
4469 gap = GPT;
4470
4471 /* Swap the regions if they're reversed. */
4472 if (start2 < end1)
4473 {
29cdc13e 4474 register EMACS_INT glumph = start1;
b229b8d1
RS
4475 start1 = start2;
4476 start2 = glumph;
4477 glumph = end1;
4478 end1 = end2;
4479 end2 = glumph;
4480 }
4481
b229b8d1
RS
4482 len1 = end1 - start1;
4483 len2 = end2 - start2;
4484
4485 if (start2 < end1)
dc3620af 4486 error ("Transposed regions overlap");
0f4aebc0
LL
4487 /* Nothing to change for adjacent regions with one being empty */
4488 else if ((start1 == end1 || start2 == end2) && end1 == start2)
4489 return Qnil;
b229b8d1
RS
4490
4491 /* The possibilities are:
4492 1. Adjacent (contiguous) regions, or separate but equal regions
4493 (no, really equal, in this case!), or
4494 2. Separate regions of unequal size.
34a7a267 4495
b229b8d1
RS
4496 The worst case is usually No. 2. It means that (aside from
4497 potential need for getting the gap out of the way), there also
4498 needs to be a shifting of the text between the two regions. So
4499 if they are spread far apart, we are that much slower... sigh. */
4500
4501 /* It must be pointed out that the really studly thing to do would
4502 be not to move the gap at all, but to leave it in place and work
4503 around it if necessary. This would be extremely efficient,
4504 especially considering that people are likely to do
4505 transpositions near where they are working interactively, which
4506 is exactly where the gap would be found. However, such code
4507 would be much harder to write and to read. So, if you are
4508 reading this comment and are feeling squirrely, by all means have
4509 a go! I just didn't feel like doing it, so I will simply move
4510 the gap the minimum distance to get it out of the way, and then
4511 deal with an unbroken array. */
3c6bc7d0
RS
4512
4513 /* Make sure the gap won't interfere, by moving it out of the text
4514 we will operate on. */
4515 if (start1 < gap && gap < end2)
4516 {
4517 if (gap - start1 < end2 - gap)
4518 move_gap (start1);
4519 else
4520 move_gap (end2);
4521 }
ec1c14f6
RS
4522
4523 start1_byte = CHAR_TO_BYTE (start1);
4524 start2_byte = CHAR_TO_BYTE (start2);
4525 len1_byte = CHAR_TO_BYTE (end1) - start1_byte;
4526 len2_byte = CHAR_TO_BYTE (end2) - start2_byte;
dc3620af 4527
9a599130 4528#ifdef BYTE_COMBINING_DEBUG
dc3620af
RS
4529 if (end1 == start2)
4530 {
9a599130
KH
4531 if (count_combining_before (BYTE_POS_ADDR (start2_byte),
4532 len2_byte, start1, start1_byte)
4533 || count_combining_before (BYTE_POS_ADDR (start1_byte),
4534 len1_byte, end2, start2_byte + len2_byte)
4535 || count_combining_after (BYTE_POS_ADDR (start1_byte),
4536 len1_byte, end2, start2_byte + len2_byte))
4537 abort ();
dc3620af
RS
4538 }
4539 else
4540 {
9a599130
KH
4541 if (count_combining_before (BYTE_POS_ADDR (start2_byte),
4542 len2_byte, start1, start1_byte)
4543 || count_combining_before (BYTE_POS_ADDR (start1_byte),
4544 len1_byte, start2, start2_byte)
4545 || count_combining_after (BYTE_POS_ADDR (start2_byte),
4546 len2_byte, end1, start1_byte + len1_byte)
4547 || count_combining_after (BYTE_POS_ADDR (start1_byte),
4548 len1_byte, end2, start2_byte + len2_byte))
4549 abort ();
dc3620af 4550 }
9a599130 4551#endif
dc3620af 4552
b229b8d1
RS
4553 /* Hmmm... how about checking to see if the gap is large
4554 enough to use as the temporary storage? That would avoid an
4555 allocation... interesting. Later, don't fool with it now. */
4556
4557 /* Working without memmove, for portability (sigh), so must be
4558 careful of overlapping subsections of the array... */
4559
4560 if (end1 == start2) /* adjacent regions */
4561 {
3e145152 4562 modify_region (current_buffer, start1, end2, 0);
b229b8d1
RS
4563 record_change (start1, len1 + len2);
4564
b229b8d1
RS
4565 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
4566 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
916480c4
CY
4567 /* Don't use Fset_text_properties: that can cause GC, which can
4568 clobber objects stored in the tmp_intervals. */
6cd0f478
CY
4569 tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0);
4570 if (!NULL_INTERVAL_P (tmp_interval3))
4571 set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
b229b8d1
RS
4572
4573 /* First region smaller than second. */
ec1c14f6 4574 if (len1_byte < len2_byte)
b229b8d1 4575 {
7e2c051b
KS
4576 USE_SAFE_ALLOCA;
4577
4578 SAFE_ALLOCA (temp, unsigned char *, len2_byte);
03240d11
KH
4579
4580 /* Don't precompute these addresses. We have to compute them
4581 at the last minute, because the relocating allocator might
4582 have moved the buffer around during the xmalloc. */
23017390
KH
4583 start1_addr = BYTE_POS_ADDR (start1_byte);
4584 start2_addr = BYTE_POS_ADDR (start2_byte);
03240d11 4585
72af86bd
AS
4586 memcpy (temp, start2_addr, len2_byte);
4587 memcpy (start1_addr + len2_byte, start1_addr, len1_byte);
4588 memcpy (start1_addr, temp, len2_byte);
e65837df 4589 SAFE_FREE ();
b229b8d1
RS
4590 }
4591 else
4592 /* First region not smaller than second. */
4593 {
7e2c051b
KS
4594 USE_SAFE_ALLOCA;
4595
4596 SAFE_ALLOCA (temp, unsigned char *, len1_byte);
23017390
KH
4597 start1_addr = BYTE_POS_ADDR (start1_byte);
4598 start2_addr = BYTE_POS_ADDR (start2_byte);
72af86bd
AS
4599 memcpy (temp, start1_addr, len1_byte);
4600 memcpy (start1_addr, start2_addr, len2_byte);
4601 memcpy (start1_addr + len2_byte, temp, len1_byte);
e65837df 4602 SAFE_FREE ();
b229b8d1 4603 }
b229b8d1
RS
4604 graft_intervals_into_buffer (tmp_interval1, start1 + len2,
4605 len1, current_buffer, 0);
4606 graft_intervals_into_buffer (tmp_interval2, start1,
4607 len2, current_buffer, 0);
d5c2c403
KH
4608 update_compositions (start1, start1 + len2, CHECK_BORDER);
4609 update_compositions (start1 + len2, end2, CHECK_TAIL);
b229b8d1
RS
4610 }
4611 /* Non-adjacent regions, because end1 != start2, bleagh... */
4612 else
4613 {
ec1c14f6
RS
4614 len_mid = start2_byte - (start1_byte + len1_byte);
4615
4616 if (len1_byte == len2_byte)
b229b8d1
RS
4617 /* Regions are same size, though, how nice. */
4618 {
7e2c051b
KS
4619 USE_SAFE_ALLOCA;
4620
3e145152
CY
4621 modify_region (current_buffer, start1, end1, 0);
4622 modify_region (current_buffer, start2, end2, 0);
b229b8d1
RS
4623 record_change (start1, len1);
4624 record_change (start2, len2);
b229b8d1
RS
4625 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
4626 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
6cd0f478
CY
4627
4628 tmp_interval3 = validate_interval_range (buf, &startr1, &endr1, 0);
4629 if (!NULL_INTERVAL_P (tmp_interval3))
4630 set_text_properties_1 (startr1, endr1, Qnil, buf, tmp_interval3);
4631
4632 tmp_interval3 = validate_interval_range (buf, &startr2, &endr2, 0);
4633 if (!NULL_INTERVAL_P (tmp_interval3))
4634 set_text_properties_1 (startr2, endr2, Qnil, buf, tmp_interval3);
b229b8d1 4635
7e2c051b 4636 SAFE_ALLOCA (temp, unsigned char *, len1_byte);
23017390
KH
4637 start1_addr = BYTE_POS_ADDR (start1_byte);
4638 start2_addr = BYTE_POS_ADDR (start2_byte);
72af86bd
AS
4639 memcpy (temp, start1_addr, len1_byte);
4640 memcpy (start1_addr, start2_addr, len2_byte);
4641 memcpy (start2_addr, temp, len1_byte);
e65837df 4642 SAFE_FREE ();
7e2c051b 4643
b229b8d1
RS
4644 graft_intervals_into_buffer (tmp_interval1, start2,
4645 len1, current_buffer, 0);
4646 graft_intervals_into_buffer (tmp_interval2, start1,
4647 len2, current_buffer, 0);
b229b8d1
RS
4648 }
4649
ec1c14f6 4650 else if (len1_byte < len2_byte) /* Second region larger than first */
b229b8d1
RS
4651 /* Non-adjacent & unequal size, area between must also be shifted. */
4652 {
7e2c051b
KS
4653 USE_SAFE_ALLOCA;
4654
3e145152 4655 modify_region (current_buffer, start1, end2, 0);
b229b8d1 4656 record_change (start1, (end2 - start1));
b229b8d1
RS
4657 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
4658 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
4659 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
6cd0f478
CY
4660
4661 tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0);
4662 if (!NULL_INTERVAL_P (tmp_interval3))
4663 set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
b229b8d1 4664
3c6bc7d0 4665 /* holds region 2 */
7e2c051b 4666 SAFE_ALLOCA (temp, unsigned char *, len2_byte);
23017390
KH
4667 start1_addr = BYTE_POS_ADDR (start1_byte);
4668 start2_addr = BYTE_POS_ADDR (start2_byte);
72af86bd
AS
4669 memcpy (temp, start2_addr, len2_byte);
4670 memcpy (start1_addr + len_mid + len2_byte, start1_addr, len1_byte);
4671 memmove (start1_addr + len2_byte, start1_addr + len1_byte, len_mid);
4672 memcpy (start1_addr, temp, len2_byte);
e65837df 4673 SAFE_FREE ();
7e2c051b 4674
b229b8d1
RS
4675 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
4676 len1, current_buffer, 0);
4677 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
4678 len_mid, current_buffer, 0);
4679 graft_intervals_into_buffer (tmp_interval2, start1,
4680 len2, current_buffer, 0);
b229b8d1
RS
4681 }
4682 else
4683 /* Second region smaller than first. */
4684 {
7e2c051b
KS
4685 USE_SAFE_ALLOCA;
4686
b229b8d1 4687 record_change (start1, (end2 - start1));
3e145152 4688 modify_region (current_buffer, start1, end2, 0);
b229b8d1 4689
b229b8d1
RS
4690 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
4691 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
4692 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
6cd0f478
CY
4693
4694 tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0);
4695 if (!NULL_INTERVAL_P (tmp_interval3))
4696 set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
b229b8d1 4697
3c6bc7d0 4698 /* holds region 1 */
7e2c051b 4699 SAFE_ALLOCA (temp, unsigned char *, len1_byte);
23017390
KH
4700 start1_addr = BYTE_POS_ADDR (start1_byte);
4701 start2_addr = BYTE_POS_ADDR (start2_byte);
72af86bd
AS
4702 memcpy (temp, start1_addr, len1_byte);
4703 memcpy (start1_addr, start2_addr, len2_byte);
4704 memcpy (start1_addr + len2_byte, start1_addr + len1_byte, len_mid);
4705 memcpy (start1_addr + len2_byte + len_mid, temp, len1_byte);
e65837df 4706 SAFE_FREE ();
7e2c051b 4707
b229b8d1
RS
4708 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
4709 len1, current_buffer, 0);
4710 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
4711 len_mid, current_buffer, 0);
4712 graft_intervals_into_buffer (tmp_interval2, start1,
4713 len2, current_buffer, 0);
b229b8d1 4714 }
d5c2c403
KH
4715
4716 update_compositions (start1, start1 + len2, CHECK_BORDER);
4717 update_compositions (end2 - len1, end2, CHECK_BORDER);
b229b8d1
RS
4718 }
4719
ec1c14f6
RS
4720 /* When doing multiple transpositions, it might be nice
4721 to optimize this. Perhaps the markers in any one buffer
4722 should be organized in some sorted data tree. */
b229b8d1 4723 if (NILP (leave_markers))
8de1d5f0 4724 {
ec1c14f6
RS
4725 transpose_markers (start1, end1, start2, end2,
4726 start1_byte, start1_byte + len1_byte,
4727 start2_byte, start2_byte + len2_byte);
6b61353c 4728 fix_start_end_in_overlays (start1, end2);
8de1d5f0 4729 }
b229b8d1 4730
c10b2810 4731 signal_after_change (start1, end2 - start1, end2 - start1);
b229b8d1
RS
4732 return Qnil;
4733}
35692fe0 4734
35692fe0
JB
4735\f
4736void
971de7fb 4737syms_of_editfns (void)
35692fe0 4738{
260e2e2a 4739 environbuf = 0;
a03fc5a6 4740 initial_tz = 0;
260e2e2a 4741
cd3520a4 4742 DEFSYM (Qbuffer_access_fontify_functions, "buffer-access-fontify-functions");
260e2e2a 4743
29208e82 4744 DEFVAR_LISP ("inhibit-field-text-motion", Vinhibit_field_text_motion,
7dcece14 4745 doc: /* Non-nil means text motion commands don't notice fields. */);
9a74e7e5
GM
4746 Vinhibit_field_text_motion = Qnil;
4747
260e2e2a 4748 DEFVAR_LISP ("buffer-access-fontify-functions",
29208e82 4749 Vbuffer_access_fontify_functions,
7ee72033 4750 doc: /* List of functions called by `buffer-substring' to fontify if necessary.
a1f17501
PJ
4751Each function is called with two arguments which specify the range
4752of the buffer being accessed. */);
260e2e2a
KH
4753 Vbuffer_access_fontify_functions = Qnil;
4754
af209db8
RS
4755 {
4756 Lisp_Object obuf;
af209db8
RS
4757 obuf = Fcurrent_buffer ();
4758 /* Do this here, because init_buffer_once is too early--it won't work. */
4759 Fset_buffer (Vprin1_to_string_buffer);
4760 /* Make sure buffer-access-fontify-functions is nil in this buffer. */
d67b4f80 4761 Fset (Fmake_local_variable (intern_c_string ("buffer-access-fontify-functions")),
af209db8
RS
4762 Qnil);
4763 Fset_buffer (obuf);
4764 }
4765
0b6fd023 4766 DEFVAR_LISP ("buffer-access-fontified-property",
29208e82 4767 Vbuffer_access_fontified_property,
7ee72033 4768 doc: /* Property which (if non-nil) indicates text has been fontified.
a1f17501
PJ
4769`buffer-substring' need not call the `buffer-access-fontify-functions'
4770functions if all the text being accessed has this property. */);
260e2e2a
KH
4771 Vbuffer_access_fontified_property = Qnil;
4772
29208e82 4773 DEFVAR_LISP ("system-name", Vsystem_name,
1a7e0117 4774 doc: /* The host name of the machine Emacs is running on. */);
34a7a267 4775
29208e82 4776 DEFVAR_LISP ("user-full-name", Vuser_full_name,
7ee72033 4777 doc: /* The full name of the user logged in. */);
f43754f6 4778
29208e82 4779 DEFVAR_LISP ("user-login-name", Vuser_login_name,
7ee72033 4780 doc: /* The user's name, taken from environment variables if possible. */);
f43754f6 4781
29208e82 4782 DEFVAR_LISP ("user-real-login-name", Vuser_real_login_name,
7ee72033 4783 doc: /* The user's name, based upon the real uid only. */);
35692fe0 4784
29208e82 4785 DEFVAR_LISP ("operating-system-release", Voperating_system_release,
3bb9abc8
ST
4786 doc: /* The release of the operating system Emacs is running on. */);
4787
0963334d 4788 defsubr (&Spropertize);
35692fe0
JB
4789 defsubr (&Schar_equal);
4790 defsubr (&Sgoto_char);
4791 defsubr (&Sstring_to_char);
4792 defsubr (&Schar_to_string);
c3bb441d 4793 defsubr (&Sbyte_to_string);
35692fe0 4794 defsubr (&Sbuffer_substring);
260e2e2a 4795 defsubr (&Sbuffer_substring_no_properties);
35692fe0
JB
4796 defsubr (&Sbuffer_string);
4797
4798 defsubr (&Spoint_marker);
4799 defsubr (&Smark_marker);
4800 defsubr (&Spoint);
4801 defsubr (&Sregion_beginning);
4802 defsubr (&Sregion_end);
7df74da6 4803
cd3520a4
JB
4804 DEFSYM (Qfield, "field");
4805 DEFSYM (Qboundary, "boundary");
0daf6e8d
GM
4806 defsubr (&Sfield_beginning);
4807 defsubr (&Sfield_end);
4808 defsubr (&Sfield_string);
4809 defsubr (&Sfield_string_no_properties);
8bf64fe8 4810 defsubr (&Sdelete_field);
0daf6e8d
GM
4811 defsubr (&Sconstrain_to_field);
4812
7df74da6
RS
4813 defsubr (&Sline_beginning_position);
4814 defsubr (&Sline_end_position);
4815
35692fe0
JB
4816/* defsubr (&Smark); */
4817/* defsubr (&Sset_mark); */
4818 defsubr (&Ssave_excursion);
4bc8c7d2 4819 defsubr (&Ssave_current_buffer);
35692fe0
JB
4820
4821 defsubr (&Sbufsize);
4822 defsubr (&Spoint_max);
4823 defsubr (&Spoint_min);
4824 defsubr (&Spoint_min_marker);
4825 defsubr (&Spoint_max_marker);
c86212b9
RS
4826 defsubr (&Sgap_position);
4827 defsubr (&Sgap_size);
7df74da6 4828 defsubr (&Sposition_bytes);
3ab0732d 4829 defsubr (&Sbyte_to_position);
c9ed721d 4830
35692fe0
JB
4831 defsubr (&Sbobp);
4832 defsubr (&Seobp);
4833 defsubr (&Sbolp);
4834 defsubr (&Seolp);
850a8179
JB
4835 defsubr (&Sfollowing_char);
4836 defsubr (&Sprevious_char);
35692fe0 4837 defsubr (&Schar_after);
fb8106e8 4838 defsubr (&Schar_before);
35692fe0
JB
4839 defsubr (&Sinsert);
4840 defsubr (&Sinsert_before_markers);
be91036a
RS
4841 defsubr (&Sinsert_and_inherit);
4842 defsubr (&Sinsert_and_inherit_before_markers);
35692fe0 4843 defsubr (&Sinsert_char);
48ef988f 4844 defsubr (&Sinsert_byte);
35692fe0
JB
4845
4846 defsubr (&Suser_login_name);
4847 defsubr (&Suser_real_login_name);
4848 defsubr (&Suser_uid);
4849 defsubr (&Suser_real_uid);
4850 defsubr (&Suser_full_name);
7fd233b3 4851 defsubr (&Semacs_pid);
d940e0e4 4852 defsubr (&Scurrent_time);
4211ee7d 4853 defsubr (&Sget_internal_run_time);
a82d387c 4854 defsubr (&Sformat_time_string);
34a7a267 4855 defsubr (&Sfloat_time);
4691c06d 4856 defsubr (&Sdecode_time);
cce7b8a0 4857 defsubr (&Sencode_time);
35692fe0 4858 defsubr (&Scurrent_time_string);
c2662aea 4859 defsubr (&Scurrent_time_zone);
143cb9a9 4860 defsubr (&Sset_time_zone_rule);
35692fe0 4861 defsubr (&Ssystem_name);
35692fe0 4862 defsubr (&Smessage);
cacc3e2c
RS
4863 defsubr (&Smessage_box);
4864 defsubr (&Smessage_or_box);
b14dda8a 4865 defsubr (&Scurrent_message);
35692fe0 4866 defsubr (&Sformat);
35692fe0
JB
4867
4868 defsubr (&Sinsert_buffer_substring);
e9cf2084 4869 defsubr (&Scompare_buffer_substrings);
35692fe0 4870 defsubr (&Ssubst_char_in_region);
8583605b 4871 defsubr (&Stranslate_region_internal);
35692fe0 4872 defsubr (&Sdelete_region);
7dae4502 4873 defsubr (&Sdelete_and_extract_region);
35692fe0
JB
4874 defsubr (&Swiden);
4875 defsubr (&Snarrow_to_region);
4876 defsubr (&Ssave_restriction);
b229b8d1 4877 defsubr (&Stranspose_regions);
35692fe0 4878}