comparison src/fileio.c @ 243:f220cc83d72e r20-5b20

Import from CVS: tag r20-5b20
author cvs
date Mon, 13 Aug 2007 10:17:07 +0200
parents 85a06df23a9a
children 677f6a0ee643
comparison
equal deleted inserted replaced
242:fc816b73a05f 243:f220cc83d72e
684 #endif /* DOS_NT */ 684 #endif /* DOS_NT */
685 return val; 685 return val;
686 } 686 }
687 687
688 DEFUN ("expand-file-name", Fexpand_file_name, 1, 2, 0, /* 688 DEFUN ("expand-file-name", Fexpand_file_name, 1, 2, 0, /*
689 Convert FILENAME to absolute, and canonicalize it. 689 Convert filename NAME to absolute, and canonicalize it.
690 Second arg DEFAULT is directory to start with if FILENAME is relative 690 Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative
691 (does not start with slash); if DEFAULT is nil or missing, 691 (does not start with slash); if DEFAULT-DIRECTORY is nil or missing,
692 the current buffer's value of default-directory is used. 692 the current buffer's value of default-directory is used.
693 Path components that are `.' are removed, and 693 File name components that are `.' are removed, and
694 path components followed by `..' are removed, along with the `..' itself; 694 so are file name components followed by `..', along with the `..' itself;
695 note that these simplifications are done without checking the resulting 695 note that these simplifications are done without checking the resulting
696 paths in the file system. 696 file names in the file system.
697 An initial `~/' expands to your home directory. 697 An initial `~/' expands to your home directory.
698 An initial `~USER/' expands to USER's home directory. 698 An initial `~USER/' expands to USER's home directory.
699 See also the function `substitute-in-file-name'. 699 See also the function `substitute-in-file-name'.
700 */ 700 */
701 (name, default_)) 701 (name, default_directory))
702 { 702 {
703 /* This function can GC. GC checked 1997.04.06. */ 703 /* This function can GC */
704 Bufbyte *nm; 704 Bufbyte *nm;
705 705
706 Bufbyte *newdir, *p, *o; 706 Bufbyte *newdir, *p, *o;
707 int tlen; 707 int tlen;
708 Bufbyte *target; 708 Bufbyte *target;
709 struct passwd *pw; 709 struct passwd *pw;
710 #ifdef DOS_NT 710 #ifdef DOS_NT
711 int drive = 0; 711 int drive = 0;
712 int collapse_newdir = 1; 712 int collapse_newdir = 1;
713 #endif /* DOS_NT */
713 int length; 714 int length;
714 #endif /* DOS_NT */
715 Lisp_Object handler; 715 Lisp_Object handler;
716 716
717 CHECK_STRING (name); 717 CHECK_STRING (name);
718 718
719 /* If the file name has special constructs in it, 719 /* If the file name has special constructs in it,
720 call the corresponding file handler. */ 720 call the corresponding file handler. */
721 handler = Ffind_file_name_handler (name, Qexpand_file_name); 721 handler = Ffind_file_name_handler (name, Qexpand_file_name);
722 if (!NILP (handler)) 722 if (!NILP (handler))
723 return call3_check_string (handler, Qexpand_file_name, name, default_); 723 return call3_check_string (handler, Qexpand_file_name, name,
724 724 default_directory);
725 /* Use the buffer's default-directory if DEFAULT_ is omitted. */ 725
726 if (NILP (default_)) 726 /* Use the buffer's default-directory if DEFAULT_DIRECTORY is omitted. */
727 default_ = current_buffer->directory; 727 if (NILP (default_directory))
728 if (NILP (default_)) /* this should be a meaningful error */ 728 default_directory = current_buffer->directory;
729 { 729 if (! STRINGP (default_directory))
730 /* #### If we had a minibuffer-only frame up then current_buffer 730 default_directory = build_string ("/");
731 is likely to not have a directory setting. We should 731
732 probably redo things to make sure that current_buffer stays 732 if (!NILP (default_directory))
733 set to something sensible. */ 733 {
734 if (!preparing_for_armageddon) 734 handler = Ffind_file_name_handler (default_directory, Qexpand_file_name);
735 signal_simple_error ("default-directory is not set",
736 make_buffer (current_buffer));
737 }
738 else
739 CHECK_STRING (default_);
740
741 if (!NILP (default_))
742 {
743 struct gcpro gcpro1;
744
745 GCPRO1 (default_); /* might be current_buffer->directory */
746 handler = Ffind_file_name_handler (default_, Qexpand_file_name);
747 UNGCPRO;
748 if (!NILP (handler)) 735 if (!NILP (handler))
749 return call3 (handler, Qexpand_file_name, name, default_); 736 return call3 (handler, Qexpand_file_name, name, default_directory);
750 } 737 }
751 738
752 /* Make sure DEFAULT_ is properly expanded. 739 o = XSTRING_DATA (default_directory);
740
741 /* Make sure DEFAULT_DIRECTORY is properly expanded.
753 It would be better to do this down below where we actually use 742 It would be better to do this down below where we actually use
754 default_. Unfortunately, calling Fexpand_file_name recursively 743 default_directory. Unfortunately, calling Fexpand_file_name recursively
755 could invoke GC, and the strings might be relocated. This would 744 could invoke GC, and the strings might be relocated. This would
756 be annoying because we have pointers into strings lying around 745 be annoying because we have pointers into strings lying around
757 that would need adjusting, and people would add new pointers to 746 that would need adjusting, and people would add new pointers to
758 the code and forget to adjust them, resulting in intermittent bugs. 747 the code and forget to adjust them, resulting in intermittent bugs.
759 Putting this call here avoids all that crud. 748 Putting this call here avoids all that crud.
760 749
761 The EQ test avoids infinite recursion. */ 750 The EQ test avoids infinite recursion. */
762 if (! NILP(default_) && !EQ (default_, name) 751 if (! NILP (default_directory) && !EQ (default_directory, name)
763 /* Save time in some common cases - as long as default_directory 752 /* Save time in some common cases - as long as default_directory
764 is not relative, it can be canonicalized with name below (if it 753 is not relative, it can be canonicalized with name below (if it
765 is needed at all) without requiring it to be expanded now. */ 754 is needed at all) without requiring it to be expanded now. */
766 && ! (XSTRING_LENGTH (default_) >= 3
767 #ifdef DOS_NT 755 #ifdef DOS_NT
768 /* Detect MSDOS file names with drive specifiers. */ 756 /* Detect MSDOS file names with drive specifiers. */
769 && (IS_DRIVE (XSTRING_BYTE (default_, 0)) 757 && ! (IS_DRIVE (o[0]) && (IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])))
770 && (IS_DEVICE_SEP (XSTRING_BYTE (default_, 1))
771 && IS_DIRECTORY_SEP (XSTRING_BYTE (default_, 2))))
772 #ifdef WINDOWSNT 758 #ifdef WINDOWSNT
773 /* Detect Windows file names in UNC format. */ 759 /* Detect Windows file names in UNC format. */
774 && ! (XSTRING_LENGTH (default_) >= 2 760 && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1]))
775 && IS_DIRECTORY_SEP (XSTRING_BYTE (default_, 0))
776 && IS_DIRECTORY_SEP (XSTRING_BYTE (default_, 1)))
777 #endif 761 #endif
778 #else /* not DOS_NT */ 762 #else /* not DOS_NT */
779 /* Detect Unix absolute file names (/... alone is not absolute on 763 /* Detect Unix absolute file names (/... alone is not absolute on
780 DOS or Windows). */ 764 DOS or Windows). */
781 && (IS_DIRECTORY_SEP (XSTRING_BYTE (default_, 0)) 765 && ! (IS_DIRECTORY_SEP (o[0]))
782 || IS_DEVICE_SEP (XSTRING_BYTE (default_, 1)))
783 #endif /* not DOS_NT */ 766 #endif /* not DOS_NT */
784 )) 767 )
785 { 768 {
786 struct gcpro gcpro1; 769 struct gcpro gcpro1;
787 770
788 GCPRO1 (default_); /* may be current_buffer->directory */ 771 GCPRO1 (name);
789 default_ = Fexpand_file_name (default_, Qnil); 772 default_directory = Fexpand_file_name (default_directory, Qnil);
790 UNGCPRO; 773 UNGCPRO;
791 } 774 }
792 775
793 #ifdef FILE_SYSTEM_CASE 776 #ifdef FILE_SYSTEM_CASE
794 name = FILE_SYSTEM_CASE (name); 777 name = FILE_SYSTEM_CASE (name);
795 #endif 778 #endif
796 779
797 /* #### dmoore - this is ugly, clean this up. Looks like nm 780 /* #### dmoore - this is ugly, clean this up. Looks like nm pointing
798 pointing into name should be safe during all of this, though. */ 781 into name should be safe during all of this, though. */
799 nm = XSTRING_DATA (name); 782 nm = XSTRING_DATA (name);
800 783
801 #ifdef DOS_NT 784 #ifdef DOS_NT
802 /* We will force directory separators to be either all \ or /, so make 785 /* We will force directory separators to be either all \ or /, so make
803 a local copy to modify, even if there ends up being no change. */ 786 a local copy to modify, even if there ends up being no change. */
805 788
806 /* Find and remove drive specifier if present; this makes nm absolute 789 /* Find and remove drive specifier if present; this makes nm absolute
807 even if the rest of the name appears to be relative. */ 790 even if the rest of the name appears to be relative. */
808 { 791 {
809 Bufbyte *colon = strrchr (nm, ':'); 792 Bufbyte *colon = strrchr (nm, ':');
793
810 if (colon) 794 if (colon)
811 /* Only recognize colon as part of drive specifier if there is a 795 /* Only recognize colon as part of drive specifier if there is a
812 single alphabetic character preceeding the colon (and if the 796 single alphabetic character preceeding the colon (and if the
813 character before the drive letter, if present, is a directory 797 character before the drive letter, if present, is a directory
814 separator); this is to support the remote system syntax used by 798 separator); this is to support the remote system syntax used by
815 ange-ftp, and the "po:username" syntax for POP mailboxes. */ 799 ange-ftp, and the "po:username" syntax for POP mailboxes. */
816 look_again: 800 look_again:
817 if (nm == colon) 801 if (nm == colon)
818 nm++; 802 nm++;
819 else if (IS_DRIVE (colon[-1]) 803 else if (IS_DRIVE (colon[-1])
820 && (colon == nm + 1 || IS_DIRECTORY_SEP (colon[-2]))) 804 && (colon == nm + 1 || IS_DIRECTORY_SEP (colon[-2])))
821 { 805 {
837 if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) 821 if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
838 nm++; 822 nm++;
839 #endif /* WINDOWSNT */ 823 #endif /* WINDOWSNT */
840 #endif /* DOS_NT */ 824 #endif /* DOS_NT */
841 825
842 /* We *don't* want to handle // and /~ that way. */
843 #if 0
844 /* Handle // and /~ in middle of file name
845 by discarding everything through the first / of that sequence. */
846 p = nm;
847 while (*p)
848 {
849 /* Since we know the path is absolute, we can assume that each
850 element starts with a "/". */
851
852 /* "//" anywhere isn't necessarily hairy; we just start afresh
853 with the second slash. */
854 if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
855 #if defined (APOLLO) || defined (WINDOWSNT)
856 /* // at start of filename is meaningful on Apollo
857 and WindowsNT systems */
858 && nm != p
859 #endif /* APOLLO || WINDOWSNT */
860 )
861 nm = p + 1;
862
863 /* "~" is hairy as the start of any path element. */
864 if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
865 nm = p + 1;
866
867 p++;
868 }
869
870 #endif /* 0 */
871
872 #ifdef WINDOWSNT 826 #ifdef WINDOWSNT
873 /* Discard any previous drive specifier if nm is now in UNC format. */ 827 /* Discard any previous drive specifier if nm is now in UNC format. */
874 if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) 828 if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
875 { 829 {
876 drive = 0; 830 drive = 0;
878 #endif /* WINDOWSNT */ 832 #endif /* WINDOWSNT */
879 833
880 /* If nm is absolute, look for /./ or /../ sequences; if none are 834 /* If nm is absolute, look for /./ or /../ sequences; if none are
881 found, we can probably return right away. We will avoid allocating 835 found, we can probably return right away. We will avoid allocating
882 a new string if name is already fully expanded. */ 836 a new string if name is already fully expanded. */
883 if (IS_DIRECTORY_SEP (nm[0]) 837 if (
838 IS_DIRECTORY_SEP (nm[0])
839 #ifdef MSDOS
840 && drive
841 #endif
884 #ifdef WINDOWSNT 842 #ifdef WINDOWSNT
885 && (drive || IS_DIRECTORY_SEP (nm[1])) 843 && (drive || IS_DIRECTORY_SEP (nm[1]))
886 #endif 844 #endif
887 ) 845 )
888 { 846 {
895 int lose = 0; 853 int lose = 0;
896 854
897 p = nm; 855 p = nm;
898 while (*p) 856 while (*p)
899 { 857 {
900 /* Since we know the path is absolute, we can assume that each 858 /* Since we know the name is absolute, we can assume that each
901 element starts with a "/". */ 859 element starts with a "/". */
902 860
903 /* "." and ".." are hairy. */ 861 /* "." and ".." are hairy. */
904 if (IS_DIRECTORY_SEP (p[0]) 862 if (IS_DIRECTORY_SEP (p[0])
905 && p[1] == '.' 863 && p[1] == '.'
923 if (strcmp (nm, XSTRING_DATA (name)) != 0) 881 if (strcmp (nm, XSTRING_DATA (name)) != 0)
924 name = build_string (nm); 882 name = build_string (nm);
925 } 883 }
926 else 884 else
927 #endif 885 #endif
928 /* drive must be set, so this is okay */ 886 /* drive must be set, so this is okay */
929 if (strcmp (nm - 2, XSTRING_DATA (name)) != 0) 887 if (strcmp (nm - 2, XSTRING_DATA (name)) != 0)
930 { 888 {
931 name = make_string (nm - 2, p - nm + 2); 889 name = make_string (nm - 2, p - nm + 2);
932 XSTRING_DATA (name)[0] = DRIVE_LETTER (drive); 890 XSTRING_DATA (name)[0] = DRIVE_LETTER (drive);
933 XSTRING_DATA (name)[1] = ':'; 891 XSTRING_DATA (name)[1] = ':';
934 } 892 }
935 return name; 893 return name;
936 #else /* not DOS_NT */ 894 #else /* not DOS_NT */
937 /* Unix */
938 if (nm == XSTRING_DATA (name)) 895 if (nm == XSTRING_DATA (name))
939 return name; 896 return name;
940 return build_string ((char *) nm); 897 return build_string (nm);
941 #endif /* DOS_NT */ 898 #endif /* not DOS_NT */
942 } 899 }
943 } 900 }
944 901
945 /* At this point, nm might or might not be an absolute file name. We 902 /* At this point, nm might or might not be an absolute file name. We
946 need to expand ~ or ~user if present, otherwise prefix nm with 903 need to expand ~ or ~user if present, otherwise prefix nm with
947 default_directory if nm is not absolute, and finally collapse /./ 904 default_directory if nm is not absolute, and finally collapse /./
948 and /foo/../ sequences. 905 and /foo/../ sequences.
949 906
950 We set newdir to be the appropriate prefix if one is needed: 907 We set newdir to be the appropriate prefix if one is needed:
951 - the relevant user directory if nm starts with ~ or ~user 908 - the relevant user directory if nm starts with ~ or ~user
952 - the specified drive's working dir (DOS/NT only) if nm does not 909 - the specified drive's working dir (DOS/NT only) if nm does not
953 start with / 910 start with /
954 - the value of default_directory. 911 - the value of default_directory.
955 912
956 Note that these prefixes are not guaranteed to be absolute (except 913 Note that these prefixes are not guaranteed to be absolute (except
957 for the working dir of a drive). Therefore, to ensure we always 914 for the working dir of a drive). Therefore, to ensure we always
958 return an absolute name, if the final prefix is not absolute we 915 return an absolute name, if the final prefix is not absolute we
959 append it to the current working directory. */ 916 append it to the current working directory. */
961 newdir = 0; 918 newdir = 0;
962 919
963 if (nm[0] == '~') /* prefix ~ */ 920 if (nm[0] == '~') /* prefix ~ */
964 { 921 {
965 if (IS_DIRECTORY_SEP (nm[1]) 922 if (IS_DIRECTORY_SEP (nm[1])
966 || nm[1] == 0) /* ~ by itself */ 923 || nm[1] == 0) /* ~ by itself */
967 { 924 {
968 if (!(newdir = (Bufbyte *) egetenv ("HOME"))) 925 if (!(newdir = (Bufbyte *) egetenv ("HOME")))
969 newdir = (Bufbyte *) ""; 926 newdir = (Bufbyte *) "";
970 /* Syncing with FSF 19.34.6 note: this is not in FSF. Since it is dated 1995,
971 I doubt it is coming from XEmacs. I (#if 0) it but let the code
972 stay there just in case. --marcpa */
973 #if 0
974 #ifdef DOS_NT
975 /* Problem when expanding "~\" if HOME is not on current drive.
976 Ulrich Leodolter, Wed Jan 11 10:20:35 1995 */
977 if (newdir[1] == ':')
978 drive = newdir[0];
979 dostounix_filename (newdir);
980 #endif /* DOS_NT */
981 #endif /* 0 */
982 nm++; 927 nm++;
983 #ifdef DOS_NT 928 #ifdef DOS_NT
984 collapse_newdir = 0; 929 collapse_newdir = 0;
985 #endif /* DOS_NT */ 930 #endif
986 } 931 }
987 else /* ~user/filename */ 932 else /* ~user/filename */
988 { 933 {
989 for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)); p++); 934 for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)); p++);
990 o = (Bufbyte *) alloca (p - nm + 1); 935 o = (Bufbyte *) alloca (p - nm + 1);
991 memcpy (o, (char *) nm, p - nm); 936 memcpy (o, (char *) nm, p - nm);
992 o [p - nm] = 0; 937 o [p - nm] = 0;
993 938
994 /* Syncing with FSF 19.34.6 note: FSF uses getpwnam even on NT, which does 939 /* #### marcpa's syncing note: FSF uses getpwnam even on NT,
995 not work. The following works only if ~USER names the user who runs 940 which does not work. The following works only if ~USER
996 this instance of XEmacs. While NT is single-user (for the moment) you 941 names the user who runs this instance of XEmacs. While
997 still can have multiple user profiles users defined, each with its 942 NT is single-user (for the moment) you still can have
998 HOME. Therefore, the following should be reworked to handle this case. 943 multiple user profiles users defined, each with its HOME.
999 --marcpa */ 944 Therefore, the following should be reworked to handle
945 this case. */
1000 #ifdef WINDOWSNT 946 #ifdef WINDOWSNT
1001 /* 947 /* Now if the file given is "~foo/file" and HOME="c:/", then
1002 ** Now if the file given is "~foo/file" and HOME="c:/", then we 948 we want the file to be named "c:/file" ("~foo" becomes
1003 ** want the file to be named "c:/file" ("~foo" becomes "c:/"). 949 "c:/"). The variable o has "~foo", so we can use the
1004 ** The variable o has "~foo", so we can use the length of 950 length of that string to offset nm. August Hill, 31 Aug
1005 ** that string to offset nm. August Hill, 31 Aug 1998. 951 1998. */
1006 */
1007 newdir = (Bufbyte *) egetenv ("HOME"); 952 newdir = (Bufbyte *) egetenv ("HOME");
1008 dostounix_filename (newdir); 953 dostounix_filename (newdir);
1009 nm += strlen(o) + 1; 954 nm += strlen(o) + 1;
1010 #else /* not WINDOWSNT */ 955 #else /* not WINDOWSNT */
1011 /* Jamie reports that getpwnam() can get wedged by SIGIO/SIGALARM 956 /* Jamie reports that getpwnam() can get wedged by SIGIO/SIGALARM
1049 } 994 }
1050 #endif /* DOS_NT */ 995 #endif /* DOS_NT */
1051 996
1052 /* Finally, if no prefix has been specified and nm is not absolute, 997 /* Finally, if no prefix has been specified and nm is not absolute,
1053 then it must be expanded relative to default_directory. */ 998 then it must be expanded relative to default_directory. */
999
1054 if (1 1000 if (1
1055 #ifndef DOS_NT 1001 #ifndef DOS_NT
1056 && !IS_ANY_SEP (nm[0]) 1002 /* /... alone is not absolute on DOS and Windows. */
1057 #endif /* not DOS_NT */ 1003 && !IS_DIRECTORY_SEP (nm[0])
1004 #endif
1058 #ifdef WINDOWSNT 1005 #ifdef WINDOWSNT
1059 && !(IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) 1006 && !(IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
1060 #endif 1007 #endif
1061 && !newdir 1008 && !newdir)
1062 && STRINGP (default_)) 1009 {
1063 { 1010 newdir = XSTRING_DATA (default_directory);
1064 newdir = XSTRING_DATA (default_);
1065 } 1011 }
1066 1012
1067 #ifdef DOS_NT 1013 #ifdef DOS_NT
1068 if (newdir) 1014 if (newdir)
1069 { 1015 {
1131 #endif 1077 #endif
1132 newdir = ""; 1078 newdir = "";
1133 } 1079 }
1134 } 1080 }
1135 #endif /* DOS_NT */ 1081 #endif /* DOS_NT */
1136 if (newdir != 0) 1082
1083 if (newdir)
1137 { 1084 {
1138 /* Get rid of any slash at the end of newdir, unless newdir is 1085 /* Get rid of any slash at the end of newdir, unless newdir is
1139 just // (an incomplete UNC name). */ 1086 just // (an incomplete UNC name). */
1140 int length = strlen ((char *) newdir); 1087 length = strlen (newdir);
1141 /* Adding `length > 1 &&' makes ~ expand into / when homedir 1088 if (length > 0 && IS_DIRECTORY_SEP (newdir[length - 1])
1142 is the root dir. People disagree about whether that is right.
1143 Anyway, we can't take the risk of this change now. */
1144 /* Syncing with FSF 19.34.6 note: FSF does the above. */
1145 if (IS_DIRECTORY_SEP (newdir[length - 1])
1146 #ifdef WINDOWSNT 1089 #ifdef WINDOWSNT
1147 && !(length == 2 && IS_DIRECTORY_SEP (newdir[0])) 1090 && !(length == 2 && IS_DIRECTORY_SEP (newdir[0]))
1148 #endif 1091 #endif
1149 ) 1092 )
1150 { 1093 {
1157 } 1100 }
1158 else 1101 else
1159 tlen = 0; 1102 tlen = 0;
1160 1103
1161 /* Now concatenate the directory and name to new space in the stack frame */ 1104 /* Now concatenate the directory and name to new space in the stack frame */
1162 tlen += strlen ((char *) nm) + 1; 1105 tlen += strlen (nm) + 1;
1163 #ifdef DOS_NT 1106 #ifdef DOS_NT
1164 /* Add reserved space for drive name. (The Microsoft x86 compiler 1107 /* Add reserved space for drive name. (The Microsoft x86 compiler
1165 produces incorrect code if the following two lines are combined.) */ 1108 produces incorrect code if the following two lines are combined.) */
1166 target = (Bufbyte *) alloca (tlen + 2); 1109 target = (Bufbyte *) alloca (tlen + 2);
1167 target += 2; 1110 target += 2;
1168 #else /* not DOS_NT */ 1111 #else /* not DOS_NT */
1169 target = (Bufbyte *) alloca (tlen); 1112 target = (Bufbyte *) alloca (tlen);
1170 #endif /* DOS_NT */ 1113 #endif /* not DOS_NT */
1171 *target = 0; 1114 *target = 0;
1172 1115
1173 if (newdir) 1116 if (newdir)
1174 { 1117 {
1175 if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0])) 1118 if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0]))
1176 strcpy ((char *) target, (char *) newdir); 1119 strcpy (target, newdir);
1177 else 1120 else
1178 file_name_as_directory ((char *) target, (char *) newdir); 1121 file_name_as_directory (target, newdir);
1179 } 1122 }
1180 1123
1181 strcat ((char *) target, (char *) nm); 1124 strcat (target, nm);
1125
1126 /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */
1182 1127
1183 /* Now canonicalize by removing /. and /foo/.. if they appear. */ 1128 /* Now canonicalize by removing /. and /foo/.. if they appear. */
1184 1129
1185 p = target; 1130 p = target;
1186 o = target; 1131 o = target;
1189 { 1134 {
1190 if (!IS_DIRECTORY_SEP (*p)) 1135 if (!IS_DIRECTORY_SEP (*p))
1191 { 1136 {
1192 *o++ = *p++; 1137 *o++ = *p++;
1193 } 1138 }
1194 else if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
1195 #if defined (APOLLO) || defined (WINDOWSNT)
1196 /* // at start of filename is meaningful in Apollo
1197 and WindowsNT systems */
1198 && o != target
1199 #endif /* APOLLO || WINDOWSNT */
1200 )
1201 {
1202 o = target;
1203 p++;
1204 }
1205 else if (IS_DIRECTORY_SEP (p[0]) 1139 else if (IS_DIRECTORY_SEP (p[0])
1206 && p[1] == '.' 1140 && p[1] == '.'
1207 && (IS_DIRECTORY_SEP (p[2]) 1141 && (IS_DIRECTORY_SEP (p[2])
1208 || p[2] == 0)) 1142 || p[2] == 0))
1209 { 1143 {
1210 /* If "/." is the entire filename, keep the "/". Otherwise, 1144 /* If "/." is the entire filename, keep the "/". Otherwise,
1211 just delete the whole "/.". */ 1145 just delete the whole "/.". */
1218 && o != target 1152 && o != target
1219 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0)) 1153 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
1220 { 1154 {
1221 while (o != target && (--o) && !IS_DIRECTORY_SEP (*o)) 1155 while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
1222 ; 1156 ;
1223 if (o == target && IS_ANY_SEP (*o) 1157 /* Keep initial / only if this is the whole name. */
1224 #ifdef DOS_NT 1158 if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
1225 && p[3] == 0
1226 #endif
1227 )
1228 ++o; 1159 ++o;
1229 p += 3; 1160 p += 3;
1230 } 1161 }
1231 else 1162 else
1232 { 1163 {