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