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