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