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