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