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