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