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