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