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