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