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