*** empty log message ***
[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);
34a7a267 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 687 Fcons (visible ? Qt : Qnil,
34a7a267 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;
34a7a267 981
ec1c14f6 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))
34a7a267 1107 return Vuser_full_name;
3415b0e9
RS
1108 else if (NUMBERP (uid))
1109 pw = (struct passwd *) getpwuid (XINT (uid));
34a7a267 1110 else if (STRINGP (uid))
3415b0e9
RS
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;
34a7a267 1117
3415b0e9
RS
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));
34a7a267 1122
3415b0e9
RS
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 1193static int
34a7a267 1194lisp_time_argument (specified_time, result, usec)
e3120ab5
JB
1195 Lisp_Object specified_time;
1196 time_t *result;
34a7a267 1197 int *usec;
e3120ab5
JB
1198{
1199 if (NILP (specified_time))
34a7a267
SS
1200 {
1201 if (usec)
1202 {
1203 EMACS_TIME t;
1204
1205 if (-1 == EMACS_GET_TIME (t))
1206 return 0;
1207 *usec = EMACS_USECS (t);
1208 *result = EMACS_SECS (t);
1209 return 1;
1210 }
1211 else
1212 return time (result) != -1;
1213 }
e3120ab5
JB
1214 else
1215 {
1216 Lisp_Object high, low;
1217 high = Fcar (specified_time);
1218 CHECK_NUMBER (high, 0);
1219 low = Fcdr (specified_time);
ae683129 1220 if (CONSP (low))
34a7a267
SS
1221 {
1222 if (usec)
1223 {
1224 Lisp_Object usec_l = Fcdr (low);
1225 if (CONSP (usec_l))
1226 usec_l = Fcar (usec_l);
1227 if (NILP (usec_l))
1228 *usec = 0;
1229 else
1230 {
1231 CHECK_NUMBER (usec_l, 0);
1232 *usec = XINT (usec_l);
1233 }
1234 }
1235 low = Fcar (low);
1236 }
1237 else if (usec)
1238 *usec = 0;
e3120ab5
JB
1239 CHECK_NUMBER (low, 0);
1240 *result = (XINT (high) << 16) + (XINT (low) & 0xffff);
1241 return *result >> 16 == XINT (high);
1242 }
1243}
1244
34a7a267
SS
1245DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0,
1246 "Return the current time, as a float number of seconds since the epoch.\n\
1247If an argument is given, it specifies a time to convert to float\n\
1248instead of the current time. The argument should have the forms:\n\
1249 (HIGH . LOW) or (HIGH LOW USEC) or (HIGH LOW . USEC).\n\
1250Thus, you can use times obtained from `current-time'\n\
1251and from `file-attributes'.")
1252 (specified_time)
1253 Lisp_Object specified_time;
1254{
1255 time_t sec;
1256 int usec;
1257
1258 if (! lisp_time_argument (specified_time, &sec, &usec))
1259 error ("Invalid time specification");
1260
1261 return make_float (sec + usec * 0.0000001);
1262}
1263
70ebbe5f
PE
1264/* Write information into buffer S of size MAXSIZE, according to the
1265 FORMAT of length FORMAT_LEN, using time information taken from *TP.
68c45bf0 1266 Default to Universal Time if UT is nonzero, local time otherwise.
70ebbe5f
PE
1267 Return the number of bytes written, not including the terminating
1268 '\0'. If S is NULL, nothing will be written anywhere; so to
1269 determine how many bytes would be written, use NULL for S and
1270 ((size_t) -1) for MAXSIZE.
1271
68c45bf0 1272 This function behaves like emacs_strftimeu, except it allows null
70ebbe5f
PE
1273 bytes in FORMAT. */
1274static size_t
68c45bf0 1275emacs_memftimeu (s, maxsize, format, format_len, tp, ut)
70ebbe5f
PE
1276 char *s;
1277 size_t maxsize;
1278 const char *format;
1279 size_t format_len;
1280 const struct tm *tp;
68c45bf0 1281 int ut;
70ebbe5f
PE
1282{
1283 size_t total = 0;
1284
be09e6e6
PE
1285 /* Loop through all the null-terminated strings in the format
1286 argument. Normally there's just one null-terminated string, but
1287 there can be arbitrarily many, concatenated together, if the
68c45bf0 1288 format contains '\0' bytes. emacs_strftimeu stops at the first
be09e6e6 1289 '\0' byte so we must invoke it separately for each such string. */
70ebbe5f
PE
1290 for (;;)
1291 {
1292 size_t len;
1293 size_t result;
1294
1295 if (s)
1296 s[0] = '\1';
1297
68c45bf0 1298 result = emacs_strftimeu (s, maxsize, format, tp, ut);
70ebbe5f
PE
1299
1300 if (s)
1301 {
1302 if (result == 0 && s[0] != '\0')
1303 return 0;
1304 s += result + 1;
1305 }
1306
1307 maxsize -= result + 1;
1308 total += result;
1309 len = strlen (format);
1310 if (len == format_len)
1311 return total;
1312 total++;
1313 format += len + 1;
1314 format_len -= len + 1;
1315 }
1316}
1317
3efcc98a 1318/*
b48382a0
RS
1319DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
1320 "Use FORMAT-STRING to format the time TIME, or now if omitted.\n\
1321TIME is specified as (HIGH LOW . IGNORED) or (HIGH . LOW), as returned by\n\
1322`current-time' or `file-attributes'.\n\
1323The third, optional, argument UNIVERSAL, if non-nil, means describe TIME\n\
1324as Universal Time; nil means describe TIME in the local time zone.\n\
1325The value is a copy of FORMAT-STRING, but with certain constructs replaced\n\
1326by text that describes the specified date and time in TIME:\n\
a82d387c 1327\n\
b48382a0
RS
1328%Y is the year, %y within the century, %C the century.\n\
1329%G is the year corresponding to the ISO week, %g within the century.\n\
b771d0da
PE
1330%m is the numeric month.\n\
1331%b and %h are the locale's abbreviated month name, %B the full name.\n\
b48382a0
RS
1332%d is the day of the month, zero-padded, %e is blank-padded.\n\
1333%u is the numeric day of week from 1 (Monday) to 7, %w from 0 (Sunday) to 6.\n\
b771d0da 1334%a is the locale's abbreviated name of the day of week, %A the full name.\n\
b48382a0
RS
1335%U is the week number starting on Sunday, %W starting on Monday,\n\
1336 %V according to ISO 8601.\n\
1337%j is the day of the year.\n\
1338\n\
1339%H is the hour on a 24-hour clock, %I is on a 12-hour clock, %k is like %H\n\
1340 only blank-padded, %l is like %I blank-padded.\n\
b771d0da 1341%p is the locale's equivalent of either AM or PM.\n\
b48382a0
RS
1342%M is the minute.\n\
1343%S is the second.\n\
1344%Z is the time zone name, %z is the numeric form.\n\
1345%s is the number of seconds since 1970-01-01 00:00:00 +0000.\n\
1346\n\
1347%c is the locale's date and time format.\n\
1348%x is the locale's \"preferred\" date format.\n\
1349%D is like \"%m/%d/%y\".\n\
1350\n\
1351%R is like \"%H:%M\", %T is like \"%H:%M:%S\", %r is like \"%I:%M:%S %p\".\n\
1352%X is the locale's \"preferred\" time format.\n\
1353\n\
b771d0da 1354Finally, %n is a newline, %t is a tab, %% is a literal %.\n\
b48382a0 1355\n\
3efcc98a 1356Certain flags and modifiers are available with some format controls.\n\
b48382a0
RS
1357The flags are `_' and `-'. For certain characters X, %_X is like %X,\n\
1358but padded with blanks; %-X is like %X, but without padding.\n\
1359%NX (where N stands for an integer) is like %X,\n\
1360but takes up at least N (a number) positions.\n\
1361The modifiers are `E' and `O'. For certain characters X,\n\
1362%EX is a locale's alternative version of %X;\n\
1363%OX is like %X, but uses the locale's number symbols.\n\
1364\n\
1365For example, to produce full ISO 8601 format, use \"%Y-%m-%dT%T%z\".")
726ed0da 1366 (format_string, time, universal)
3efcc98a
RS
1367*/
1368
1369DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
1370 0 /* See immediately above */)
b48382a0
RS
1371 (format_string, time, universal)
1372 Lisp_Object format_string, time, universal;
a82d387c
RS
1373{
1374 time_t value;
1375 int size;
177ea5f1 1376 struct tm *tm;
68c45bf0 1377 int ut = ! NILP (universal);
a82d387c
RS
1378
1379 CHECK_STRING (format_string, 1);
1380
34a7a267 1381 if (! lisp_time_argument (time, &value, NULL))
a82d387c
RS
1382 error ("Invalid time specification");
1383
68c45bf0
PE
1384 format_string = code_convert_string_norecord (format_string,
1385 Vlocale_coding_system, 1);
1386
a82d387c 1387 /* This is probably enough. */
dc3620af 1388 size = STRING_BYTES (XSTRING (format_string)) * 6 + 50;
a82d387c 1389
68c45bf0 1390 tm = ut ? gmtime (&value) : localtime (&value);
177ea5f1
PE
1391 if (! tm)
1392 error ("Specified time is not representable");
1393
ca9c0567 1394 synchronize_system_time_locale ();
68c45bf0 1395
a82d387c
RS
1396 while (1)
1397 {
b48382a0
RS
1398 char *buf = (char *) alloca (size + 1);
1399 int result;
1400
bfbcc5ee 1401 buf[0] = '\1';
68c45bf0
PE
1402 result = emacs_memftimeu (buf, size, XSTRING (format_string)->data,
1403 STRING_BYTES (XSTRING (format_string)),
1404 tm, ut);
bfbcc5ee 1405 if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0'))
68c45bf0
PE
1406 return code_convert_string_norecord (make_string (buf, result),
1407 Vlocale_coding_system, 0);
b48382a0
RS
1408
1409 /* If buffer was too small, make it bigger and try again. */
68c45bf0
PE
1410 result = emacs_memftimeu (NULL, (size_t) -1,
1411 XSTRING (format_string)->data,
1412 STRING_BYTES (XSTRING (format_string)),
1413 tm, ut);
b48382a0 1414 size = result + 1;
a82d387c
RS
1415 }
1416}
1417
4691c06d
RS
1418DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 1, 0,
1419 "Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST ZONE).\n\
1420The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED)\n\
1421or (HIGH . LOW), as from `current-time' and `file-attributes', or `nil'\n\
1422to use the current time. The list has the following nine members:\n\
145b0681
RS
1423SEC is an integer between 0 and 60; SEC is 60 for a leap second, which\n\
1424only some operating systems support. MINUTE is an integer between 0 and 59.\n\
4691c06d
RS
1425HOUR is an integer between 0 and 23. DAY is an integer between 1 and 31.\n\
1426MONTH is an integer between 1 and 12. YEAR is an integer indicating the\n\
1427four-digit year. DOW is the day of week, an integer between 0 and 6, where\n\
14280 is Sunday. DST is t if daylight savings time is effect, otherwise nil.\n\
1429ZONE is an integer indicating the number of seconds east of Greenwich.\n\
2c6c7c72 1430\(Note that Common Lisp has different meanings for DOW and ZONE.)")
4691c06d
RS
1431 (specified_time)
1432 Lisp_Object specified_time;
1433{
1434 time_t time_spec;
3c887943 1435 struct tm save_tm;
4691c06d
RS
1436 struct tm *decoded_time;
1437 Lisp_Object list_args[9];
34a7a267
SS
1438
1439 if (! lisp_time_argument (specified_time, &time_spec, NULL))
4691c06d
RS
1440 error ("Invalid time specification");
1441
1442 decoded_time = localtime (&time_spec);
177ea5f1
PE
1443 if (! decoded_time)
1444 error ("Specified time is not representable");
3c887943
KH
1445 XSETFASTINT (list_args[0], decoded_time->tm_sec);
1446 XSETFASTINT (list_args[1], decoded_time->tm_min);
1447 XSETFASTINT (list_args[2], decoded_time->tm_hour);
1448 XSETFASTINT (list_args[3], decoded_time->tm_mday);
1449 XSETFASTINT (list_args[4], decoded_time->tm_mon + 1);
236ebf35 1450 XSETINT (list_args[5], decoded_time->tm_year + 1900);
3c887943 1451 XSETFASTINT (list_args[6], decoded_time->tm_wday);
4691c06d 1452 list_args[7] = (decoded_time->tm_isdst)? Qt : Qnil;
3c887943
KH
1453
1454 /* Make a copy, in case gmtime modifies the struct. */
1455 save_tm = *decoded_time;
1456 decoded_time = gmtime (&time_spec);
1457 if (decoded_time == 0)
1458 list_args[8] = Qnil;
1459 else
94751666 1460 XSETINT (list_args[8], tm_diff (&save_tm, decoded_time));
4691c06d
RS
1461 return Flist (9, list_args);
1462}
1463
6ee9061c 1464DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0,
2591ec64 1465 "Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time.\n\
6ee9061c
RS
1466This is the reverse operation of `decode-time', which see.\n\
1467ZONE defaults to the current time zone rule. This can\n\
085e9fcb 1468be a string or t (as from `set-time-zone-rule'), or it can be a list\n\
7459d65b 1469\(as from `current-time-zone') or an integer (as from `decode-time')\n\
c59b5089 1470applied without consideration for daylight savings time.\n\
6ee9061c
RS
1471\n\
1472You can pass more than 7 arguments; then the first six arguments\n\
1473are used as SECOND through YEAR, and the *last* argument is used as ZONE.\n\
1474The intervening arguments are ignored.\n\
1475This feature lets (apply 'encode-time (decode-time ...)) work.\n\
1476\n\
c59b5089
PE
1477Out-of-range values for SEC, MINUTE, HOUR, DAY, or MONTH are allowed;\n\
1478for example, a DAY of 0 means the day preceding the given month.\n\
01ba8cce 1479Year numbers less than 100 are treated just like other year numbers.\n\
c59b5089 1480If you want them to stand for years in this century, you must do that yourself.")
6ee9061c
RS
1481 (nargs, args)
1482 int nargs;
1483 register Lisp_Object *args;
cce7b8a0 1484{
1b8fa736 1485 time_t time;
c59b5089 1486 struct tm tm;
60653898 1487 Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil);
6ee9061c
RS
1488
1489 CHECK_NUMBER (args[0], 0); /* second */
1490 CHECK_NUMBER (args[1], 1); /* minute */
1491 CHECK_NUMBER (args[2], 2); /* hour */
1492 CHECK_NUMBER (args[3], 3); /* day */
1493 CHECK_NUMBER (args[4], 4); /* month */
1494 CHECK_NUMBER (args[5], 5); /* year */
1495
1496 tm.tm_sec = XINT (args[0]);
1497 tm.tm_min = XINT (args[1]);
1498 tm.tm_hour = XINT (args[2]);
1499 tm.tm_mday = XINT (args[3]);
1500 tm.tm_mon = XINT (args[4]) - 1;
1501 tm.tm_year = XINT (args[5]) - 1900;
c59b5089
PE
1502 tm.tm_isdst = -1;
1503
1504 if (CONSP (zone))
1505 zone = Fcar (zone);
1b8fa736 1506 if (NILP (zone))
c59b5089
PE
1507 time = mktime (&tm);
1508 else
1b8fa736 1509 {
c59b5089
PE
1510 char tzbuf[100];
1511 char *tzstring;
1512 char **oldenv = environ, **newenv;
34a7a267 1513
2e34157c 1514 if (EQ (zone, Qt))
085e9fcb
EN
1515 tzstring = "UTC0";
1516 else if (STRINGP (zone))
4d4c1514 1517 tzstring = (char *) XSTRING (zone)->data;
c59b5089 1518 else if (INTEGERP (zone))
1b8fa736 1519 {
c59b5089
PE
1520 int abszone = abs (XINT (zone));
1521 sprintf (tzbuf, "XXX%s%d:%02d:%02d", "-" + (XINT (zone) < 0),
1522 abszone / (60*60), (abszone/60) % 60, abszone % 60);
1523 tzstring = tzbuf;
1b8fa736 1524 }
c59b5089
PE
1525 else
1526 error ("Invalid time zone specification");
1527
34a7a267 1528 /* Set TZ before calling mktime; merely adjusting mktime's returned
c59b5089
PE
1529 value doesn't suffice, since that would mishandle leap seconds. */
1530 set_time_zone_rule (tzstring);
1531
1532 time = mktime (&tm);
1533
1534 /* Restore TZ to previous value. */
1535 newenv = environ;
1536 environ = oldenv;
c0efcacf 1537 xfree (newenv);
c59b5089
PE
1538#ifdef LOCALTIME_CACHE
1539 tzset ();
1540#endif
1b8fa736 1541 }
1b8fa736 1542
c59b5089
PE
1543 if (time == (time_t) -1)
1544 error ("Specified time is not representable");
1545
1546 return make_time (time);
cce7b8a0
RS
1547}
1548
2148f2b4 1549DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 1, 0,
35692fe0 1550 "Return the current time, as a human-readable string.\n\
2148f2b4
RS
1551Programs can use this function to decode a time,\n\
1552since the number of columns in each field is fixed.\n\
1553The format is `Sun Sep 16 01:03:52 1973'.\n\
7a8630da
RS
1554However, see also the functions `decode-time' and `format-time-string'\n\
1555which provide a much more powerful and general facility.\n\
1556\n\
2148f2b4
RS
1557If an argument is given, it specifies a time to format\n\
1558instead of the current time. The argument should have the form:\n\
1559 (HIGH . LOW)\n\
1560or the form:\n\
1561 (HIGH LOW . IGNORED).\n\
1562Thus, you can use times obtained from `current-time'\n\
1563and from `file-attributes'.")
1564 (specified_time)
1565 Lisp_Object specified_time;
1566{
e3120ab5 1567 time_t value;
35692fe0 1568 char buf[30];
2148f2b4
RS
1569 register char *tem;
1570
34a7a267 1571 if (! lisp_time_argument (specified_time, &value, NULL))
e3120ab5 1572 value = -1;
2148f2b4 1573 tem = (char *) ctime (&value);
35692fe0
JB
1574
1575 strncpy (buf, tem, 24);
1576 buf[24] = 0;
1577
1578 return build_string (buf);
1579}
c2662aea 1580
94751666 1581#define TM_YEAR_BASE 1900
e3120ab5 1582
94751666
PE
1583/* Yield A - B, measured in seconds.
1584 This function is copied from the GNU C Library. */
1585static int
1586tm_diff (a, b)
e3120ab5
JB
1587 struct tm *a, *b;
1588{
94751666
PE
1589 /* Compute intervening leap days correctly even if year is negative.
1590 Take care to avoid int overflow in leap day calculations,
1591 but it's OK to assume that A and B are close to each other. */
1592 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
1593 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
1594 int a100 = a4 / 25 - (a4 % 25 < 0);
1595 int b100 = b4 / 25 - (b4 % 25 < 0);
1596 int a400 = a100 >> 2;
1597 int b400 = b100 >> 2;
1598 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
1599 int years = a->tm_year - b->tm_year;
1600 int days = (365 * years + intervening_leap_days
1601 + (a->tm_yday - b->tm_yday));
1602 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
1603 + (a->tm_min - b->tm_min))
8e718b4e 1604 + (a->tm_sec - b->tm_sec));
e3120ab5
JB
1605}
1606
1607DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0,
1608 "Return the offset and name for the local time zone.\n\
1609This returns a list of the form (OFFSET NAME).\n\
1610OFFSET is an integer number of seconds ahead of UTC (east of Greenwich).\n\
1611 A negative value means west of Greenwich.\n\
1612NAME is a string giving the name of the time zone.\n\
1613If an argument is given, it specifies when the time zone offset is determined\n\
1614instead of using the current time. The argument should have the form:\n\
1615 (HIGH . LOW)\n\
1616or the form:\n\
1617 (HIGH LOW . IGNORED).\n\
1618Thus, you can use times obtained from `current-time'\n\
1619and from `file-attributes'.\n\
773c1fd3
JB
1620\n\
1621Some operating systems cannot provide all this information to Emacs;\n\
2d88f747 1622in this case, `current-time-zone' returns a list containing nil for\n\
773c1fd3 1623the data it can't find.")
e3120ab5
JB
1624 (specified_time)
1625 Lisp_Object specified_time;
c2662aea 1626{
e3120ab5
JB
1627 time_t value;
1628 struct tm *t;
177ea5f1 1629 struct tm gmt;
c2662aea 1630
34a7a267 1631 if (lisp_time_argument (specified_time, &value, NULL)
177ea5f1
PE
1632 && (t = gmtime (&value)) != 0
1633 && (gmt = *t, t = localtime (&value)) != 0)
e3120ab5 1634 {
177ea5f1
PE
1635 int offset = tm_diff (t, &gmt);
1636 char *s = 0;
1637 char buf[6];
e3120ab5
JB
1638#ifdef HAVE_TM_ZONE
1639 if (t->tm_zone)
5fd4de15 1640 s = (char *)t->tm_zone;
a7971c39
RS
1641#else /* not HAVE_TM_ZONE */
1642#ifdef HAVE_TZNAME
1643 if (t->tm_isdst == 0 || t->tm_isdst == 1)
1644 s = tzname[t->tm_isdst];
c2662aea 1645#endif
a7971c39 1646#endif /* not HAVE_TM_ZONE */
e3120ab5
JB
1647 if (!s)
1648 {
1649 /* No local time zone name is available; use "+-NNNN" instead. */
00fc94d0 1650 int am = (offset < 0 ? -offset : offset) / 60;
e3120ab5
JB
1651 sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60);
1652 s = buf;
1653 }
1654 return Fcons (make_number (offset), Fcons (build_string (s), Qnil));
1655 }
1656 else
09dbcf71 1657 return Fmake_list (make_number (2), Qnil);
c2662aea
JB
1658}
1659
260e2e2a
KH
1660/* This holds the value of `environ' produced by the previous
1661 call to Fset_time_zone_rule, or 0 if Fset_time_zone_rule
1662 has never been called. */
1663static char **environbuf;
1664
143cb9a9
RS
1665DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
1666 "Set the local time zone using TZ, a string specifying a time zone rule.\n\
085e9fcb
EN
1667If TZ is nil, use implementation-defined default time zone information.\n\
1668If TZ is t, use Universal Time.")
143cb9a9
RS
1669 (tz)
1670 Lisp_Object tz;
1671{
143cb9a9
RS
1672 char *tzstring;
1673
1674 if (NILP (tz))
1675 tzstring = 0;
2e34157c 1676 else if (EQ (tz, Qt))
085e9fcb 1677 tzstring = "UTC0";
143cb9a9
RS
1678 else
1679 {
1680 CHECK_STRING (tz, 0);
4d4c1514 1681 tzstring = (char *) XSTRING (tz)->data;
143cb9a9
RS
1682 }
1683
c59b5089
PE
1684 set_time_zone_rule (tzstring);
1685 if (environbuf)
1686 free (environbuf);
1687 environbuf = environ;
1688
1689 return Qnil;
1690}
1691
e0bf9faf
PE
1692#ifdef LOCALTIME_CACHE
1693
1694/* These two values are known to load tz files in buggy implementations,
1695 i.e. Solaris 1 executables running under either Solaris 1 or Solaris 2.
1155c453 1696 Their values shouldn't matter in non-buggy implementations.
34a7a267 1697 We don't use string literals for these strings,
1155c453
RS
1698 since if a string in the environment is in readonly
1699 storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
1700 See Sun bugs 1113095 and 1114114, ``Timezone routines
1701 improperly modify environment''. */
1702
e0bf9faf
PE
1703static char set_time_zone_rule_tz1[] = "TZ=GMT+0";
1704static char set_time_zone_rule_tz2[] = "TZ=GMT+1";
1705
1706#endif
1155c453 1707
c59b5089
PE
1708/* Set the local time zone rule to TZSTRING.
1709 This allocates memory into `environ', which it is the caller's
1710 responsibility to free. */
a92ae0ce 1711void
c59b5089
PE
1712set_time_zone_rule (tzstring)
1713 char *tzstring;
1714{
1715 int envptrs;
1716 char **from, **to, **newenv;
1717
aafe5147 1718 /* Make the ENVIRON vector longer with room for TZSTRING. */
143cb9a9
RS
1719 for (from = environ; *from; from++)
1720 continue;
1721 envptrs = from - environ + 2;
1722 newenv = to = (char **) xmalloc (envptrs * sizeof (char *)
1723 + (tzstring ? strlen (tzstring) + 4 : 0));
aafe5147
RS
1724
1725 /* Add TZSTRING to the end of environ, as a value for TZ. */
143cb9a9
RS
1726 if (tzstring)
1727 {
1728 char *t = (char *) (to + envptrs);
1729 strcpy (t, "TZ=");
1730 strcat (t, tzstring);
1731 *to++ = t;
1732 }
1733
aafe5147
RS
1734 /* Copy the old environ vector elements into NEWENV,
1735 but don't copy the TZ variable.
1736 So we have only one definition of TZ, which came from TZSTRING. */
143cb9a9
RS
1737 for (from = environ; *from; from++)
1738 if (strncmp (*from, "TZ=", 3) != 0)
1739 *to++ = *from;
1740 *to = 0;
1741
1742 environ = newenv;
143cb9a9 1743
aafe5147
RS
1744 /* If we do have a TZSTRING, NEWENV points to the vector slot where
1745 the TZ variable is stored. If we do not have a TZSTRING,
1746 TO points to the vector slot which has the terminating null. */
1747
143cb9a9 1748#ifdef LOCALTIME_CACHE
aafe5147
RS
1749 {
1750 /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
1751 "US/Pacific" that loads a tz file, then changes to a value like
1752 "XXX0" that does not load a tz file, and then changes back to
1753 its original value, the last change is (incorrectly) ignored.
1754 Also, if TZ changes twice in succession to values that do
1755 not load a tz file, tzset can dump core (see Sun bug#1225179).
1756 The following code works around these bugs. */
1757
aafe5147
RS
1758 if (tzstring)
1759 {
1760 /* Temporarily set TZ to a value that loads a tz file
1761 and that differs from tzstring. */
1762 char *tz = *newenv;
1155c453
RS
1763 *newenv = (strcmp (tzstring, set_time_zone_rule_tz1 + 3) == 0
1764 ? set_time_zone_rule_tz2 : set_time_zone_rule_tz1);
aafe5147
RS
1765 tzset ();
1766 *newenv = tz;
1767 }
1768 else
1769 {
1770 /* The implied tzstring is unknown, so temporarily set TZ to
1771 two different values that each load a tz file. */
1155c453 1772 *to = set_time_zone_rule_tz1;
aafe5147
RS
1773 to[1] = 0;
1774 tzset ();
1155c453 1775 *to = set_time_zone_rule_tz2;
aafe5147
RS
1776 tzset ();
1777 *to = 0;
1778 }
1779
1780 /* Now TZ has the desired value, and tzset can be invoked safely. */
1781 }
1782
143cb9a9
RS
1783 tzset ();
1784#endif
143cb9a9 1785}
35692fe0 1786\f
fb8106e8
KH
1787/* Insert NARGS Lisp objects in the array ARGS by calling INSERT_FUNC
1788 (if a type of object is Lisp_Int) or INSERT_FROM_STRING_FUNC (if a
1789 type of object is Lisp_String). INHERIT is passed to
1790 INSERT_FROM_STRING_FUNC as the last argument. */
1791
d11ba98c 1792void
fb8106e8
KH
1793general_insert_function (insert_func, insert_from_string_func,
1794 inherit, nargs, args)
d11ba98c 1795 void (*insert_func) P_ ((unsigned char *, int));
1f24f4fd 1796 void (*insert_from_string_func) P_ ((Lisp_Object, int, int, int, int, int));
fb8106e8
KH
1797 int inherit, nargs;
1798 register Lisp_Object *args;
1799{
1800 register int argnum;
1801 register Lisp_Object val;
1802
1803 for (argnum = 0; argnum < nargs; argnum++)
1804 {
1805 val = args[argnum];
1806 retry:
1807 if (INTEGERP (val))
1808 {
d5c2c403 1809 unsigned char str[MAX_MULTIBYTE_LENGTH];
fb8106e8
KH
1810 int len;
1811
1812 if (!NILP (current_buffer->enable_multibyte_characters))
d5c2c403 1813 len = CHAR_STRING (XFASTINT (val), str);
fb8106e8 1814 else
13c148b8 1815 {
d5c2c403
KH
1816 str[0] = (SINGLE_BYTE_CHAR_P (XINT (val))
1817 ? XINT (val)
1818 : multibyte_char_to_unibyte (XINT (val), Qnil));
13c148b8
KH
1819 len = 1;
1820 }
fb8106e8
KH
1821 (*insert_func) (str, len);
1822 }
1823 else if (STRINGP (val))
1824 {
1f24f4fd
RS
1825 (*insert_from_string_func) (val, 0, 0,
1826 XSTRING (val)->size,
dc3620af 1827 STRING_BYTES (XSTRING (val)),
1f24f4fd 1828 inherit);
fb8106e8
KH
1829 }
1830 else
1831 {
1832 val = wrong_type_argument (Qchar_or_string_p, val);
1833 goto retry;
1834 }
1835 }
1836}
1837
35692fe0
JB
1838void
1839insert1 (arg)
1840 Lisp_Object arg;
1841{
1842 Finsert (1, &arg);
1843}
1844
52b14ac0
JB
1845
1846/* Callers passing one argument to Finsert need not gcpro the
1847 argument "array", since the only element of the array will
1848 not be used after calling insert or insert_from_string, so
1849 we don't care if it gets trashed. */
1850
35692fe0
JB
1851DEFUN ("insert", Finsert, Sinsert, 0, MANY, 0,
1852 "Insert the arguments, either strings or characters, at point.\n\
24d6bf26 1853Point and before-insertion markers move forward to end up\n\
fb8106e8 1854 after the inserted text.\n\
24d6bf26
RS
1855Any other markers at the point of insertion remain before the text.\n\
1856\n\
1857If the current buffer is multibyte, unibyte strings are converted\n\
1858to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
13903932 1859If the current buffer is unibyte, multibyte strings are converted\n\
24d6bf26 1860to unibyte for insertion.")
35692fe0
JB
1861 (nargs, args)
1862 int nargs;
1863 register Lisp_Object *args;
1864{
fb8106e8 1865 general_insert_function (insert, insert_from_string, 0, nargs, args);
be91036a
RS
1866 return Qnil;
1867}
1868
1869DEFUN ("insert-and-inherit", Finsert_and_inherit, Sinsert_and_inherit,
1870 0, MANY, 0,
1871 "Insert the arguments at point, inheriting properties from adjoining text.\n\
24d6bf26 1872Point and before-insertion markers move forward to end up\n\
fb8106e8 1873 after the inserted text.\n\
24d6bf26
RS
1874Any other markers at the point of insertion remain before the text.\n\
1875\n\
1876If the current buffer is multibyte, unibyte strings are converted\n\
1877to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
13903932 1878If the current buffer is unibyte, multibyte strings are converted\n\
24d6bf26 1879to unibyte for insertion.")
be91036a
RS
1880 (nargs, args)
1881 int nargs;
1882 register Lisp_Object *args;
1883{
fb8106e8
KH
1884 general_insert_function (insert_and_inherit, insert_from_string, 1,
1885 nargs, args);
35692fe0
JB
1886 return Qnil;
1887}
1888
1889DEFUN ("insert-before-markers", Finsert_before_markers, Sinsert_before_markers, 0, MANY, 0,
1890 "Insert strings or characters at point, relocating markers after the text.\n\
24d6bf26
RS
1891Point and markers move forward to end up after the inserted text.\n\
1892\n\
1893If the current buffer is multibyte, unibyte strings are converted\n\
1894to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
13903932 1895If the current buffer is unibyte, multibyte strings are converted\n\
24d6bf26 1896to unibyte for insertion.")
35692fe0
JB
1897 (nargs, args)
1898 int nargs;
1899 register Lisp_Object *args;
1900{
fb8106e8
KH
1901 general_insert_function (insert_before_markers,
1902 insert_from_string_before_markers, 0,
1903 nargs, args);
be91036a
RS
1904 return Qnil;
1905}
1906
a0d76c27
EN
1907DEFUN ("insert-before-markers-and-inherit", Finsert_and_inherit_before_markers,
1908 Sinsert_and_inherit_before_markers, 0, MANY, 0,
be91036a 1909 "Insert text at point, relocating markers and inheriting properties.\n\
24d6bf26
RS
1910Point and markers move forward to end up after the inserted text.\n\
1911\n\
1912If the current buffer is multibyte, unibyte strings are converted\n\
1913to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
13903932 1914If the current buffer is unibyte, multibyte strings are converted\n\
24d6bf26 1915to unibyte for insertion.")
be91036a
RS
1916 (nargs, args)
1917 int nargs;
1918 register Lisp_Object *args;
1919{
fb8106e8
KH
1920 general_insert_function (insert_before_markers_and_inherit,
1921 insert_from_string_before_markers, 1,
1922 nargs, args);
35692fe0
JB
1923 return Qnil;
1924}
1925\f
e2eeabbb 1926DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0,
2591ec64 1927 "Insert COUNT (second arg) copies of CHARACTER (first arg).\n\
e2eeabbb 1928Both arguments are required.\n\
ba88b322 1929Point, and before-insertion markers, are relocated as in the function `insert'.\n\
e2eeabbb
RS
1930The optional third arg INHERIT, if non-nil, says to inherit text properties\n\
1931from adjoining text, if those properties are sticky.")
2591ec64
EN
1932 (character, count, inherit)
1933 Lisp_Object character, count, inherit;
35692fe0
JB
1934{
1935 register unsigned char *string;
1936 register int strlen;
1937 register int i, n;
fb8106e8 1938 int len;
d5c2c403 1939 unsigned char str[MAX_MULTIBYTE_LENGTH];
35692fe0 1940
2591ec64 1941 CHECK_NUMBER (character, 0);
35692fe0
JB
1942 CHECK_NUMBER (count, 1);
1943
fb8106e8 1944 if (!NILP (current_buffer->enable_multibyte_characters))
d5c2c403 1945 len = CHAR_STRING (XFASTINT (character), str);
fb8106e8 1946 else
d5c2c403 1947 str[0] = XFASTINT (character), len = 1;
fb8106e8 1948 n = XINT (count) * len;
35692fe0
JB
1949 if (n <= 0)
1950 return Qnil;
fb8106e8 1951 strlen = min (n, 256 * len);
35692fe0
JB
1952 string = (unsigned char *) alloca (strlen);
1953 for (i = 0; i < strlen; i++)
fb8106e8 1954 string[i] = str[i % len];
35692fe0
JB
1955 while (n >= strlen)
1956 {
54e42e2d 1957 QUIT;
e2eeabbb
RS
1958 if (!NILP (inherit))
1959 insert_and_inherit (string, strlen);
1960 else
1961 insert (string, strlen);
35692fe0
JB
1962 n -= strlen;
1963 }
1964 if (n > 0)
83951f1e
KH
1965 {
1966 if (!NILP (inherit))
1967 insert_and_inherit (string, n);
1968 else
1969 insert (string, n);
1970 }
35692fe0
JB
1971 return Qnil;
1972}
1973
1974\f
ffd56f97
JB
1975/* Making strings from buffer contents. */
1976
1977/* Return a Lisp_String containing the text of the current buffer from
74d6d8c5 1978 START to END. If text properties are in use and the current buffer
eb8c3be9 1979 has properties in the range specified, the resulting string will also
260e2e2a 1980 have them, if PROPS is nonzero.
ffd56f97
JB
1981
1982 We don't want to use plain old make_string here, because it calls
1983 make_uninit_string, which can cause the buffer arena to be
1984 compacted. make_string has no way of knowing that the data has
1985 been moved, and thus copies the wrong data into the string. This
1986 doesn't effect most of the other users of make_string, so it should
1987 be left as is. But we should use this function when conjuring
1988 buffer substrings. */
74d6d8c5 1989
ffd56f97 1990Lisp_Object
260e2e2a 1991make_buffer_string (start, end, props)
ffd56f97 1992 int start, end;
260e2e2a 1993 int props;
ffd56f97 1994{
ec1c14f6
RS
1995 int start_byte = CHAR_TO_BYTE (start);
1996 int end_byte = CHAR_TO_BYTE (end);
ffd56f97 1997
88441c8e
RS
1998 return make_buffer_string_both (start, start_byte, end, end_byte, props);
1999}
2000
2001/* Return a Lisp_String containing the text of the current buffer from
2002 START / START_BYTE to END / END_BYTE.
2003
2004 If text properties are in use and the current buffer
2005 has properties in the range specified, the resulting string will also
2006 have them, if PROPS is nonzero.
2007
2008 We don't want to use plain old make_string here, because it calls
2009 make_uninit_string, which can cause the buffer arena to be
2010 compacted. make_string has no way of knowing that the data has
2011 been moved, and thus copies the wrong data into the string. This
2012 doesn't effect most of the other users of make_string, so it should
2013 be left as is. But we should use this function when conjuring
2014 buffer substrings. */
2015
2016Lisp_Object
2017make_buffer_string_both (start, start_byte, end, end_byte, props)
2018 int start, start_byte, end, end_byte;
2019 int props;
2020{
2021 Lisp_Object result, tem, tem1;
2022
ffd56f97
JB
2023 if (start < GPT && GPT < end)
2024 move_gap (start);
2025
5f75e666
RS
2026 if (! NILP (current_buffer->enable_multibyte_characters))
2027 result = make_uninit_multibyte_string (end - start, end_byte - start_byte);
2028 else
2029 result = make_uninit_string (end - start);
ec1c14f6
RS
2030 bcopy (BYTE_POS_ADDR (start_byte), XSTRING (result)->data,
2031 end_byte - start_byte);
ffd56f97 2032
260e2e2a 2033 /* If desired, update and copy the text properties. */
260e2e2a
KH
2034 if (props)
2035 {
2036 update_buffer_properties (start, end);
2037
2038 tem = Fnext_property_change (make_number (start), Qnil, make_number (end));
2039 tem1 = Ftext_properties_at (make_number (start), Qnil);
2040
2041 if (XINT (tem) != end || !NILP (tem1))
ec1c14f6
RS
2042 copy_intervals_to_string (result, current_buffer, start,
2043 end - start);
260e2e2a 2044 }
74d6d8c5 2045
ffd56f97
JB
2046 return result;
2047}
35692fe0 2048
260e2e2a
KH
2049/* Call Vbuffer_access_fontify_functions for the range START ... END
2050 in the current buffer, if necessary. */
2051
2052static void
2053update_buffer_properties (start, end)
2054 int start, end;
2055{
260e2e2a
KH
2056 /* If this buffer has some access functions,
2057 call them, specifying the range of the buffer being accessed. */
2058 if (!NILP (Vbuffer_access_fontify_functions))
2059 {
2060 Lisp_Object args[3];
2061 Lisp_Object tem;
2062
2063 args[0] = Qbuffer_access_fontify_functions;
2064 XSETINT (args[1], start);
2065 XSETINT (args[2], end);
2066
2067 /* But don't call them if we can tell that the work
2068 has already been done. */
2069 if (!NILP (Vbuffer_access_fontified_property))
2070 {
2071 tem = Ftext_property_any (args[1], args[2],
2072 Vbuffer_access_fontified_property,
2073 Qnil, Qnil);
2074 if (! NILP (tem))
ced1d19a 2075 Frun_hook_with_args (3, args);
260e2e2a
KH
2076 }
2077 else
ced1d19a 2078 Frun_hook_with_args (3, args);
260e2e2a 2079 }
260e2e2a
KH
2080}
2081
35692fe0
JB
2082DEFUN ("buffer-substring", Fbuffer_substring, Sbuffer_substring, 2, 2, 0,
2083 "Return the contents of part of the current buffer as a string.\n\
2084The two arguments START and END are character positions;\n\
24d6bf26
RS
2085they can be in either order.\n\
2086The string returned is multibyte if the buffer is multibyte.")
2591ec64
EN
2087 (start, end)
2088 Lisp_Object start, end;
35692fe0 2089{
2591ec64 2090 register int b, e;
35692fe0 2091
2591ec64
EN
2092 validate_region (&start, &end);
2093 b = XINT (start);
2094 e = XINT (end);
35692fe0 2095
2591ec64 2096 return make_buffer_string (b, e, 1);
260e2e2a
KH
2097}
2098
2099DEFUN ("buffer-substring-no-properties", Fbuffer_substring_no_properties,
2100 Sbuffer_substring_no_properties, 2, 2, 0,
2101 "Return the characters of part of the buffer, without the text properties.\n\
2102The two arguments START and END are character positions;\n\
2103they can be in either order.")
2591ec64
EN
2104 (start, end)
2105 Lisp_Object start, end;
260e2e2a 2106{
2591ec64 2107 register int b, e;
260e2e2a 2108
2591ec64
EN
2109 validate_region (&start, &end);
2110 b = XINT (start);
2111 e = XINT (end);
260e2e2a 2112
2591ec64 2113 return make_buffer_string (b, e, 0);
35692fe0
JB
2114}
2115
2116DEFUN ("buffer-string", Fbuffer_string, Sbuffer_string, 0, 0, 0,
af7bd86c
KH
2117 "Return the contents of the current buffer as a string.\n\
2118If narrowing is in effect, this function returns only the visible part\n\
2da8bf64
GM
2119of the buffer. If in a mini-buffer, don't include the prompt in the\n\
2120string returned.")
35692fe0
JB
2121 ()
2122{
0daf6e8d 2123 return make_buffer_string (BEGV, ZV, 1);
35692fe0
JB
2124}
2125
2126DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
2127 1, 3, 0,
83ea6fc2 2128 "Insert before point a substring of the contents of buffer BUFFER.\n\
35692fe0
JB
2129BUFFER may be a buffer or a buffer name.\n\
2130Arguments START and END are character numbers specifying the substring.\n\
2131They default to the beginning and the end of BUFFER.")
2591ec64
EN
2132 (buf, start, end)
2133 Lisp_Object buf, start, end;
35692fe0 2134{
2591ec64 2135 register int b, e, temp;
260e2e2a 2136 register struct buffer *bp, *obuf;
3fff2dfa 2137 Lisp_Object buffer;
35692fe0 2138
3fff2dfa
RS
2139 buffer = Fget_buffer (buf);
2140 if (NILP (buffer))
2141 nsberror (buf);
2142 bp = XBUFFER (buffer);
93b62e82
KH
2143 if (NILP (bp->name))
2144 error ("Selecting deleted buffer");
35692fe0 2145
2591ec64
EN
2146 if (NILP (start))
2147 b = BUF_BEGV (bp);
35692fe0
JB
2148 else
2149 {
2591ec64
EN
2150 CHECK_NUMBER_COERCE_MARKER (start, 0);
2151 b = XINT (start);
35692fe0 2152 }
2591ec64
EN
2153 if (NILP (end))
2154 e = BUF_ZV (bp);
35692fe0
JB
2155 else
2156 {
2591ec64
EN
2157 CHECK_NUMBER_COERCE_MARKER (end, 1);
2158 e = XINT (end);
35692fe0
JB
2159 }
2160
2591ec64
EN
2161 if (b > e)
2162 temp = b, b = e, e = temp;
35692fe0 2163
2591ec64
EN
2164 if (!(BUF_BEGV (bp) <= b && e <= BUF_ZV (bp)))
2165 args_out_of_range (start, end);
35692fe0 2166
260e2e2a
KH
2167 obuf = current_buffer;
2168 set_buffer_internal_1 (bp);
2591ec64 2169 update_buffer_properties (b, e);
260e2e2a
KH
2170 set_buffer_internal_1 (obuf);
2171
2591ec64 2172 insert_from_buffer (bp, b, e - b, 0);
35692fe0
JB
2173 return Qnil;
2174}
e9cf2084
RS
2175
2176DEFUN ("compare-buffer-substrings", Fcompare_buffer_substrings, Scompare_buffer_substrings,
2177 6, 6, 0,
2178 "Compare two substrings of two buffers; return result as number.\n\
2179the value is -N if first string is less after N-1 chars,\n\
2180+N if first string is greater after N-1 chars, or 0 if strings match.\n\
2181Each substring is represented as three arguments: BUFFER, START and END.\n\
2182That makes six args in all, three for each substring.\n\n\
2183The value of `case-fold-search' in the current buffer\n\
2184determines whether case is significant or ignored.")
2185 (buffer1, start1, end1, buffer2, start2, end2)
2186 Lisp_Object buffer1, start1, end1, buffer2, start2, end2;
2187{
07422a12 2188 register int begp1, endp1, begp2, endp2, temp;
e9cf2084 2189 register struct buffer *bp1, *bp2;
2a8b0ff0 2190 register Lisp_Object *trt
e9cf2084 2191 = (!NILP (current_buffer->case_fold_search)
2a8b0ff0 2192 ? XCHAR_TABLE (current_buffer->case_canon_table)->contents : 0);
ec1c14f6 2193 int chars = 0;
07422a12 2194 int i1, i2, i1_byte, i2_byte;
e9cf2084
RS
2195
2196 /* Find the first buffer and its substring. */
2197
2198 if (NILP (buffer1))
2199 bp1 = current_buffer;
2200 else
2201 {
3fff2dfa
RS
2202 Lisp_Object buf1;
2203 buf1 = Fget_buffer (buffer1);
2204 if (NILP (buf1))
2205 nsberror (buffer1);
2206 bp1 = XBUFFER (buf1);
93b62e82
KH
2207 if (NILP (bp1->name))
2208 error ("Selecting deleted buffer");
e9cf2084
RS
2209 }
2210
2211 if (NILP (start1))
2212 begp1 = BUF_BEGV (bp1);
2213 else
2214 {
2215 CHECK_NUMBER_COERCE_MARKER (start1, 1);
2216 begp1 = XINT (start1);
2217 }
2218 if (NILP (end1))
2219 endp1 = BUF_ZV (bp1);
2220 else
2221 {
2222 CHECK_NUMBER_COERCE_MARKER (end1, 2);
2223 endp1 = XINT (end1);
2224 }
2225
2226 if (begp1 > endp1)
2227 temp = begp1, begp1 = endp1, endp1 = temp;
2228
2229 if (!(BUF_BEGV (bp1) <= begp1
2230 && begp1 <= endp1
2231 && endp1 <= BUF_ZV (bp1)))
2232 args_out_of_range (start1, end1);
2233
2234 /* Likewise for second substring. */
2235
2236 if (NILP (buffer2))
2237 bp2 = current_buffer;
2238 else
2239 {
3fff2dfa
RS
2240 Lisp_Object buf2;
2241 buf2 = Fget_buffer (buffer2);
2242 if (NILP (buf2))
2243 nsberror (buffer2);
3b1fdd85 2244 bp2 = XBUFFER (buf2);
93b62e82
KH
2245 if (NILP (bp2->name))
2246 error ("Selecting deleted buffer");
e9cf2084
RS
2247 }
2248
2249 if (NILP (start2))
2250 begp2 = BUF_BEGV (bp2);
2251 else
2252 {
2253 CHECK_NUMBER_COERCE_MARKER (start2, 4);
2254 begp2 = XINT (start2);
2255 }
2256 if (NILP (end2))
2257 endp2 = BUF_ZV (bp2);
2258 else
2259 {
2260 CHECK_NUMBER_COERCE_MARKER (end2, 5);
2261 endp2 = XINT (end2);
2262 }
2263
2264 if (begp2 > endp2)
2265 temp = begp2, begp2 = endp2, endp2 = temp;
2266
2267 if (!(BUF_BEGV (bp2) <= begp2
2268 && begp2 <= endp2
2269 && endp2 <= BUF_ZV (bp2)))
2270 args_out_of_range (start2, end2);
2271
07422a12
RS
2272 i1 = begp1;
2273 i2 = begp2;
2274 i1_byte = buf_charpos_to_bytepos (bp1, i1);
2275 i2_byte = buf_charpos_to_bytepos (bp2, i2);
e9cf2084 2276
07422a12 2277 while (i1 < endp1 && i2 < endp2)
e9cf2084 2278 {
07422a12
RS
2279 /* When we find a mismatch, we must compare the
2280 characters, not just the bytes. */
2281 int c1, c2;
ec1c14f6 2282
07422a12
RS
2283 if (! NILP (bp1->enable_multibyte_characters))
2284 {
2285 c1 = BUF_FETCH_MULTIBYTE_CHAR (bp1, i1_byte);
2286 BUF_INC_POS (bp1, i1_byte);
2287 i1++;
2288 }
2289 else
2290 {
2291 c1 = BUF_FETCH_BYTE (bp1, i1);
2292 c1 = unibyte_char_to_multibyte (c1);
2293 i1++;
2294 }
2295
2296 if (! NILP (bp2->enable_multibyte_characters))
2297 {
2298 c2 = BUF_FETCH_MULTIBYTE_CHAR (bp2, i2_byte);
2299 BUF_INC_POS (bp2, i2_byte);
2300 i2++;
2301 }
2302 else
2303 {
2304 c2 = BUF_FETCH_BYTE (bp2, i2);
2305 c2 = unibyte_char_to_multibyte (c2);
2306 i2++;
2307 }
ec1c14f6 2308
e9cf2084
RS
2309 if (trt)
2310 {
1b10fb77
RS
2311 c1 = XINT (trt[c1]);
2312 c2 = XINT (trt[c2]);
e9cf2084
RS
2313 }
2314 if (c1 < c2)
ec1c14f6 2315 return make_number (- 1 - chars);
e9cf2084 2316 if (c1 > c2)
ec1c14f6 2317 return make_number (chars + 1);
07422a12
RS
2318
2319 chars++;
e9cf2084
RS
2320 }
2321
2322 /* The strings match as far as they go.
2323 If one is shorter, that one is less. */
07422a12 2324 if (chars < endp1 - begp1)
ec1c14f6 2325 return make_number (chars + 1);
07422a12 2326 else if (chars < endp2 - begp2)
ec1c14f6 2327 return make_number (- chars - 1);
e9cf2084
RS
2328
2329 /* Same length too => they are equal. */
2330 return make_number (0);
2331}
35692fe0 2332\f
d5a539cd
RS
2333static Lisp_Object
2334subst_char_in_region_unwind (arg)
2335 Lisp_Object arg;
2336{
2337 return current_buffer->undo_list = arg;
2338}
2339
c8e76b47
RS
2340static Lisp_Object
2341subst_char_in_region_unwind_1 (arg)
2342 Lisp_Object arg;
2343{
2344 return current_buffer->filename = arg;
2345}
2346
35692fe0
JB
2347DEFUN ("subst-char-in-region", Fsubst_char_in_region,
2348 Ssubst_char_in_region, 4, 5, 0,
2349 "From START to END, replace FROMCHAR with TOCHAR each time it occurs.\n\
2350If optional arg NOUNDO is non-nil, don't record this change for undo\n\
fb8106e8
KH
2351and don't mark the buffer as really changed.\n\
2352Both characters must have the same length of multi-byte form.")
35692fe0
JB
2353 (start, end, fromchar, tochar, noundo)
2354 Lisp_Object start, end, fromchar, tochar, noundo;
2355{
84246b95 2356 register int pos, pos_byte, stop, i, len, end_byte;
60b96ee7 2357 int changed = 0;
d5c2c403
KH
2358 unsigned char fromstr[MAX_MULTIBYTE_LENGTH], tostr[MAX_MULTIBYTE_LENGTH];
2359 unsigned char *p;
d5a539cd 2360 int count = specpdl_ptr - specpdl;
aa801467
KH
2361#define COMBINING_NO 0
2362#define COMBINING_BEFORE 1
2363#define COMBINING_AFTER 2
2364#define COMBINING_BOTH (COMBINING_BEFORE | COMBINING_AFTER)
2365 int maybe_byte_combining = COMBINING_NO;
d5c2c403 2366 int last_changed;
7439e5b9 2367 int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
35692fe0
JB
2368
2369 validate_region (&start, &end);
2370 CHECK_NUMBER (fromchar, 2);
2371 CHECK_NUMBER (tochar, 3);
2372
7439e5b9 2373 if (multibyte_p)
fb8106e8 2374 {
d5c2c403
KH
2375 len = CHAR_STRING (XFASTINT (fromchar), fromstr);
2376 if (CHAR_STRING (XFASTINT (tochar), tostr) != len)
fb8106e8 2377 error ("Characters in subst-char-in-region have different byte-lengths");
aa801467
KH
2378 if (!ASCII_BYTE_P (*tostr))
2379 {
2380 /* If *TOSTR is in the range 0x80..0x9F and TOCHAR is not a
2381 complete multibyte character, it may be combined with the
2382 after bytes. If it is in the range 0xA0..0xFF, it may be
2383 combined with the before and after bytes. */
2384 if (!CHAR_HEAD_P (*tostr))
2385 maybe_byte_combining = COMBINING_BOTH;
2386 else if (BYTES_BY_CHAR_HEAD (*tostr) > len)
2387 maybe_byte_combining = COMBINING_AFTER;
2388 }
fb8106e8
KH
2389 }
2390 else
2391 {
2392 len = 1;
d5c2c403
KH
2393 fromstr[0] = XFASTINT (fromchar);
2394 tostr[0] = XFASTINT (tochar);
fb8106e8
KH
2395 }
2396
84246b95
KH
2397 pos = XINT (start);
2398 pos_byte = CHAR_TO_BYTE (pos);
ec1c14f6
RS
2399 stop = CHAR_TO_BYTE (XINT (end));
2400 end_byte = stop;
35692fe0 2401
d5a539cd
RS
2402 /* If we don't want undo, turn off putting stuff on the list.
2403 That's faster than getting rid of things,
c8e76b47
RS
2404 and it prevents even the entry for a first change.
2405 Also inhibit locking the file. */
d5a539cd
RS
2406 if (!NILP (noundo))
2407 {
2408 record_unwind_protect (subst_char_in_region_unwind,
2409 current_buffer->undo_list);
2410 current_buffer->undo_list = Qt;
c8e76b47
RS
2411 /* Don't do file-locking. */
2412 record_unwind_protect (subst_char_in_region_unwind_1,
2413 current_buffer->filename);
2414 current_buffer->filename = Qnil;
d5a539cd
RS
2415 }
2416
84246b95 2417 if (pos_byte < GPT_BYTE)
ec1c14f6 2418 stop = min (stop, GPT_BYTE);
fb8106e8 2419 while (1)
35692fe0 2420 {
a3360ff9
KH
2421 int pos_byte_next = pos_byte;
2422
84246b95 2423 if (pos_byte >= stop)
fb8106e8 2424 {
84246b95 2425 if (pos_byte >= end_byte) break;
ec1c14f6 2426 stop = end_byte;
fb8106e8 2427 }
84246b95 2428 p = BYTE_POS_ADDR (pos_byte);
7439e5b9
GM
2429 if (multibyte_p)
2430 INC_POS (pos_byte_next);
2431 else
2432 ++pos_byte_next;
a3360ff9
KH
2433 if (pos_byte_next - pos_byte == len
2434 && p[0] == fromstr[0]
fb8106e8
KH
2435 && (len == 1
2436 || (p[1] == fromstr[1]
2437 && (len == 2 || (p[2] == fromstr[2]
2438 && (len == 3 || p[3] == fromstr[3]))))))
35692fe0 2439 {
60b96ee7
RS
2440 if (! changed)
2441 {
d5c2c403
KH
2442 changed = pos;
2443 modify_region (current_buffer, changed, XINT (end));
7653d030
RS
2444
2445 if (! NILP (noundo))
2446 {
1e158d25
RS
2447 if (MODIFF - 1 == SAVE_MODIFF)
2448 SAVE_MODIFF++;
7653d030
RS
2449 if (MODIFF - 1 == current_buffer->auto_save_modified)
2450 current_buffer->auto_save_modified++;
2451 }
60b96ee7
RS
2452 }
2453
0c1e3b85 2454 /* Take care of the case where the new character
34a7a267 2455 combines with neighboring bytes. */
a3360ff9 2456 if (maybe_byte_combining
aa801467
KH
2457 && (maybe_byte_combining == COMBINING_AFTER
2458 ? (pos_byte_next < Z_BYTE
2459 && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
2460 : ((pos_byte_next < Z_BYTE
2461 && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
2462 || (pos_byte > BEG_BYTE
2463 && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))))))
0c1e3b85
RS
2464 {
2465 Lisp_Object tem, string;
2466
2467 struct gcpro gcpro1;
2468
2469 tem = current_buffer->undo_list;
2470 GCPRO1 (tem);
2471
aa801467
KH
2472 /* Make a multibyte string containing this single character. */
2473 string = make_multibyte_string (tostr, 1, len);
0c1e3b85
RS
2474 /* replace_range is less efficient, because it moves the gap,
2475 but it handles combining correctly. */
2476 replace_range (pos, pos + 1, string,
9869520f 2477 0, 0, 1);
a3360ff9
KH
2478 pos_byte_next = CHAR_TO_BYTE (pos);
2479 if (pos_byte_next > pos_byte)
2480 /* Before combining happened. We should not increment
3f5409d3
KH
2481 POS. So, to cancel the later increment of POS,
2482 decrease it now. */
2483 pos--;
a3360ff9 2484 else
3f5409d3 2485 INC_POS (pos_byte_next);
34a7a267 2486
0c1e3b85
RS
2487 if (! NILP (noundo))
2488 current_buffer->undo_list = tem;
2489
2490 UNGCPRO;
2491 }
2492 else
2493 {
2494 if (NILP (noundo))
2495 record_change (pos, 1);
2496 for (i = 0; i < len; i++) *p++ = tostr[i];
2497 }
d5c2c403 2498 last_changed = pos + 1;
35692fe0 2499 }
3f5409d3
KH
2500 pos_byte = pos_byte_next;
2501 pos++;
35692fe0
JB
2502 }
2503
60b96ee7 2504 if (changed)
d5c2c403
KH
2505 {
2506 signal_after_change (changed,
2507 last_changed - changed, last_changed - changed);
2508 update_compositions (changed, last_changed, CHECK_ALL);
2509 }
60b96ee7 2510
d5a539cd 2511 unbind_to (count, Qnil);
35692fe0
JB
2512 return Qnil;
2513}
2514
2515DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
2516 "From START to END, translate characters according to TABLE.\n\
2517TABLE is a string; the Nth character in it is the mapping\n\
1f24f4fd
RS
2518for the character with code N.\n\
2519This function does not alter multibyte characters.\n\
2520It returns the number of characters changed.")
35692fe0
JB
2521 (start, end, table)
2522 Lisp_Object start;
2523 Lisp_Object end;
2524 register Lisp_Object table;
2525{
ec1c14f6 2526 register int pos_byte, stop; /* Limits of the region. */
35692fe0 2527 register unsigned char *tt; /* Trans table. */
35692fe0
JB
2528 register int nc; /* New character. */
2529 int cnt; /* Number of changes made. */
35692fe0 2530 int size; /* Size of translate table. */
1f24f4fd 2531 int pos;
e8cce5af 2532 int multibyte = !NILP (current_buffer->enable_multibyte_characters);
35692fe0
JB
2533
2534 validate_region (&start, &end);
2535 CHECK_STRING (table, 2);
2536
dc3620af 2537 size = STRING_BYTES (XSTRING (table));
35692fe0
JB
2538 tt = XSTRING (table)->data;
2539
ec1c14f6
RS
2540 pos_byte = CHAR_TO_BYTE (XINT (start));
2541 stop = CHAR_TO_BYTE (XINT (end));
2542 modify_region (current_buffer, XINT (start), XINT (end));
1f24f4fd 2543 pos = XINT (start);
35692fe0
JB
2544
2545 cnt = 0;
1f24f4fd 2546 for (; pos_byte < stop; )
35692fe0 2547 {
ec1c14f6 2548 register unsigned char *p = BYTE_POS_ADDR (pos_byte);
1f24f4fd
RS
2549 int len;
2550 int oc;
a3360ff9 2551 int pos_byte_next;
ec1c14f6 2552
e8cce5af
KH
2553 if (multibyte)
2554 oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
2555 else
2556 oc = *p, len = 1;
a3360ff9 2557 pos_byte_next = pos_byte + len;
1f24f4fd 2558 if (oc < size && len == 1)
35692fe0
JB
2559 {
2560 nc = tt[oc];
2561 if (nc != oc)
2562 {
0c1e3b85 2563 /* Take care of the case where the new character
34a7a267 2564 combines with neighboring bytes. */
a3360ff9
KH
2565 if (!ASCII_BYTE_P (nc)
2566 && (CHAR_HEAD_P (nc)
2567 ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))
48839d2e 2568 : (pos_byte > BEG_BYTE
a3360ff9 2569 && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))))
0c1e3b85
RS
2570 {
2571 Lisp_Object string;
2572
a3360ff9 2573 string = make_multibyte_string (tt + oc, 1, 1);
0c1e3b85
RS
2574 /* This is less efficient, because it moves the gap,
2575 but it handles combining correctly. */
2576 replace_range (pos, pos + 1, string,
a3360ff9
KH
2577 1, 0, 1);
2578 pos_byte_next = CHAR_TO_BYTE (pos);
2579 if (pos_byte_next > pos_byte)
2580 /* Before combining happened. We should not
3f5409d3
KH
2581 increment POS. So, to cancel the later
2582 increment of POS, we decrease it now. */
2583 pos--;
a3360ff9 2584 else
3f5409d3 2585 INC_POS (pos_byte_next);
0c1e3b85
RS
2586 }
2587 else
2588 {
2589 record_change (pos, 1);
2590 *p = nc;
2591 signal_after_change (pos, 1, 1);
d5c2c403 2592 update_compositions (pos, pos + 1, CHECK_BORDER);
0c1e3b85 2593 }
35692fe0
JB
2594 ++cnt;
2595 }
2596 }
3f5409d3
KH
2597 pos_byte = pos_byte_next;
2598 pos++;
35692fe0
JB
2599 }
2600
ec1c14f6 2601 return make_number (cnt);
35692fe0
JB
2602}
2603
2604DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r",
2605 "Delete the text between point and mark.\n\
2606When called from a program, expects two arguments,\n\
2607positions (integers or markers) specifying the stretch to be deleted.")
2591ec64
EN
2608 (start, end)
2609 Lisp_Object start, end;
35692fe0 2610{
2591ec64
EN
2611 validate_region (&start, &end);
2612 del_range (XINT (start), XINT (end));
35692fe0
JB
2613 return Qnil;
2614}
7dae4502
SM
2615
2616DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
2617 Sdelete_and_extract_region, 2, 2, 0,
2618 "Delete the text between START and END and return it.")
2619 (start, end)
2620 Lisp_Object start, end;
2621{
2622 validate_region (&start, &end);
2623 return del_range_1 (XINT (start), XINT (end), 1, 1);
2624}
35692fe0
JB
2625\f
2626DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
2627 "Remove restrictions (narrowing) from current buffer.\n\
2628This allows the buffer's full text to be seen and edited.")
2629 ()
2630{
2cad2e34
RS
2631 if (BEG != BEGV || Z != ZV)
2632 current_buffer->clip_changed = 1;
35692fe0 2633 BEGV = BEG;
ec1c14f6
RS
2634 BEGV_BYTE = BEG_BYTE;
2635 SET_BUF_ZV_BOTH (current_buffer, Z, Z_BYTE);
52b14ac0
JB
2636 /* Changing the buffer bounds invalidates any recorded current column. */
2637 invalidate_current_column ();
35692fe0
JB
2638 return Qnil;
2639}
2640
2641DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
2642 "Restrict editing in this buffer to the current region.\n\
2643The rest of the text becomes temporarily invisible and untouchable\n\
2644but is not deleted; if you save the buffer in a file, the invisible\n\
2645text is included in the file. \\[widen] makes all visible again.\n\
2646See also `save-restriction'.\n\
2647\n\
2648When calling from a program, pass two arguments; positions (integers\n\
2649or markers) bounding the text that should remain visible.")
2591ec64
EN
2650 (start, end)
2651 register Lisp_Object start, end;
35692fe0 2652{
2591ec64
EN
2653 CHECK_NUMBER_COERCE_MARKER (start, 0);
2654 CHECK_NUMBER_COERCE_MARKER (end, 1);
35692fe0 2655
2591ec64 2656 if (XINT (start) > XINT (end))
35692fe0 2657 {
b5a6948e 2658 Lisp_Object tem;
2591ec64 2659 tem = start; start = end; end = tem;
35692fe0
JB
2660 }
2661
2591ec64
EN
2662 if (!(BEG <= XINT (start) && XINT (start) <= XINT (end) && XINT (end) <= Z))
2663 args_out_of_range (start, end);
35692fe0 2664
2cad2e34
RS
2665 if (BEGV != XFASTINT (start) || ZV != XFASTINT (end))
2666 current_buffer->clip_changed = 1;
2667
ec1c14f6 2668 SET_BUF_BEGV (current_buffer, XFASTINT (start));
2591ec64 2669 SET_BUF_ZV (current_buffer, XFASTINT (end));
6ec8bbd2 2670 if (PT < XFASTINT (start))
2591ec64 2671 SET_PT (XFASTINT (start));
6ec8bbd2 2672 if (PT > XFASTINT (end))
2591ec64 2673 SET_PT (XFASTINT (end));
52b14ac0
JB
2674 /* Changing the buffer bounds invalidates any recorded current column. */
2675 invalidate_current_column ();
35692fe0
JB
2676 return Qnil;
2677}
2678
2679Lisp_Object
2680save_restriction_save ()
2681{
2682 register Lisp_Object bottom, top;
2683 /* Note: I tried using markers here, but it does not win
2684 because insertion at the end of the saved region
2685 does not advance mh and is considered "outside" the saved region. */
55561c63
KH
2686 XSETFASTINT (bottom, BEGV - BEG);
2687 XSETFASTINT (top, Z - ZV);
35692fe0
JB
2688
2689 return Fcons (Fcurrent_buffer (), Fcons (bottom, top));
2690}
2691
2692Lisp_Object
2693save_restriction_restore (data)
2694 Lisp_Object data;
2695{
2696 register struct buffer *buf;
2697 register int newhead, newtail;
2698 register Lisp_Object tem;
2cad2e34 2699 int obegv, ozv;
35692fe0 2700
03699b14 2701 buf = XBUFFER (XCAR (data));
35692fe0 2702
03699b14 2703 data = XCDR (data);
35692fe0 2704
03699b14 2705 tem = XCAR (data);
35692fe0 2706 newhead = XINT (tem);
03699b14 2707 tem = XCDR (data);
35692fe0
JB
2708 newtail = XINT (tem);
2709 if (newhead + newtail > BUF_Z (buf) - BUF_BEG (buf))
2710 {
2711 newhead = 0;
2712 newtail = 0;
2713 }
2cad2e34
RS
2714
2715 obegv = BUF_BEGV (buf);
2716 ozv = BUF_ZV (buf);
2717
ec1c14f6 2718 SET_BUF_BEGV (buf, BUF_BEG (buf) + newhead);
35692fe0 2719 SET_BUF_ZV (buf, BUF_Z (buf) - newtail);
2cad2e34
RS
2720
2721 if (obegv != BUF_BEGV (buf) || ozv != BUF_ZV (buf))
2722 current_buffer->clip_changed = 1;
35692fe0
JB
2723
2724 /* If point is outside the new visible range, move it inside. */
ec1c14f6
RS
2725 SET_BUF_PT_BOTH (buf,
2726 clip_to_bounds (BUF_BEGV (buf), BUF_PT (buf), BUF_ZV (buf)),
2727 clip_to_bounds (BUF_BEGV_BYTE (buf), BUF_PT_BYTE (buf),
2728 BUF_ZV_BYTE (buf)));
35692fe0
JB
2729
2730 return Qnil;
2731}
2732
2733DEFUN ("save-restriction", Fsave_restriction, Ssave_restriction, 0, UNEVALLED, 0,
2734 "Execute BODY, saving and restoring current buffer's restrictions.\n\
2735The buffer's restrictions make parts of the beginning and end invisible.\n\
2736\(They are set up with `narrow-to-region' and eliminated with `widen'.)\n\
2737This special form, `save-restriction', saves the current buffer's restrictions\n\
2738when it is entered, and restores them when it is exited.\n\
2739So any `narrow-to-region' within BODY lasts only until the end of the form.\n\
2740The old restrictions settings are restored\n\
2741even in case of abnormal exit (throw or error).\n\
2742\n\
2743The value returned is the value of the last form in BODY.\n\
2744\n\
2745`save-restriction' can get confused if, within the BODY, you widen\n\
2746and then make changes outside the area within the saved restrictions.\n\
5b2a5316 2747See Info node `(elisp)Narrowing' for details and an appropriate technique.\n\
35692fe0
JB
2748\n\
2749Note: if you are using both `save-excursion' and `save-restriction',\n\
2750use `save-excursion' outermost:\n\
2751 (save-excursion (save-restriction ...))")
2752 (body)
2753 Lisp_Object body;
2754{
2755 register Lisp_Object val;
2756 int count = specpdl_ptr - specpdl;
2757
2758 record_unwind_protect (save_restriction_restore, save_restriction_save ());
2759 val = Fprogn (body);
2760 return unbind_to (count, val);
2761}
2762\f
2ea0266e
GM
2763#ifndef HAVE_MENUS
2764
671fbc4d
KH
2765/* Buffer for the most recent text displayed by Fmessage. */
2766static char *message_text;
2767
2768/* Allocated length of that buffer. */
2769static int message_length;
2770
2ea0266e
GM
2771#endif /* not HAVE_MENUS */
2772
35692fe0
JB
2773DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
2774 "Print a one-line message at the bottom of the screen.\n\
98fc5c3c
RS
2775The first argument is a format control string, and the rest are data\n\
2776to be formatted under control of the string. See `format' for details.\n\
2777\n\
ccdac5be
JB
2778If the first argument is nil, clear any existing message; let the\n\
2779minibuffer contents show.")
35692fe0
JB
2780 (nargs, args)
2781 int nargs;
2782 Lisp_Object *args;
2783{
ccdac5be 2784 if (NILP (args[0]))
f0250249
JB
2785 {
2786 message (0);
2787 return Qnil;
2788 }
ccdac5be
JB
2789 else
2790 {
2791 register Lisp_Object val;
2792 val = Fformat (nargs, args);
5e6d5493 2793 message3 (val, STRING_BYTES (XSTRING (val)), STRING_MULTIBYTE (val));
ccdac5be
JB
2794 return val;
2795 }
35692fe0
JB
2796}
2797
cacc3e2c
RS
2798DEFUN ("message-box", Fmessage_box, Smessage_box, 1, MANY, 0,
2799 "Display a message, in a dialog box if possible.\n\
2800If a dialog box is not available, use the echo area.\n\
f8250f01
RS
2801The first argument is a format control string, and the rest are data\n\
2802to be formatted under control of the string. See `format' for details.\n\
2803\n\
cacc3e2c
RS
2804If the first argument is nil, clear any existing message; let the\n\
2805minibuffer contents show.")
2806 (nargs, args)
2807 int nargs;
2808 Lisp_Object *args;
2809{
2810 if (NILP (args[0]))
2811 {
2812 message (0);
2813 return Qnil;
2814 }
2815 else
2816 {
2817 register Lisp_Object val;
2818 val = Fformat (nargs, args);
f8250f01 2819#ifdef HAVE_MENUS
cacc3e2c
RS
2820 {
2821 Lisp_Object pane, menu, obj;
2822 struct gcpro gcpro1;
2823 pane = Fcons (Fcons (build_string ("OK"), Qt), Qnil);
2824 GCPRO1 (pane);
2825 menu = Fcons (val, pane);
2826 obj = Fx_popup_dialog (Qt, menu);
2827 UNGCPRO;
2828 return val;
2829 }
f8250f01 2830#else /* not HAVE_MENUS */
cacc3e2c
RS
2831 /* Copy the data so that it won't move when we GC. */
2832 if (! message_text)
2833 {
2834 message_text = (char *)xmalloc (80);
2835 message_length = 80;
2836 }
dc3620af 2837 if (STRING_BYTES (XSTRING (val)) > message_length)
cacc3e2c 2838 {
dc3620af 2839 message_length = STRING_BYTES (XSTRING (val));
cacc3e2c
RS
2840 message_text = (char *)xrealloc (message_text, message_length);
2841 }
dc3620af 2842 bcopy (XSTRING (val)->data, message_text, STRING_BYTES (XSTRING (val)));
d13a8480
RS
2843 message2 (message_text, STRING_BYTES (XSTRING (val)),
2844 STRING_MULTIBYTE (val));
cacc3e2c 2845 return val;
f8250f01 2846#endif /* not HAVE_MENUS */
cacc3e2c
RS
2847 }
2848}
f8250f01 2849#ifdef HAVE_MENUS
cacc3e2c
RS
2850extern Lisp_Object last_nonmenu_event;
2851#endif
f8250f01 2852
cacc3e2c
RS
2853DEFUN ("message-or-box", Fmessage_or_box, Smessage_or_box, 1, MANY, 0,
2854 "Display a message in a dialog box or in the echo area.\n\
2855If this command was invoked with the mouse, use a dialog box.\n\
2856Otherwise, use the echo area.\n\
f8250f01
RS
2857The first argument is a format control string, and the rest are data\n\
2858to be formatted under control of the string. See `format' for details.\n\
cacc3e2c 2859\n\
cacc3e2c
RS
2860If the first argument is nil, clear any existing message; let the\n\
2861minibuffer contents show.")
2862 (nargs, args)
2863 int nargs;
2864 Lisp_Object *args;
2865{
f8250f01 2866#ifdef HAVE_MENUS
5920df33 2867 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
c01fbf95 2868 && use_dialog_box)
0a56ee6b 2869 return Fmessage_box (nargs, args);
cacc3e2c
RS
2870#endif
2871 return Fmessage (nargs, args);
2872}
2873
b14dda8a
RS
2874DEFUN ("current-message", Fcurrent_message, Scurrent_message, 0, 0, 0,
2875 "Return the string currently displayed in the echo area, or nil if none.")
2876 ()
2877{
0634a78e 2878 return current_message ();
b14dda8a
RS
2879}
2880
2d9811c4 2881
0963334d 2882DEFUN ("propertize", Fpropertize, Spropertize, 3, MANY, 0,
2d9811c4
GM
2883 "Return a copy of STRING with text properties added.\n\
2884First argument is the string to copy.\n\
76329875 2885Remaining arguments form a sequence of PROPERTY VALUE pairs for text\n\
2d9811c4
GM
2886properties to add to the result ")
2887 (nargs, args)
2888 int nargs;
2889 Lisp_Object *args;
2890{
2891 Lisp_Object properties, string;
2892 struct gcpro gcpro1, gcpro2;
2893 int i;
2894
2895 /* Number of args must be odd. */
2896 if ((nargs & 1) == 0 || nargs < 3)
2897 error ("Wrong number of arguments");
2898
2899 properties = string = Qnil;
2900 GCPRO2 (properties, string);
34a7a267 2901
2d9811c4
GM
2902 /* First argument must be a string. */
2903 CHECK_STRING (args[0], 0);
2904 string = Fcopy_sequence (args[0]);
2905
2906 for (i = 1; i < nargs; i += 2)
2907 {
2908 CHECK_SYMBOL (args[i], i);
2909 properties = Fcons (args[i], Fcons (args[i + 1], properties));
2910 }
2911
2912 Fadd_text_properties (make_number (0),
2913 make_number (XSTRING (string)->size),
2914 properties, string);
2915 RETURN_UNGCPRO (string);
2916}
2917
2918
1f24f4fd
RS
2919/* Number of bytes that STRING will occupy when put into the result.
2920 MULTIBYTE is nonzero if the result should be multibyte. */
2921
2922#define CONVERTED_BYTE_SIZE(MULTIBYTE, STRING) \
2923 (((MULTIBYTE) && ! STRING_MULTIBYTE (STRING)) \
8d6179dc 2924 ? count_size_as_multibyte (XSTRING (STRING)->data, \
dc3620af
RS
2925 STRING_BYTES (XSTRING (STRING))) \
2926 : STRING_BYTES (XSTRING (STRING)))
1f24f4fd 2927
35692fe0
JB
2928DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
2929 "Format a string out of a control-string and arguments.\n\
2930The first argument is a control string.\n\
2931The other arguments are substituted into it to make the result, a string.\n\
2932It may contain %-sequences meaning to substitute the next argument.\n\
2933%s means print a string argument. Actually, prints any object, with `princ'.\n\
2934%d means print as number in decimal (%o octal, %x hex).\n\
9db1775a
RS
2935%e means print a number in exponential notation.\n\
2936%f means print a number in decimal-point notation.\n\
2937%g means print a number in exponential notation\n\
2938 or decimal-point notation, whichever uses fewer characters.\n\
35692fe0 2939%c means print a number as a single character.\n\
d6c0ea99 2940%S means print any object as an s-expression (using `prin1').\n\
9db1775a 2941 The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.\n\
52b14ac0 2942Use %% to put a single % into the output.")
35692fe0
JB
2943 (nargs, args)
2944 int nargs;
2945 register Lisp_Object *args;
2946{
2947 register int n; /* The number of the next arg to substitute */
e781c49e 2948 register int total; /* An estimate of the final length */
1f24f4fd 2949 char *buf, *p;
35692fe0 2950 register unsigned char *format, *end;
2ea0266e 2951 int nchars;
1f24f4fd
RS
2952 /* Nonzero if the output should be a multibyte string,
2953 which is true if any of the inputs is one. */
2954 int multibyte = 0;
8f2917e4
KH
2955 /* When we make a multibyte string, we must pay attention to the
2956 byte combining problem, i.e., a byte may be combined with a
2957 multibyte charcter of the previous string. This flag tells if we
2958 must consider such a situation or not. */
2959 int maybe_combine_byte;
1f24f4fd 2960 unsigned char *this_format;
e781c49e 2961 int longest_format;
8d6179dc 2962 Lisp_Object val;
5e6d5493
GM
2963 struct info
2964 {
2965 int start, end;
2966 } *info = 0;
1f24f4fd 2967
35692fe0 2968 extern char *index ();
1f24f4fd 2969
35692fe0
JB
2970 /* It should not be necessary to GCPRO ARGS, because
2971 the caller in the interpreter should take care of that. */
2972
e781c49e
RS
2973 /* Try to determine whether the result should be multibyte.
2974 This is not always right; sometimes the result needs to be multibyte
2975 because of an object that we will pass through prin1,
2976 and in that case, we won't know it here. */
1f24f4fd
RS
2977 for (n = 0; n < nargs; n++)
2978 if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
2979 multibyte = 1;
2980
35692fe0 2981 CHECK_STRING (args[0], 0);
e781c49e
RS
2982
2983 /* If we start out planning a unibyte result,
2984 and later find it has to be multibyte, we jump back to retry. */
2985 retry:
2986
35692fe0 2987 format = XSTRING (args[0])->data;
dc3620af 2988 end = format + STRING_BYTES (XSTRING (args[0]));
e781c49e 2989 longest_format = 0;
1f24f4fd
RS
2990
2991 /* Make room in result for all the non-%-codes in the control string. */
e781c49e 2992 total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]);
1f24f4fd
RS
2993
2994 /* Add to TOTAL enough space to hold the converted arguments. */
35692fe0
JB
2995
2996 n = 0;
2997 while (format != end)
2998 if (*format++ == '%')
2999 {
1f24f4fd
RS
3000 int minlen, thissize = 0;
3001 unsigned char *this_format_start = format - 1;
35692fe0
JB
3002
3003 /* Process a numeric arg and skip it. */
3004 minlen = atoi (format);
537dfb13
RS
3005 if (minlen < 0)
3006 minlen = - minlen;
3007
35692fe0
JB
3008 while ((*format >= '0' && *format <= '9')
3009 || *format == '-' || *format == ' ' || *format == '.')
3010 format++;
3011
1f24f4fd
RS
3012 if (format - this_format_start + 1 > longest_format)
3013 longest_format = format - this_format_start + 1;
3014
bf6ab66c
KH
3015 if (format == end)
3016 error ("Format string ends in middle of format specifier");
35692fe0
JB
3017 if (*format == '%')
3018 format++;
3019 else if (++n >= nargs)
537dfb13 3020 error ("Not enough arguments for format string");
35692fe0
JB
3021 else if (*format == 'S')
3022 {
3023 /* For `S', prin1 the argument and then treat like a string. */
3024 register Lisp_Object tem;
3025 tem = Fprin1_to_string (args[n], Qnil);
e781c49e
RS
3026 if (STRING_MULTIBYTE (tem) && ! multibyte)
3027 {
3028 multibyte = 1;
3029 goto retry;
3030 }
35692fe0
JB
3031 args[n] = tem;
3032 goto string;
3033 }
ae683129 3034 else if (SYMBOLP (args[n]))
35692fe0 3035 {
c01fbf95
KR
3036 /* Use a temp var to avoid problems when ENABLE_CHECKING
3037 is turned on. */
3038 struct Lisp_String *t = XSYMBOL (args[n])->name;
3039 XSETSTRING (args[n], t);
7df74da6
RS
3040 if (STRING_MULTIBYTE (args[n]) && ! multibyte)
3041 {
3042 multibyte = 1;
3043 goto retry;
3044 }
35692fe0
JB
3045 goto string;
3046 }
ae683129 3047 else if (STRINGP (args[n]))
35692fe0
JB
3048 {
3049 string:
b22e7ecc 3050 if (*format != 's' && *format != 'S')
bf6ab66c 3051 error ("Format specifier doesn't match argument type");
1f24f4fd 3052 thissize = CONVERTED_BYTE_SIZE (multibyte, args[n]);
35692fe0
JB
3053 }
3054 /* Would get MPV otherwise, since Lisp_Int's `point' to low memory. */
ae683129 3055 else if (INTEGERP (args[n]) && *format != 's')
35692fe0 3056 {
eb8c3be9 3057 /* The following loop assumes the Lisp type indicates
35692fe0
JB
3058 the proper way to pass the argument.
3059 So make sure we have a flonum if the argument should
3060 be a double. */
3061 if (*format == 'e' || *format == 'f' || *format == 'g')
3062 args[n] = Ffloat (args[n]);
4224cb62 3063 else
4224cb62 3064 if (*format != 'd' && *format != 'o' && *format != 'x'
00d65216 3065 && *format != 'i' && *format != 'X' && *format != 'c')
4224cb62
KH
3066 error ("Invalid format operation %%%c", *format);
3067
34a7a267 3068 thissize = 30;
25c9e7fb
RS
3069 if (*format == 'c'
3070 && (! SINGLE_BYTE_CHAR_P (XINT (args[n]))
3071 || XINT (args[n]) == 0))
f49a2d74
KH
3072 {
3073 if (! multibyte)
3074 {
3075 multibyte = 1;
3076 goto retry;
3077 }
3078 args[n] = Fchar_to_string (args[n]);
dc3620af 3079 thissize = STRING_BYTES (XSTRING (args[n]));
f49a2d74 3080 }
35692fe0 3081 }
ae683129 3082 else if (FLOATP (args[n]) && *format != 's')
35692fe0
JB
3083 {
3084 if (! (*format == 'e' || *format == 'f' || *format == 'g'))
247422ce 3085 args[n] = Ftruncate (args[n], Qnil);
b413f895 3086 thissize = 200;
35692fe0
JB
3087 }
3088 else
3089 {
3090 /* Anything but a string, convert to a string using princ. */
3091 register Lisp_Object tem;
3092 tem = Fprin1_to_string (args[n], Qt);
a4e91443 3093 if (STRING_MULTIBYTE (tem) & ! multibyte)
e781c49e
RS
3094 {
3095 multibyte = 1;
3096 goto retry;
3097 }
35692fe0
JB
3098 args[n] = tem;
3099 goto string;
3100 }
34a7a267 3101
1f24f4fd
RS
3102 if (thissize < minlen)
3103 thissize = minlen;
3104
3105 total += thissize + 4;
35692fe0
JB
3106 }
3107
e781c49e
RS
3108 /* Now we can no longer jump to retry.
3109 TOTAL and LONGEST_FORMAT are known for certain. */
3110
1f24f4fd 3111 this_format = (unsigned char *) alloca (longest_format + 1);
50aa2f90 3112
1f24f4fd
RS
3113 /* Allocate the space for the result.
3114 Note that TOTAL is an overestimate. */
3115 if (total < 1000)
3c6db9d5 3116 buf = (char *) alloca (total + 1);
1f24f4fd 3117 else
3c6db9d5 3118 buf = (char *) xmalloc (total + 1);
35692fe0 3119
1f24f4fd
RS
3120 p = buf;
3121 nchars = 0;
3122 n = 0;
35692fe0 3123
1f24f4fd
RS
3124 /* Scan the format and store result in BUF. */
3125 format = XSTRING (args[0])->data;
8f2917e4 3126 maybe_combine_byte = 0;
1f24f4fd
RS
3127 while (format != end)
3128 {
3129 if (*format == '%')
3130 {
3131 int minlen;
25c9e7fb 3132 int negative = 0;
1f24f4fd 3133 unsigned char *this_format_start = format;
35692fe0 3134
1f24f4fd 3135 format++;
fb893977 3136
1f24f4fd
RS
3137 /* Process a numeric arg and skip it. */
3138 minlen = atoi (format);
3139 if (minlen < 0)
25c9e7fb 3140 minlen = - minlen, negative = 1;
35692fe0 3141
1f24f4fd
RS
3142 while ((*format >= '0' && *format <= '9')
3143 || *format == '-' || *format == ' ' || *format == '.')
3144 format++;
35692fe0 3145
1f24f4fd
RS
3146 if (*format++ == '%')
3147 {
3148 *p++ = '%';
3149 nchars++;
3150 continue;
3151 }
3152
3153 ++n;
3154
3155 if (STRINGP (args[n]))
3156 {
25c9e7fb
RS
3157 int padding, nbytes;
3158 int width = strwidth (XSTRING (args[n])->data,
dc3620af 3159 STRING_BYTES (XSTRING (args[n])));
5e6d5493 3160 int start = nchars;
25c9e7fb
RS
3161
3162 /* If spec requires it, pad on right with spaces. */
3163 padding = minlen - width;
3164 if (! negative)
3165 while (padding-- > 0)
3166 {
3167 *p++ = ' ';
3168 nchars++;
3169 }
1f24f4fd 3170
8f2917e4
KH
3171 if (p > buf
3172 && multibyte
25aa5d64 3173 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
8f2917e4 3174 && STRING_MULTIBYTE (args[n])
25aa5d64 3175 && !CHAR_HEAD_P (XSTRING (args[n])->data[0]))
8f2917e4 3176 maybe_combine_byte = 1;
1f24f4fd 3177 nbytes = copy_text (XSTRING (args[n])->data, p,
dc3620af 3178 STRING_BYTES (XSTRING (args[n])),
1f24f4fd
RS
3179 STRING_MULTIBYTE (args[n]), multibyte);
3180 p += nbytes;
3181 nchars += XSTRING (args[n])->size;
3182
25c9e7fb
RS
3183 if (negative)
3184 while (padding-- > 0)
3185 {
3186 *p++ = ' ';
3187 nchars++;
3188 }
5e6d5493
GM
3189
3190 /* If this argument has text properties, record where
3191 in the result string it appears. */
3192 if (XSTRING (args[n])->intervals)
3193 {
3194 if (!info)
3195 {
3196 int nbytes = nargs * sizeof *info;
3197 info = (struct info *) alloca (nbytes);
3198 bzero (info, nbytes);
3199 }
34a7a267 3200
5e6d5493
GM
3201 info[n].start = start;
3202 info[n].end = nchars;
3203 }
1f24f4fd
RS
3204 }
3205 else if (INTEGERP (args[n]) || FLOATP (args[n]))
3206 {
3207 int this_nchars;
3208
3209 bcopy (this_format_start, this_format,
3210 format - this_format_start);
3211 this_format[format - this_format_start] = 0;
3212
d0183d38
RS
3213 if (INTEGERP (args[n]))
3214 sprintf (p, this_format, XINT (args[n]));
3215 else
03699b14 3216 sprintf (p, this_format, XFLOAT_DATA (args[n]));
1f24f4fd 3217
8f2917e4
KH
3218 if (p > buf
3219 && multibyte
25aa5d64
KH
3220 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
3221 && !CHAR_HEAD_P (*((unsigned char *) p)))
8f2917e4 3222 maybe_combine_byte = 1;
1f24f4fd 3223 this_nchars = strlen (p);
9a599130
KH
3224 if (multibyte)
3225 p += str_to_multibyte (p, buf + total - p, this_nchars);
3226 else
3227 p += this_nchars;
1f24f4fd
RS
3228 nchars += this_nchars;
3229 }
3230 }
7df74da6
RS
3231 else if (STRING_MULTIBYTE (args[0]))
3232 {
3233 /* Copy a whole multibyte character. */
8f2917e4
KH
3234 if (p > buf
3235 && multibyte
25aa5d64
KH
3236 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
3237 && !CHAR_HEAD_P (*format))
8f2917e4 3238 maybe_combine_byte = 1;
7df74da6
RS
3239 *p++ = *format++;
3240 while (! CHAR_HEAD_P (*format)) *p++ = *format++;
3241 nchars++;
3242 }
3243 else if (multibyte)
1f24f4fd
RS
3244 {
3245 /* Convert a single-byte character to multibyte. */
3246 int len = copy_text (format, p, 1, 0, 1);
3247
3248 p += len;
3249 format++;
3250 nchars++;
3251 }
3252 else
3253 *p++ = *format++, nchars++;
3254 }
3255
8f2917e4
KH
3256 if (maybe_combine_byte)
3257 nchars = multibyte_chars_in_text (buf, p - buf);
5f75e666 3258 val = make_specified_string (buf, nchars, p - buf, multibyte);
8d6179dc 3259
1f24f4fd
RS
3260 /* If we allocated BUF with malloc, free it too. */
3261 if (total >= 1000)
3262 xfree (buf);
35692fe0 3263
5e6d5493
GM
3264 /* If the format string has text properties, or any of the string
3265 arguments has text properties, set up text properties of the
3266 result string. */
34a7a267 3267
5e6d5493
GM
3268 if (XSTRING (args[0])->intervals || info)
3269 {
3270 Lisp_Object len, new_len, props;
3271 struct gcpro gcpro1;
34a7a267 3272
5e6d5493
GM
3273 /* Add text properties from the format string. */
3274 len = make_number (XSTRING (args[0])->size);
3275 props = text_property_list (args[0], make_number (0), len, Qnil);
3276 GCPRO1 (props);
34a7a267 3277
5e6d5493
GM
3278 if (CONSP (props))
3279 {
3280 new_len = make_number (XSTRING (val)->size);
3281 extend_property_ranges (props, len, new_len);
3282 add_text_properties_from_list (val, props, make_number (0));
3283 }
3284
3285 /* Add text properties from arguments. */
3286 if (info)
3287 for (n = 1; n < nargs; ++n)
3288 if (info[n].end)
3289 {
3290 len = make_number (XSTRING (args[n])->size);
3291 new_len = make_number (info[n].end - info[n].start);
3292 props = text_property_list (args[n], make_number (0), len, Qnil);
3293 extend_property_ranges (props, len, new_len);
be17069b
KH
3294 /* If successive arguments have properites, be sure that
3295 the value of `composition' property be the copy. */
3296 if (n > 1 && info[n - 1].end)
3297 make_composition_value_copy (props);
5e6d5493
GM
3298 add_text_properties_from_list (val, props,
3299 make_number (info[n].start));
3300 }
3301
3302 UNGCPRO;
3303 }
3304
8d6179dc 3305 return val;
35692fe0
JB
3306}
3307
2d9811c4 3308
35692fe0
JB
3309/* VARARGS 1 */
3310Lisp_Object
3311#ifdef NO_ARG_ARRAY
3312format1 (string1, arg0, arg1, arg2, arg3, arg4)
679e18b1 3313 EMACS_INT arg0, arg1, arg2, arg3, arg4;
35692fe0
JB
3314#else
3315format1 (string1)
3316#endif
3317 char *string1;
3318{
3319 char buf[100];
3320#ifdef NO_ARG_ARRAY
679e18b1 3321 EMACS_INT args[5];
35692fe0
JB
3322 args[0] = arg0;
3323 args[1] = arg1;
3324 args[2] = arg2;
3325 args[3] = arg3;
3326 args[4] = arg4;
e3670faa 3327 doprnt (buf, sizeof buf, string1, (char *)0, 5, (char **) args);
35692fe0 3328#else
ea4d2909 3329 doprnt (buf, sizeof buf, string1, (char *)0, 5, &string1 + 1);
35692fe0
JB
3330#endif
3331 return build_string (buf);
3332}
3333\f
3334DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
3335 "Return t if two characters match, optionally ignoring case.\n\
3336Both arguments must be characters (i.e. integers).\n\
3337Case is ignored if `case-fold-search' is non-nil in the current buffer.")
3338 (c1, c2)
3339 register Lisp_Object c1, c2;
3340{
1b5d98bb 3341 int i1, i2;
35692fe0
JB
3342 CHECK_NUMBER (c1, 0);
3343 CHECK_NUMBER (c2, 1);
3344
1b5d98bb 3345 if (XINT (c1) == XINT (c2))
35692fe0 3346 return Qt;
1b5d98bb
RS
3347 if (NILP (current_buffer->case_fold_search))
3348 return Qnil;
3349
3350 /* Do these in separate statements,
3351 then compare the variables.
3352 because of the way DOWNCASE uses temp variables. */
3353 i1 = DOWNCASE (XFASTINT (c1));
3354 i2 = DOWNCASE (XFASTINT (c2));
3355 return (i1 == i2 ? Qt : Qnil);
35692fe0 3356}
b229b8d1
RS
3357\f
3358/* Transpose the markers in two regions of the current buffer, and
3359 adjust the ones between them if necessary (i.e.: if the regions
3360 differ in size).
3361
ec1c14f6
RS
3362 START1, END1 are the character positions of the first region.
3363 START1_BYTE, END1_BYTE are the byte positions.
3364 START2, END2 are the character positions of the second region.
3365 START2_BYTE, END2_BYTE are the byte positions.
3366
b229b8d1
RS
3367 Traverses the entire marker list of the buffer to do so, adding an
3368 appropriate amount to some, subtracting from some, and leaving the
3369 rest untouched. Most of this is copied from adjust_markers in insdel.c.
34a7a267 3370
ec1c14f6 3371 It's the caller's job to ensure that START1 <= END1 <= START2 <= END2. */
b229b8d1
RS
3372
3373void
ec1c14f6
RS
3374transpose_markers (start1, end1, start2, end2,
3375 start1_byte, end1_byte, start2_byte, end2_byte)
b229b8d1 3376 register int start1, end1, start2, end2;
ec1c14f6 3377 register int start1_byte, end1_byte, start2_byte, end2_byte;
b229b8d1 3378{
ec1c14f6 3379 register int amt1, amt1_byte, amt2, amt2_byte, diff, diff_byte, mpos;
b229b8d1 3380 register Lisp_Object marker;
b229b8d1 3381
03240d11 3382 /* Update point as if it were a marker. */
8de1d5f0
KH
3383 if (PT < start1)
3384 ;
3385 else if (PT < end1)
ec1c14f6
RS
3386 TEMP_SET_PT_BOTH (PT + (end2 - end1),
3387 PT_BYTE + (end2_byte - end1_byte));
8de1d5f0 3388 else if (PT < start2)
ec1c14f6
RS
3389 TEMP_SET_PT_BOTH (PT + (end2 - start2) - (end1 - start1),
3390 (PT_BYTE + (end2_byte - start2_byte)
3391 - (end1_byte - start1_byte)));
8de1d5f0 3392 else if (PT < end2)
ec1c14f6
RS
3393 TEMP_SET_PT_BOTH (PT - (start2 - start1),
3394 PT_BYTE - (start2_byte - start1_byte));
8de1d5f0 3395
03240d11
KH
3396 /* We used to adjust the endpoints here to account for the gap, but that
3397 isn't good enough. Even if we assume the caller has tried to move the
3398 gap out of our way, it might still be at start1 exactly, for example;
3399 and that places it `inside' the interval, for our purposes. The amount
3400 of adjustment is nontrivial if there's a `denormalized' marker whose
3401 position is between GPT and GPT + GAP_SIZE, so it's simpler to leave
3402 the dirty work to Fmarker_position, below. */
b229b8d1
RS
3403
3404 /* The difference between the region's lengths */
3405 diff = (end2 - start2) - (end1 - start1);
ec1c14f6 3406 diff_byte = (end2_byte - start2_byte) - (end1_byte - start1_byte);
34a7a267 3407
b229b8d1 3408 /* For shifting each marker in a region by the length of the other
ec1c14f6 3409 region plus the distance between the regions. */
b229b8d1
RS
3410 amt1 = (end2 - start2) + (start2 - end1);
3411 amt2 = (end1 - start1) + (start2 - end1);
ec1c14f6
RS
3412 amt1_byte = (end2_byte - start2_byte) + (start2_byte - end1_byte);
3413 amt2_byte = (end1_byte - start1_byte) + (start2_byte - end1_byte);
b229b8d1 3414
1e158d25 3415 for (marker = BUF_MARKERS (current_buffer); !NILP (marker);
03240d11 3416 marker = XMARKER (marker)->chain)
b229b8d1 3417 {
ec1c14f6
RS
3418 mpos = marker_byte_position (marker);
3419 if (mpos >= start1_byte && mpos < end2_byte)
3420 {
3421 if (mpos < end1_byte)
3422 mpos += amt1_byte;
3423 else if (mpos < start2_byte)
3424 mpos += diff_byte;
3425 else
3426 mpos -= amt2_byte;
f3e1f752 3427 XMARKER (marker)->bytepos = mpos;
ec1c14f6
RS
3428 }
3429 mpos = XMARKER (marker)->charpos;
03240d11
KH
3430 if (mpos >= start1 && mpos < end2)
3431 {
3432 if (mpos < end1)
3433 mpos += amt1;
3434 else if (mpos < start2)
3435 mpos += diff;
3436 else
3437 mpos -= amt2;
03240d11 3438 }
ec1c14f6 3439 XMARKER (marker)->charpos = mpos;
b229b8d1
RS
3440 }
3441}
3442
3443DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5, 0,
3444 "Transpose region START1 to END1 with START2 to END2.\n\
3445The regions may not be overlapping, because the size of the buffer is\n\
3446never changed in a transposition.\n\
3447\n\
ec1c14f6 3448Optional fifth arg LEAVE_MARKERS, if non-nil, means don't update\n\
b229b8d1
RS
3449any markers that happen to be located in the regions.\n\
3450\n\
3451Transposing beyond buffer boundaries is an error.")
3452 (startr1, endr1, startr2, endr2, leave_markers)
3453 Lisp_Object startr1, endr1, startr2, endr2, leave_markers;
3454{
ec1c14f6
RS
3455 register int start1, end1, start2, end2;
3456 int start1_byte, start2_byte, len1_byte, len2_byte;
3457 int gap, len1, len_mid, len2;
3c6bc7d0 3458 unsigned char *start1_addr, *start2_addr, *temp;
dc3620af 3459 struct gcpro gcpro1, gcpro2;
b229b8d1 3460
b229b8d1 3461 INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
1e158d25 3462 cur_intv = BUF_INTERVALS (current_buffer);
b229b8d1
RS
3463
3464 validate_region (&startr1, &endr1);
3465 validate_region (&startr2, &endr2);
3466
3467 start1 = XFASTINT (startr1);
3468 end1 = XFASTINT (endr1);
3469 start2 = XFASTINT (startr2);
3470 end2 = XFASTINT (endr2);
3471 gap = GPT;
3472
3473 /* Swap the regions if they're reversed. */
3474 if (start2 < end1)
3475 {
3476 register int glumph = start1;
3477 start1 = start2;
3478 start2 = glumph;
3479 glumph = end1;
3480 end1 = end2;
3481 end2 = glumph;
3482 }
3483
b229b8d1
RS
3484 len1 = end1 - start1;
3485 len2 = end2 - start2;
3486
3487 if (start2 < end1)
dc3620af 3488 error ("Transposed regions overlap");
b229b8d1 3489 else if (start1 == end1 || start2 == end2)
dc3620af 3490 error ("Transposed region has length 0");
b229b8d1
RS
3491
3492 /* The possibilities are:
3493 1. Adjacent (contiguous) regions, or separate but equal regions
3494 (no, really equal, in this case!), or
3495 2. Separate regions of unequal size.
34a7a267 3496
b229b8d1
RS
3497 The worst case is usually No. 2. It means that (aside from
3498 potential need for getting the gap out of the way), there also
3499 needs to be a shifting of the text between the two regions. So
3500 if they are spread far apart, we are that much slower... sigh. */
3501
3502 /* It must be pointed out that the really studly thing to do would
3503 be not to move the gap at all, but to leave it in place and work
3504 around it if necessary. This would be extremely efficient,
3505 especially considering that people are likely to do
3506 transpositions near where they are working interactively, which
3507 is exactly where the gap would be found. However, such code
3508 would be much harder to write and to read. So, if you are
3509 reading this comment and are feeling squirrely, by all means have
3510 a go! I just didn't feel like doing it, so I will simply move
3511 the gap the minimum distance to get it out of the way, and then
3512 deal with an unbroken array. */
3c6bc7d0
RS
3513
3514 /* Make sure the gap won't interfere, by moving it out of the text
3515 we will operate on. */
3516 if (start1 < gap && gap < end2)
3517 {
3518 if (gap - start1 < end2 - gap)
3519 move_gap (start1);
3520 else
3521 move_gap (end2);
3522 }
ec1c14f6
RS
3523
3524 start1_byte = CHAR_TO_BYTE (start1);
3525 start2_byte = CHAR_TO_BYTE (start2);
3526 len1_byte = CHAR_TO_BYTE (end1) - start1_byte;
3527 len2_byte = CHAR_TO_BYTE (end2) - start2_byte;
dc3620af 3528
9a599130 3529#ifdef BYTE_COMBINING_DEBUG
dc3620af
RS
3530 if (end1 == start2)
3531 {
9a599130
KH
3532 if (count_combining_before (BYTE_POS_ADDR (start2_byte),
3533 len2_byte, start1, start1_byte)
3534 || count_combining_before (BYTE_POS_ADDR (start1_byte),
3535 len1_byte, end2, start2_byte + len2_byte)
3536 || count_combining_after (BYTE_POS_ADDR (start1_byte),
3537 len1_byte, end2, start2_byte + len2_byte))
3538 abort ();
dc3620af
RS
3539 }
3540 else
3541 {
9a599130
KH
3542 if (count_combining_before (BYTE_POS_ADDR (start2_byte),
3543 len2_byte, start1, start1_byte)
3544 || count_combining_before (BYTE_POS_ADDR (start1_byte),
3545 len1_byte, start2, start2_byte)
3546 || count_combining_after (BYTE_POS_ADDR (start2_byte),
3547 len2_byte, end1, start1_byte + len1_byte)
3548 || count_combining_after (BYTE_POS_ADDR (start1_byte),
3549 len1_byte, end2, start2_byte + len2_byte))
3550 abort ();
dc3620af 3551 }
9a599130 3552#endif
dc3620af 3553
b229b8d1
RS
3554 /* Hmmm... how about checking to see if the gap is large
3555 enough to use as the temporary storage? That would avoid an
3556 allocation... interesting. Later, don't fool with it now. */
3557
3558 /* Working without memmove, for portability (sigh), so must be
3559 careful of overlapping subsections of the array... */
3560
3561 if (end1 == start2) /* adjacent regions */
3562 {
b229b8d1
RS
3563 modify_region (current_buffer, start1, end2);
3564 record_change (start1, len1 + len2);
3565
b229b8d1
RS
3566 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
3567 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
09dbcf71
RS
3568 Fset_text_properties (make_number (start1), make_number (end2),
3569 Qnil, Qnil);
b229b8d1
RS
3570
3571 /* First region smaller than second. */
ec1c14f6 3572 if (len1_byte < len2_byte)
b229b8d1 3573 {
3c6bc7d0
RS
3574 /* We use alloca only if it is small,
3575 because we want to avoid stack overflow. */
ec1c14f6
RS
3576 if (len2_byte > 20000)
3577 temp = (unsigned char *) xmalloc (len2_byte);
3c6bc7d0 3578 else
ec1c14f6 3579 temp = (unsigned char *) alloca (len2_byte);
03240d11
KH
3580
3581 /* Don't precompute these addresses. We have to compute them
3582 at the last minute, because the relocating allocator might
3583 have moved the buffer around during the xmalloc. */
23017390
KH
3584 start1_addr = BYTE_POS_ADDR (start1_byte);
3585 start2_addr = BYTE_POS_ADDR (start2_byte);
03240d11 3586
ec1c14f6
RS
3587 bcopy (start2_addr, temp, len2_byte);
3588 bcopy (start1_addr, start1_addr + len2_byte, len1_byte);
3589 bcopy (temp, start1_addr, len2_byte);
3590 if (len2_byte > 20000)
3c6bc7d0 3591 free (temp);
b229b8d1
RS
3592 }
3593 else
3594 /* First region not smaller than second. */
3595 {
ec1c14f6
RS
3596 if (len1_byte > 20000)
3597 temp = (unsigned char *) xmalloc (len1_byte);
3c6bc7d0 3598 else
ec1c14f6 3599 temp = (unsigned char *) alloca (len1_byte);
23017390
KH
3600 start1_addr = BYTE_POS_ADDR (start1_byte);
3601 start2_addr = BYTE_POS_ADDR (start2_byte);
ec1c14f6
RS
3602 bcopy (start1_addr, temp, len1_byte);
3603 bcopy (start2_addr, start1_addr, len2_byte);
3604 bcopy (temp, start1_addr + len2_byte, len1_byte);
3605 if (len1_byte > 20000)
3c6bc7d0 3606 free (temp);
b229b8d1 3607 }
b229b8d1
RS
3608 graft_intervals_into_buffer (tmp_interval1, start1 + len2,
3609 len1, current_buffer, 0);
3610 graft_intervals_into_buffer (tmp_interval2, start1,
3611 len2, current_buffer, 0);
d5c2c403
KH
3612 update_compositions (start1, start1 + len2, CHECK_BORDER);
3613 update_compositions (start1 + len2, end2, CHECK_TAIL);
b229b8d1
RS
3614 }
3615 /* Non-adjacent regions, because end1 != start2, bleagh... */
3616 else
3617 {
ec1c14f6
RS
3618 len_mid = start2_byte - (start1_byte + len1_byte);
3619
3620 if (len1_byte == len2_byte)
b229b8d1
RS
3621 /* Regions are same size, though, how nice. */
3622 {
3623 modify_region (current_buffer, start1, end1);
3624 modify_region (current_buffer, start2, end2);
3625 record_change (start1, len1);
3626 record_change (start2, len2);
b229b8d1
RS
3627 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
3628 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
09dbcf71
RS
3629 Fset_text_properties (make_number (start1), make_number (end1),
3630 Qnil, Qnil);
3631 Fset_text_properties (make_number (start2), make_number (end2),
3632 Qnil, Qnil);
b229b8d1 3633
ec1c14f6
RS
3634 if (len1_byte > 20000)
3635 temp = (unsigned char *) xmalloc (len1_byte);
3c6bc7d0 3636 else
ec1c14f6 3637 temp = (unsigned char *) alloca (len1_byte);
23017390
KH
3638 start1_addr = BYTE_POS_ADDR (start1_byte);
3639 start2_addr = BYTE_POS_ADDR (start2_byte);
ec1c14f6
RS
3640 bcopy (start1_addr, temp, len1_byte);
3641 bcopy (start2_addr, start1_addr, len2_byte);
3642 bcopy (temp, start2_addr, len1_byte);
3643 if (len1_byte > 20000)
3c6bc7d0 3644 free (temp);
b229b8d1
RS
3645 graft_intervals_into_buffer (tmp_interval1, start2,
3646 len1, current_buffer, 0);
3647 graft_intervals_into_buffer (tmp_interval2, start1,
3648 len2, current_buffer, 0);
b229b8d1
RS
3649 }
3650
ec1c14f6 3651 else if (len1_byte < len2_byte) /* Second region larger than first */
b229b8d1
RS
3652 /* Non-adjacent & unequal size, area between must also be shifted. */
3653 {
b229b8d1
RS
3654 modify_region (current_buffer, start1, end2);
3655 record_change (start1, (end2 - start1));
b229b8d1
RS
3656 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
3657 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
3658 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
09dbcf71
RS
3659 Fset_text_properties (make_number (start1), make_number (end2),
3660 Qnil, Qnil);
b229b8d1 3661
3c6bc7d0 3662 /* holds region 2 */
ec1c14f6
RS
3663 if (len2_byte > 20000)
3664 temp = (unsigned char *) xmalloc (len2_byte);
3c6bc7d0 3665 else
ec1c14f6 3666 temp = (unsigned char *) alloca (len2_byte);
23017390
KH
3667 start1_addr = BYTE_POS_ADDR (start1_byte);
3668 start2_addr = BYTE_POS_ADDR (start2_byte);
ec1c14f6
RS
3669 bcopy (start2_addr, temp, len2_byte);
3670 bcopy (start1_addr, start1_addr + len_mid + len2_byte, len1_byte);
3671 safe_bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
3672 bcopy (temp, start1_addr, len2_byte);
3673 if (len2_byte > 20000)
3c6bc7d0 3674 free (temp);
b229b8d1
RS
3675 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
3676 len1, current_buffer, 0);
3677 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
3678 len_mid, current_buffer, 0);
3679 graft_intervals_into_buffer (tmp_interval2, start1,
3680 len2, current_buffer, 0);
b229b8d1
RS
3681 }
3682 else
3683 /* Second region smaller than first. */
3684 {
b229b8d1
RS
3685 record_change (start1, (end2 - start1));
3686 modify_region (current_buffer, start1, end2);
3687
b229b8d1
RS
3688 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
3689 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
3690 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
09dbcf71
RS
3691 Fset_text_properties (make_number (start1), make_number (end2),
3692 Qnil, Qnil);
b229b8d1 3693
3c6bc7d0 3694 /* holds region 1 */
ec1c14f6
RS
3695 if (len1_byte > 20000)
3696 temp = (unsigned char *) xmalloc (len1_byte);
3c6bc7d0 3697 else
ec1c14f6 3698 temp = (unsigned char *) alloca (len1_byte);
23017390
KH
3699 start1_addr = BYTE_POS_ADDR (start1_byte);
3700 start2_addr = BYTE_POS_ADDR (start2_byte);
ec1c14f6
RS
3701 bcopy (start1_addr, temp, len1_byte);
3702 bcopy (start2_addr, start1_addr, len2_byte);
3703 bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
3704 bcopy (temp, start1_addr + len2_byte + len_mid, len1_byte);
3705 if (len1_byte > 20000)
3c6bc7d0 3706 free (temp);
b229b8d1
RS
3707 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
3708 len1, current_buffer, 0);
3709 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
3710 len_mid, current_buffer, 0);
3711 graft_intervals_into_buffer (tmp_interval2, start1,
3712 len2, current_buffer, 0);
b229b8d1 3713 }
d5c2c403
KH
3714
3715 update_compositions (start1, start1 + len2, CHECK_BORDER);
3716 update_compositions (end2 - len1, end2, CHECK_BORDER);
b229b8d1
RS
3717 }
3718
ec1c14f6
RS
3719 /* When doing multiple transpositions, it might be nice
3720 to optimize this. Perhaps the markers in any one buffer
3721 should be organized in some sorted data tree. */
b229b8d1 3722 if (NILP (leave_markers))
8de1d5f0 3723 {
ec1c14f6
RS
3724 transpose_markers (start1, end1, start2, end2,
3725 start1_byte, start1_byte + len1_byte,
3726 start2_byte, start2_byte + len2_byte);
8de1d5f0
KH
3727 fix_overlays_in_range (start1, end2);
3728 }
b229b8d1
RS
3729
3730 return Qnil;
3731}
35692fe0 3732
35692fe0
JB
3733\f
3734void
3735syms_of_editfns ()
3736{
260e2e2a
KH
3737 environbuf = 0;
3738
3739 Qbuffer_access_fontify_functions
3740 = intern ("buffer-access-fontify-functions");
3741 staticpro (&Qbuffer_access_fontify_functions);
3742
9a74e7e5
GM
3743 DEFVAR_LISP ("inhibit-field-text-motion", &Vinhibit_field_text_motion,
3744 "Non-nil means.text motion commands don't notice fields.");
3745 Vinhibit_field_text_motion = Qnil;
3746
260e2e2a
KH
3747 DEFVAR_LISP ("buffer-access-fontify-functions",
3748 &Vbuffer_access_fontify_functions,
3749 "List of functions called by `buffer-substring' to fontify if necessary.\n\
3750Each function is called with two arguments which specify the range\n\
3751of the buffer being accessed.");
3752 Vbuffer_access_fontify_functions = Qnil;
3753
af209db8
RS
3754 {
3755 Lisp_Object obuf;
3756 extern Lisp_Object Vprin1_to_string_buffer;
3757 obuf = Fcurrent_buffer ();
3758 /* Do this here, because init_buffer_once is too early--it won't work. */
3759 Fset_buffer (Vprin1_to_string_buffer);
3760 /* Make sure buffer-access-fontify-functions is nil in this buffer. */
3761 Fset (Fmake_local_variable (intern ("buffer-access-fontify-functions")),
3762 Qnil);
3763 Fset_buffer (obuf);
3764 }
3765
0b6fd023 3766 DEFVAR_LISP ("buffer-access-fontified-property",
260e2e2a
KH
3767 &Vbuffer_access_fontified_property,
3768 "Property which (if non-nil) indicates text has been fontified.\n\
3769`buffer-substring' need not call the `buffer-access-fontify-functions'\n\
3770functions if all the text being accessed has this property.");
3771 Vbuffer_access_fontified_property = Qnil;
3772
f43754f6
KH
3773 DEFVAR_LISP ("system-name", &Vsystem_name,
3774 "The name of the machine Emacs is running on.");
34a7a267 3775
f43754f6
KH
3776 DEFVAR_LISP ("user-full-name", &Vuser_full_name,
3777 "The full name of the user logged in.");
3778
35b34f72 3779 DEFVAR_LISP ("user-login-name", &Vuser_login_name,
f43754f6
KH
3780 "The user's name, taken from environment variables if possible.");
3781
35b34f72 3782 DEFVAR_LISP ("user-real-login-name", &Vuser_real_login_name,
f43754f6 3783 "The user's name, based upon the real uid only.");
35692fe0 3784
0963334d 3785 defsubr (&Spropertize);
35692fe0
JB
3786 defsubr (&Schar_equal);
3787 defsubr (&Sgoto_char);
3788 defsubr (&Sstring_to_char);
3789 defsubr (&Schar_to_string);
3790 defsubr (&Sbuffer_substring);
260e2e2a 3791 defsubr (&Sbuffer_substring_no_properties);
35692fe0
JB
3792 defsubr (&Sbuffer_string);
3793
3794 defsubr (&Spoint_marker);
3795 defsubr (&Smark_marker);
3796 defsubr (&Spoint);
3797 defsubr (&Sregion_beginning);
3798 defsubr (&Sregion_end);
7df74da6 3799
0daf6e8d
GM
3800 staticpro (&Qfield);
3801 Qfield = intern ("field");
ee547125
MB
3802 staticpro (&Qboundary);
3803 Qboundary = intern ("boundary");
0daf6e8d
GM
3804 defsubr (&Sfield_beginning);
3805 defsubr (&Sfield_end);
3806 defsubr (&Sfield_string);
3807 defsubr (&Sfield_string_no_properties);
8bf64fe8 3808 defsubr (&Sdelete_field);
0daf6e8d
GM
3809 defsubr (&Sconstrain_to_field);
3810
7df74da6
RS
3811 defsubr (&Sline_beginning_position);
3812 defsubr (&Sline_end_position);
3813
35692fe0
JB
3814/* defsubr (&Smark); */
3815/* defsubr (&Sset_mark); */
3816 defsubr (&Ssave_excursion);
4bc8c7d2 3817 defsubr (&Ssave_current_buffer);
35692fe0
JB
3818
3819 defsubr (&Sbufsize);
3820 defsubr (&Spoint_max);
3821 defsubr (&Spoint_min);
3822 defsubr (&Spoint_min_marker);
3823 defsubr (&Spoint_max_marker);
c86212b9
RS
3824 defsubr (&Sgap_position);
3825 defsubr (&Sgap_size);
7df74da6 3826 defsubr (&Sposition_bytes);
3ab0732d 3827 defsubr (&Sbyte_to_position);
c9ed721d 3828
35692fe0
JB
3829 defsubr (&Sbobp);
3830 defsubr (&Seobp);
3831 defsubr (&Sbolp);
3832 defsubr (&Seolp);
850a8179
JB
3833 defsubr (&Sfollowing_char);
3834 defsubr (&Sprevious_char);
35692fe0 3835 defsubr (&Schar_after);
fb8106e8 3836 defsubr (&Schar_before);
35692fe0
JB
3837 defsubr (&Sinsert);
3838 defsubr (&Sinsert_before_markers);
be91036a
RS
3839 defsubr (&Sinsert_and_inherit);
3840 defsubr (&Sinsert_and_inherit_before_markers);
35692fe0
JB
3841 defsubr (&Sinsert_char);
3842
3843 defsubr (&Suser_login_name);
3844 defsubr (&Suser_real_login_name);
3845 defsubr (&Suser_uid);
3846 defsubr (&Suser_real_uid);
3847 defsubr (&Suser_full_name);
7fd233b3 3848 defsubr (&Semacs_pid);
d940e0e4 3849 defsubr (&Scurrent_time);
a82d387c 3850 defsubr (&Sformat_time_string);
34a7a267 3851 defsubr (&Sfloat_time);
4691c06d 3852 defsubr (&Sdecode_time);
cce7b8a0 3853 defsubr (&Sencode_time);
35692fe0 3854 defsubr (&Scurrent_time_string);
c2662aea 3855 defsubr (&Scurrent_time_zone);
143cb9a9 3856 defsubr (&Sset_time_zone_rule);
35692fe0 3857 defsubr (&Ssystem_name);
35692fe0 3858 defsubr (&Smessage);
cacc3e2c
RS
3859 defsubr (&Smessage_box);
3860 defsubr (&Smessage_or_box);
b14dda8a 3861 defsubr (&Scurrent_message);
35692fe0 3862 defsubr (&Sformat);
35692fe0
JB
3863
3864 defsubr (&Sinsert_buffer_substring);
e9cf2084 3865 defsubr (&Scompare_buffer_substrings);
35692fe0
JB
3866 defsubr (&Ssubst_char_in_region);
3867 defsubr (&Stranslate_region);
3868 defsubr (&Sdelete_region);
7dae4502 3869 defsubr (&Sdelete_and_extract_region);
35692fe0
JB
3870 defsubr (&Swiden);
3871 defsubr (&Snarrow_to_region);
3872 defsubr (&Ssave_restriction);
b229b8d1 3873 defsubr (&Stranspose_regions);
35692fe0 3874}