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