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