Move the include of Xlocale.h after setting HAVE_X11R5.
[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,
956ace37
JB
546 "Return the current time, as the number of seconds since 12:00 AM January 1970.\n\
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))
740 tzstring = XSTRING (zone)->data;
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);
896 tzstring = XSTRING (tz)->data;
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
35692fe0 1899 else
50aa2f90 1900 strings[i++] = XSTRING (args[n])->data;
35692fe0
JB
1901 }
1902
fb893977
RS
1903 /* Make room in result for all the non-%-codes in the control string. */
1904 total += XSTRING (args[0])->size;
1905
35692fe0
JB
1906 /* Format it in bigger and bigger buf's until it all fits. */
1907 while (1)
1908 {
1909 buf = (char *) alloca (total + 1);
1910 buf[total - 1] = 0;
1911
50aa2f90 1912 length = doprnt (buf, total + 1, strings[0], end, i-1, strings + 1);
35692fe0
JB
1913 if (buf[total - 1] == 0)
1914 break;
1915
1916 total *= 2;
1917 }
1918 }
1919
1920 /* UNGCPRO; */
1921 return make_string (buf, length);
1922}
1923
1924/* VARARGS 1 */
1925Lisp_Object
1926#ifdef NO_ARG_ARRAY
1927format1 (string1, arg0, arg1, arg2, arg3, arg4)
679e18b1 1928 EMACS_INT arg0, arg1, arg2, arg3, arg4;
35692fe0
JB
1929#else
1930format1 (string1)
1931#endif
1932 char *string1;
1933{
1934 char buf[100];
1935#ifdef NO_ARG_ARRAY
679e18b1 1936 EMACS_INT args[5];
35692fe0
JB
1937 args[0] = arg0;
1938 args[1] = arg1;
1939 args[2] = arg2;
1940 args[3] = arg3;
1941 args[4] = arg4;
ea4d2909 1942 doprnt (buf, sizeof buf, string1, (char *)0, 5, args);
35692fe0 1943#else
ea4d2909 1944 doprnt (buf, sizeof buf, string1, (char *)0, 5, &string1 + 1);
35692fe0
JB
1945#endif
1946 return build_string (buf);
1947}
1948\f
1949DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
1950 "Return t if two characters match, optionally ignoring case.\n\
1951Both arguments must be characters (i.e. integers).\n\
1952Case is ignored if `case-fold-search' is non-nil in the current buffer.")
1953 (c1, c2)
1954 register Lisp_Object c1, c2;
1955{
be46733f 1956 Lisp_Object *downcase = DOWNCASE_TABLE;
35692fe0
JB
1957 CHECK_NUMBER (c1, 0);
1958 CHECK_NUMBER (c2, 1);
1959
56a98455 1960 if (!NILP (current_buffer->case_fold_search)
be46733f
RS
1961 ? ((XINT (downcase[0xff & XFASTINT (c1)])
1962 == XINT (downcase[0xff & XFASTINT (c2)]))
c34beca9 1963 && (XFASTINT (c1) & ~0xff) == (XFASTINT (c2) & ~0xff))
35692fe0
JB
1964 : XINT (c1) == XINT (c2))
1965 return Qt;
1966 return Qnil;
1967}
b229b8d1
RS
1968\f
1969/* Transpose the markers in two regions of the current buffer, and
1970 adjust the ones between them if necessary (i.e.: if the regions
1971 differ in size).
1972
1973 Traverses the entire marker list of the buffer to do so, adding an
1974 appropriate amount to some, subtracting from some, and leaving the
1975 rest untouched. Most of this is copied from adjust_markers in insdel.c.
1976
03240d11 1977 It's the caller's job to see that (start1 <= end1 <= start2 <= end2). */
b229b8d1
RS
1978
1979void
1980transpose_markers (start1, end1, start2, end2)
1981 register int start1, end1, start2, end2;
1982{
1983 register int amt1, amt2, diff, mpos;
1984 register Lisp_Object marker;
b229b8d1 1985
03240d11 1986 /* Update point as if it were a marker. */
8de1d5f0
KH
1987 if (PT < start1)
1988 ;
1989 else if (PT < end1)
1990 TEMP_SET_PT (PT + (end2 - end1));
1991 else if (PT < start2)
1992 TEMP_SET_PT (PT + (end2 - start2) - (end1 - start1));
1993 else if (PT < end2)
1994 TEMP_SET_PT (PT - (start2 - start1));
1995
03240d11
KH
1996 /* We used to adjust the endpoints here to account for the gap, but that
1997 isn't good enough. Even if we assume the caller has tried to move the
1998 gap out of our way, it might still be at start1 exactly, for example;
1999 and that places it `inside' the interval, for our purposes. The amount
2000 of adjustment is nontrivial if there's a `denormalized' marker whose
2001 position is between GPT and GPT + GAP_SIZE, so it's simpler to leave
2002 the dirty work to Fmarker_position, below. */
b229b8d1
RS
2003
2004 /* The difference between the region's lengths */
2005 diff = (end2 - start2) - (end1 - start1);
2006
2007 /* For shifting each marker in a region by the length of the other
2008 * region plus the distance between the regions.
2009 */
2010 amt1 = (end2 - start2) + (start2 - end1);
2011 amt2 = (end1 - start1) + (start2 - end1);
2012
1e158d25 2013 for (marker = BUF_MARKERS (current_buffer); !NILP (marker);
03240d11 2014 marker = XMARKER (marker)->chain)
b229b8d1 2015 {
03240d11
KH
2016 mpos = Fmarker_position (marker);
2017 if (mpos >= start1 && mpos < end2)
2018 {
2019 if (mpos < end1)
2020 mpos += amt1;
2021 else if (mpos < start2)
2022 mpos += diff;
2023 else
2024 mpos -= amt2;
2025 if (mpos > GPT) mpos += GAP_SIZE;
2026 XMARKER (marker)->bufpos = mpos;
2027 }
b229b8d1
RS
2028 }
2029}
2030
2031DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5, 0,
2032 "Transpose region START1 to END1 with START2 to END2.\n\
2033The regions may not be overlapping, because the size of the buffer is\n\
2034never changed in a transposition.\n\
2035\n\
2036Optional fifth arg LEAVE_MARKERS, if non-nil, means don't transpose\n\
2037any markers that happen to be located in the regions.\n\
2038\n\
2039Transposing beyond buffer boundaries is an error.")
2040 (startr1, endr1, startr2, endr2, leave_markers)
2041 Lisp_Object startr1, endr1, startr2, endr2, leave_markers;
2042{
2043 register int start1, end1, start2, end2,
2044 gap, len1, len_mid, len2;
3c6bc7d0 2045 unsigned char *start1_addr, *start2_addr, *temp;
b229b8d1
RS
2046
2047#ifdef USE_TEXT_PROPERTIES
2048 INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
1e158d25 2049 cur_intv = BUF_INTERVALS (current_buffer);
b229b8d1
RS
2050#endif /* USE_TEXT_PROPERTIES */
2051
2052 validate_region (&startr1, &endr1);
2053 validate_region (&startr2, &endr2);
2054
2055 start1 = XFASTINT (startr1);
2056 end1 = XFASTINT (endr1);
2057 start2 = XFASTINT (startr2);
2058 end2 = XFASTINT (endr2);
2059 gap = GPT;
2060
2061 /* Swap the regions if they're reversed. */
2062 if (start2 < end1)
2063 {
2064 register int glumph = start1;
2065 start1 = start2;
2066 start2 = glumph;
2067 glumph = end1;
2068 end1 = end2;
2069 end2 = glumph;
2070 }
2071
b229b8d1
RS
2072 len1 = end1 - start1;
2073 len2 = end2 - start2;
2074
2075 if (start2 < end1)
2076 error ("transposed regions not properly ordered");
2077 else if (start1 == end1 || start2 == end2)
2078 error ("transposed region may not be of length 0");
2079
2080 /* The possibilities are:
2081 1. Adjacent (contiguous) regions, or separate but equal regions
2082 (no, really equal, in this case!), or
2083 2. Separate regions of unequal size.
2084
2085 The worst case is usually No. 2. It means that (aside from
2086 potential need for getting the gap out of the way), there also
2087 needs to be a shifting of the text between the two regions. So
2088 if they are spread far apart, we are that much slower... sigh. */
2089
2090 /* It must be pointed out that the really studly thing to do would
2091 be not to move the gap at all, but to leave it in place and work
2092 around it if necessary. This would be extremely efficient,
2093 especially considering that people are likely to do
2094 transpositions near where they are working interactively, which
2095 is exactly where the gap would be found. However, such code
2096 would be much harder to write and to read. So, if you are
2097 reading this comment and are feeling squirrely, by all means have
2098 a go! I just didn't feel like doing it, so I will simply move
2099 the gap the minimum distance to get it out of the way, and then
2100 deal with an unbroken array. */
3c6bc7d0
RS
2101
2102 /* Make sure the gap won't interfere, by moving it out of the text
2103 we will operate on. */
2104 if (start1 < gap && gap < end2)
2105 {
2106 if (gap - start1 < end2 - gap)
2107 move_gap (start1);
2108 else
2109 move_gap (end2);
2110 }
b229b8d1
RS
2111
2112 /* Hmmm... how about checking to see if the gap is large
2113 enough to use as the temporary storage? That would avoid an
2114 allocation... interesting. Later, don't fool with it now. */
2115
2116 /* Working without memmove, for portability (sigh), so must be
2117 careful of overlapping subsections of the array... */
2118
2119 if (end1 == start2) /* adjacent regions */
2120 {
b229b8d1
RS
2121 modify_region (current_buffer, start1, end2);
2122 record_change (start1, len1 + len2);
2123
2124#ifdef USE_TEXT_PROPERTIES
2125 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
2126 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
2127 Fset_text_properties (start1, end2, Qnil, Qnil);
2128#endif /* USE_TEXT_PROPERTIES */
2129
2130 /* First region smaller than second. */
2131 if (len1 < len2)
2132 {
3c6bc7d0
RS
2133 /* We use alloca only if it is small,
2134 because we want to avoid stack overflow. */
2135 if (len2 > 20000)
2136 temp = (unsigned char *) xmalloc (len2);
2137 else
2138 temp = (unsigned char *) alloca (len2);
03240d11
KH
2139
2140 /* Don't precompute these addresses. We have to compute them
2141 at the last minute, because the relocating allocator might
2142 have moved the buffer around during the xmalloc. */
2143 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
2144 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
2145
b229b8d1
RS
2146 bcopy (start2_addr, temp, len2);
2147 bcopy (start1_addr, start1_addr + len2, len1);
2148 bcopy (temp, start1_addr, len2);
3c6bc7d0
RS
2149 if (len2 > 20000)
2150 free (temp);
b229b8d1
RS
2151 }
2152 else
2153 /* First region not smaller than second. */
2154 {
3c6bc7d0
RS
2155 if (len1 > 20000)
2156 temp = (unsigned char *) xmalloc (len1);
2157 else
2158 temp = (unsigned char *) alloca (len1);
03240d11
KH
2159 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
2160 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
b229b8d1
RS
2161 bcopy (start1_addr, temp, len1);
2162 bcopy (start2_addr, start1_addr, len2);
2163 bcopy (temp, start1_addr + len2, len1);
3c6bc7d0
RS
2164 if (len1 > 20000)
2165 free (temp);
b229b8d1
RS
2166 }
2167#ifdef USE_TEXT_PROPERTIES
2168 graft_intervals_into_buffer (tmp_interval1, start1 + len2,
2169 len1, current_buffer, 0);
2170 graft_intervals_into_buffer (tmp_interval2, start1,
2171 len2, current_buffer, 0);
2172#endif /* USE_TEXT_PROPERTIES */
2173 }
2174 /* Non-adjacent regions, because end1 != start2, bleagh... */
2175 else
2176 {
b229b8d1
RS
2177 if (len1 == len2)
2178 /* Regions are same size, though, how nice. */
2179 {
2180 modify_region (current_buffer, start1, end1);
2181 modify_region (current_buffer, start2, end2);
2182 record_change (start1, len1);
2183 record_change (start2, len2);
2184#ifdef USE_TEXT_PROPERTIES
2185 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
2186 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
2187 Fset_text_properties (start1, end1, Qnil, Qnil);
2188 Fset_text_properties (start2, end2, Qnil, Qnil);
2189#endif /* USE_TEXT_PROPERTIES */
2190
3c6bc7d0
RS
2191 if (len1 > 20000)
2192 temp = (unsigned char *) xmalloc (len1);
2193 else
2194 temp = (unsigned char *) alloca (len1);
03240d11
KH
2195 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
2196 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
b229b8d1
RS
2197 bcopy (start1_addr, temp, len1);
2198 bcopy (start2_addr, start1_addr, len2);
2199 bcopy (temp, start2_addr, len1);
3c6bc7d0
RS
2200 if (len1 > 20000)
2201 free (temp);
b229b8d1
RS
2202#ifdef USE_TEXT_PROPERTIES
2203 graft_intervals_into_buffer (tmp_interval1, start2,
2204 len1, current_buffer, 0);
2205 graft_intervals_into_buffer (tmp_interval2, start1,
2206 len2, current_buffer, 0);
2207#endif /* USE_TEXT_PROPERTIES */
2208 }
2209
2210 else if (len1 < len2) /* Second region larger than first */
2211 /* Non-adjacent & unequal size, area between must also be shifted. */
2212 {
2213 len_mid = start2 - end1;
2214 modify_region (current_buffer, start1, end2);
2215 record_change (start1, (end2 - start1));
2216#ifdef USE_TEXT_PROPERTIES
2217 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
2218 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
2219 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
2220 Fset_text_properties (start1, end2, Qnil, Qnil);
2221#endif /* USE_TEXT_PROPERTIES */
2222
3c6bc7d0
RS
2223 /* holds region 2 */
2224 if (len2 > 20000)
2225 temp = (unsigned char *) xmalloc (len2);
2226 else
2227 temp = (unsigned char *) alloca (len2);
03240d11
KH
2228 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
2229 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
3c6bc7d0 2230 bcopy (start2_addr, temp, len2);
b229b8d1 2231 bcopy (start1_addr, start1_addr + len_mid + len2, len1);
3c6bc7d0
RS
2232 safe_bcopy (start1_addr + len1, start1_addr + len2, len_mid);
2233 bcopy (temp, start1_addr, len2);
2234 if (len2 > 20000)
2235 free (temp);
b229b8d1
RS
2236#ifdef USE_TEXT_PROPERTIES
2237 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
2238 len1, current_buffer, 0);
2239 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
2240 len_mid, current_buffer, 0);
2241 graft_intervals_into_buffer (tmp_interval2, start1,
2242 len2, current_buffer, 0);
2243#endif /* USE_TEXT_PROPERTIES */
2244 }
2245 else
2246 /* Second region smaller than first. */
2247 {
2248 len_mid = start2 - end1;
2249 record_change (start1, (end2 - start1));
2250 modify_region (current_buffer, start1, end2);
2251
2252#ifdef USE_TEXT_PROPERTIES
2253 tmp_interval1 = copy_intervals (cur_intv, start1, len1);
2254 tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
2255 tmp_interval2 = copy_intervals (cur_intv, start2, len2);
2256 Fset_text_properties (start1, end2, Qnil, Qnil);
2257#endif /* USE_TEXT_PROPERTIES */
2258
3c6bc7d0
RS
2259 /* holds region 1 */
2260 if (len1 > 20000)
2261 temp = (unsigned char *) xmalloc (len1);
2262 else
2263 temp = (unsigned char *) alloca (len1);
03240d11
KH
2264 start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1);
2265 start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2);
3c6bc7d0 2266 bcopy (start1_addr, temp, len1);
b229b8d1 2267 bcopy (start2_addr, start1_addr, len2);
3c6bc7d0
RS
2268 bcopy (start1_addr + len1, start1_addr + len2, len_mid);
2269 bcopy (temp, start1_addr + len2 + len_mid, len1);
2270 if (len1 > 20000)
2271 free (temp);
b229b8d1
RS
2272#ifdef USE_TEXT_PROPERTIES
2273 graft_intervals_into_buffer (tmp_interval1, end2 - len1,
2274 len1, current_buffer, 0);
2275 graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
2276 len_mid, current_buffer, 0);
2277 graft_intervals_into_buffer (tmp_interval2, start1,
2278 len2, current_buffer, 0);
2279#endif /* USE_TEXT_PROPERTIES */
2280 }
2281 }
2282
2283 /* todo: this will be slow, because for every transposition, we
2284 traverse the whole friggin marker list. Possible solutions:
2285 somehow get a list of *all* the markers across multiple
2286 transpositions and do it all in one swell phoop. Or maybe modify
2287 Emacs' marker code to keep an ordered list or tree. This might
2288 be nicer, and more beneficial in the long run, but would be a
2289 bunch of work. Plus the way they're arranged now is nice. */
2290 if (NILP (leave_markers))
8de1d5f0
KH
2291 {
2292 transpose_markers (start1, end1, start2, end2);
2293 fix_overlays_in_range (start1, end2);
2294 }
b229b8d1
RS
2295
2296 return Qnil;
2297}
35692fe0 2298
35692fe0
JB
2299\f
2300void
2301syms_of_editfns ()
2302{
f43754f6
KH
2303 DEFVAR_LISP ("system-name", &Vsystem_name,
2304 "The name of the machine Emacs is running on.");
2305
2306 DEFVAR_LISP ("user-full-name", &Vuser_full_name,
2307 "The full name of the user logged in.");
2308
35b34f72 2309 DEFVAR_LISP ("user-login-name", &Vuser_login_name,
f43754f6
KH
2310 "The user's name, taken from environment variables if possible.");
2311
35b34f72 2312 DEFVAR_LISP ("user-real-login-name", &Vuser_real_login_name,
f43754f6 2313 "The user's name, based upon the real uid only.");
35692fe0
JB
2314
2315 defsubr (&Schar_equal);
2316 defsubr (&Sgoto_char);
2317 defsubr (&Sstring_to_char);
2318 defsubr (&Schar_to_string);
2319 defsubr (&Sbuffer_substring);
2320 defsubr (&Sbuffer_string);
2321
2322 defsubr (&Spoint_marker);
2323 defsubr (&Smark_marker);
2324 defsubr (&Spoint);
2325 defsubr (&Sregion_beginning);
2326 defsubr (&Sregion_end);
2327/* defsubr (&Smark); */
2328/* defsubr (&Sset_mark); */
2329 defsubr (&Ssave_excursion);
2330
2331 defsubr (&Sbufsize);
2332 defsubr (&Spoint_max);
2333 defsubr (&Spoint_min);
2334 defsubr (&Spoint_min_marker);
2335 defsubr (&Spoint_max_marker);
2336
2337 defsubr (&Sbobp);
2338 defsubr (&Seobp);
2339 defsubr (&Sbolp);
2340 defsubr (&Seolp);
850a8179
JB
2341 defsubr (&Sfollowing_char);
2342 defsubr (&Sprevious_char);
35692fe0
JB
2343 defsubr (&Schar_after);
2344 defsubr (&Sinsert);
2345 defsubr (&Sinsert_before_markers);
be91036a
RS
2346 defsubr (&Sinsert_and_inherit);
2347 defsubr (&Sinsert_and_inherit_before_markers);
35692fe0
JB
2348 defsubr (&Sinsert_char);
2349
2350 defsubr (&Suser_login_name);
2351 defsubr (&Suser_real_login_name);
2352 defsubr (&Suser_uid);
2353 defsubr (&Suser_real_uid);
2354 defsubr (&Suser_full_name);
7fd233b3 2355 defsubr (&Semacs_pid);
d940e0e4 2356 defsubr (&Scurrent_time);
a82d387c 2357 defsubr (&Sformat_time_string);
4691c06d 2358 defsubr (&Sdecode_time);
cce7b8a0 2359 defsubr (&Sencode_time);
35692fe0 2360 defsubr (&Scurrent_time_string);
c2662aea 2361 defsubr (&Scurrent_time_zone);
143cb9a9 2362 defsubr (&Sset_time_zone_rule);
35692fe0 2363 defsubr (&Ssystem_name);
35692fe0 2364 defsubr (&Smessage);
cacc3e2c
RS
2365 defsubr (&Smessage_box);
2366 defsubr (&Smessage_or_box);
35692fe0 2367 defsubr (&Sformat);
35692fe0
JB
2368
2369 defsubr (&Sinsert_buffer_substring);
e9cf2084 2370 defsubr (&Scompare_buffer_substrings);
35692fe0
JB
2371 defsubr (&Ssubst_char_in_region);
2372 defsubr (&Stranslate_region);
2373 defsubr (&Sdelete_region);
2374 defsubr (&Swiden);
2375 defsubr (&Snarrow_to_region);
2376 defsubr (&Ssave_restriction);
b229b8d1 2377 defsubr (&Stranspose_regions);
35692fe0 2378}