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