comparison src/editfns.c @ 771:943eaba38521

[xemacs-hg @ 2002-03-13 08:51:24 by ben] The big ben-mule-21-5 check-in! Various files were added and deleted. See CHANGES-ben-mule. There are still some test suite failures. No crashes, though. Many of the failures have to do with problems in the test suite itself rather than in the actual code. I'll be addressing these in the next day or so -- none of the test suite failures are at all critical. Meanwhile I'll be trying to address the biggest issues -- i.e. build or run failures, which will almost certainly happen on various platforms. All comments should be sent to ben@xemacs.org -- use a Cc: if necessary when sending to mailing lists. There will be pre- and post- tags, something like pre-ben-mule-21-5-merge-in, and post-ben-mule-21-5-merge-in.
author ben
date Wed, 13 Mar 2002 08:54:06 +0000
parents a307f9a2021d
children e38acbeb1cae
comparison
equal deleted inserted replaced
770:336a418893b5 771:943eaba38521
1 /* Lisp functions pertaining to editing. 1 /* Lisp functions pertaining to editing.
2 Copyright (C) 1985-1987, 1989, 1992-1995 Free Software Foundation, Inc. 2 Copyright (C) 1985-1987, 1989, 1992-1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. 3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
4 Copyright (C) 1996 Ben Wing. 4 Copyright (C) 1996, 2001, 2002 Ben Wing.
5 5
6 This file is part of XEmacs. 6 This file is part of XEmacs.
7 7
8 XEmacs is free software; you can redistribute it and/or modify it 8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the 9 under the terms of the GNU General Public License as published by the
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */ 21 Boston, MA 02111-1307, USA. */
22 22
23 /* Synched up with: Mule 2.0, FSF 19.30. */ 23 /* Synched up with: Mule 2.0, FSF 19.30. */
24 24
25 /* This file has been Mule-ized. */ 25 /* This file has been Mule-ized, June 2001. */
26 26
27 /* Hacked on for Mule by Ben Wing, December 1994. */ 27 /* Hacked on for Mule by Ben Wing, December 1994. */
28 28
29 #include <config.h> 29 #include <config.h>
30 #include "lisp.h" 30 #include "lisp.h"
41 #include "line-number.h" 41 #include "line-number.h"
42 42
43 #include "systime.h" 43 #include "systime.h"
44 #include "sysdep.h" 44 #include "sysdep.h"
45 #include "syspwd.h" 45 #include "syspwd.h"
46 #include "sysfile.h" /* for getcwd */ 46 #include "sysproc.h" /* for qxe_getpid() */
47 #include "sysfile.h"
48 #include "sysdir.h"
47 49
48 /* Some static data, and a function to initialize it for each run */ 50 /* Some static data, and a function to initialize it for each run */
49 51
50 Lisp_Object Vsystem_name; /* #### - I don't see why this should be */ 52 Lisp_Object Vsystem_name; /* #### - I don't see why this should be */
51 /* static, either... --Stig */ 53 /* static, either... --Stig */
71 Lisp_Object Quser_files_and_directories; 73 Lisp_Object Quser_files_and_directories;
72 74
73 /* This holds the value of `environ' produced by the previous 75 /* This holds the value of `environ' produced by the previous
74 call to Fset_time_zone_rule, or 0 if Fset_time_zone_rule 76 call to Fset_time_zone_rule, or 0 if Fset_time_zone_rule
75 has never been called. */ 77 has never been called. */
76 static char **environbuf; 78 static Extbyte **environbuf;
77 79
78 void 80 void
79 init_editfns (void) 81 init_editfns (void)
80 { 82 {
81 /* Only used in removed code below. */ 83 /* Only used in removed code below. */
82 char *p; 84 Intbyte *p;
83 85
84 environbuf = 0; 86 environbuf = 0;
85 87
86 /* Set up system_name even when dumping. */ 88 /* Set up system_name even when dumping. */
87 init_system_name (); 89 init_system_name ();
89 #ifndef CANNOT_DUMP 91 #ifndef CANNOT_DUMP
90 if (!initialized) 92 if (!initialized)
91 return; 93 return;
92 #endif 94 #endif
93 95
94 if ((p = getenv ("NAME"))) 96 if ((p = egetenv ("NAME")))
95 /* I don't think it's the right thing to do the ampersand 97 /* I don't think it's the right thing to do the ampersand
96 modification on NAME. Not that it matters anymore... -hniksic */ 98 modification on NAME. Not that it matters anymore... -hniksic */
97 Vuser_full_name = build_ext_string (p, Qnative); 99 Vuser_full_name = build_intstring (p);
98 else 100 else
99 Vuser_full_name = Fuser_full_name (Qnil); 101 Vuser_full_name = Fuser_full_name (Qnil);
100 } 102 }
101 103
102 DEFUN ("char-to-string", Fchar_to_string, 1, 1, 0, /* 104 DEFUN ("char-to-string", Fchar_to_string, 1, 1, 0, /*
395 /* This function can GC */ 397 /* This function can GC */
396 int speccount = specpdl_depth (); 398 int speccount = specpdl_depth ();
397 399
398 record_unwind_protect (save_excursion_restore, save_excursion_save ()); 400 record_unwind_protect (save_excursion_restore, save_excursion_save ());
399 401
400 return unbind_to (speccount, Fprogn (args)); 402 return unbind_to_1 (speccount, Fprogn (args));
401 } 403 }
402 404
403 Lisp_Object 405 Lisp_Object
404 save_current_buffer_restore (Lisp_Object buffer) 406 save_current_buffer_restore (Lisp_Object buffer)
405 { 407 {
420 /* This function can GC */ 422 /* This function can GC */
421 int speccount = specpdl_depth (); 423 int speccount = specpdl_depth ();
422 424
423 record_unwind_protect (save_current_buffer_restore, Fcurrent_buffer ()); 425 record_unwind_protect (save_current_buffer_restore, Fcurrent_buffer ());
424 426
425 return unbind_to (speccount, Fprogn (args)); 427 return unbind_to_1 (speccount, Fprogn (args));
426 } 428 }
427 429
428 DEFUN ("buffer-size", Fbuffer_size, 0, 1, 0, /* 430 DEFUN ("buffer-size", Fbuffer_size, 0, 1, 0, /*
429 Return the number of characters in BUFFER. 431 Return the number of characters in BUFFER.
430 If BUFFER is nil, the current buffer is assumed. 432 If BUFFER is nil, the current buffer is assumed.
454 If BUFFER is nil, the current buffer is assumed. 456 If BUFFER is nil, the current buffer is assumed.
455 */ 457 */
456 (buffer)) 458 (buffer))
457 { 459 {
458 struct buffer *b = decode_buffer (buffer, 1); 460 struct buffer *b = decode_buffer (buffer, 1);
459 return buildmark (BUF_BEGV (b), make_buffer (b)); 461 return buildmark (BUF_BEGV (b), wrap_buffer (b));
460 } 462 }
461 463
462 DEFUN ("point-max", Fpoint_max, 0, 1, 0, /* 464 DEFUN ("point-max", Fpoint_max, 0, 1, 0, /*
463 Return the maximum permissible value of point in BUFFER. 465 Return the maximum permissible value of point in BUFFER.
464 This is (1+ (buffer-size)), unless narrowing (a buffer restriction) 466 This is (1+ (buffer-size)), unless narrowing (a buffer restriction)
478 If BUFFER is nil, the current buffer is assumed. 480 If BUFFER is nil, the current buffer is assumed.
479 */ 481 */
480 (buffer)) 482 (buffer))
481 { 483 {
482 struct buffer *b = decode_buffer (buffer, 1); 484 struct buffer *b = decode_buffer (buffer, 1);
483 return buildmark (BUF_ZV (b), make_buffer (b)); 485 return buildmark (BUF_ZV (b), wrap_buffer (b));
484 } 486 }
485 487
486 DEFUN ("following-char", Ffollowing_char, 0, 1, 0, /* 488 DEFUN ("following-char", Ffollowing_char, 0, 1, 0, /*
487 Return the character following point. 489 Return the character following point.
488 At the end of the buffer or accessible region, return 0. 490 At the end of the buffer or accessible region, return 0.
598 if (n < BUF_BEGV (b)) 600 if (n < BUF_BEGV (b))
599 return Qnil; 601 return Qnil;
600 return make_char (BUF_FETCH_CHAR (b, n)); 602 return make_char (BUF_FETCH_CHAR (b, n));
601 } 603 }
602 604
603 #if !defined(WINDOWSNT) && !defined(MSDOS)
604 #include <sys/stat.h>
605 #include <fcntl.h>
606 #include <errno.h>
607 #include <limits.h>
608 #endif
609 605
610 DEFUN ("temp-directory", Ftemp_directory, 0, 0, 0, /* 606 DEFUN ("temp-directory", Ftemp_directory, 0, 0, 0, /*
611 Return the pathname to the directory to use for temporary files. 607 Return the pathname to the directory to use for temporary files.
612 On MS Windows, this is obtained from the TEMP or TMP environment variables, 608 On MS Windows, this is obtained from the TEMP or TMP environment variables,
613 defaulting to / if they are both undefined. 609 defaulting to c:\\ if they are both undefined.
614 On Unix it is obtained from TMPDIR, with /tmp as the default. 610 On Unix it is obtained from TMPDIR, with /tmp as the default.
615 */ 611 */
616 ()) 612 ())
617 { 613 {
618 char *tmpdir; 614 Intbyte *tmpdir;
619 #if defined(WIN32_NATIVE) 615 #if defined(WIN32_NATIVE)
620 tmpdir = getenv ("TEMP"); 616 tmpdir = egetenv ("TEMP");
621 if (!tmpdir) 617 if (!tmpdir)
622 tmpdir = getenv ("TMP"); 618 tmpdir = egetenv ("TMP");
623 if (!tmpdir) 619 if (!tmpdir)
624 tmpdir = "/"; 620 tmpdir = (Intbyte *) "c:\\";
625 #else /* WIN32_NATIVE */ 621 #else /* WIN32_NATIVE */
626 tmpdir = getenv ("TMPDIR"); 622 tmpdir = egetenv ("TMPDIR");
627 if (!tmpdir) 623 if (!tmpdir)
628 { 624 {
629 struct stat st; 625 struct stat st;
630 int myuid = getuid(); 626 int myuid = getuid ();
631 static char path[5 /* strlen ("/tmp/") */ + 1 + _POSIX_PATH_MAX]; 627 Intbyte *login_name = user_login_name (NULL);
632 628 DECLARE_EISTRING (eipath);
633 strcpy (path, "/tmp/"); 629 Intbyte *path;
634 strncat (path, user_login_name (NULL), _POSIX_PATH_MAX); 630
635 if (lstat(path, &st) < 0 && errno == ENOENT) 631 eicpy_c (eipath, "/tmp/");
636 { 632 eicat_rawz (eipath, login_name);
637 mkdir(path, 0700); /* ignore retval -- checked next anyway. */ 633 path = eidata (eipath);
638 } 634 if (qxe_lstat (path, &st) < 0 && errno == ENOENT)
639 if (lstat(path, &st) == 0 && st.st_uid == (uid_t) myuid && 635 qxe_mkdir (path, 0700); /* ignore retval -- checked next anyway. */
640 S_ISDIR(st.st_mode)) 636 if (qxe_lstat (path, &st) == 0 && (int) st.st_uid == myuid
641 { 637 && S_ISDIR (st.st_mode))
642 tmpdir = path; 638 tmpdir = path;
643 }
644 else 639 else
645 { 640 {
646 strcpy(path, getenv("HOME")); strncat(path, "/tmp/", _POSIX_PATH_MAX); 641 eicpy_rawz (eipath, egetenv ("HOME"));
647 if (stat(path, &st) < 0 && errno == ENOENT) 642 eicat_c (eipath, "/tmp/");
643 path = eidata (eipath);
644 if (qxe_stat (path, &st) < 0 && errno == ENOENT)
648 { 645 {
649 int fd; 646 int fd;
650 char warnpath[1+_POSIX_PATH_MAX]; 647 DECLARE_EISTRING (eiwarnpath);
651 mkdir(path, 0700); /* ignore retvals */ 648
652 strcpy(warnpath, path); 649 qxe_mkdir (path, 0700); /* ignore retvals */
653 strncat(warnpath, ".created_by_xemacs", _POSIX_PATH_MAX); 650 eicpy_ei (eiwarnpath, eipath);
654 if ((fd = open(warnpath, O_WRONLY|O_CREAT, 0644)) > 0) 651 eicat_c (eiwarnpath, ".created_by_xemacs");
652 if ((fd = qxe_open (eidata (eiwarnpath),
653 O_WRONLY | O_CREAT, 0644)) > 0)
655 { 654 {
656 write(fd, "XEmacs created this directory because /tmp/<yourname> was unavailable -- \nPlease check !\n", 89); 655 retry_write (fd, "XEmacs created this directory because "
657 close(fd); 656 "/tmp/<yourname> was unavailable -- \n"
657 "Please check !\n", 89);
658 retry_close (fd);
658 } 659 }
659 } 660 }
660 if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) 661 if (qxe_stat (path, &st) == 0 && S_ISDIR (st.st_mode))
661 { 662 tmpdir = path;
662 tmpdir = path;
663 }
664 else 663 else
665 { 664 tmpdir = (Intbyte *) "/tmp";
666 tmpdir = "/tmp";
667 }
668 } 665 }
669 } 666 }
670 #endif 667 #endif
671 668
672 return build_ext_string (tmpdir, Qfile_name); 669 return build_intstring (tmpdir);
673 } 670 }
674 671
675 DEFUN ("user-login-name", Fuser_login_name, 0, 1, 0, /* 672 DEFUN ("user-login-name", Fuser_login_name, 0, 1, 0, /*
676 Return the name under which the user logged in, as a string. 673 Return the name under which the user logged in, as a string.
677 This is based on the effective uid, not the real uid. 674 This is based on the effective uid, not the real uid.
680 If the optional argument UID is present, then environment variables are 677 If the optional argument UID is present, then environment variables are
681 ignored and this function returns the login name for that UID, or nil. 678 ignored and this function returns the login name for that UID, or nil.
682 */ 679 */
683 (uid)) 680 (uid))
684 { 681 {
685 char *returned_name; 682 Intbyte *returned_name;
686 uid_t local_uid; 683 uid_t local_uid;
687 684
688 if (!NILP (uid)) 685 if (!NILP (uid))
689 { 686 {
690 CHECK_INT (uid); 687 CHECK_INT (uid);
696 returned_name = user_login_name (NULL); 693 returned_name = user_login_name (NULL);
697 } 694 }
698 /* #### - I believe this should return nil instead of "unknown" when pw==0 695 /* #### - I believe this should return nil instead of "unknown" when pw==0
699 pw=0 is indicated by a null return from user_login_name 696 pw=0 is indicated by a null return from user_login_name
700 */ 697 */
701 return returned_name ? build_string (returned_name) : Qnil; 698 return returned_name ? build_intstring (returned_name) : Qnil;
702 } 699 }
703 700
704 /* This function may be called from other C routines when a 701 /* This function may be called from other C routines when a
705 character string representation of the user_login_name is 702 character string representation of the user_login_name is
706 needed but a Lisp Object is not. The UID is passed by 703 needed but a Lisp Object is not. The UID is passed by
707 reference. If UID == NULL, then the USER name 704 reference. If UID == NULL, then the USER name
708 for the user running XEmacs will be returned. This 705 for the user running XEmacs will be returned. This
709 corresponds to a nil argument to Fuser_login_name. 706 corresponds to a nil argument to Fuser_login_name.
710 */ 707
711 char* 708 WARNING: The string returned comes from the data of a Lisp_String and
709 therefore will become garbage after the next GC.
710 */
711 Intbyte *
712 user_login_name (uid_t *uid) 712 user_login_name (uid_t *uid)
713 { 713 {
714 /* uid == NULL to return name of this user */ 714 /* uid == NULL to return name of this user */
715 if (uid != NULL) 715 if (uid != NULL)
716 { 716 {
717 struct passwd *pw = getpwuid (*uid); 717 struct passwd *pw = qxe_getpwuid (*uid);
718 return pw ? pw->pw_name : NULL; 718 return pw ? (Intbyte *) pw->pw_name : NULL;
719 } 719 }
720 else 720 else
721 { 721 {
722 /* #### - when euid != uid, then LOGNAME and USER are leftovers from the 722 /* #### - when euid != uid, then LOGNAME and USER are leftovers from the
723 old environment (I site observed behavior on sunos and linux), so the 723 old environment (I site observed behavior on sunos and linux), so the
724 environment variables should be disregarded in that case. --Stig */ 724 environment variables should be disregarded in that case. --Stig */
725 char *user_name = getenv ("LOGNAME"); 725 Intbyte *user_name = egetenv ("LOGNAME");
726 if (!user_name) 726 if (!user_name)
727 user_name = getenv ( 727 user_name = egetenv (
728 #ifdef WIN32_NATIVE 728 #ifdef WIN32_NATIVE
729 "USERNAME" /* it's USERNAME on NT */ 729 "USERNAME" /* it's USERNAME on NT */
730 #else 730 #else
731 "USER" 731 "USER"
732 #endif 732 #endif
733 ); 733 );
734 if (user_name) 734 if (user_name)
735 return (user_name); 735 return user_name;
736 else 736 else
737 { 737 {
738 struct passwd *pw = getpwuid (geteuid ()); 738 struct passwd *pw = qxe_getpwuid (geteuid ());
739 #ifdef CYGWIN 739 #ifdef CYGWIN
740 /* Since the Cygwin environment may not have an /etc/passwd, 740 /* Since the Cygwin environment may not have an /etc/passwd,
741 return "unknown" instead of the null if the username 741 return "unknown" instead of the null if the username
742 cannot be determined. 742 cannot be determined.
743 */ 743 */
744 /* !!#### fix up in my mule ws */ 744 /* !!#### fix up in my mule ws */
745 return pw ? pw->pw_name : (char *) "unknown"; 745 return (Intbyte *) (pw ? pw->pw_name : "unknown");
746 #else 746 #else
747 /* For all but Cygwin return NULL (nil) */ 747 /* For all but Cygwin return NULL (nil) */
748 return pw ? pw->pw_name : NULL; 748 return pw ? pw->pw_name : NULL;
749 #endif 749 #endif
750 } 750 }
756 This ignores the environment variables LOGNAME and USER, so it differs from 756 This ignores the environment variables LOGNAME and USER, so it differs from
757 `user-login-name' when running under `su'. 757 `user-login-name' when running under `su'.
758 */ 758 */
759 ()) 759 ())
760 { 760 {
761 struct passwd *pw = getpwuid (getuid ()); 761 struct passwd *pw = qxe_getpwuid (getuid ());
762 /* #### - I believe this should return nil instead of "unknown" when pw==0 */ 762 /* #### - I believe this should return nil instead of "unknown" when pw==0 */
763 763
764 Lisp_Object tem = build_string (pw ? pw->pw_name : "unknown");/* no gettext */ 764 Lisp_Object tem = build_string (pw ? pw->pw_name : "unknown");
765 return tem; 765 return tem;
766 } 766 }
767 767
768 DEFUN ("user-uid", Fuser_uid, 0, 0, 0, /* 768 DEFUN ("user-uid", Fuser_uid, 0, 0, 0, /*
769 Return the effective uid of Emacs, as an integer. 769 Return the effective uid of Emacs, as an integer.
792 (user)) 792 (user))
793 { 793 {
794 Lisp_Object user_name; 794 Lisp_Object user_name;
795 struct passwd *pw = NULL; 795 struct passwd *pw = NULL;
796 Lisp_Object tem; 796 Lisp_Object tem;
797 const char *p, *q; 797 const Intbyte *p, *q;
798 798
799 if (NILP (user) && STRINGP (Vuser_full_name)) 799 if (NILP (user) && STRINGP (Vuser_full_name))
800 return Vuser_full_name; 800 return Vuser_full_name;
801 801
802 user_name = (STRINGP (user) ? user : Fuser_login_name (user)); 802 user_name = (STRINGP (user) ? user : Fuser_login_name (user));
803 if (!NILP (user_name)) /* nil when nonexistent UID passed as arg */ 803 if (!NILP (user_name)) /* nil when nonexistent UID passed as arg */
804 { 804 {
805 const char *user_name_ext;
806
807 /* Fuck me. getpwnam() can call select() and (under IRIX at least) 805 /* Fuck me. getpwnam() can call select() and (under IRIX at least)
808 things get wedged if a SIGIO arrives during this time. */ 806 things get wedged if a SIGIO arrives during this time. */
809 TO_EXTERNAL_FORMAT (LISP_STRING, user_name,
810 C_STRING_ALLOCA, user_name_ext,
811 Qnative);
812 slow_down_interrupts (); 807 slow_down_interrupts ();
813 pw = (struct passwd *) getpwnam (user_name_ext); 808 pw = qxe_getpwnam (XSTRING_DATA (user_name));
814 speed_up_interrupts (); 809 speed_up_interrupts ();
815 } 810 }
816 811
817 /* #### - Stig sez: this should return nil instead of "unknown" when pw==0 */ 812 /* #### - Stig sez: this should return nil instead of "unknown" when pw==0 */
818 /* Ben sez: bad idea because it's likely to break something */ 813 /* Ben sez: bad idea because it's likely to break something */
819 #ifndef AMPERSAND_FULL_NAME 814 #ifndef AMPERSAND_FULL_NAME
820 p = pw ? USER_FULL_NAME : "unknown"; /* don't gettext */ 815 p = (Intbyte *) (pw ? USER_FULL_NAME : "unknown"); /* don't gettext */
821 q = strchr (p, ','); 816 q = qxestrchr (p, ',');
822 #else 817 #else
823 p = pw ? USER_FULL_NAME : "unknown"; /* don't gettext */ 818 p = (Intbyte *) (pw ? USER_FULL_NAME : "unknown"); /* don't gettext */
824 q = strchr (p, ','); 819 q = qxestrchr (p, ',');
825 #endif 820 #endif
826 tem = ((!NILP (user) && !pw) 821 tem = ((!NILP (user) && !pw)
827 ? Qnil 822 ? Qnil
828 : make_ext_string ((Extbyte *) p, (q ? q - p : (int) strlen (p)), 823 : make_string (p, (q ? q - p : qxestrlen (p))));
829 Qnative));
830 824
831 #ifdef AMPERSAND_FULL_NAME 825 #ifdef AMPERSAND_FULL_NAME
832 if (!NILP (tem)) 826 if (!NILP (tem))
833 { 827 {
834 p = (char *) XSTRING_DATA (tem); 828 p = XSTRING_DATA (tem);
835 q = strchr (p, '&'); 829 q = qxestrchr (p, '&');
836 /* Substitute the login name for the &, upcasing the first character. */ 830 /* Substitute the login name for the &, upcasing the first character. */
837 if (q) 831 if (q)
838 { 832 {
839 char *r = (char *) alloca (strlen (p) + XSTRING_LENGTH (user_name) + 1); 833 DECLARE_EISTRING (r);
840 memcpy (r, p, q - p); 834 eicpy_raw (r, p, q - p);
841 r[q - p] = 0; 835 eicat_lstr (r, user_name);
842 strcat (r, (char *) XSTRING_DATA (user_name)); 836 eisetch (r, q - p, UPCASE (0, eigetch (r, q - p)));
843 /* #### current_buffer dependency! */ 837 eicat_rawz (r, q + 1);
844 r[q - p] = UPCASE (current_buffer, r[q - p]); 838 tem = eimake_string (r);
845 strcat (r, q + 1);
846 tem = build_string (r);
847 } 839 }
848 } 840 }
849 #endif /* AMPERSAND_FULL_NAME */ 841 #endif /* AMPERSAND_FULL_NAME */
850 842
851 return tem; 843 return tem;
852 } 844 }
853 845
854 static Extbyte *cached_home_directory; 846 static Intbyte *cached_home_directory;
855 847
856 void 848 void
857 uncache_home_directory (void) 849 uncache_home_directory (void)
858 { 850 {
859 cached_home_directory = NULL; /* in some cases, this may cause the leaking 851 if (cached_home_directory)
860 of a few bytes */ 852 xfree (cached_home_directory);
861 } 853 cached_home_directory = NULL;
862 854 }
863 /* !!#### not Mule correct. */ 855
864 856 /* Returns the home directory */
865 /* Returns the home directory, in external format */ 857 Intbyte *
866 Extbyte *
867 get_home_directory (void) 858 get_home_directory (void)
868 { 859 {
869 /* !!#### this is hopelessly bogus. Rule #1: Do not make any assumptions
870 about what format an external string is in. Could be Unicode, for all
871 we know, and then all the operations below are totally bogus.
872 Instead, convert all data to internal format *right* at the juncture
873 between XEmacs and the outside world, the very moment we first get
874 the data. --ben */
875 int output_home_warning = 0; 860 int output_home_warning = 0;
876 861
877 if (cached_home_directory == NULL) 862 if (cached_home_directory == NULL)
878 { 863 {
879 if ((cached_home_directory = (Extbyte *) getenv("HOME")) == NULL) 864 cached_home_directory = egetenv ("HOME");
865 if (cached_home_directory)
866 cached_home_directory = qxestrdup (cached_home_directory);
867 else
880 { 868 {
881 #if defined(WIN32_NATIVE) 869 #if defined (WIN32_NATIVE)
882 char *homedrive, *homepath; 870 Intbyte *homedrive, *homepath;
883 871
884 if ((homedrive = getenv("HOMEDRIVE")) != NULL && 872 if ((homedrive = egetenv ("HOMEDRIVE")) != NULL &&
885 (homepath = getenv("HOMEPATH")) != NULL) 873 (homepath = egetenv ("HOMEPATH")) != NULL)
886 { 874 {
887 cached_home_directory = 875 cached_home_directory =
888 (Extbyte *) xmalloc (strlen (homedrive) + 876 (Intbyte *) xmalloc (qxestrlen (homedrive) +
889 strlen (homepath) + 1); 877 qxestrlen (homepath) + 1);
890 sprintf((char *) cached_home_directory, "%s%s", 878 qxesprintf (cached_home_directory, "%s%s",
891 homedrive, 879 homedrive,
892 homepath); 880 homepath);
893 } 881 }
894 else 882 else
895 { 883 {
896 # if 0 /* changed by ben. This behavior absolutely stinks, and the 884 cached_home_directory = qxestrdup ((Intbyte *) "C:\\");
897 possibility being addressed here occurs quite commonly.
898 Using the current directory makes absolutely no sense. */
899 /*
900 * Use the current directory.
901 * This preserves the existing XEmacs behavior, but is different
902 * from NT Emacs.
903 */
904 if (initial_directory[0] != '\0')
905 {
906 cached_home_directory = (Extbyte*) initial_directory;
907 }
908 else
909 {
910 /* This will probably give the wrong value */
911 cached_home_directory = (Extbyte*) getcwd (NULL, 0);
912 }
913 # else
914 /*
915 * This is NT Emacs behavior
916 */
917 cached_home_directory = (Extbyte *) "C:\\";
918 output_home_warning = 1; 885 output_home_warning = 1;
919 # endif
920 } 886 }
921 #else /* !WIN32_NATIVE */ 887 #else /* !WIN32_NATIVE */
922 /* 888 /*
923 * Unix, typically. 889 * Unix, typically.
924 * Using "/" isn't quite right, but what should we do? 890 * Using "/" isn't quite right, but what should we do?
925 * We probably should try to extract pw_dir from /etc/passwd, 891 * We probably should try to extract pw_dir from /etc/passwd,
926 * before falling back to this. 892 * before falling back to this.
927 */ 893 */
928 cached_home_directory = (Extbyte *) "/"; 894 cached_home_directory = qxestrdup ((Intbyte *) "/");
929 output_home_warning = 1; 895 output_home_warning = 1;
930 #endif /* !WIN32_NATIVE */ 896 #endif /* !WIN32_NATIVE */
931 } 897 }
932 if (initialized && output_home_warning) 898 if (initialized && output_home_warning)
933 { 899 {
946 DEFUN ("user-home-directory", Fuser_home_directory, 0, 0, 0, /* 912 DEFUN ("user-home-directory", Fuser_home_directory, 0, 0, 0, /*
947 Return the user's home directory, as a string. 913 Return the user's home directory, as a string.
948 */ 914 */
949 ()) 915 ())
950 { 916 {
951 Extbyte *path = get_home_directory (); 917 Intbyte *path = get_home_directory ();
952 918
953 return path == NULL ? Qnil : 919 return !path ? Qnil :
954 Fexpand_file_name (Fsubstitute_in_file_name 920 Fexpand_file_name (Fsubstitute_in_file_name (build_intstring (path)),
955 (build_ext_string ((char *) path, Qfile_name)),
956 Qnil); 921 Qnil);
957 } 922 }
958 923
959 DEFUN ("system-name", Fsystem_name, 0, 0, 0, /* 924 DEFUN ("system-name", Fsystem_name, 0, 0, 0, /*
960 Return the name of the machine you are running on, as a string. 925 Return the name of the machine you are running on, as a string.
961 */ 926 */
962 ()) 927 ())
963 { 928 {
964 return Fcopy_sequence (Vsystem_name); 929 return Fcopy_sequence (Vsystem_name);
965 } 930 }
966 931
967 DEFUN ("emacs-pid", Femacs_pid, 0, 0, 0, /* 932 DEFUN ("emacs-pid", Femacs_pid, 0, 0, 0, /*
968 Return the process ID of Emacs, as an integer. 933 Return the process ID of Emacs, as an integer.
969 */ 934 */
970 ()) 935 ())
971 { 936 {
972 return make_int (getpid ()); 937 return make_int (qxe_getpid ());
973 } 938 }
974 939
975 DEFUN ("current-time", Fcurrent_time, 0, 0, 0, /* 940 DEFUN ("current-time", Fcurrent_time, 0, 0, 0, /*
976 Return the current time, as the number of seconds since 1970-01-01 00:00:00. 941 Return the current time, as the number of seconds since 1970-01-01 00:00:00.
977 The time is returned as a list of three integers. The first has the 942 The time is returned as a list of three integers. The first has the
1050 { 1015 {
1051 unsigned int item = (unsigned int) the_time; 1016 unsigned int item = (unsigned int) the_time;
1052 return Fcons (make_int (item >> 16), make_int (item & 0xffff)); 1017 return Fcons (make_int (item >> 16), make_int (item & 0xffff));
1053 } 1018 }
1054 1019
1055 size_t emacs_strftime (char *string, size_t max, const char *format, 1020 size_t emacs_strftime (Extbyte *string, size_t max, const Extbyte *format,
1056 const struct tm *tm); 1021 const struct tm *tm);
1057 static long difftm (const struct tm *a, const struct tm *b); 1022 static long difftm (const struct tm *a, const struct tm *b);
1058 1023
1059 1024
1060 DEFUN ("format-time-string", Fformat_time_string, 1, 2, 0, /* 1025 DEFUN ("format-time-string", Fformat_time_string, 1, 2, 0, /*
1116 /* This is probably enough. */ 1081 /* This is probably enough. */
1117 size = XSTRING_LENGTH (format_string) * 6 + 50; 1082 size = XSTRING_LENGTH (format_string) * 6 + 50;
1118 1083
1119 while (1) 1084 while (1)
1120 { 1085 {
1121 char *buf = (char *) alloca (size); 1086 Extbyte *buf = (Extbyte *) alloca (size);
1087 Extbyte *formext;
1122 *buf = 1; 1088 *buf = 1;
1123 if (emacs_strftime (buf, size, 1089
1124 (const char *) XSTRING_DATA (format_string), 1090 /* !!#### this use of external here is not totally safe, and
1091 potentially data lossy. */
1092 LISP_STRING_TO_EXTERNAL (format_string, formext, Qnative);
1093 if (emacs_strftime (buf, size, formext,
1125 localtime (&value)) 1094 localtime (&value))
1126 || !*buf) 1095 || !*buf)
1127 return build_ext_string (buf, Qbinary); 1096 return build_ext_string (buf, Qnative);
1128 /* If buffer was too small, make it bigger. */ 1097 /* If buffer was too small, make it bigger. */
1129 size *= 2; 1098 size *= 2;
1130 } 1099 }
1131 } 1100 }
1132 1101
1172 else 1141 else
1173 list_args[8] = make_int (difftm (&save_tm, decoded_time)); 1142 list_args[8] = make_int (difftm (&save_tm, decoded_time));
1174 return Flist (9, list_args); 1143 return Flist (9, list_args);
1175 } 1144 }
1176 1145
1177 static void set_time_zone_rule (char *tzstring); 1146 static void set_time_zone_rule (Extbyte *tzstring);
1178 1147
1179 /* from GNU Emacs 21, per Simon Josefsson, modified by stephen 1148 /* from GNU Emacs 21, per Simon Josefsson, modified by stephen
1180 The slight inefficiency is justified since negative times are weird. */ 1149 The slight inefficiency is justified since negative times are weird. */
1181 Lisp_Object 1150 Lisp_Object
1182 make_time (time_t time) 1151 make_time (time_t tiempo)
1183 { 1152 {
1184 return list2 (make_int (time < 0 ? time / 0x10000 : time >> 16), 1153 return list2 (make_int (tiempo < 0 ? tiempo / 0x10000 : tiempo >> 16),
1185 make_int (time & 0xFFFF)); 1154 make_int (tiempo & 0xFFFF));
1186 } 1155 }
1187 1156
1188 DEFUN ("encode-time", Fencode_time, 6, MANY, 0, /* 1157 DEFUN ("encode-time", Fencode_time, 6, MANY, 0, /*
1189 Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time. 1158 Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time.
1190 This is the reverse operation of `decode-time', which see. 1159 This is the reverse operation of `decode-time', which see.
1222 zone = XCAR (zone); 1191 zone = XCAR (zone);
1223 if (NILP (zone)) 1192 if (NILP (zone))
1224 the_time = mktime (&tm); 1193 the_time = mktime (&tm);
1225 else 1194 else
1226 { 1195 {
1227 char tzbuf[100]; 1196 /* #### This business of modifying environ is horrendous!
1228 char *tzstring; 1197 Why don't we just putenv()? Why don't we implement our own
1229 char **oldenv = environ, **newenv; 1198 funs that don't require this futzing? */
1199 Extbyte tzbuf[100];
1200 Extbyte *tzstring;
1201 Extbyte **oldenv = environ, **newenv;
1230 1202
1231 if (STRINGP (zone)) 1203 if (STRINGP (zone))
1232 tzstring = (char *) XSTRING_DATA (zone); 1204 LISP_STRING_TO_EXTERNAL (zone, tzstring, Qnative);
1233 else if (INTP (zone)) 1205 else if (INTP (zone))
1234 { 1206 {
1235 int abszone = abs (XINT (zone)); 1207 int abszone = abs (XINT (zone));
1236 sprintf (tzbuf, "XXX%s%d:%02d:%02d", "-" + (XINT (zone) < 0), 1208 sprintf (tzbuf, "XXX%s%d:%02d:%02d", "-" + (XINT (zone) < 0),
1237 abszone / (60*60), (abszone/60) % 60, abszone % 60); 1209 abszone / (60*60), (abszone/60) % 60, abszone % 60);
1238 tzstring = tzbuf; 1210 tzstring = tzbuf;
1239 } 1211 }
1240 else 1212 else
1241 invalid_argument ("Invalid time zone specification", Qunbound); 1213 invalid_argument ("Invalid time zone specification", Qunbound);
1242 1214
1243 /* Set TZ before calling mktime; merely adjusting mktime's returned 1215 /* Set TZ before calling mktime; merely adjusting mktime's returned
1244 value doesn't suffice, since that would mishandle leap seconds. */ 1216 value doesn't suffice, since that would mishandle leap seconds. */
1245 set_time_zone_rule (tzstring); 1217 set_time_zone_rule (tzstring);
1246 1218
1275 and from `file-attributes'. 1247 and from `file-attributes'.
1276 */ 1248 */
1277 (specified_time)) 1249 (specified_time))
1278 { 1250 {
1279 time_t value; 1251 time_t value;
1280 char *the_ctime; 1252 Intbyte *the_ctime;
1281 EMACS_INT len; /* this is what make_ext_string() accepts; #### 1253 EMACS_INT len; /* this is what make_ext_string() accepts; ####
1282 should it be an Bytecount? */ 1254 should it be an Bytecount? */
1283 1255
1284 if (! lisp_to_time (specified_time, &value)) 1256 if (! lisp_to_time (specified_time, &value))
1285 value = -1; 1257 value = -1;
1286 the_ctime = ctime (&value); 1258 the_ctime = qxe_ctime (&value);
1287 1259
1288 /* ctime is documented as always returning a "\n\0"-terminated 1260 /* ctime is documented as always returning a "\n\0"-terminated
1289 26-byte American time string, but let's be careful anyways. */ 1261 26-byte American time string, but let's be careful anyways. */
1290 for (len = 0; the_ctime[len] != '\n' && the_ctime[len] != '\0'; len++) 1262 for (len = 0; the_ctime[len] != '\n' && the_ctime[len] != '\0'; len++)
1291 ; 1263 ;
1292 1264
1293 return make_ext_string ((Extbyte *) the_ctime, len, Qbinary); 1265 return make_string (the_ctime, len);
1294 } 1266 }
1295 1267
1296 #define TM_YEAR_ORIGIN 1900 1268 #define TM_YEAR_ORIGIN 1900
1297 1269
1298 /* Yield A - B, measured in seconds. */ 1270 /* Yield A - B, measured in seconds. */
1343 if (lisp_to_time (specified_time, &value) 1315 if (lisp_to_time (specified_time, &value)
1344 && (t = gmtime (&value)) != 0) 1316 && (t = gmtime (&value)) != 0)
1345 { 1317 {
1346 struct tm gmt = *t; /* Make a copy, in case localtime modifies *t. */ 1318 struct tm gmt = *t; /* Make a copy, in case localtime modifies *t. */
1347 long offset; 1319 long offset;
1348 char *s, buf[6]; 1320 Extbyte *s;
1321 Lisp_Object tem;
1349 1322
1350 t = localtime (&value); 1323 t = localtime (&value);
1351 offset = difftm (t, &gmt); 1324 offset = difftm (t, &gmt);
1352 s = 0; 1325 s = 0;
1353 #ifdef HAVE_TM_ZONE 1326 #ifdef HAVE_TM_ZONE
1354 if (t->tm_zone) 1327 if (t->tm_zone)
1355 s = (char *)t->tm_zone; 1328 s = (Extbyte *) t->tm_zone;
1356 #else /* not HAVE_TM_ZONE */ 1329 #else /* not HAVE_TM_ZONE */
1357 #ifdef HAVE_TZNAME 1330 #ifdef HAVE_TZNAME
1358 if (t->tm_isdst == 0 || t->tm_isdst == 1) 1331 if (t->tm_isdst == 0 || t->tm_isdst == 1)
1359 s = tzname[t->tm_isdst]; 1332 s = tzname[t->tm_isdst];
1360 #endif 1333 #endif
1361 #endif /* not HAVE_TM_ZONE */ 1334 #endif /* not HAVE_TM_ZONE */
1362 if (!s) 1335 if (s)
1336 tem = build_ext_string (s, Qnative);
1337 else
1363 { 1338 {
1339 Intbyte buf[6];
1340
1364 /* No local time zone name is available; use "+-NNNN" instead. */ 1341 /* No local time zone name is available; use "+-NNNN" instead. */
1365 int am = (offset < 0 ? -offset : offset) / 60; 1342 int am = (offset < 0 ? -offset : offset) / 60;
1366 sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60); 1343 qxesprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60,
1367 s = buf; 1344 am%60);
1345 tem = build_intstring (buf);
1368 } 1346 }
1369 return list2 (make_int (offset), build_string (s)); 1347 return list2 (make_int (offset), tem);
1370 } 1348 }
1371 else 1349 else
1372 return list2 (Qnil, Qnil); 1350 return list2 (Qnil, Qnil);
1373 } 1351 }
1374 1352
1381 since if a string in the environment is in readonly 1359 since if a string in the environment is in readonly
1382 storage, it runs afoul of bugs in SVR4 and Solaris 2.3. 1360 storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
1383 See Sun bugs 1113095 and 1114114, ``Timezone routines 1361 See Sun bugs 1113095 and 1114114, ``Timezone routines
1384 improperly modify environment''. */ 1362 improperly modify environment''. */
1385 1363
1386 static char set_time_zone_rule_tz1[] = "TZ=GMT+0"; 1364 static Char_ASCII set_time_zone_rule_tz1[] = "TZ=GMT+0";
1387 static char set_time_zone_rule_tz2[] = "TZ=GMT+1"; 1365 static Char_ASCII set_time_zone_rule_tz2[] = "TZ=GMT+1";
1388 1366
1389 #endif 1367 #endif
1390 1368
1391 /* Set the local time zone rule to TZSTRING. 1369 /* Set the local time zone rule to TZSTRING.
1392 This allocates memory into `environ', which it is the caller's 1370 This allocates memory into `environ', which it is the caller's
1393 responsibility to free. */ 1371 responsibility to free. */
1394 static void 1372 static void
1395 set_time_zone_rule (char *tzstring) 1373 set_time_zone_rule (Extbyte *tzstring)
1396 { 1374 {
1397 int envptrs; 1375 int envptrs;
1398 char **from, **to, **newenv; 1376 Extbyte **from, **to, **newenv;
1399 1377
1400 for (from = environ; *from; from++) 1378 for (from = environ; *from; from++)
1401 continue; 1379 continue;
1402 envptrs = from - environ + 2; 1380 envptrs = from - environ + 2;
1403 newenv = to = (char **) xmalloc (envptrs * sizeof (char *) 1381 newenv = to = (Extbyte **) xmalloc (envptrs * sizeof (Extbyte *)
1404 + (tzstring ? strlen (tzstring) + 4 : 0)); 1382 + (tzstring ? strlen (tzstring) + 4 : 0));
1405 if (tzstring) 1383 if (tzstring)
1406 { 1384 {
1407 char *t = (char *) (to + envptrs); 1385 Extbyte *t = (Extbyte *) (to + envptrs);
1408 strcpy (t, "TZ="); 1386 strcpy (t, "TZ=");
1409 strcat (t, tzstring); 1387 strcat (t, tzstring);
1410 *to++ = t; 1388 *to++ = t;
1411 } 1389 }
1412 1390
1429 1407
1430 if (tzstring) 1408 if (tzstring)
1431 { 1409 {
1432 /* Temporarily set TZ to a value that loads a tz file 1410 /* Temporarily set TZ to a value that loads a tz file
1433 and that differs from tzstring. */ 1411 and that differs from tzstring. */
1434 char *tz = *newenv; 1412 Extbyte *tz = *newenv;
1435 *newenv = (strcmp (tzstring, set_time_zone_rule_tz1 + 3) == 0 1413 *newenv = (strcmp (tzstring, set_time_zone_rule_tz1 + 3) == 0
1436 ? set_time_zone_rule_tz2 : set_time_zone_rule_tz1); 1414 ? set_time_zone_rule_tz2 : set_time_zone_rule_tz1);
1437 tzset (); 1415 tzset ();
1438 *newenv = tz; 1416 *newenv = tz;
1439 } 1417 }
1460 Set the local time zone using TZ, a string specifying a time zone rule. 1438 Set the local time zone using TZ, a string specifying a time zone rule.
1461 If TZ is nil, use implementation-defined default time zone information. 1439 If TZ is nil, use implementation-defined default time zone information.
1462 */ 1440 */
1463 (tz)) 1441 (tz))
1464 { 1442 {
1465 char *tzstring; 1443 Extbyte *tzstring;
1466 1444
1467 if (NILP (tz)) 1445 if (NILP (tz))
1468 tzstring = 0; 1446 tzstring = 0;
1469 else 1447 else
1470 { 1448 {
1471 CHECK_STRING (tz); 1449 CHECK_STRING (tz);
1472 tzstring = (char *) XSTRING_DATA (tz); 1450 LISP_STRING_TO_EXTERNAL (tz, tzstring, Qnative);
1473 } 1451 }
1474 1452
1475 set_time_zone_rule (tzstring); 1453 set_time_zone_rule (tzstring);
1476 if (environbuf) 1454 if (environbuf)
1477 xfree (environbuf); 1455 xfree (environbuf);
1843 } 1821 }
1844 pos++; 1822 pos++;
1845 } 1823 }
1846 end_multiple_change (buf, mc_count); 1824 end_multiple_change (buf, mc_count);
1847 1825
1848 unbind_to (count, Qnil); 1826 unbind_to (count);
1849 return Qnil; 1827 return Qnil;
1850 } 1828 }
1851 1829
1852 /* #### Shouldn't this also accept a BUFFER argument, in the good old 1830 /* #### Shouldn't this also accept a BUFFER argument, in the good old
1853 XEmacs tradition? */ 1831 XEmacs tradition? */
2185 /* This function can GC */ 2163 /* This function can GC */
2186 int speccount = specpdl_depth (); 2164 int speccount = specpdl_depth ();
2187 2165
2188 record_unwind_protect (save_restriction_restore, save_restriction_save ()); 2166 record_unwind_protect (save_restriction_restore, save_restriction_save ());
2189 2167
2190 return unbind_to (speccount, Fprogn (body)); 2168 return unbind_to_1 (speccount, Fprogn (body));
2191 } 2169 }
2192 2170
2193 2171
2194 DEFUN ("format", Fformat, 1, MANY, 0, /* 2172 DEFUN ("format", Fformat, 1, MANY, 0, /*
2195 Format a string out of a control-string and arguments. 2173 Format a string out of a control-string and arguments.
2264 { 2242 {
2265 /* It should not be necessary to GCPRO ARGS, because 2243 /* It should not be necessary to GCPRO ARGS, because
2266 the caller in the interpreter should take care of that. */ 2244 the caller in the interpreter should take care of that. */
2267 2245
2268 CHECK_STRING (args[0]); 2246 CHECK_STRING (args[0]);
2269 return emacs_doprnt_string_lisp (0, args[0], 0, nargs - 1, args + 1); 2247 return emacs_vsprintf_string_lisp (0, args[0], nargs - 1, args + 1);
2270 } 2248 }
2271 2249
2272 2250
2273 DEFUN ("char-equal", Fchar_equal, 2, 3, 0, /* 2251 DEFUN ("char-equal", Fchar_equal, 2, 3, 0, /*
2274 Return t if two characters match, optionally ignoring case. 2252 Return t if two characters match, optionally ignoring case.
2578 needed to get the desired behavior for atomic extents and unfortunately 2556 needed to get the desired behavior for atomic extents and unfortunately
2579 is not available by any other means. 2557 is not available by any other means.
2580 */ ); 2558 */ );
2581 atomic_extent_goto_char_p = 0; 2559 atomic_extent_goto_char_p = 0;
2582 #ifdef AMPERSAND_FULL_NAME 2560 #ifdef AMPERSAND_FULL_NAME
2583 Fprovide(intern("ampersand-full-name")); 2561 Fprovide (intern ("ampersand-full-name"));
2584 #endif 2562 #endif
2585 2563
2586 DEFVAR_LISP ("user-full-name", &Vuser_full_name /* 2564 DEFVAR_LISP ("user-full-name", &Vuser_full_name /*
2587 *The name of the user. 2565 *The name of the user.
2588 The function `user-full-name', which will return the value of this 2566 The function `user-full-name', which will return the value of this