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