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