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