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