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