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