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