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