1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2017 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33 
34 /*
35  * path.c - host operating system specific pathname manipulation functions
36  *
37  * This file is inherently nonportable ... please help adjusting it to
38  * any new platforms that may be necessary.
39  */
40 
41 #include "compiler.h"
42 #include "nasmlib.h"
43 #include "error.h"
44 
45 #if defined(__MSDOS__) || defined(__DOS__) || \
46     defined(__WINDOWS__) || defined(_Windows) ||                        \
47     defined(__OS2__) || defined(_WIN16) || defined(WIN32) || defined(_WIN32)
48 /* MS-DOS/Windows and like operating systems */
49 # define separators "/\\:"
50 # define cleandirend "/\\"
51 # define catsep '\\'
52 # define leaveonclean 2         /* Leave \\ at the start alone */
53 # define curdir "."
54 #elif defined(unix) || defined(__unix) || defined(__unix__) ||   \
55     defined(__UNIX__) || defined(__Unix__) || \
56     defined(__MACH__) || defined(__BEOS__)
57 /* Unix and Unix-like operating systems and others using
58  * the equivalent syntax (slashes as only separators, no concept of volume)
59  *
60  * This must come after the __MSDOS__ section, since it seems that at
61  * least DJGPP defines __unix__ despite not being a Unix environment at all.
62  */
63 # define separators "/"
64 # define cleandirend "/"
65 # define catsep '/'
66 # define leaveonclean 1
67 # define curdir "."
68 #elif defined(Macintosh) || defined(macintosh)
69 /* MacOS classic */
70 # define separators ":"
71 # define curdir ":"
72 # define catsep ':'
73 # define cleandirend ":"
74 # define leaveonclean 0
75 # define leave_leading 1
76 #elif defined(__VMS)
77 /* VMS *
78  *
79  * VMS filenames may have ;version at the end.  Assume we should count that
80  * as part of the filename anyway.
81  */
82 # define separators ":]"
83 # define curdir "[]"
84 #else
85 /* No idea what to do here, do nothing.  Feel free to add new ones. */
86 # define curdir ""
87 #endif
88 
89 /*
90  * This is an inline, because most compilers can greatly simplify this
91  * for a fixed string, like we have here.
92  */
ismatch(const char * charset,char ch)93 static inline bool ismatch(const char *charset, char ch)
94 {
95     const char *p;
96 
97     for (p = charset; *p; p++) {
98         if (ch == *p)
99             return true;
100     }
101 
102     return false;
103 }
104 
first_filename_char(const char * path)105 static const char *first_filename_char(const char *path)
106 {
107 #ifdef separators
108     const char *p = path + strlen(path);
109 
110     while (p > path) {
111         if (ismatch(separators, p[-1]))
112             return p;
113         p--;
114     }
115 
116     return p;
117 #else
118     return path;
119 #endif
120 }
121 
122 /* Return the filename portion of a PATH as a new string */
nasm_basename(const char * path)123 char *nasm_basename(const char *path)
124 {
125     return nasm_strdup(first_filename_char(path));
126 }
127 
128 /* Return the directory name portion of a PATH as a new string */
nasm_dirname(const char * path)129 char *nasm_dirname(const char *path)
130 {
131     const char *p = first_filename_char(path);
132     const char *p0 = p;
133     (void)p0;                   /* Don't warn if unused */
134 
135     if (p == path)
136         return nasm_strdup(curdir);
137 
138 #ifdef cleandirend
139     while (p > path+leaveonclean) {
140         if (ismatch(cleandirend, p[-1]))
141             break;
142         p--;
143     }
144 #endif
145 
146 #ifdef leave_leading
147     /* If the directory contained ONLY separators, leave as-is */
148     if (p == path+leaveonclean)
149         p = p0;
150 #endif
151 
152     return nasm_strndup(path, p-path);
153 }
154 
155 /*
156  * Concatenate a directory path and a filename.  Note that this function
157  * currently does NOT handle the case where file itself contains
158  * directory components (except on Unix platforms, because it is trivial.)
159  */
nasm_catfile(const char * dir,const char * file)160 char *nasm_catfile(const char *dir, const char *file)
161 {
162 #ifndef catsep
163     return nasm_strcat(dir, file);
164 #else
165     size_t dl = strlen(dir);
166     size_t fl = strlen(file);
167     char *p, *pp;
168     bool dosep = true;
169 
170     if (!dl || ismatch(separators, dir[dl-1])) {
171         /* No separator necessary */
172         dosep = false;
173     }
174 
175     p = pp = nasm_malloc(dl + fl + dosep + 1);
176 
177     memcpy(pp, dir, dl);
178     pp += dl;
179     if (dosep)
180         *pp++ = catsep;
181 
182     memcpy(pp, file, fl+1);
183 
184     return p;
185 #endif
186 }
187