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