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