1 /*************
2 * Various utility functions.
3 * 2002 R. Oktas, <roktas@omu.edu.tr>
4 ************/
5
6 #include "ngspice/ngspice.h"
7 #include "util.h"
8
9 /* **************************************************************** */
10 /* */
11 /* Stuff for Filename Handling */
12 /* */
13 /* **************************************************************** */
14
15 /* Canonicalize PATH, and return a new path. The new path differs from PATH
16 in that:
17 Multple `/'s are collapsed to a single `/'.
18 Leading `./'s and trailing `/.'s are removed.
19 Trailing `/'s are removed.
20 Non-leading `../'s and trailing `..'s are handled by removing
21 portions of the path.
22
23 Stolen from Bash source (slightly modified).
24 Credit goes to Chet Ramey, et al. -- ro */
25
26 char *
canonicalize_pathname(char * path)27 canonicalize_pathname(char *path)
28 {
29 int i, start;
30 char stub_char;
31 char *result;
32
33 /* The result cannot be larger than the input PATH. */
34 result = copy(path);
35
36 stub_char = '.';
37 if(*path == '/')
38 stub_char = '/';
39
40 /* Walk along RESULT looking for things to compact. */
41 i = 0;
42 for (;;) {
43 if (!result[i])
44 break;
45
46 while (result[i] && result[i] != '/')
47 i++;
48
49 start = i++;
50
51 /* If we didn't find any slashes, then there is nothing left to do. */
52 if (!result[start])
53 break;
54
55 /* Handle multiple `/'s in a row. */
56 while (result[i] == '/')
57 i++;
58
59 #if !defined (apollo)
60 if ((start + 1) != i)
61 #else
62 if ((start + 1) != i && (start != 0 || i != 2))
63 #endif /* apollo */
64 {
65 strcpy (result + start + 1, result + i);
66 i = start + 1;
67 }
68
69 #if 0
70 /* Handle backslash-quoted `/'. */
71 if (start > 0 && result[start - 1] == '\\')
72 continue;
73 #endif
74
75 /* Check for trailing `/'. */
76 if (start && !result[i]) {
77 zero_last:
78 result[--i] = '\0';
79 break;
80 }
81
82 /* Check for `../', `./' or trailing `.' by itself. */
83 if (result[i] == '.') {
84 /* Handle trailing `.' by itself. */
85 if (!result[i + 1])
86 goto zero_last;
87
88 /* Handle `./'. */
89 if (result[i + 1] == '/') {
90 strcpy(result + i, result + i + 1);
91 i = (start < 0) ? 0 : start;
92 continue;
93 }
94
95 /* Handle `../' or trailing `..' by itself. */
96 if (result[i + 1] == '.' &&
97 (result[i + 2] == '/' || !result[i + 2])) {
98 while (--start > -1 && result[start] != '/')
99 ;
100 strcpy(result + start + 1, result + i + 2);
101 i = (start < 0) ? 0 : start;
102 continue;
103 }
104 }
105 }
106
107 if (!*result) {
108 *result = stub_char;
109 result[1] = '\0';
110 }
111 return (result);
112 }
113
114
115 /* Turn STRING (a pathname) into an absolute pathname, assuming that
116 DOT_PATH contains the symbolic location of `.'. This always
117 returns a new string, even if STRING was an absolute pathname to
118 begin with.
119
120 Stolen from Bash source (slightly modified).
121 Credit goes to Chet Ramey, et al. -- ro */
122
absolute_pathname(char * string,char * dot_path)123 char * absolute_pathname(char *string, char *dot_path)
124 {
125 char *result;
126 size_t result_len;
127
128 if (!dot_path || *string == '/')
129 result = copy(string);
130 else {
131 if (dot_path && dot_path[0]) {
132 result = TMALLOC(char, 2 + strlen(dot_path) + strlen(string));
133 strcpy(result, dot_path);
134 result_len = strlen(result);
135 if (result[result_len - 1] != '/') {
136 result[result_len++] = '/';
137 result[result_len] = '\0';
138 }
139 } else {
140 result = TMALLOC(char, 3 + strlen (string));
141 result[0] = '.'; result[1] = '/'; result[2] = '\0';
142 result_len = 2;
143 }
144
145 strcpy(result + result_len, string);
146 }
147
148 return (result);
149 }
150
151
152 /*
153
154 char *
155 basename(const char *name)
156 {
157 char *base;
158 char *p;
159 static char *tmp = NULL;
160 int len;
161
162 if (tmp) {
163 tfree(tmp);
164 tmp = NULL;
165 }
166
167 if (!name || !strcmp(name, ""))
168 return "";
169
170 if (!strcmp(name, "/"))
171 return "/";
172
173 len = strlen(name);
174 if (name[len - 1] == '/') {
175 // ditch the trailing '/'
176 p = tmp = TMALLOC(char, len);
177 strncpy(p, name, len - 1);
178 } else {
179 p = (char *) name;
180 }
181
182 for (base = p; *p; p++)
183 if (*p == '/')
184 base = p + 1;
185
186 return base;
187 }
188 */
189
190
191 #if defined(HAS_WINGUI) || defined(_MSC_VER) || defined(__MINGW32__)
192 /* This function returns the path portion of name or "." if it is NULL.
193 * The returned string is a new allocation that must be freed by the
194 * caller */
ngdirname(const char * name)195 char *ngdirname(const char *name)
196 {
197 /* If name not given, return "." */
198 if (name == (char *) NULL) {
199 return dup_string(".", 1);
200 }
201
202 /* Offset to start of path name after any drive letter present */
203 const int start = (((name[0] >= 'a' && name[0] <= 'z') ||
204 (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':') ? 2 : 0;
205
206 /* Find last dir separator, if any, and return the input directory up to
207 * that separator or including it if it is the 1st char after any drive
208 *specification. */
209 {
210 const char *p0 = name + start; /* 1st char past drive */
211 const char *p;
212 for (p = p0 + strlen(name + start) - 1; p >= p0; --p) {
213 const char ch_cur = *p;
214 if (ch_cur == '/' || ch_cur == '\\') { /* at last dir sep */
215 /* Stop copy at last dir sep or right after if
216 * it is the first char after any drive spec.
217 * In the second case return "[drive]<dir sep>" */
218 const char * const end = p + (p == p0);
219 return copy_substring(name, end);
220 }
221 }
222 }
223
224 /* No directory separator found so return "[drive]." */
225 {
226 char * const ret = TMALLOC(char, 2 + start);
227 char *p = ret;
228 if (start) { /* Add drive letter if found */
229 *p++ = name[0];
230 *p++ = name[1];
231 }
232 *p++ = '.';
233 *p = '\0';
234 return ret;
235 }
236 } /* end of function ngdirname */
237
238 #else
239
240 char *
ngdirname(const char * name)241 ngdirname(const char *name)
242 {
243 char *ret;
244 const char *end;
245
246 end = name ? strrchr(name, '/') : NULL;
247
248 if(end && end == name)
249 end++;
250
251 if(end)
252 ret = copy_substring(name, end);
253 else
254 ret = copy(".");
255
256 return ret;
257 }
258
259 #endif
260
261 /* Replacement for fopen, when using wide chars (utf-16) */
262 #ifndef EXT_ASC
263 #if defined(__MINGW32__) || defined(_MSC_VER)
264 #undef BOOLEAN
265 #include <windows.h>
266 FILE *
newfopen(const char * fn,const char * md)267 newfopen(const char *fn, const char* md)
268 {
269 FILE* fp;
270 if (fn == NULL)
271 return NULL;
272 wchar_t wfn[BSIZE_SP];
273 wchar_t wmd[16];
274 MultiByteToWideChar(CP_UTF8, 0, md, -1, wmd, 15);
275 if (MultiByteToWideChar(CP_UTF8, 0, fn, -1, wfn, BSIZE_SP - 1) == 0) {
276 fprintf(stderr, "UTF-8 to UTF-16 conversion failed with 0x%x\n", GetLastError());
277 fprintf(stderr, "%s could not be converted\n", fn);
278 return NULL;
279 }
280 fp = _wfopen(wfn, wmd);
281
282 /* If wide char fails, at least fopen may try the potentially ANSI encoded special characters like � */
283 #undef fopen
284 if (fp == NULL)
285 fp = fopen(fn, md);
286 #define fopen newfopen
287
288 return fp;
289 }
290 #endif
291 #endif
292
293