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