(gud-filter): Don't bind inhibit-quit.
[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)
55561c63 131 XSETFASTINT (val, ((unsigned char *) p->data)[0]);
35692fe0 132 else
55561c63 133 XSETFASTINT (val, 0);
35692fe0
JB
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;
55561c63 153 XSETFASTINT (temp, point);
35692fe0
JB
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;
55561c63 360 XSETFASTINT (temp, Z - BEG);
35692fe0
JB
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;
55561c63 370 XSETFASTINT (temp, BEGV);
35692fe0
JB
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;
55561c63 389 XSETFASTINT (temp, ZV);
35692fe0
JB
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 408 if (point >= ZV)
55561c63 409 XSETFASTINT (temp, 0);
850a8179 410 else
55561c63 411 XSETFASTINT (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)
55561c63 422 XSETFASTINT (temp, 0);
35692fe0 423 else
55561c63 424 XSETFASTINT (temp, FETCH_CHAR (point - 1));
35692fe0
JB
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
55561c63 482 XSETFASTINT (val, FETCH_CHAR (n));
35692fe0
JB
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);
d2fd0445
KH
563 XSETINT (result[0], (EMACS_SECS (t) >> 16) & 0xffff);
564 XSETINT (result[1], (EMACS_SECS (t) >> 0) & 0xffff);
565 XSETINT (result[2], EMACS_USECS (t));
956ace37
JB
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);
ae683129 584 if (CONSP (low))
e3120ab5
JB
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
a82d387c
RS
592DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 2, 2, 0,
593 "Use FORMAT-STRING to format the time TIME.\n\
594TIME is specified as (HIGH LOW . IGNORED) or (HIGH . LOW), as from\n\
595`current-time' and `file-attributes'.\n\
596FORMAT-STRING may contain %-sequences to substitute parts of the time.\n\
597%a is replaced by the abbreviated name of the day of week.\n\
598%A is replaced by the full name of the day of week.\n\
599%b is replaced by the abbreviated name of the month.\n\
600%B is replaced by the full name of the month.\n\
601%c is a synonym for \"%x %X\".\n\
602%C is a locale-specific synonym, which defaults to \"%A, %B %e, %Y\" in the C locale.\n\
603%d is replaced by the day of month, zero-padded.\n\
604%D is a synonym for \"%m/%d/%y\".\n\
605%e is replaced by the day of month, blank-padded.\n\
606%h is a synonym for \"%b\".\n\
607%H is replaced by the hour (00-23).\n\
608%I is replaced by the hour (00-12).\n\
609%j is replaced by the day of the year (001-366).\n\
610%k is replaced by the hour (0-23), blank padded.\n\
611%l is replaced by the hour (1-12), blank padded.\n\
612%m is replaced by the month (01-12).\n\
613%M is replaced by the minut (00-59).\n\
614%n is a synonym for \"\\n\".\n\
615%p is replaced by AM or PM, as appropriate.\n\
616%r is a synonym for \"%I:%M:%S %p\".\n\
617%R is a synonym for \"%H:%M\".\n\
618%S is replaced by the seconds (00-60).\n\
619%t is a synonym for \"\\t\".\n\
620%T is a synonym for \"%H:%M:%S\".\n\
621%U is replaced by the week of the year (01-52), first day of week is Sunday.\n\
622%w is replaced by the day of week (0-6), Sunday is day 0.\n\
623%W is replaced by the week of the year (01-52), first day of week is Monday.\n\
624%x is a locale-specific synonym, which defaults to \"%D\" in the C locale.\n\
625%X is a locale-specific synonym, which defaults to \"%T\" in the C locale.\n\
626%y is replaced by the year without century (00-99).\n\
627%Y is replaced by the year with century.\n\
628%Z is replaced by the time zone abbreviation.\n\
629\n\
630The number of options reflects the strftime(3) function.")
631 (format_string, time)
632 Lisp_Object format_string, time;
633{
634 time_t value;
635 int size;
636
637 CHECK_STRING (format_string, 1);
638
639 if (! lisp_time_argument (time, &value))
640 error ("Invalid time specification");
641
642 /* This is probably enough. */
643 size = XSTRING (format_string)->size * 6 + 50;
644
645 while (1)
646 {
647 char *buf = (char *) alloca (size);
648 if (strftime (buf, size, XSTRING (format_string)->data,
649 localtime (&value)))
650 return build_string (buf);
651 /* If buffer was too small, make it bigger. */
652 size *= 2;
653 }
654}
655
2148f2b4 656DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 1, 0,
35692fe0 657 "Return the current time, as a human-readable string.\n\
2148f2b4
RS
658Programs can use this function to decode a time,\n\
659since the number of columns in each field is fixed.\n\
660The format is `Sun Sep 16 01:03:52 1973'.\n\
661If an argument is given, it specifies a time to format\n\
662instead of the current time. The argument should have the form:\n\
663 (HIGH . LOW)\n\
664or the form:\n\
665 (HIGH LOW . IGNORED).\n\
666Thus, you can use times obtained from `current-time'\n\
667and from `file-attributes'.")
668 (specified_time)
669 Lisp_Object specified_time;
670{
e3120ab5 671 time_t value;
35692fe0 672 char buf[30];
2148f2b4
RS
673 register char *tem;
674
e3120ab5
JB
675 if (! lisp_time_argument (specified_time, &value))
676 value = -1;
2148f2b4 677 tem = (char *) ctime (&value);
35692fe0
JB
678
679 strncpy (buf, tem, 24);
680 buf[24] = 0;
681
682 return build_string (buf);
683}
c2662aea 684
e3120ab5
JB
685#define TM_YEAR_ORIGIN 1900
686
687/* Yield A - B, measured in seconds. */
688static long
8e718b4e 689difftm (a, b)
e3120ab5
JB
690 struct tm *a, *b;
691{
692 int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
693 int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
8e718b4e 694 /* Some compilers can't handle this as a single return statement. */
68a49b18 695 long days = (
8e718b4e
KH
696 /* difference in day of year */
697 a->tm_yday - b->tm_yday
698 /* + intervening leap days */
699 + ((ay >> 2) - (by >> 2))
700 - (ay/100 - by/100)
701 + ((ay/100 >> 2) - (by/100 >> 2))
702 /* + difference in years * 365 */
703 + (long)(ay-by) * 365
704 );
705 return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
706 + (a->tm_min - b->tm_min))
707 + (a->tm_sec - b->tm_sec));
e3120ab5
JB
708}
709
710DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0,
711 "Return the offset and name for the local time zone.\n\
712This returns a list of the form (OFFSET NAME).\n\
713OFFSET is an integer number of seconds ahead of UTC (east of Greenwich).\n\
714 A negative value means west of Greenwich.\n\
715NAME is a string giving the name of the time zone.\n\
716If an argument is given, it specifies when the time zone offset is determined\n\
717instead of using the current time. The argument should have the form:\n\
718 (HIGH . LOW)\n\
719or the form:\n\
720 (HIGH LOW . IGNORED).\n\
721Thus, you can use times obtained from `current-time'\n\
722and from `file-attributes'.\n\
773c1fd3
JB
723\n\
724Some operating systems cannot provide all this information to Emacs;\n\
2d88f747 725in this case, `current-time-zone' returns a list containing nil for\n\
773c1fd3 726the data it can't find.")
e3120ab5
JB
727 (specified_time)
728 Lisp_Object specified_time;
c2662aea 729{
e3120ab5
JB
730 time_t value;
731 struct tm *t;
c2662aea 732
e3120ab5 733 if (lisp_time_argument (specified_time, &value)
2d88f747 734 && (t = gmtime (&value)) != 0)
e3120ab5 735 {
2d88f747 736 struct tm gmt;
e3120ab5
JB
737 long offset;
738 char *s, buf[6];
2d88f747
RS
739
740 gmt = *t; /* Make a copy, in case localtime modifies *t. */
741 t = localtime (&value);
742 offset = difftm (t, &gmt);
e3120ab5
JB
743 s = 0;
744#ifdef HAVE_TM_ZONE
745 if (t->tm_zone)
5fd4de15 746 s = (char *)t->tm_zone;
a7971c39
RS
747#else /* not HAVE_TM_ZONE */
748#ifdef HAVE_TZNAME
749 if (t->tm_isdst == 0 || t->tm_isdst == 1)
750 s = tzname[t->tm_isdst];
c2662aea 751#endif
a7971c39 752#endif /* not HAVE_TM_ZONE */
e3120ab5
JB
753 if (!s)
754 {
755 /* No local time zone name is available; use "+-NNNN" instead. */
00fc94d0 756 int am = (offset < 0 ? -offset : offset) / 60;
e3120ab5
JB
757 sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60);
758 s = buf;
759 }
760 return Fcons (make_number (offset), Fcons (build_string (s), Qnil));
761 }
762 else
763 return Fmake_list (2, Qnil);
c2662aea
JB
764}
765
35692fe0
JB
766\f
767void
768insert1 (arg)
769 Lisp_Object arg;
770{
771 Finsert (1, &arg);
772}
773
52b14ac0
JB
774
775/* Callers passing one argument to Finsert need not gcpro the
776 argument "array", since the only element of the array will
777 not be used after calling insert or insert_from_string, so
778 we don't care if it gets trashed. */
779
35692fe0
JB
780DEFUN ("insert", Finsert, Sinsert, 0, MANY, 0,
781 "Insert the arguments, either strings or characters, at point.\n\
782Point moves forward so that it ends up after the inserted text.\n\
783Any other markers at the point of insertion remain before the text.")
784 (nargs, args)
785 int nargs;
786 register Lisp_Object *args;
787{
788 register int argnum;
789 register Lisp_Object tem;
790 char str[1];
35692fe0
JB
791
792 for (argnum = 0; argnum < nargs; argnum++)
793 {
794 tem = args[argnum];
795 retry:
ae683129 796 if (INTEGERP (tem))
35692fe0
JB
797 {
798 str[0] = XINT (tem);
799 insert (str, 1);
800 }
ae683129 801 else if (STRINGP (tem))
35692fe0 802 {
be91036a
RS
803 insert_from_string (tem, 0, XSTRING (tem)->size, 0);
804 }
805 else
806 {
807 tem = wrong_type_argument (Qchar_or_string_p, tem);
808 goto retry;
809 }
810 }
811
812 return Qnil;
813}
814
815DEFUN ("insert-and-inherit", Finsert_and_inherit, Sinsert_and_inherit,
816 0, MANY, 0,
817 "Insert the arguments at point, inheriting properties from adjoining text.\n\
818Point moves forward so that it ends up after the inserted text.\n\
819Any other markers at the point of insertion remain before the text.")
820 (nargs, args)
821 int nargs;
822 register Lisp_Object *args;
823{
824 register int argnum;
825 register Lisp_Object tem;
826 char str[1];
827
828 for (argnum = 0; argnum < nargs; argnum++)
829 {
830 tem = args[argnum];
831 retry:
ae683129 832 if (INTEGERP (tem))
be91036a
RS
833 {
834 str[0] = XINT (tem);
107740f5 835 insert_and_inherit (str, 1);
be91036a 836 }
ae683129 837 else if (STRINGP (tem))
be91036a
RS
838 {
839 insert_from_string (tem, 0, XSTRING (tem)->size, 1);
35692fe0
JB
840 }
841 else
842 {
843 tem = wrong_type_argument (Qchar_or_string_p, tem);
844 goto retry;
845 }
846 }
847
35692fe0
JB
848 return Qnil;
849}
850
851DEFUN ("insert-before-markers", Finsert_before_markers, Sinsert_before_markers, 0, MANY, 0,
852 "Insert strings or characters at point, relocating markers after the text.\n\
853Point moves forward so that it ends up after the inserted text.\n\
854Any other markers at the point of insertion also end up after the text.")
855 (nargs, args)
856 int nargs;
857 register Lisp_Object *args;
858{
859 register int argnum;
860 register Lisp_Object tem;
861 char str[1];
35692fe0
JB
862
863 for (argnum = 0; argnum < nargs; argnum++)
864 {
865 tem = args[argnum];
866 retry:
ae683129 867 if (INTEGERP (tem))
35692fe0
JB
868 {
869 str[0] = XINT (tem);
870 insert_before_markers (str, 1);
871 }
ae683129 872 else if (STRINGP (tem))
35692fe0 873 {
be91036a
RS
874 insert_from_string_before_markers (tem, 0, XSTRING (tem)->size, 0);
875 }
876 else
877 {
878 tem = wrong_type_argument (Qchar_or_string_p, tem);
879 goto retry;
880 }
881 }
882
883 return Qnil;
884}
885
886DEFUN ("insert-before-markers-and-inherit",
887 Finsert_and_inherit_before_markers, Sinsert_and_inherit_before_markers,
888 0, MANY, 0,
889 "Insert text at point, relocating markers and inheriting properties.\n\
890Point moves forward so that it ends up after the inserted text.\n\
891Any other markers at the point of insertion also end up after the text.")
892 (nargs, args)
893 int nargs;
894 register Lisp_Object *args;
895{
896 register int argnum;
897 register Lisp_Object tem;
898 char str[1];
899
900 for (argnum = 0; argnum < nargs; argnum++)
901 {
902 tem = args[argnum];
903 retry:
ae683129 904 if (INTEGERP (tem))
be91036a
RS
905 {
906 str[0] = XINT (tem);
107740f5 907 insert_before_markers_and_inherit (str, 1);
be91036a 908 }
ae683129 909 else if (STRINGP (tem))
be91036a
RS
910 {
911 insert_from_string_before_markers (tem, 0, XSTRING (tem)->size, 1);
35692fe0
JB
912 }
913 else
914 {
915 tem = wrong_type_argument (Qchar_or_string_p, tem);
916 goto retry;
917 }
918 }
919
35692fe0
JB
920 return Qnil;
921}
922\f
e2eeabbb 923DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0,
35692fe0
JB
924 "Insert COUNT (second arg) copies of CHAR (first arg).\n\
925Point and all markers are affected as in the function `insert'.\n\
e2eeabbb
RS
926Both arguments are required.\n\
927The optional third arg INHERIT, if non-nil, says to inherit text properties\n\
928from adjoining text, if those properties are sticky.")
929 (chr, count, inherit)
930 Lisp_Object chr, count, inherit;
35692fe0
JB
931{
932 register unsigned char *string;
933 register int strlen;
934 register int i, n;
935
936 CHECK_NUMBER (chr, 0);
937 CHECK_NUMBER (count, 1);
938
939 n = XINT (count);
940 if (n <= 0)
941 return Qnil;
942 strlen = min (n, 256);
943 string = (unsigned char *) alloca (strlen);
944 for (i = 0; i < strlen; i++)
945 string[i] = XFASTINT (chr);
946 while (n >= strlen)
947 {
e2eeabbb
RS
948 if (!NILP (inherit))
949 insert_and_inherit (string, strlen);
950 else
951 insert (string, strlen);
35692fe0
JB
952 n -= strlen;
953 }
954 if (n > 0)
955 insert (string, n);
956 return Qnil;
957}
958
959\f
ffd56f97
JB
960/* Making strings from buffer contents. */
961
962/* Return a Lisp_String containing the text of the current buffer from
74d6d8c5 963 START to END. If text properties are in use and the current buffer
eb8c3be9 964 has properties in the range specified, the resulting string will also
74d6d8c5 965 have them.
ffd56f97
JB
966
967 We don't want to use plain old make_string here, because it calls
968 make_uninit_string, which can cause the buffer arena to be
969 compacted. make_string has no way of knowing that the data has
970 been moved, and thus copies the wrong data into the string. This
971 doesn't effect most of the other users of make_string, so it should
972 be left as is. But we should use this function when conjuring
973 buffer substrings. */
74d6d8c5 974
ffd56f97
JB
975Lisp_Object
976make_buffer_string (start, end)
977 int start, end;
978{
36b0d50e 979 Lisp_Object result, tem, tem1;
ffd56f97
JB
980
981 if (start < GPT && GPT < end)
982 move_gap (start);
983
984 result = make_uninit_string (end - start);
985 bcopy (&FETCH_CHAR (start), XSTRING (result)->data, end - start);
986
60b96ee7 987 tem = Fnext_property_change (make_number (start), Qnil, make_number (end));
36b0d50e 988 tem1 = Ftext_properties_at (make_number (start), Qnil);
60b96ee7
RS
989
990#ifdef USE_TEXT_PROPERTIES
36b0d50e 991 if (XINT (tem) != end || !NILP (tem1))
60b96ee7
RS
992 copy_intervals_to_string (result, current_buffer, start, end - start);
993#endif
74d6d8c5 994
ffd56f97
JB
995 return result;
996}
35692fe0
JB
997
998DEFUN ("buffer-substring", Fbuffer_substring, Sbuffer_substring, 2, 2, 0,
999 "Return the contents of part of the current buffer as a string.\n\
1000The two arguments START and END are character positions;\n\
1001they can be in either order.")
1002 (b, e)
1003 Lisp_Object b, e;
1004{
1005 register int beg, end;
35692fe0
JB
1006
1007 validate_region (&b, &e);
1008 beg = XINT (b);
1009 end = XINT (e);
1010
ffd56f97 1011 return make_buffer_string (beg, end);
35692fe0
JB
1012}
1013
1014DEFUN ("buffer-string", Fbuffer_string, Sbuffer_string, 0, 0, 0,
1015 "Return the contents of the current buffer as a string.")
1016 ()
1017{
ffd56f97 1018 return make_buffer_string (BEGV, ZV);
35692fe0
JB
1019}
1020
1021DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
1022 1, 3, 0,
83ea6fc2 1023 "Insert before point a substring of the contents of buffer BUFFER.\n\
35692fe0
JB
1024BUFFER may be a buffer or a buffer name.\n\
1025Arguments START and END are character numbers specifying the substring.\n\
1026They default to the beginning and the end of BUFFER.")
1027 (buf, b, e)
1028 Lisp_Object buf, b, e;
1029{
74d6d8c5 1030 register int beg, end, temp, len, opoint, start;
35692fe0 1031 register struct buffer *bp;
3fff2dfa 1032 Lisp_Object buffer;
35692fe0 1033
3fff2dfa
RS
1034 buffer = Fget_buffer (buf);
1035 if (NILP (buffer))
1036 nsberror (buf);
1037 bp = XBUFFER (buffer);
35692fe0 1038
56a98455 1039 if (NILP (b))
35692fe0
JB
1040 beg = BUF_BEGV (bp);
1041 else
1042 {
1043 CHECK_NUMBER_COERCE_MARKER (b, 0);
1044 beg = XINT (b);
1045 }
56a98455 1046 if (NILP (e))
35692fe0
JB
1047 end = BUF_ZV (bp);
1048 else
1049 {
1050 CHECK_NUMBER_COERCE_MARKER (e, 1);
1051 end = XINT (e);
1052 }
1053
1054 if (beg > end)
74d6d8c5 1055 temp = beg, beg = end, end = temp;
35692fe0
JB
1056
1057 /* Move the gap or create enough gap in the current buffer. */
1058
1059 if (point != GPT)
1060 move_gap (point);
1061 if (GAP_SIZE < end - beg)
1062 make_gap (end - beg - GAP_SIZE);
1063
74d6d8c5
JA
1064 len = end - beg;
1065 start = beg;
1066 opoint = point;
1067
35692fe0
JB
1068 if (!(BUF_BEGV (bp) <= beg
1069 && beg <= end
1070 && end <= BUF_ZV (bp)))
1071 args_out_of_range (b, e);
1072
1073 /* Now the actual insertion will not do any gap motion,
1074 so it matters not if BUF is the current buffer. */
1075 if (beg < BUF_GPT (bp))
1076 {
1077 insert (BUF_CHAR_ADDRESS (bp, beg), min (end, BUF_GPT (bp)) - beg);
1078 beg = min (end, BUF_GPT (bp));
1079 }
1080 if (beg < end)
1081 insert (BUF_CHAR_ADDRESS (bp, beg), end - beg);
1082
74d6d8c5
JA
1083 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
1084 graft_intervals_into_buffer (copy_intervals (bp->intervals, start, len),
60b96ee7 1085 opoint, len, current_buffer, 0);
74d6d8c5 1086
35692fe0
JB
1087 return Qnil;
1088}
e9cf2084
RS
1089
1090DEFUN ("compare-buffer-substrings", Fcompare_buffer_substrings, Scompare_buffer_substrings,
1091 6, 6, 0,
1092 "Compare two substrings of two buffers; return result as number.\n\
1093the value is -N if first string is less after N-1 chars,\n\
1094+N if first string is greater after N-1 chars, or 0 if strings match.\n\
1095Each substring is represented as three arguments: BUFFER, START and END.\n\
1096That makes six args in all, three for each substring.\n\n\
1097The value of `case-fold-search' in the current buffer\n\
1098determines whether case is significant or ignored.")
1099 (buffer1, start1, end1, buffer2, start2, end2)
1100 Lisp_Object buffer1, start1, end1, buffer2, start2, end2;
1101{
1102 register int begp1, endp1, begp2, endp2, temp, len1, len2, length, i;
1103 register struct buffer *bp1, *bp2;
1104 register unsigned char *trt
1105 = (!NILP (current_buffer->case_fold_search)
1106 ? XSTRING (current_buffer->case_canon_table)->data : 0);
1107
1108 /* Find the first buffer and its substring. */
1109
1110 if (NILP (buffer1))
1111 bp1 = current_buffer;
1112 else
1113 {
3fff2dfa
RS
1114 Lisp_Object buf1;
1115 buf1 = Fget_buffer (buffer1);
1116 if (NILP (buf1))
1117 nsberror (buffer1);
1118 bp1 = XBUFFER (buf1);
e9cf2084
RS
1119 }
1120
1121 if (NILP (start1))
1122 begp1 = BUF_BEGV (bp1);
1123 else
1124 {
1125 CHECK_NUMBER_COERCE_MARKER (start1, 1);
1126 begp1 = XINT (start1);
1127 }
1128 if (NILP (end1))
1129 endp1 = BUF_ZV (bp1);
1130 else
1131 {
1132 CHECK_NUMBER_COERCE_MARKER (end1, 2);
1133 endp1 = XINT (end1);
1134 }
1135
1136 if (begp1 > endp1)
1137 temp = begp1, begp1 = endp1, endp1 = temp;
1138
1139 if (!(BUF_BEGV (bp1) <= begp1
1140 && begp1 <= endp1
1141 && endp1 <= BUF_ZV (bp1)))
1142 args_out_of_range (start1, end1);
1143
1144 /* Likewise for second substring. */
1145
1146 if (NILP (buffer2))
1147 bp2 = current_buffer;
1148 else
1149 {
3fff2dfa
RS
1150 Lisp_Object buf2;
1151 buf2 = Fget_buffer (buffer2);
1152 if (NILP (buf2))
1153 nsberror (buffer2);
e9cf2084
RS
1154 bp2 = XBUFFER (buffer2);
1155 }
1156
1157 if (NILP (start2))
1158 begp2 = BUF_BEGV (bp2);
1159 else
1160 {
1161 CHECK_NUMBER_COERCE_MARKER (start2, 4);
1162 begp2 = XINT (start2);
1163 }
1164 if (NILP (end2))
1165 endp2 = BUF_ZV (bp2);
1166 else
1167 {
1168 CHECK_NUMBER_COERCE_MARKER (end2, 5);
1169 endp2 = XINT (end2);
1170 }
1171
1172 if (begp2 > endp2)
1173 temp = begp2, begp2 = endp2, endp2 = temp;
1174
1175 if (!(BUF_BEGV (bp2) <= begp2
1176 && begp2 <= endp2
1177 && endp2 <= BUF_ZV (bp2)))
1178 args_out_of_range (start2, end2);
1179
1180 len1 = endp1 - begp1;
1181 len2 = endp2 - begp2;
1182 length = len1;
1183 if (len2 < length)
1184 length = len2;
1185
1186 for (i = 0; i < length; i++)
1187 {
1188 int c1 = *BUF_CHAR_ADDRESS (bp1, begp1 + i);
1189 int c2 = *BUF_CHAR_ADDRESS (bp2, begp2 + i);
1190 if (trt)
1191 {
1192 c1 = trt[c1];
1193 c2 = trt[c2];
1194 }
1195 if (c1 < c2)
1196 return make_number (- 1 - i);
1197 if (c1 > c2)
1198 return make_number (i + 1);
1199 }
1200
1201 /* The strings match as far as they go.
1202 If one is shorter, that one is less. */
1203 if (length < len1)
1204 return make_number (length + 1);
1205 else if (length < len2)
1206 return make_number (- length - 1);
1207
1208 /* Same length too => they are equal. */
1209 return make_number (0);
1210}
35692fe0
JB
1211\f
1212DEFUN ("subst-char-in-region", Fsubst_char_in_region,
1213 Ssubst_char_in_region, 4, 5, 0,
1214 "From START to END, replace FROMCHAR with TOCHAR each time it occurs.\n\
1215If optional arg NOUNDO is non-nil, don't record this change for undo\n\
1216and don't mark the buffer as really changed.")
1217 (start, end, fromchar, tochar, noundo)
1218 Lisp_Object start, end, fromchar, tochar, noundo;
1219{
1220 register int pos, stop, look;
60b96ee7 1221 int changed = 0;
35692fe0
JB
1222
1223 validate_region (&start, &end);
1224 CHECK_NUMBER (fromchar, 2);
1225 CHECK_NUMBER (tochar, 3);
1226
1227 pos = XINT (start);
1228 stop = XINT (end);
1229 look = XINT (fromchar);
1230
35692fe0
JB
1231 while (pos < stop)
1232 {
1233 if (FETCH_CHAR (pos) == look)
1234 {
60b96ee7
RS
1235 if (! changed)
1236 {
1237 modify_region (current_buffer, XINT (start), stop);
7653d030
RS
1238
1239 if (! NILP (noundo))
1240 {
1241 if (MODIFF - 1 == current_buffer->save_modified)
1242 current_buffer->save_modified++;
1243 if (MODIFF - 1 == current_buffer->auto_save_modified)
1244 current_buffer->auto_save_modified++;
1245 }
1246
1247 changed = 1;
60b96ee7
RS
1248 }
1249
56a98455 1250 if (NILP (noundo))
35692fe0
JB
1251 record_change (pos, 1);
1252 FETCH_CHAR (pos) = XINT (tochar);
35692fe0
JB
1253 }
1254 pos++;
1255 }
1256
60b96ee7
RS
1257 if (changed)
1258 signal_after_change (XINT (start),
1259 stop - XINT (start), stop - XINT (start));
1260
35692fe0
JB
1261 return Qnil;
1262}
1263
1264DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
1265 "From START to END, translate characters according to TABLE.\n\
1266TABLE is a string; the Nth character in it is the mapping\n\
1267for the character with code N. Returns the number of characters changed.")
1268 (start, end, table)
1269 Lisp_Object start;
1270 Lisp_Object end;
1271 register Lisp_Object table;
1272{
1273 register int pos, stop; /* Limits of the region. */
1274 register unsigned char *tt; /* Trans table. */
1275 register int oc; /* Old character. */
1276 register int nc; /* New character. */
1277 int cnt; /* Number of changes made. */
1278 Lisp_Object z; /* Return. */
1279 int size; /* Size of translate table. */
1280
1281 validate_region (&start, &end);
1282 CHECK_STRING (table, 2);
1283
1284 size = XSTRING (table)->size;
1285 tt = XSTRING (table)->data;
1286
1287 pos = XINT (start);
1288 stop = XINT (end);
04a759c8 1289 modify_region (current_buffer, pos, stop);
35692fe0
JB
1290
1291 cnt = 0;
1292 for (; pos < stop; ++pos)
1293 {
1294 oc = FETCH_CHAR (pos);
1295 if (oc < size)
1296 {
1297 nc = tt[oc];
1298 if (nc != oc)
1299 {
1300 record_change (pos, 1);
1301 FETCH_CHAR (pos) = nc;
1302 signal_after_change (pos, 1, 1);
1303 ++cnt;
1304 }
1305 }
1306 }
1307
55561c63 1308 XSETFASTINT (z, cnt);
35692fe0
JB
1309 return (z);
1310}
1311
1312DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r",
1313 "Delete the text between point and mark.\n\
1314When called from a program, expects two arguments,\n\
1315positions (integers or markers) specifying the stretch to be deleted.")
1316 (b, e)
1317 Lisp_Object b, e;
1318{
1319 validate_region (&b, &e);
1320 del_range (XINT (b), XINT (e));
1321 return Qnil;
1322}
1323\f
1324DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
1325 "Remove restrictions (narrowing) from current buffer.\n\
1326This allows the buffer's full text to be seen and edited.")
1327 ()
1328{
1329 BEGV = BEG;
1330 SET_BUF_ZV (current_buffer, Z);
1331 clip_changed = 1;
52b14ac0
JB
1332 /* Changing the buffer bounds invalidates any recorded current column. */
1333 invalidate_current_column ();
35692fe0
JB
1334 return Qnil;
1335}
1336
1337DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
1338 "Restrict editing in this buffer to the current region.\n\
1339The rest of the text becomes temporarily invisible and untouchable\n\
1340but is not deleted; if you save the buffer in a file, the invisible\n\
1341text is included in the file. \\[widen] makes all visible again.\n\
1342See also `save-restriction'.\n\
1343\n\
1344When calling from a program, pass two arguments; positions (integers\n\
1345or markers) bounding the text that should remain visible.")
1346 (b, e)
1347 register Lisp_Object b, e;
1348{
679e18b1 1349 register EMACS_INT i;
35692fe0
JB
1350
1351 CHECK_NUMBER_COERCE_MARKER (b, 0);
1352 CHECK_NUMBER_COERCE_MARKER (e, 1);
1353
1354 if (XINT (b) > XINT (e))
1355 {
1356 i = XFASTINT (b);
1357 b = e;
55561c63 1358 XSETFASTINT (e, i);
35692fe0
JB
1359 }
1360
1361 if (!(BEG <= XINT (b) && XINT (b) <= XINT (e) && XINT (e) <= Z))
1362 args_out_of_range (b, e);
1363
1364 BEGV = XFASTINT (b);
1365 SET_BUF_ZV (current_buffer, XFASTINT (e));
1366 if (point < XFASTINT (b))
1367 SET_PT (XFASTINT (b));
1368 if (point > XFASTINT (e))
1369 SET_PT (XFASTINT (e));
1370 clip_changed = 1;
52b14ac0
JB
1371 /* Changing the buffer bounds invalidates any recorded current column. */
1372 invalidate_current_column ();
35692fe0
JB
1373 return Qnil;
1374}
1375
1376Lisp_Object
1377save_restriction_save ()
1378{
1379 register Lisp_Object bottom, top;
1380 /* Note: I tried using markers here, but it does not win
1381 because insertion at the end of the saved region
1382 does not advance mh and is considered "outside" the saved region. */
55561c63
KH
1383 XSETFASTINT (bottom, BEGV - BEG);
1384 XSETFASTINT (top, Z - ZV);
35692fe0
JB
1385
1386 return Fcons (Fcurrent_buffer (), Fcons (bottom, top));
1387}
1388
1389Lisp_Object
1390save_restriction_restore (data)
1391 Lisp_Object data;
1392{
1393 register struct buffer *buf;
1394 register int newhead, newtail;
1395 register Lisp_Object tem;
1396
1397 buf = XBUFFER (XCONS (data)->car);
1398
1399 data = XCONS (data)->cdr;
1400
1401 tem = XCONS (data)->car;
1402 newhead = XINT (tem);
1403 tem = XCONS (data)->cdr;
1404 newtail = XINT (tem);
1405 if (newhead + newtail > BUF_Z (buf) - BUF_BEG (buf))
1406 {
1407 newhead = 0;
1408 newtail = 0;
1409 }
1410 BUF_BEGV (buf) = BUF_BEG (buf) + newhead;
1411 SET_BUF_ZV (buf, BUF_Z (buf) - newtail);
1412 clip_changed = 1;
1413
1414 /* If point is outside the new visible range, move it inside. */
1415 SET_BUF_PT (buf,
1416 clip_to_bounds (BUF_BEGV (buf), BUF_PT (buf), BUF_ZV (buf)));
1417
1418 return Qnil;
1419}
1420
1421DEFUN ("save-restriction", Fsave_restriction, Ssave_restriction, 0, UNEVALLED, 0,
1422 "Execute BODY, saving and restoring current buffer's restrictions.\n\
1423The buffer's restrictions make parts of the beginning and end invisible.\n\
1424\(They are set up with `narrow-to-region' and eliminated with `widen'.)\n\
1425This special form, `save-restriction', saves the current buffer's restrictions\n\
1426when it is entered, and restores them when it is exited.\n\
1427So any `narrow-to-region' within BODY lasts only until the end of the form.\n\
1428The old restrictions settings are restored\n\
1429even in case of abnormal exit (throw or error).\n\
1430\n\
1431The value returned is the value of the last form in BODY.\n\
1432\n\
1433`save-restriction' can get confused if, within the BODY, you widen\n\
1434and then make changes outside the area within the saved restrictions.\n\
1435\n\
1436Note: if you are using both `save-excursion' and `save-restriction',\n\
1437use `save-excursion' outermost:\n\
1438 (save-excursion (save-restriction ...))")
1439 (body)
1440 Lisp_Object body;
1441{
1442 register Lisp_Object val;
1443 int count = specpdl_ptr - specpdl;
1444
1445 record_unwind_protect (save_restriction_restore, save_restriction_save ());
1446 val = Fprogn (body);
1447 return unbind_to (count, val);
1448}
1449\f
671fbc4d
KH
1450/* Buffer for the most recent text displayed by Fmessage. */
1451static char *message_text;
1452
1453/* Allocated length of that buffer. */
1454static int message_length;
1455
35692fe0
JB
1456DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
1457 "Print a one-line message at the bottom of the screen.\n\
1458The first argument is a control string.\n\
1459It may contain %s or %d or %c to print successive following arguments.\n\
1460%s means print an argument as a string, %d means print as number in decimal,\n\
1461%c means print a number as a single character.\n\
1462The argument used by %s must be a string or a symbol;\n\
ccdac5be
JB
1463the argument used by %d or %c must be a number.\n\
1464If the first argument is nil, clear any existing message; let the\n\
1465minibuffer contents show.")
35692fe0
JB
1466 (nargs, args)
1467 int nargs;
1468 Lisp_Object *args;
1469{
ccdac5be 1470 if (NILP (args[0]))
f0250249
JB
1471 {
1472 message (0);
1473 return Qnil;
1474 }
ccdac5be
JB
1475 else
1476 {
1477 register Lisp_Object val;
1478 val = Fformat (nargs, args);
671fbc4d
KH
1479 /* Copy the data so that it won't move when we GC. */
1480 if (! message_text)
1481 {
1482 message_text = (char *)xmalloc (80);
1483 message_length = 80;
1484 }
1485 if (XSTRING (val)->size > message_length)
1486 {
1487 message_length = XSTRING (val)->size;
1488 message_text = (char *)xrealloc (message_text, message_length);
1489 }
1490 bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size);
1491 message2 (message_text, XSTRING (val)->size);
ccdac5be
JB
1492 return val;
1493 }
35692fe0
JB
1494}
1495
cacc3e2c
RS
1496DEFUN ("message-box", Fmessage_box, Smessage_box, 1, MANY, 0,
1497 "Display a message, in a dialog box if possible.\n\
1498If a dialog box is not available, use the echo area.\n\
1499The first argument is a control string.\n\
1500It may contain %s or %d or %c to print successive following arguments.\n\
1501%s means print an argument as a string, %d means print as number in decimal,\n\
1502%c means print a number as a single character.\n\
1503The argument used by %s must be a string or a symbol;\n\
1504the argument used by %d or %c must be a number.\n\
1505If the first argument is nil, clear any existing message; let the\n\
1506minibuffer contents show.")
1507 (nargs, args)
1508 int nargs;
1509 Lisp_Object *args;
1510{
1511 if (NILP (args[0]))
1512 {
1513 message (0);
1514 return Qnil;
1515 }
1516 else
1517 {
1518 register Lisp_Object val;
1519 val = Fformat (nargs, args);
1520#ifdef HAVE_X_MENU
1521 {
1522 Lisp_Object pane, menu, obj;
1523 struct gcpro gcpro1;
1524 pane = Fcons (Fcons (build_string ("OK"), Qt), Qnil);
1525 GCPRO1 (pane);
1526 menu = Fcons (val, pane);
1527 obj = Fx_popup_dialog (Qt, menu);
1528 UNGCPRO;
1529 return val;
1530 }
1531#else
1532 /* Copy the data so that it won't move when we GC. */
1533 if (! message_text)
1534 {
1535 message_text = (char *)xmalloc (80);
1536 message_length = 80;
1537 }
1538 if (XSTRING (val)->size > message_length)
1539 {
1540 message_length = XSTRING (val)->size;
1541 message_text = (char *)xrealloc (message_text, message_length);
1542 }
1543 bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size);
1544 message2 (message_text, XSTRING (val)->size);
1545 return val;
1546#endif
1547 }
1548}
1549#ifdef HAVE_X_MENU
1550extern Lisp_Object last_nonmenu_event;
1551#endif
1552DEFUN ("message-or-box", Fmessage_or_box, Smessage_or_box, 1, MANY, 0,
1553 "Display a message in a dialog box or in the echo area.\n\
1554If this command was invoked with the mouse, use a dialog box.\n\
1555Otherwise, use the echo area.\n\
1556\n\
1557The first argument is a control string.\n\
1558It may contain %s or %d or %c to print successive following arguments.\n\
1559%s means print an argument as a string, %d means print as number in decimal,\n\
1560%c means print a number as a single character.\n\
1561The argument used by %s must be a string or a symbol;\n\
1562the argument used by %d or %c must be a number.\n\
1563If the first argument is nil, clear any existing message; let the\n\
1564minibuffer contents show.")
1565 (nargs, args)
1566 int nargs;
1567 Lisp_Object *args;
1568{
1569#ifdef HAVE_X_MENU
1570 if (NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
0a56ee6b 1571 return Fmessage_box (nargs, args);
cacc3e2c
RS
1572#endif
1573 return Fmessage (nargs, args);
1574}
1575
35692fe0
JB
1576DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
1577 "Format a string out of a control-string and arguments.\n\
1578The first argument is a control string.\n\
1579The other arguments are substituted into it to make the result, a string.\n\
1580It may contain %-sequences meaning to substitute the next argument.\n\
1581%s means print a string argument. Actually, prints any object, with `princ'.\n\
1582%d means print as number in decimal (%o octal, %x hex).\n\
1583%c means print a number as a single character.\n\
1584%S means print any object as an s-expression (using prin1).\n\
52b14ac0
JB
1585 The argument used for %d, %o, %x or %c must be a number.\n\
1586Use %% to put a single % into the output.")
35692fe0
JB
1587 (nargs, args)
1588 int nargs;
1589 register Lisp_Object *args;
1590{
1591 register int n; /* The number of the next arg to substitute */
1592 register int total = 5; /* An estimate of the final length */
1593 char *buf;
1594 register unsigned char *format, *end;
1595 int length;
1596 extern char *index ();
1597 /* It should not be necessary to GCPRO ARGS, because
1598 the caller in the interpreter should take care of that. */
1599
1600 CHECK_STRING (args[0], 0);
1601 format = XSTRING (args[0])->data;
1602 end = format + XSTRING (args[0])->size;
1603
1604 n = 0;
1605 while (format != end)
1606 if (*format++ == '%')
1607 {
1608 int minlen;
1609
1610 /* Process a numeric arg and skip it. */
1611 minlen = atoi (format);
1612 if (minlen > 0)
1613 total += minlen;
1614 else
1615 total -= minlen;
1616 while ((*format >= '0' && *format <= '9')
1617 || *format == '-' || *format == ' ' || *format == '.')
1618 format++;
1619
1620 if (*format == '%')
1621 format++;
1622 else if (++n >= nargs)
60764552 1623 error ("not enough arguments for format string");
35692fe0
JB
1624 else if (*format == 'S')
1625 {
1626 /* For `S', prin1 the argument and then treat like a string. */
1627 register Lisp_Object tem;
1628 tem = Fprin1_to_string (args[n], Qnil);
1629 args[n] = tem;
1630 goto string;
1631 }
ae683129 1632 else if (SYMBOLP (args[n]))
35692fe0 1633 {
d2fd0445 1634 XSETSTRING (args[n], XSYMBOL (args[n])->name);
35692fe0
JB
1635 goto string;
1636 }
ae683129 1637 else if (STRINGP (args[n]))
35692fe0
JB
1638 {
1639 string:
b22e7ecc
KH
1640 if (*format != 's' && *format != 'S')
1641 error ("format specifier doesn't match argument type");
35692fe0
JB
1642 total += XSTRING (args[n])->size;
1643 }
1644 /* Would get MPV otherwise, since Lisp_Int's `point' to low memory. */
ae683129 1645 else if (INTEGERP (args[n]) && *format != 's')
35692fe0 1646 {
4746118a 1647#ifdef LISP_FLOAT_TYPE
eb8c3be9 1648 /* The following loop assumes the Lisp type indicates
35692fe0
JB
1649 the proper way to pass the argument.
1650 So make sure we have a flonum if the argument should
1651 be a double. */
1652 if (*format == 'e' || *format == 'f' || *format == 'g')
1653 args[n] = Ffloat (args[n]);
4746118a 1654#endif
35692fe0
JB
1655 total += 10;
1656 }
4746118a 1657#ifdef LISP_FLOAT_TYPE
ae683129 1658 else if (FLOATP (args[n]) && *format != 's')
35692fe0
JB
1659 {
1660 if (! (*format == 'e' || *format == 'f' || *format == 'g'))
1661 args[n] = Ftruncate (args[n]);
1662 total += 20;
1663 }
4746118a 1664#endif
35692fe0
JB
1665 else
1666 {
1667 /* Anything but a string, convert to a string using princ. */
1668 register Lisp_Object tem;
1669 tem = Fprin1_to_string (args[n], Qt);
1670 args[n] = tem;
1671 goto string;
1672 }
1673 }
1674
1675 {
1676 register int nstrings = n + 1;
50aa2f90
JB
1677
1678 /* Allocate twice as many strings as we have %-escapes; floats occupy
1679 two slots, and we're not sure how many of those we have. */
35692fe0 1680 register unsigned char **strings
50aa2f90
JB
1681 = (unsigned char **) alloca (2 * nstrings * sizeof (unsigned char *));
1682 int i;
35692fe0 1683
50aa2f90 1684 i = 0;
35692fe0
JB
1685 for (n = 0; n < nstrings; n++)
1686 {
1687 if (n >= nargs)
50aa2f90 1688 strings[i++] = (unsigned char *) "";
ae683129 1689 else if (INTEGERP (args[n]))
35692fe0
JB
1690 /* We checked above that the corresponding format effector
1691 isn't %s, which would cause MPV. */
50aa2f90 1692 strings[i++] = (unsigned char *) XINT (args[n]);
4746118a 1693#ifdef LISP_FLOAT_TYPE
ae683129 1694 else if (FLOATP (args[n]))
35692fe0
JB
1695 {
1696 union { double d; int half[2]; } u;
1697
1698 u.d = XFLOAT (args[n])->data;
50aa2f90
JB
1699 strings[i++] = (unsigned char *) u.half[0];
1700 strings[i++] = (unsigned char *) u.half[1];
35692fe0 1701 }
4746118a 1702#endif
35692fe0 1703 else
50aa2f90 1704 strings[i++] = XSTRING (args[n])->data;
35692fe0
JB
1705 }
1706
1707 /* Format it in bigger and bigger buf's until it all fits. */
1708 while (1)
1709 {
1710 buf = (char *) alloca (total + 1);
1711 buf[total - 1] = 0;
1712
50aa2f90 1713 length = doprnt (buf, total + 1, strings[0], end, i-1, strings + 1);
35692fe0
JB
1714 if (buf[total - 1] == 0)
1715 break;
1716
1717 total *= 2;
1718 }
1719 }
1720
1721 /* UNGCPRO; */
1722 return make_string (buf, length);
1723}
1724
1725/* VARARGS 1 */
1726Lisp_Object
1727#ifdef NO_ARG_ARRAY
1728format1 (string1, arg0, arg1, arg2, arg3, arg4)
679e18b1 1729 EMACS_INT arg0, arg1, arg2, arg3, arg4;
35692fe0
JB
1730#else
1731format1 (string1)
1732#endif
1733 char *string1;
1734{
1735 char buf[100];
1736#ifdef NO_ARG_ARRAY
679e18b1 1737 EMACS_INT args[5];
35692fe0
JB
1738 args[0] = arg0;
1739 args[1] = arg1;
1740 args[2] = arg2;
1741 args[3] = arg3;
1742 args[4] = arg4;
1743 doprnt (buf, sizeof buf, string1, 0, 5, args);
1744#else
1745 doprnt (buf, sizeof buf, string1, 0, 5, &string1 + 1);
1746#endif
1747 return build_string (buf);
1748}
1749\f
1750DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
1751 "Return t if two characters match, optionally ignoring case.\n\
1752Both arguments must be characters (i.e. integers).\n\
1753Case is ignored if `case-fold-search' is non-nil in the current buffer.")
1754 (c1, c2)
1755 register Lisp_Object c1, c2;
1756{
1757 unsigned char *downcase = DOWNCASE_TABLE;
1758 CHECK_NUMBER (c1, 0);
1759 CHECK_NUMBER (c2, 1);
1760
56a98455 1761 if (!NILP (current_buffer->case_fold_search)
c34beca9
RS
1762 ? (downcase[0xff & XFASTINT (c1)] == downcase[0xff & XFASTINT (c2)]
1763 && (XFASTINT (c1) & ~0xff) == (XFASTINT (c2) & ~0xff))
35692fe0
JB
1764 : XINT (c1) == XINT (c2))
1765 return Qt;
1766 return Qnil;
1767}
b229b8d1
RS
1768\f
1769/* Transpose the markers in two regions of the current buffer, and
1770 adjust the ones between them if necessary (i.e.: if the regions
1771 differ in size).
1772
1773 Traverses the entire marker list of the buffer to do so, adding an
1774 appropriate amount to some, subtracting from some, and leaving the
1775 rest untouched. Most of this is copied from adjust_markers in insdel.c.
1776
03240d11 1777 It's the caller's job to see that (start1 <= end1 <= start2 <= end2). */
b229b8d1
RS
1778
1779void
1780transpose_markers (start1, end1, start2, end2)
1781 register int start1, end1, start2, end2;
1782{
1783 register int amt1, amt2, diff, mpos;
1784 register Lisp_Object marker;
b229b8d1 1785
03240d11 1786 /* Update point as if it were a marker. */
8de1d5f0
KH
1787 if (PT < start1)
1788 ;
1789 else if (PT < end1)
1790 TEMP_SET_PT (PT + (end2 - end1));
1791 else if (PT < start2)
1792 TEMP_SET_PT (PT + (end2 - start2) - (end1 - start1));
1793 else if (PT < end2)
1794 TEMP_SET_PT (PT - (start2 - start1));
1795
03240d11
KH
1796 /* We used to adjust the endpoints here to account for the gap, but that
1797 isn't good enough. Even if we assume the caller has tried to move the
1798 gap out of our way, it might still be at start1 exactly, for example;
1799 and that places it `inside' the interval, for our purposes. The amount
1800 of adjustment is nontrivial if there's a `denormalized' marker whose
1801 position is between GPT and GPT + GAP_SIZE, so it's simpler to leave
1802 the dirty work to Fmarker_position, below. */
b229b8d1
RS
1803
1804 /* The difference between the region's lengths */
1805 diff = (end2 - start2) - (end1 - start1);
1806
1807 /* For shifting each marker in a region by the length of the other
1808 * region plus the distance between the regions.
1809 */
1810 amt1 = (end2 - start2) + (start2 - end1);
1811 amt2 = (end1 - start1) + (start2 - end1);
1812
03240d11
KH
1813 for (marker = current_buffer->markers; !NILP (marker);
1814 marker = XMARKER (marker)->chain)
b229b8d1 1815 {
03240d11
KH
1816 mpos = Fmarker_position (marker);
1817 if (mpos >= start1 && mpos < end2)
1818 {
1819 if (mpos < end1)
1820 mpos += amt1;
1821 else if (mpos < start2)
1822 mpos += diff;
1823 else
1824 mpos -= amt2;
1825 if (mpos > GPT) mpos += GAP_SIZE;
1826 XMARKER (marker)->bufpos = mpos;
1827 }
b229b8d1
RS
1828 }
1829}
1830
1831DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5, 0,
1832 "Transpose region START1 to END1 with START2 to END2.\n\
1833The regions may not be overlapping, because the size of the buffer is\n\
1834never changed in a transposition.\n\
1835\n\
1836Optional fifth arg LEAVE_MARKERS, if non-nil, means don't transpose\n\
1837any markers that happen to be located in the regions.\n\
1838\n\
1839Transposing beyond buffer boundaries is an error.")
1840 (startr1, endr1, startr2, endr2, leave_markers)
1841 Lisp_Object startr1, endr1, startr2, endr2, leave_markers;
1842{
1843 register int start1, end1, start2, end2,
1844 gap, len1, len_mid, len2;
3c6bc7d0 1845 unsigned char *start1_addr, *start2_addr, *temp;
b229b8d1
RS
1846
1847#ifdef USE_TEXT_PROPERTIES
1848 INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
1849 cur_intv = current_buffer->intervals;
1850#endif /* USE_TEXT_PROPERTIES */
1851
1852 validate_region (&startr1, &endr1);
1853 validate_region (&startr2, &endr2);
1854
1855 start1 = XFASTINT (startr1);
1856 end1 = XFASTINT (endr1);
1857 start2 = XFASTINT (startr2);
1858 end2 = XFASTINT (endr2);
1859 gap = GPT;
1860
1861 /* Swap the regions if they're reversed. */
1862 if (start2 < end1)
1863 {
1864 register int glumph = start1;
1865 start1 = start2;
1866 start2 = glumph;
1867 glumph = end1;
1868 end1 = end2;
1869 end2 = glumph;
1870 }
1871
b229b8d1
RS
1872 len1 = end1 - start1;
1873 len2 = end2 - start2;
1874
1875 if (start2 < end1)
1876 error ("transposed regions not properly ordered");
1877 else if (start1 == end1 || start2 == end2)
1878 error ("transposed region may not be of length 0");
1879
1880 /* The possibilities are:
1881 1. Adjacent (contiguous) regions, or separate but equal regions
1882 (no, really equal, in this case!), or
1883 2. Separate regions of unequal size.
1884
1885 The worst case is usually No. 2. It means that (aside from
1886 potential need for getting the gap out of the way), there also
1887 needs to be a shifting of the text between the two regions. So
1888 if they are spread far apart, we are that much slower... sigh. */
1889
1890 /* It must be pointed out that the really studly thing to do would
1891 be not to move the gap at all, but to leave it in place and work
1892 around it if necessary. This would be extremely efficient,
1893 especially considering that people are likely to do
1894 transpositions near where they are working interactively, which
1895 is exactly where the gap would be found. However, such code
1896 would be much harder to write and to read. So, if you are
1897 reading this comment and are feeling squirrely, by all means have
1898 a go! I just didn't feel like doing it, so I will simply move
1899 the gap the minimum distance to get it out of the way, and then
1900 deal with an unbroken array. */
3c6bc7d0
RS
1901
1902 /* Make sure the gap won't interfere, by moving it out of the text
1903 we will operate on. */
1904 if (start1 < gap && gap < end2)
1905 {
1906 if (gap - start1 < end2 - gap)
1907 move_gap (start1);
1908 else
1909 move_gap (end2);
1910 }
b229b8d1
RS
1911
1912 /* Hmmm... how about checking to see if the gap is large
1913 enough to use as the temporary storage? That would avoid an
1914 allocation... interesting. Later, don't fool with it now. */
1915
1916 /* Working without memmove, for portability (sigh), so must be
1917 careful of overlapping subsections of the array... */
1918
1919 if (end1 == start2) /* adjacent regions */
1920 {
b229b8d1
RS
1921 modify_region (current_buffer, start1, end2);
1922 record_change (start1, len1 + len2);
1923
1924#ifdef USE_TEXT_PROPERTIES
1925 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
1926 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
1927 Fset_text_properties (start1, end2, Qnil, Qnil);
1928#endif /* USE_TEXT_PROPERTIES */
1929
1930 /* First region smaller than second. */
1931 if (len1 < len2)
1932 {
3c6bc7d0
RS
1933 /* We use alloca only if it is small,
1934 because we want to avoid stack overflow. */
1935 if (len2 > 20000)
1936 temp = (unsigned char *) xmalloc (len2);
1937 else
1938 temp = (unsigned char *) alloca (len2);
03240d11
KH
1939
1940 /* Don't precompute these addresses. We have to compute them
1941 at the last minute, because the relocating allocator might
1942 have moved the buffer around during the xmalloc. */
1943 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
1944 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
1945
b229b8d1
RS
1946 bcopy (start2_addr, temp, len2);
1947 bcopy (start1_addr, start1_addr + len2, len1);
1948 bcopy (temp, start1_addr, len2);
3c6bc7d0
RS
1949 if (len2 > 20000)
1950 free (temp);
b229b8d1
RS
1951 }
1952 else
1953 /* First region not smaller than second. */
1954 {
3c6bc7d0
RS
1955 if (len1 > 20000)
1956 temp = (unsigned char *) xmalloc (len1);
1957 else
1958 temp = (unsigned char *) alloca (len1);
03240d11
KH
1959 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
1960 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
b229b8d1
RS
1961 bcopy (start1_addr, temp, len1);
1962 bcopy (start2_addr, start1_addr, len2);
1963 bcopy (temp, start1_addr + len2, len1);
3c6bc7d0
RS
1964 if (len1 > 20000)
1965 free (temp);
b229b8d1
RS
1966 }
1967#ifdef USE_TEXT_PROPERTIES
1968 graft_intervals_into_buffer (tmp_interval1, start1 + len2,
1969 len1, current_buffer, 0);
1970 graft_intervals_into_buffer (tmp_interval2, start1,
1971 len2, current_buffer, 0);
1972#endif /* USE_TEXT_PROPERTIES */
1973 }
1974 /* Non-adjacent regions, because end1 != start2, bleagh... */
1975 else
1976 {
b229b8d1
RS
1977 if (len1 == len2)
1978 /* Regions are same size, though, how nice. */
1979 {
1980 modify_region (current_buffer, start1, end1);
1981 modify_region (current_buffer, start2, end2);
1982 record_change (start1, len1);
1983 record_change (start2, len2);
1984#ifdef USE_TEXT_PROPERTIES
1985 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
1986 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
1987 Fset_text_properties (start1, end1, Qnil, Qnil);
1988 Fset_text_properties (start2, end2, Qnil, Qnil);
1989#endif /* USE_TEXT_PROPERTIES */
1990
3c6bc7d0
RS
1991 if (len1 > 20000)
1992 temp = (unsigned char *) xmalloc (len1);
1993 else
1994 temp = (unsigned char *) alloca (len1);
03240d11
KH
1995 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
1996 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
b229b8d1
RS
1997 bcopy (start1_addr, temp, len1);
1998 bcopy (start2_addr, start1_addr, len2);
1999 bcopy (temp, start2_addr, len1);
3c6bc7d0
RS
2000 if (len1 > 20000)
2001 free (temp);
b229b8d1
RS
2002#ifdef USE_TEXT_PROPERTIES
2003 graft_intervals_into_buffer (tmp_interval1, start2,
2004 len1, current_buffer, 0);
2005 graft_intervals_into_buffer (tmp_interval2, start1,
2006 len2, current_buffer, 0);
2007#endif /* USE_TEXT_PROPERTIES */
2008 }
2009
2010 else if (len1 < len2) /* Second region larger than first */
2011 /* Non-adjacent & unequal size, area between must also be shifted. */
2012 {
2013 len_mid = start2 - end1;
2014 modify_region (current_buffer, start1, end2);
2015 record_change (start1, (end2 - start1));
2016#ifdef USE_TEXT_PROPERTIES
2017 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
2018 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
2019 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
2020 Fset_text_properties (start1, end2, Qnil, Qnil);
2021#endif /* USE_TEXT_PROPERTIES */
2022
3c6bc7d0
RS
2023 /* holds region 2 */
2024 if (len2 > 20000)
2025 temp = (unsigned char *) xmalloc (len2);
2026 else
2027 temp = (unsigned char *) alloca (len2);
03240d11
KH
2028 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
2029 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
3c6bc7d0 2030 bcopy (start2_addr, temp, len2);
b229b8d1 2031 bcopy (start1_addr, start1_addr + len_mid + len2, len1);
3c6bc7d0
RS
2032 safe_bcopy (start1_addr + len1, start1_addr + len2, len_mid);
2033 bcopy (temp, start1_addr, len2);
2034 if (len2 > 20000)
2035 free (temp);
b229b8d1
RS
2036#ifdef USE_TEXT_PROPERTIES
2037 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
2038 len1, current_buffer, 0);
2039 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
2040 len_mid, current_buffer, 0);
2041 graft_intervals_into_buffer (tmp_interval2, start1,
2042 len2, current_buffer, 0);
2043#endif /* USE_TEXT_PROPERTIES */
2044 }
2045 else
2046 /* Second region smaller than first. */
2047 {
2048 len_mid = start2 - end1;
2049 record_change (start1, (end2 - start1));
2050 modify_region (current_buffer, start1, end2);
2051
2052#ifdef USE_TEXT_PROPERTIES
2053 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
2054 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
2055 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
2056 Fset_text_properties (start1, end2, Qnil, Qnil);
2057#endif /* USE_TEXT_PROPERTIES */
2058
3c6bc7d0
RS
2059 /* holds region 1 */
2060 if (len1 > 20000)
2061 temp = (unsigned char *) xmalloc (len1);
2062 else
2063 temp = (unsigned char *) alloca (len1);
03240d11
KH
2064 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
2065 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
3c6bc7d0 2066 bcopy (start1_addr, temp, len1);
b229b8d1 2067 bcopy (start2_addr, start1_addr, len2);
3c6bc7d0
RS
2068 bcopy (start1_addr + len1, start1_addr + len2, len_mid);
2069 bcopy (temp, start1_addr + len2 + len_mid, len1);
2070 if (len1 > 20000)
2071 free (temp);
b229b8d1
RS
2072#ifdef USE_TEXT_PROPERTIES
2073 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
2074 len1, current_buffer, 0);
2075 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
2076 len_mid, current_buffer, 0);
2077 graft_intervals_into_buffer (tmp_interval2, start1,
2078 len2, current_buffer, 0);
2079#endif /* USE_TEXT_PROPERTIES */
2080 }
2081 }
2082
2083 /* todo: this will be slow, because for every transposition, we
2084 traverse the whole friggin marker list. Possible solutions:
2085 somehow get a list of *all* the markers across multiple
2086 transpositions and do it all in one swell phoop. Or maybe modify
2087 Emacs' marker code to keep an ordered list or tree. This might
2088 be nicer, and more beneficial in the long run, but would be a
2089 bunch of work. Plus the way they're arranged now is nice. */
2090 if (NILP (leave_markers))
8de1d5f0
KH
2091 {
2092 transpose_markers (start1, end1, start2, end2);
2093 fix_overlays_in_range (start1, end2);
2094 }
b229b8d1
RS
2095
2096 return Qnil;
2097}
35692fe0 2098
35692fe0
JB
2099\f
2100void
2101syms_of_editfns ()
2102{
f43754f6
KH
2103 DEFVAR_LISP ("system-name", &Vsystem_name,
2104 "The name of the machine Emacs is running on.");
2105
2106 DEFVAR_LISP ("user-full-name", &Vuser_full_name,
2107 "The full name of the user logged in.");
2108
2109 DEFVAR_LISP ("user-name", &Vuser_name,
2110 "The user's name, taken from environment variables if possible.");
2111
2112 DEFVAR_LISP ("user-real-name", &Vuser_real_name,
2113 "The user's name, based upon the real uid only.");
35692fe0
JB
2114
2115 defsubr (&Schar_equal);
2116 defsubr (&Sgoto_char);
2117 defsubr (&Sstring_to_char);
2118 defsubr (&Schar_to_string);
2119 defsubr (&Sbuffer_substring);
2120 defsubr (&Sbuffer_string);
2121
2122 defsubr (&Spoint_marker);
2123 defsubr (&Smark_marker);
2124 defsubr (&Spoint);
2125 defsubr (&Sregion_beginning);
2126 defsubr (&Sregion_end);
2127/* defsubr (&Smark); */
2128/* defsubr (&Sset_mark); */
2129 defsubr (&Ssave_excursion);
2130
2131 defsubr (&Sbufsize);
2132 defsubr (&Spoint_max);
2133 defsubr (&Spoint_min);
2134 defsubr (&Spoint_min_marker);
2135 defsubr (&Spoint_max_marker);
2136
2137 defsubr (&Sbobp);
2138 defsubr (&Seobp);
2139 defsubr (&Sbolp);
2140 defsubr (&Seolp);
850a8179
JB
2141 defsubr (&Sfollowing_char);
2142 defsubr (&Sprevious_char);
35692fe0
JB
2143 defsubr (&Schar_after);
2144 defsubr (&Sinsert);
2145 defsubr (&Sinsert_before_markers);
be91036a
RS
2146 defsubr (&Sinsert_and_inherit);
2147 defsubr (&Sinsert_and_inherit_before_markers);
35692fe0
JB
2148 defsubr (&Sinsert_char);
2149
2150 defsubr (&Suser_login_name);
2151 defsubr (&Suser_real_login_name);
2152 defsubr (&Suser_uid);
2153 defsubr (&Suser_real_uid);
2154 defsubr (&Suser_full_name);
7fd233b3 2155 defsubr (&Semacs_pid);
d940e0e4 2156 defsubr (&Scurrent_time);
a82d387c 2157 defsubr (&Sformat_time_string);
35692fe0 2158 defsubr (&Scurrent_time_string);
c2662aea 2159 defsubr (&Scurrent_time_zone);
35692fe0 2160 defsubr (&Ssystem_name);
35692fe0 2161 defsubr (&Smessage);
cacc3e2c
RS
2162 defsubr (&Smessage_box);
2163 defsubr (&Smessage_or_box);
35692fe0 2164 defsubr (&Sformat);
35692fe0
JB
2165
2166 defsubr (&Sinsert_buffer_substring);
e9cf2084 2167 defsubr (&Scompare_buffer_substrings);
35692fe0
JB
2168 defsubr (&Ssubst_char_in_region);
2169 defsubr (&Stranslate_region);
2170 defsubr (&Sdelete_region);
2171 defsubr (&Swiden);
2172 defsubr (&Snarrow_to_region);
2173 defsubr (&Ssave_restriction);
b229b8d1 2174 defsubr (&Stranspose_regions);
35692fe0 2175}