Initial revision
[bpt/emacs.git] / src / editfns.c
CommitLineData
35692fe0
JB
1/* Lisp functions pertaining to editing.
2 Copyright (C) 1985, 1986, 1987, 1989 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21#include "config.h"
bfb61299
JB
22
23#ifdef VMS
24#include "pwd.h"
25#else
35692fe0 26#include <pwd.h>
bfb61299
JB
27#endif
28
35692fe0
JB
29#include "lisp.h"
30#include "buffer.h"
31#include "window.h"
32
33#ifdef NEED_TIME_H
34#include <time.h>
35#else /* not NEED_TIME_H */
36#ifdef HAVE_TIMEVAL
37#include <sys/time.h>
38#endif /* HAVE_TIMEVAL */
39#endif /* not NEED_TIME_H */
40
41#define min(a, b) ((a) < (b) ? (a) : (b))
42#define max(a, b) ((a) > (b) ? (a) : (b))
43
44/* Some static data, and a function to initialize it for each run */
45
46Lisp_Object Vsystem_name;
47Lisp_Object Vuser_real_name; /* login name of current user ID */
48Lisp_Object Vuser_full_name; /* full name of current user */
49Lisp_Object Vuser_name; /* user name from USER or LOGNAME. */
50
51void
52init_editfns ()
53{
52b14ac0 54 char *user_name;
35692fe0
JB
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
62 Vsystem_name = build_string (get_system_name ());
63 p = XSTRING (Vsystem_name)->data;
64 while (*p)
65 {
66 if (*p == ' ' || *p == '\t')
67 *p = '-';
68 p++;
69 }
70
71#ifndef CANNOT_DUMP
72 /* Don't bother with this on initial start when just dumping out */
73 if (!initialized)
74 return;
75#endif /* not CANNOT_DUMP */
76
77 pw = (struct passwd *) getpwuid (getuid ());
78 Vuser_real_name = build_string (pw ? pw->pw_name : "unknown");
79
52b14ac0
JB
80 /* Get the effective user name, by consulting environment variables,
81 or the effective uid if those are unset. */
82 user_name = (char *) getenv ("USER");
35692fe0 83 if (!user_name)
52b14ac0
JB
84 user_name = (char *) getenv ("LOGNAME");
85 if (!user_name)
86 {
87 pw = (struct passwd *) getpwuid (geteuid ());
88 user_name = (char *) (pw ? pw->pw_name : "unknown");
89 }
90 Vuser_name = build_string (user_name);
35692fe0 91
52b14ac0
JB
92 /* If the user name claimed in the environment vars differs from
93 the real uid, use the claimed name to find the full name. */
35692fe0 94 tem = Fstring_equal (Vuser_name, Vuser_real_name);
56a98455 95 if (NILP (tem))
52b14ac0 96 pw = (struct passwd *) getpwnam (XSTRING (Vuser_name)->data);
35692fe0
JB
97
98 p = (unsigned char *) (pw ? USER_FULL_NAME : "unknown");
99 q = (unsigned char *) index (p, ',');
100 Vuser_full_name = make_string (p, q ? q - p : strlen (p));
101
102#ifdef AMPERSAND_FULL_NAME
103 p = XSTRING (Vuser_full_name)->data;
104 q = (char *) index (p, '&');
105 /* Substitute the login name for the &, upcasing the first character. */
106 if (q)
107 {
108 r = (char *) alloca (strlen (p) + XSTRING (Vuser_name)->size + 1);
109 bcopy (p, r, q - p);
110 r[q - p] = 0;
52b14ac0 111 strcat (r, XSTRING (Vuser_name)->data);
35692fe0
JB
112 r[q - p] = UPCASE (r[q - p]);
113 strcat (r, q + 1);
114 Vuser_full_name = build_string (r);
115 }
116#endif /* AMPERSAND_FULL_NAME */
117}
118\f
119DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
120 "Convert arg CHAR to a one-character string containing that character.")
121 (n)
122 Lisp_Object n;
123{
124 char c;
125 CHECK_NUMBER (n, 0);
126
127 c = XINT (n);
128 return make_string (&c, 1);
129}
130
131DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0,
132 "Convert arg STRING to a character, the first character of that string.")
133 (str)
134 register Lisp_Object str;
135{
136 register Lisp_Object val;
137 register struct Lisp_String *p;
138 CHECK_STRING (str, 0);
139
140 p = XSTRING (str);
141 if (p->size)
142 XFASTINT (val) = ((unsigned char *) p->data)[0];
143 else
144 XFASTINT (val) = 0;
145 return val;
146}
147\f
148static Lisp_Object
149buildmark (val)
150 int val;
151{
152 register Lisp_Object mark;
153 mark = Fmake_marker ();
154 Fset_marker (mark, make_number (val), Qnil);
155 return mark;
156}
157
158DEFUN ("point", Fpoint, Spoint, 0, 0, 0,
159 "Return value of point, as an integer.\n\
160Beginning of buffer is position (point-min)")
161 ()
162{
163 Lisp_Object temp;
164 XFASTINT (temp) = point;
165 return temp;
166}
167
168DEFUN ("point-marker", Fpoint_marker, Spoint_marker, 0, 0, 0,
169 "Return value of point, as a marker object.")
170 ()
171{
172 return buildmark (point);
173}
174
175int
176clip_to_bounds (lower, num, upper)
177 int lower, num, upper;
178{
179 if (num < lower)
180 return lower;
181 else if (num > upper)
182 return upper;
183 else
184 return num;
185}
186
187DEFUN ("goto-char", Fgoto_char, Sgoto_char, 1, 1, "NGoto char: ",
188 "Set point to POSITION, a number or marker.\n\
189Beginning of buffer is position (point-min), end is (point-max).")
190 (n)
191 register Lisp_Object n;
192{
193 CHECK_NUMBER_COERCE_MARKER (n, 0);
194
195 SET_PT (clip_to_bounds (BEGV, XINT (n), ZV));
196 return n;
197}
198
199static Lisp_Object
200region_limit (beginningp)
201 int beginningp;
202{
203 register Lisp_Object m;
204 m = Fmarker_position (current_buffer->mark);
56a98455 205 if (NILP (m)) error ("There is no region now");
35692fe0
JB
206 if ((point < XFASTINT (m)) == beginningp)
207 return (make_number (point));
208 else
209 return (m);
210}
211
212DEFUN ("region-beginning", Fregion_beginning, Sregion_beginning, 0, 0, 0,
213 "Return position of beginning of region, as an integer.")
214 ()
215{
216 return (region_limit (1));
217}
218
219DEFUN ("region-end", Fregion_end, Sregion_end, 0, 0, 0,
220 "Return position of end of region, as an integer.")
221 ()
222{
223 return (region_limit (0));
224}
225
226#if 0 /* now in lisp code */
227DEFUN ("mark", Fmark, Smark, 0, 0, 0,
228 "Return this buffer's mark value as integer, or nil if no mark.\n\
229If you are using this in an editing command, you are most likely making\n\
230a mistake; see the documentation of `set-mark'.")
231 ()
232{
233 return Fmarker_position (current_buffer->mark);
234}
235#endif /* commented out code */
236
237DEFUN ("mark-marker", Fmark_marker, Smark_marker, 0, 0, 0,
238 "Return this buffer's mark, as a marker object.\n\
239Watch out! Moving this marker changes the mark position.\n\
240If you set the marker not to point anywhere, the buffer will have no mark.")
241 ()
242{
243 return current_buffer->mark;
244}
245
246#if 0 /* this is now in lisp code */
247DEFUN ("set-mark", Fset_mark, Sset_mark, 1, 1, 0,
248 "Set this buffer's mark to POS. Don't use this function!\n\
249That is to say, don't use this function unless you want\n\
250the user to see that the mark has moved, and you want the previous\n\
251mark position to be lost.\n\
252\n\
253Normally, when a new mark is set, the old one should go on the stack.\n\
254This is why most applications should use push-mark, not set-mark.\n\
255\n\
256Novice programmers often try to use the mark for the wrong purposes.\n\
257The mark saves a location for the user's convenience.\n\
258Most editing commands should not alter the mark.\n\
259To remember a location for internal use in the Lisp program,\n\
260store it in a Lisp variable. Example:\n\
261\n\
262 (let ((beg (point))) (forward-line 1) (delete-region beg (point))).")
263 (pos)
264 Lisp_Object pos;
265{
56a98455 266 if (NILP (pos))
35692fe0
JB
267 {
268 current_buffer->mark = Qnil;
269 return Qnil;
270 }
271 CHECK_NUMBER_COERCE_MARKER (pos, 0);
272
56a98455 273 if (NILP (current_buffer->mark))
35692fe0
JB
274 current_buffer->mark = Fmake_marker ();
275
276 Fset_marker (current_buffer->mark, pos, Qnil);
277 return pos;
278}
279#endif /* commented-out code */
280
281Lisp_Object
282save_excursion_save ()
283{
284 register int visible = XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer;
285
286 return Fcons (Fpoint_marker (),
287 Fcons (Fcopy_marker (current_buffer->mark), visible ? Qt : Qnil));
288}
289
290Lisp_Object
291save_excursion_restore (info)
292 register Lisp_Object info;
293{
294 register Lisp_Object tem;
295
296 tem = Fmarker_buffer (Fcar (info));
297 /* If buffer being returned to is now deleted, avoid error */
298 /* Otherwise could get error here while unwinding to top level
299 and crash */
300 /* In that case, Fmarker_buffer returns nil now. */
56a98455 301 if (NILP (tem))
35692fe0
JB
302 return Qnil;
303 Fset_buffer (tem);
304 tem = Fcar (info);
305 Fgoto_char (tem);
306 unchain_marker (tem);
307 tem = Fcar (Fcdr (info));
308 Fset_marker (current_buffer->mark, tem, Fcurrent_buffer ());
309 unchain_marker (tem);
310 tem = Fcdr (Fcdr (info));
56a98455 311 if (!NILP (tem) && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
35692fe0
JB
312 Fswitch_to_buffer (Fcurrent_buffer (), Qnil);
313 return Qnil;
314}
315
316DEFUN ("save-excursion", Fsave_excursion, Ssave_excursion, 0, UNEVALLED, 0,
317 "Save point, mark, and current buffer; execute BODY; restore those things.\n\
318Executes BODY just like `progn'.\n\
319The values of point, mark and the current buffer are restored\n\
320even in case of abnormal exit (throw or error).")
321 (args)
322 Lisp_Object args;
323{
324 register Lisp_Object val;
325 int count = specpdl_ptr - specpdl;
326
327 record_unwind_protect (save_excursion_restore, save_excursion_save ());
328
329 val = Fprogn (args);
330 return unbind_to (count, val);
331}
332\f
333DEFUN ("buffer-size", Fbufsize, Sbufsize, 0, 0, 0,
334 "Return the number of characters in the current buffer.")
335 ()
336{
337 Lisp_Object temp;
338 XFASTINT (temp) = Z - BEG;
339 return temp;
340}
341
342DEFUN ("point-min", Fpoint_min, Spoint_min, 0, 0, 0,
343 "Return the minimum permissible value of point in the current buffer.\n\
344This is 1, unless a clipping restriction is in effect.")
345 ()
346{
347 Lisp_Object temp;
348 XFASTINT (temp) = BEGV;
349 return temp;
350}
351
352DEFUN ("point-min-marker", Fpoint_min_marker, Spoint_min_marker, 0, 0, 0,
353 "Return a marker to the minimum permissible value of point in this buffer.\n\
354This is the beginning, unless a clipping restriction is in effect.")
355 ()
356{
357 return buildmark (BEGV);
358}
359
360DEFUN ("point-max", Fpoint_max, Spoint_max, 0, 0, 0,
361 "Return the maximum permissible value of point in the current buffer.\n\
362This is (1+ (buffer-size)), unless a clipping restriction is in effect,\n\
363in which case it is less.")
364 ()
365{
366 Lisp_Object temp;
367 XFASTINT (temp) = ZV;
368 return temp;
369}
370
371DEFUN ("point-max-marker", Fpoint_max_marker, Spoint_max_marker, 0, 0, 0,
372 "Return a marker to the maximum permissible value of point in this buffer.\n\
373This is (1+ (buffer-size)), unless a clipping restriction is in effect,\n\
374in which case it is less.")
375 ()
376{
377 return buildmark (ZV);
378}
379
850a8179
JB
380DEFUN ("following-char", Ffollowing_char, Sfollowing_char, 0, 0, 0,
381 "Return the character following point, as a number.\n\
382At the end of the buffer or accessible region, return 0.")
35692fe0
JB
383 ()
384{
385 Lisp_Object temp;
850a8179
JB
386 if (point >= ZV)
387 XFASTINT (temp) = 0;
388 else
389 XFASTINT (temp) = FETCH_CHAR (point);
35692fe0
JB
390 return temp;
391}
392
850a8179
JB
393DEFUN ("preceding-char", Fprevious_char, Sprevious_char, 0, 0, 0,
394 "Return the character preceding point, as a number.\n\
395At the beginning of the buffer or accessible region, return 0.")
35692fe0
JB
396 ()
397{
398 Lisp_Object temp;
399 if (point <= BEGV)
400 XFASTINT (temp) = 0;
401 else
402 XFASTINT (temp) = FETCH_CHAR (point - 1);
403 return temp;
404}
405
406DEFUN ("bobp", Fbobp, Sbobp, 0, 0, 0,
407 "Return T if point is at the beginning of the buffer.\n\
408If the buffer is narrowed, this means the beginning of the narrowed part.")
409 ()
410{
411 if (point == BEGV)
412 return Qt;
413 return Qnil;
414}
415
416DEFUN ("eobp", Feobp, Seobp, 0, 0, 0,
417 "Return T if point is at the end of the buffer.\n\
418If the buffer is narrowed, this means the end of the narrowed part.")
419 ()
420{
421 if (point == ZV)
422 return Qt;
423 return Qnil;
424}
425
426DEFUN ("bolp", Fbolp, Sbolp, 0, 0, 0,
427 "Return T if point is at the beginning of a line.")
428 ()
429{
430 if (point == BEGV || FETCH_CHAR (point - 1) == '\n')
431 return Qt;
432 return Qnil;
433}
434
435DEFUN ("eolp", Feolp, Seolp, 0, 0, 0,
436 "Return T if point is at the end of a line.\n\
437`End of a line' includes point being at the end of the buffer.")
438 ()
439{
440 if (point == ZV || FETCH_CHAR (point) == '\n')
441 return Qt;
442 return Qnil;
443}
444
445DEFUN ("char-after", Fchar_after, Schar_after, 1, 1, 0,
446 "Return character in current buffer at position POS.\n\
447POS is an integer or a buffer pointer.\n\
448If POS is out of range, the value is nil.")
449 (pos)
450 Lisp_Object pos;
451{
452 register Lisp_Object val;
453 register int n;
454
455 CHECK_NUMBER_COERCE_MARKER (pos, 0);
456
457 n = XINT (pos);
458 if (n < BEGV || n >= ZV) return Qnil;
459
460 XFASTINT (val) = FETCH_CHAR (n);
461 return val;
462}
463\f
464DEFUN ("user-login-name", Fuser_login_name, Suser_login_name, 0, 0, 0,
465 "Return the name under which the user logged in, as a string.\n\
466This is based on the effective uid, not the real uid.\n\
467Also, if the environment variable USER or LOGNAME is set,\n\
468that determines the value of this function.")
469 ()
470{
471 return Vuser_name;
472}
473
474DEFUN ("user-real-login-name", Fuser_real_login_name, Suser_real_login_name,
475 0, 0, 0,
476 "Return the name of the user's real uid, as a string.\n\
477Differs from `user-login-name' when running under `su'.")
478 ()
479{
480 return Vuser_real_name;
481}
482
483DEFUN ("user-uid", Fuser_uid, Suser_uid, 0, 0, 0,
484 "Return the effective uid of Emacs, as an integer.")
485 ()
486{
487 return make_number (geteuid ());
488}
489
490DEFUN ("user-real-uid", Fuser_real_uid, Suser_real_uid, 0, 0, 0,
491 "Return the real uid of Emacs, as an integer.")
492 ()
493{
494 return make_number (getuid ());
495}
496
497DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 0, 0,
498 "Return the full name of the user logged in, as a string.")
499 ()
500{
501 return Vuser_full_name;
502}
503
504DEFUN ("system-name", Fsystem_name, Ssystem_name, 0, 0, 0,
505 "Return the name of the machine you are running on, as a string.")
506 ()
507{
508 return Vsystem_name;
509}
510
d940e0e4
JB
511DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0,
512 "Return the current time, as an integer.")
513 ()
514{
515 return make_number (time(0));
516}
517\f
518
35692fe0
JB
519DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 0, 0,
520 "Return the current time, as a human-readable string.\n\
521Programs can use it too, since the number of columns in each field is fixed.\n\
522The format is `Sun Sep 16 01:03:52 1973'.\n\
523In a future Emacs version, the time zone may be added at the end,\n\
524if we can figure out a reasonably easy way to get that information.")
525 ()
526{
527 long current_time = time ((long *) 0);
528 char buf[30];
529 register char *tem = (char *) ctime (&current_time);
530
531 strncpy (buf, tem, 24);
532 buf[24] = 0;
533
534 return build_string (buf);
535}
536
537#ifdef unix
538
539DEFUN ("set-default-file-mode", Fset_default_file_mode, Sset_default_file_mode, 1, 1, "p",
540 "Set Unix `umask' value to ARGUMENT, and return old value.\n\
541The `umask' value is the default protection mode for new files.")
542 (nmask)
543 Lisp_Object nmask;
544{
545 CHECK_NUMBER (nmask, 0);
546 return make_number (umask (XINT (nmask)));
547}
548
549DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
550 "Tell Unix to finish all pending disk updates.")
551 ()
552{
553 sync ();
554 return Qnil;
555}
556
557#endif /* unix */
558\f
559void
560insert1 (arg)
561 Lisp_Object arg;
562{
563 Finsert (1, &arg);
564}
565
52b14ac0
JB
566
567/* Callers passing one argument to Finsert need not gcpro the
568 argument "array", since the only element of the array will
569 not be used after calling insert or insert_from_string, so
570 we don't care if it gets trashed. */
571
35692fe0
JB
572DEFUN ("insert", Finsert, Sinsert, 0, MANY, 0,
573 "Insert the arguments, either strings or characters, at point.\n\
574Point moves forward so that it ends up after the inserted text.\n\
575Any other markers at the point of insertion remain before the text.")
576 (nargs, args)
577 int nargs;
578 register Lisp_Object *args;
579{
580 register int argnum;
581 register Lisp_Object tem;
582 char str[1];
35692fe0
JB
583
584 for (argnum = 0; argnum < nargs; argnum++)
585 {
586 tem = args[argnum];
587 retry:
588 if (XTYPE (tem) == Lisp_Int)
589 {
590 str[0] = XINT (tem);
591 insert (str, 1);
592 }
593 else if (XTYPE (tem) == Lisp_String)
594 {
595 insert_from_string (tem, 0, XSTRING (tem)->size);
596 }
597 else
598 {
599 tem = wrong_type_argument (Qchar_or_string_p, tem);
600 goto retry;
601 }
602 }
603
35692fe0
JB
604 return Qnil;
605}
606
607DEFUN ("insert-before-markers", Finsert_before_markers, Sinsert_before_markers, 0, MANY, 0,
608 "Insert strings or characters at point, relocating markers after the text.\n\
609Point moves forward so that it ends up after the inserted text.\n\
610Any other markers at the point of insertion also end up after the text.")
611 (nargs, args)
612 int nargs;
613 register Lisp_Object *args;
614{
615 register int argnum;
616 register Lisp_Object tem;
617 char str[1];
35692fe0
JB
618
619 for (argnum = 0; argnum < nargs; argnum++)
620 {
621 tem = args[argnum];
622 retry:
623 if (XTYPE (tem) == Lisp_Int)
624 {
625 str[0] = XINT (tem);
626 insert_before_markers (str, 1);
627 }
628 else if (XTYPE (tem) == Lisp_String)
629 {
630 insert_from_string_before_markers (tem, 0, XSTRING (tem)->size);
631 }
632 else
633 {
634 tem = wrong_type_argument (Qchar_or_string_p, tem);
635 goto retry;
636 }
637 }
638
35692fe0
JB
639 return Qnil;
640}
641\f
642DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 2, 0,
643 "Insert COUNT (second arg) copies of CHAR (first arg).\n\
644Point and all markers are affected as in the function `insert'.\n\
645Both arguments are required.")
646 (chr, count)
647 Lisp_Object chr, count;
648{
649 register unsigned char *string;
650 register int strlen;
651 register int i, n;
652
653 CHECK_NUMBER (chr, 0);
654 CHECK_NUMBER (count, 1);
655
656 n = XINT (count);
657 if (n <= 0)
658 return Qnil;
659 strlen = min (n, 256);
660 string = (unsigned char *) alloca (strlen);
661 for (i = 0; i < strlen; i++)
662 string[i] = XFASTINT (chr);
663 while (n >= strlen)
664 {
665 insert (string, strlen);
666 n -= strlen;
667 }
668 if (n > 0)
669 insert (string, n);
670 return Qnil;
671}
672
673\f
674/* Return a string with the contents of the current region */
675
676DEFUN ("buffer-substring", Fbuffer_substring, Sbuffer_substring, 2, 2, 0,
677 "Return the contents of part of the current buffer as a string.\n\
678The two arguments START and END are character positions;\n\
679they can be in either order.")
680 (b, e)
681 Lisp_Object b, e;
682{
683 register int beg, end;
684 Lisp_Object result;
685
686 validate_region (&b, &e);
687 beg = XINT (b);
688 end = XINT (e);
689
690 if (beg < GPT && end > GPT)
691 move_gap (beg);
692
693 /* Plain old make_string calls make_uninit_string, which can cause
694 the buffer arena to be compacted. make_string has no way of
695 knowing that the data has been moved, and thus copies the wrong
696 data into the string. This doesn't effect most of the other
697 users of make_string, so it should be left as is. */
698 result = make_uninit_string (end - beg);
699 bcopy (&FETCH_CHAR (beg), XSTRING (result)->data, end - beg);
700
701 return result;
702}
703
704DEFUN ("buffer-string", Fbuffer_string, Sbuffer_string, 0, 0, 0,
705 "Return the contents of the current buffer as a string.")
706 ()
707{
708 if (BEGV < GPT && ZV > GPT)
709 move_gap (BEGV);
710 return make_string (BEGV_ADDR, ZV - BEGV);
711}
712
713DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
714 1, 3, 0,
715 "Insert before point a substring of the contents buffer BUFFER.\n\
716BUFFER may be a buffer or a buffer name.\n\
717Arguments START and END are character numbers specifying the substring.\n\
718They default to the beginning and the end of BUFFER.")
719 (buf, b, e)
720 Lisp_Object buf, b, e;
721{
722 register int beg, end, exch;
723 register struct buffer *bp;
724
725 buf = Fget_buffer (buf);
726 bp = XBUFFER (buf);
727
56a98455 728 if (NILP (b))
35692fe0
JB
729 beg = BUF_BEGV (bp);
730 else
731 {
732 CHECK_NUMBER_COERCE_MARKER (b, 0);
733 beg = XINT (b);
734 }
56a98455 735 if (NILP (e))
35692fe0
JB
736 end = BUF_ZV (bp);
737 else
738 {
739 CHECK_NUMBER_COERCE_MARKER (e, 1);
740 end = XINT (e);
741 }
742
743 if (beg > end)
744 exch = beg, beg = end, end = exch;
745
746 /* Move the gap or create enough gap in the current buffer. */
747
748 if (point != GPT)
749 move_gap (point);
750 if (GAP_SIZE < end - beg)
751 make_gap (end - beg - GAP_SIZE);
752
753 if (!(BUF_BEGV (bp) <= beg
754 && beg <= end
755 && end <= BUF_ZV (bp)))
756 args_out_of_range (b, e);
757
758 /* Now the actual insertion will not do any gap motion,
759 so it matters not if BUF is the current buffer. */
760 if (beg < BUF_GPT (bp))
761 {
762 insert (BUF_CHAR_ADDRESS (bp, beg), min (end, BUF_GPT (bp)) - beg);
763 beg = min (end, BUF_GPT (bp));
764 }
765 if (beg < end)
766 insert (BUF_CHAR_ADDRESS (bp, beg), end - beg);
767
768 return Qnil;
769}
770\f
771DEFUN ("subst-char-in-region", Fsubst_char_in_region,
772 Ssubst_char_in_region, 4, 5, 0,
773 "From START to END, replace FROMCHAR with TOCHAR each time it occurs.\n\
774If optional arg NOUNDO is non-nil, don't record this change for undo\n\
775and don't mark the buffer as really changed.")
776 (start, end, fromchar, tochar, noundo)
777 Lisp_Object start, end, fromchar, tochar, noundo;
778{
779 register int pos, stop, look;
780
781 validate_region (&start, &end);
782 CHECK_NUMBER (fromchar, 2);
783 CHECK_NUMBER (tochar, 3);
784
785 pos = XINT (start);
786 stop = XINT (end);
787 look = XINT (fromchar);
788
789 modify_region (pos, stop);
56a98455 790 if (! NILP (noundo))
35692fe0
JB
791 {
792 if (MODIFF - 1 == current_buffer->save_modified)
793 current_buffer->save_modified++;
794 if (MODIFF - 1 == current_buffer->auto_save_modified)
795 current_buffer->auto_save_modified++;
796 }
797
798 while (pos < stop)
799 {
800 if (FETCH_CHAR (pos) == look)
801 {
56a98455 802 if (NILP (noundo))
35692fe0
JB
803 record_change (pos, 1);
804 FETCH_CHAR (pos) = XINT (tochar);
56a98455 805 if (NILP (noundo))
35692fe0
JB
806 signal_after_change (pos, 1, 1);
807 }
808 pos++;
809 }
810
811 return Qnil;
812}
813
814DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
815 "From START to END, translate characters according to TABLE.\n\
816TABLE is a string; the Nth character in it is the mapping\n\
817for the character with code N. Returns the number of characters changed.")
818 (start, end, table)
819 Lisp_Object start;
820 Lisp_Object end;
821 register Lisp_Object table;
822{
823 register int pos, stop; /* Limits of the region. */
824 register unsigned char *tt; /* Trans table. */
825 register int oc; /* Old character. */
826 register int nc; /* New character. */
827 int cnt; /* Number of changes made. */
828 Lisp_Object z; /* Return. */
829 int size; /* Size of translate table. */
830
831 validate_region (&start, &end);
832 CHECK_STRING (table, 2);
833
834 size = XSTRING (table)->size;
835 tt = XSTRING (table)->data;
836
837 pos = XINT (start);
838 stop = XINT (end);
839 modify_region (pos, stop);
840
841 cnt = 0;
842 for (; pos < stop; ++pos)
843 {
844 oc = FETCH_CHAR (pos);
845 if (oc < size)
846 {
847 nc = tt[oc];
848 if (nc != oc)
849 {
850 record_change (pos, 1);
851 FETCH_CHAR (pos) = nc;
852 signal_after_change (pos, 1, 1);
853 ++cnt;
854 }
855 }
856 }
857
858 XFASTINT (z) = cnt;
859 return (z);
860}
861
862DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r",
863 "Delete the text between point and mark.\n\
864When called from a program, expects two arguments,\n\
865positions (integers or markers) specifying the stretch to be deleted.")
866 (b, e)
867 Lisp_Object b, e;
868{
869 validate_region (&b, &e);
870 del_range (XINT (b), XINT (e));
871 return Qnil;
872}
873\f
874DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
875 "Remove restrictions (narrowing) from current buffer.\n\
876This allows the buffer's full text to be seen and edited.")
877 ()
878{
879 BEGV = BEG;
880 SET_BUF_ZV (current_buffer, Z);
881 clip_changed = 1;
52b14ac0
JB
882 /* Changing the buffer bounds invalidates any recorded current column. */
883 invalidate_current_column ();
35692fe0
JB
884 return Qnil;
885}
886
887DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
888 "Restrict editing in this buffer to the current region.\n\
889The rest of the text becomes temporarily invisible and untouchable\n\
890but is not deleted; if you save the buffer in a file, the invisible\n\
891text is included in the file. \\[widen] makes all visible again.\n\
892See also `save-restriction'.\n\
893\n\
894When calling from a program, pass two arguments; positions (integers\n\
895or markers) bounding the text that should remain visible.")
896 (b, e)
897 register Lisp_Object b, e;
898{
899 register int i;
900
901 CHECK_NUMBER_COERCE_MARKER (b, 0);
902 CHECK_NUMBER_COERCE_MARKER (e, 1);
903
904 if (XINT (b) > XINT (e))
905 {
906 i = XFASTINT (b);
907 b = e;
908 XFASTINT (e) = i;
909 }
910
911 if (!(BEG <= XINT (b) && XINT (b) <= XINT (e) && XINT (e) <= Z))
912 args_out_of_range (b, e);
913
914 BEGV = XFASTINT (b);
915 SET_BUF_ZV (current_buffer, XFASTINT (e));
916 if (point < XFASTINT (b))
917 SET_PT (XFASTINT (b));
918 if (point > XFASTINT (e))
919 SET_PT (XFASTINT (e));
920 clip_changed = 1;
52b14ac0
JB
921 /* Changing the buffer bounds invalidates any recorded current column. */
922 invalidate_current_column ();
35692fe0
JB
923 return Qnil;
924}
925
926Lisp_Object
927save_restriction_save ()
928{
929 register Lisp_Object bottom, top;
930 /* Note: I tried using markers here, but it does not win
931 because insertion at the end of the saved region
932 does not advance mh and is considered "outside" the saved region. */
933 XFASTINT (bottom) = BEGV - BEG;
934 XFASTINT (top) = Z - ZV;
935
936 return Fcons (Fcurrent_buffer (), Fcons (bottom, top));
937}
938
939Lisp_Object
940save_restriction_restore (data)
941 Lisp_Object data;
942{
943 register struct buffer *buf;
944 register int newhead, newtail;
945 register Lisp_Object tem;
946
947 buf = XBUFFER (XCONS (data)->car);
948
949 data = XCONS (data)->cdr;
950
951 tem = XCONS (data)->car;
952 newhead = XINT (tem);
953 tem = XCONS (data)->cdr;
954 newtail = XINT (tem);
955 if (newhead + newtail > BUF_Z (buf) - BUF_BEG (buf))
956 {
957 newhead = 0;
958 newtail = 0;
959 }
960 BUF_BEGV (buf) = BUF_BEG (buf) + newhead;
961 SET_BUF_ZV (buf, BUF_Z (buf) - newtail);
962 clip_changed = 1;
963
964 /* If point is outside the new visible range, move it inside. */
965 SET_BUF_PT (buf,
966 clip_to_bounds (BUF_BEGV (buf), BUF_PT (buf), BUF_ZV (buf)));
967
968 return Qnil;
969}
970
971DEFUN ("save-restriction", Fsave_restriction, Ssave_restriction, 0, UNEVALLED, 0,
972 "Execute BODY, saving and restoring current buffer's restrictions.\n\
973The buffer's restrictions make parts of the beginning and end invisible.\n\
974\(They are set up with `narrow-to-region' and eliminated with `widen'.)\n\
975This special form, `save-restriction', saves the current buffer's restrictions\n\
976when it is entered, and restores them when it is exited.\n\
977So any `narrow-to-region' within BODY lasts only until the end of the form.\n\
978The old restrictions settings are restored\n\
979even in case of abnormal exit (throw or error).\n\
980\n\
981The value returned is the value of the last form in BODY.\n\
982\n\
983`save-restriction' can get confused if, within the BODY, you widen\n\
984and then make changes outside the area within the saved restrictions.\n\
985\n\
986Note: if you are using both `save-excursion' and `save-restriction',\n\
987use `save-excursion' outermost:\n\
988 (save-excursion (save-restriction ...))")
989 (body)
990 Lisp_Object body;
991{
992 register Lisp_Object val;
993 int count = specpdl_ptr - specpdl;
994
995 record_unwind_protect (save_restriction_restore, save_restriction_save ());
996 val = Fprogn (body);
997 return unbind_to (count, val);
998}
999\f
1000DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
1001 "Print a one-line message at the bottom of the screen.\n\
1002The first argument is a control string.\n\
1003It may contain %s or %d or %c to print successive following arguments.\n\
1004%s means print an argument as a string, %d means print as number in decimal,\n\
1005%c means print a number as a single character.\n\
1006The argument used by %s must be a string or a symbol;\n\
1007the argument used by %d or %c must be a number.")
1008 (nargs, args)
1009 int nargs;
1010 Lisp_Object *args;
1011{
1012 register Lisp_Object val;
1013
35692fe0
JB
1014 val = Fformat (nargs, args);
1015 message ("%s", XSTRING (val)->data);
1016 return val;
1017}
1018
1019DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
1020 "Format a string out of a control-string and arguments.\n\
1021The first argument is a control string.\n\
1022The other arguments are substituted into it to make the result, a string.\n\
1023It may contain %-sequences meaning to substitute the next argument.\n\
1024%s means print a string argument. Actually, prints any object, with `princ'.\n\
1025%d means print as number in decimal (%o octal, %x hex).\n\
1026%c means print a number as a single character.\n\
1027%S means print any object as an s-expression (using prin1).\n\
52b14ac0
JB
1028 The argument used for %d, %o, %x or %c must be a number.\n\
1029Use %% to put a single % into the output.")
35692fe0
JB
1030 (nargs, args)
1031 int nargs;
1032 register Lisp_Object *args;
1033{
1034 register int n; /* The number of the next arg to substitute */
1035 register int total = 5; /* An estimate of the final length */
1036 char *buf;
1037 register unsigned char *format, *end;
1038 int length;
1039 extern char *index ();
1040 /* It should not be necessary to GCPRO ARGS, because
1041 the caller in the interpreter should take care of that. */
1042
1043 CHECK_STRING (args[0], 0);
1044 format = XSTRING (args[0])->data;
1045 end = format + XSTRING (args[0])->size;
1046
1047 n = 0;
1048 while (format != end)
1049 if (*format++ == '%')
1050 {
1051 int minlen;
1052
1053 /* Process a numeric arg and skip it. */
1054 minlen = atoi (format);
1055 if (minlen > 0)
1056 total += minlen;
1057 else
1058 total -= minlen;
1059 while ((*format >= '0' && *format <= '9')
1060 || *format == '-' || *format == ' ' || *format == '.')
1061 format++;
1062
1063 if (*format == '%')
1064 format++;
1065 else if (++n >= nargs)
1066 ;
1067 else if (*format == 'S')
1068 {
1069 /* For `S', prin1 the argument and then treat like a string. */
1070 register Lisp_Object tem;
1071 tem = Fprin1_to_string (args[n], Qnil);
1072 args[n] = tem;
1073 goto string;
1074 }
1075 else if (XTYPE (args[n]) == Lisp_Symbol)
1076 {
1077 XSET (args[n], Lisp_String, XSYMBOL (args[n])->name);
1078 goto string;
1079 }
1080 else if (XTYPE (args[n]) == Lisp_String)
1081 {
1082 string:
1083 total += XSTRING (args[n])->size;
1084 }
1085 /* Would get MPV otherwise, since Lisp_Int's `point' to low memory. */
1086 else if (XTYPE (args[n]) == Lisp_Int && *format != 's')
1087 {
1088 /* The following loop issumes the Lisp type indicates
1089 the proper way to pass the argument.
1090 So make sure we have a flonum if the argument should
1091 be a double. */
1092 if (*format == 'e' || *format == 'f' || *format == 'g')
1093 args[n] = Ffloat (args[n]);
1094 total += 10;
1095 }
1096 else if (XTYPE (args[n]) == Lisp_Float && *format != 's')
1097 {
1098 if (! (*format == 'e' || *format == 'f' || *format == 'g'))
1099 args[n] = Ftruncate (args[n]);
1100 total += 20;
1101 }
1102 else
1103 {
1104 /* Anything but a string, convert to a string using princ. */
1105 register Lisp_Object tem;
1106 tem = Fprin1_to_string (args[n], Qt);
1107 args[n] = tem;
1108 goto string;
1109 }
1110 }
1111
1112 {
1113 register int nstrings = n + 1;
1114 register unsigned char **strings
1115 = (unsigned char **) alloca (nstrings * sizeof (unsigned char *));
1116
1117 for (n = 0; n < nstrings; n++)
1118 {
1119 if (n >= nargs)
1120 strings[n] = (unsigned char *) "";
1121 else if (XTYPE (args[n]) == Lisp_Int)
1122 /* We checked above that the corresponding format effector
1123 isn't %s, which would cause MPV. */
1124 strings[n] = (unsigned char *) XINT (args[n]);
1125 else if (XTYPE (args[n]) == Lisp_Float)
1126 {
1127 union { double d; int half[2]; } u;
1128
1129 u.d = XFLOAT (args[n])->data;
1130 strings[n++] = (unsigned char *) u.half[0];
1131 strings[n] = (unsigned char *) u.half[1];
1132 }
1133 else
1134 strings[n] = XSTRING (args[n])->data;
1135 }
1136
1137 /* Format it in bigger and bigger buf's until it all fits. */
1138 while (1)
1139 {
1140 buf = (char *) alloca (total + 1);
1141 buf[total - 1] = 0;
1142
1143 length = doprnt (buf, total + 1, strings[0], end, nargs, strings + 1);
1144 if (buf[total - 1] == 0)
1145 break;
1146
1147 total *= 2;
1148 }
1149 }
1150
1151 /* UNGCPRO; */
1152 return make_string (buf, length);
1153}
1154
1155/* VARARGS 1 */
1156Lisp_Object
1157#ifdef NO_ARG_ARRAY
1158format1 (string1, arg0, arg1, arg2, arg3, arg4)
1159 int arg0, arg1, arg2, arg3, arg4;
1160#else
1161format1 (string1)
1162#endif
1163 char *string1;
1164{
1165 char buf[100];
1166#ifdef NO_ARG_ARRAY
1167 int args[5];
1168 args[0] = arg0;
1169 args[1] = arg1;
1170 args[2] = arg2;
1171 args[3] = arg3;
1172 args[4] = arg4;
1173 doprnt (buf, sizeof buf, string1, 0, 5, args);
1174#else
1175 doprnt (buf, sizeof buf, string1, 0, 5, &string1 + 1);
1176#endif
1177 return build_string (buf);
1178}
1179\f
1180DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
1181 "Return t if two characters match, optionally ignoring case.\n\
1182Both arguments must be characters (i.e. integers).\n\
1183Case is ignored if `case-fold-search' is non-nil in the current buffer.")
1184 (c1, c2)
1185 register Lisp_Object c1, c2;
1186{
1187 unsigned char *downcase = DOWNCASE_TABLE;
1188 CHECK_NUMBER (c1, 0);
1189 CHECK_NUMBER (c2, 1);
1190
56a98455 1191 if (!NILP (current_buffer->case_fold_search)
35692fe0
JB
1192 ? downcase[0xff & XFASTINT (c1)] == downcase[0xff & XFASTINT (c2)]
1193 : XINT (c1) == XINT (c2))
1194 return Qt;
1195 return Qnil;
1196}
1197
35692fe0
JB
1198\f
1199void
1200syms_of_editfns ()
1201{
1202 DEFVAR_LISP ("system-name", &Vsystem_name,
1203 "The name of the machine Emacs is running on.");
1204
1205 DEFVAR_LISP ("user-full-name", &Vuser_full_name,
1206 "The full name of the user logged in.");
1207
1208 DEFVAR_LISP ("user-name", &Vuser_name,
1209 "The user's name, based on the effective uid.");
1210
1211 DEFVAR_LISP ("user-real-name", &Vuser_real_name,
1212 "The user's name, base upon the real uid.");
1213
1214 defsubr (&Schar_equal);
1215 defsubr (&Sgoto_char);
1216 defsubr (&Sstring_to_char);
1217 defsubr (&Schar_to_string);
1218 defsubr (&Sbuffer_substring);
1219 defsubr (&Sbuffer_string);
1220
1221 defsubr (&Spoint_marker);
1222 defsubr (&Smark_marker);
1223 defsubr (&Spoint);
1224 defsubr (&Sregion_beginning);
1225 defsubr (&Sregion_end);
1226/* defsubr (&Smark); */
1227/* defsubr (&Sset_mark); */
1228 defsubr (&Ssave_excursion);
1229
1230 defsubr (&Sbufsize);
1231 defsubr (&Spoint_max);
1232 defsubr (&Spoint_min);
1233 defsubr (&Spoint_min_marker);
1234 defsubr (&Spoint_max_marker);
1235
1236 defsubr (&Sbobp);
1237 defsubr (&Seobp);
1238 defsubr (&Sbolp);
1239 defsubr (&Seolp);
850a8179
JB
1240 defsubr (&Sfollowing_char);
1241 defsubr (&Sprevious_char);
35692fe0
JB
1242 defsubr (&Schar_after);
1243 defsubr (&Sinsert);
1244 defsubr (&Sinsert_before_markers);
1245 defsubr (&Sinsert_char);
1246
1247 defsubr (&Suser_login_name);
1248 defsubr (&Suser_real_login_name);
1249 defsubr (&Suser_uid);
1250 defsubr (&Suser_real_uid);
1251 defsubr (&Suser_full_name);
d940e0e4 1252 defsubr (&Scurrent_time);
35692fe0
JB
1253 defsubr (&Scurrent_time_string);
1254 defsubr (&Ssystem_name);
1255 defsubr (&Sset_default_file_mode);
1256 defsubr (&Sunix_sync);
1257 defsubr (&Smessage);
1258 defsubr (&Sformat);
35692fe0
JB
1259
1260 defsubr (&Sinsert_buffer_substring);
1261 defsubr (&Ssubst_char_in_region);
1262 defsubr (&Stranslate_region);
1263 defsubr (&Sdelete_region);
1264 defsubr (&Swiden);
1265 defsubr (&Snarrow_to_region);
1266 defsubr (&Ssave_restriction);
1267}