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