auxfile.c /size: 10 Kb    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5# include <stdio.h>
6# include <sys/stat.h>
7
8# include "auxfile.h"
9# include "auxmemory.h"
10
11# ifdef _WIN32
12
13    # include <windows.h>
14    # include <ctype.h>
15    # include <io.h>
16    # include <shellapi.h>
17    # include <fileapi.h>
18
19    LPWSTR aux_utf8_to_wide(const char *utf8str) {
20        if (utf8str) {
21            int length = MultiByteToWideChar(CP_UTF8, 0, utf8str, -1, NULL, 0); /* preroll */
22            LPWSTR wide = (LPWSTR) lmt_memory_malloc(sizeof(WCHAR) * length);
23            MultiByteToWideChar(CP_UTF8, 0, utf8str, -1, wide, length);
24            return wide;
25        } else {
26            return NULL;
27        }
28    }
29
30    char *aux_utf8_from_wide(LPWSTR widestr) {
31        if (widestr) {
32            int length = WideCharToMultiByte(CP_UTF8, 0, widestr, -1, NULL, 0, NULL, NULL);
33            char * utf8str = (char *) lmt_memory_malloc(sizeof(char) * length);
34            WideCharToMultiByte(CP_UTF8, 0, widestr, -1, utf8str, length, NULL, NULL);
35            return (char *) utf8str;
36        } else {
37            return NULL;
38        }
39    }
40
41    FILE *aux_utf8_fopen(const char *path, const char *mode) {
42        if (path && mode) {
43            LPWSTR wpath = aux_utf8_to_wide(path);
44            LPWSTR wmode = aux_utf8_to_wide(mode);
45            FILE *f = _wfopen(wpath,wmode);
46            lmt_memory_free(wpath);
47            lmt_memory_free(wmode);
48            return f;
49        } else {
50            return NULL;
51        }
52    }
53
54    FILE *aux_utf8_popen(const char *path, const char *mode) {
55        if (path && mode) {
56            LPWSTR wpath = aux_utf8_to_wide(path);
57            LPWSTR wmode = aux_utf8_to_wide(mode);
58            FILE *f = _wpopen(wpath,wmode);
59            lmt_memory_free(wpath);
60            lmt_memory_free(wmode);
61            return f;
62        } else {
63            return NULL;
64        }
65    }
66
67    int aux_utf8_system(const char *cmd)
68    {
69        LPWSTR wcmd = aux_utf8_to_wide(cmd);
70        int result = _wsystem(wcmd);
71        lmt_memory_free(wcmd);
72        return result;
73    }
74
75    int aux_utf8_remove(const char *name)
76    {
77        LPWSTR wname = aux_utf8_to_wide(name);
78        int result = _wremove(wname);
79        lmt_memory_free(wname);
80        return result;
81    }
82
83    int aux_utf8_rename(const char *oldname, const char *newname)
84    {
85        LPWSTR woldname = aux_utf8_to_wide(oldname);
86        LPWSTR wnewname = aux_utf8_to_wide(newname);
87        int result = _wrename(woldname, wnewname);
88        lmt_memory_free(woldname);
89        lmt_memory_free(wnewname);
90        return result;
91    }
92
93    int aux_utf8_setargv(char * **av, char **argv, int argc)
94    {
95        if (argv) {
96            int c = 0;
97            LPWSTR *l = CommandLineToArgvW(GetCommandLineW(), &c);
98            if (l != NULL) {
99                char **v = lmt_memory_malloc(sizeof(char *) * c);
100                for (int i = 0; i < c; i++) {
101                    v[i] = aux_utf8_from_wide(l[i]);
102                }
103                *av = v;
104                /*tex Let's be nice with path names: |c:\\foo\\etc| */
105                if (c > 1) {
106                    if ((strlen(v[c-1]) > 2) && isalpha(v[c-1][0]) && (v[c-1][1] == ':') && (v[c-1][2] == '\\')) {
107                        for (char *p = v[c-1]+2; *p; p++) {
108                            if (*p == '\\') {
109                                *p = '/';
110                            }
111                        }
112                    }
113                }
114            }
115            return c;
116        } else {
117            *av = NULL;
118            return argc;
119        }
120    }
121
122    char *aux_utf8_getownpath(const char *file)
123    {
124        if (file) {
125            char *path = NULL;
126            char buffer[MAX_PATH];
127            GetModuleFileName(NULL, buffer, sizeof(buffer));
128            path = lmt_memory_strdup(buffer);
129            if (strlen(path) > 0) {
130                for (size_t i = 0; i < strlen(path); i++) {
131                    if (path[i] == '\\') {
132                        path[i] = '/';
133                    }
134                }
135                return path;
136            }
137        }
138        return lmt_memory_strdup(".");
139    }
140
141    /*tex We alwways return a copy so that we're consistent with windows/unix. */
142
143 // # if defined(__MINGW64__) || defined(__MINGW32__)
144 //     extern DWORD GetFinalPathNameByHandleW(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
145 // # endif 
146
147    char *aux_utf8_readlink(const char *file)
148    {
149        LPWSTR wide = aux_utf8_to_wide(file);
150        HANDLE handle = CreateFileW(wide, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
151        char *link = NULL;
152        if (handle == INVALID_HANDLE_VALUE) {
153            LPWSTR path = (LPWSTR) lmt_memory_malloc((MAX_PATH+1) * sizeof(WCHAR));
154            DWORD size = GetFinalPathNameByHandleW(handle, path, MAX_PATH, VOLUME_NAME_NT);
155            if (size > 0 && size < MAX_PATH) {
156                path[size] = '\0';
157                link = aux_utf8_from_wide(path);
158            }
159            lmt_memory_free(path);
160        }
161        CloseHandle(handle);
162        lmt_memory_free(wide);
163        return link ? link : lmt_memory_strdup(file);
164    }
165
166# else
167
168    # include <string.h>
169    # include <stdlib.h>
170    # include <unistd.h>
171
172    int aux_utf8_setargv(char * **av, char **argv, int argc)
173    {
174        *av = argv;
175        return argc;
176    }
177
178    char *aux_utf8_getownpath(const char *file)
179    {
180        if (strchr(file, '/')) {
181            return lmt_memory_strdup(file);
182        } else {
183            const char *esp;
184            size_t prefixlen = 0;
185            size_t totallen = 0;
186            size_t filelen = strlen(file);
187            char *path = NULL;
188            char *searchpath = lmt_memory_strdup(getenv("PATH"));
189            const char *index = searchpath;
190            if (index) {
191                do {
192                    esp = strchr(index, ':');
193                    if (esp) {
194                        prefixlen = (size_t) (esp - index);
195                    } else {
196                        prefixlen = strlen(index);
197                    }
198                    if (prefixlen == 0 || index[prefixlen - 1] == '/') {
199                        totallen = prefixlen + filelen;
200# ifdef PATH_MAX
201                        if (totallen >= PATH_MAX) {
202                            continue;
203                        }
204# endif
205                        path = lmt_memory_malloc(totallen + 1);
206                        memcpy(path, index, prefixlen);
207                        memcpy(path + prefixlen, file, filelen);
208                    } else {
209                        totallen = prefixlen + filelen + 1;
210# ifdef PATH_MAX
211                        if (totallen >= PATH_MAX) {
212                            continue;
213                        }
214# endif
215                        path = lmt_memory_malloc(totallen + 1);
216                        memcpy(path, index, prefixlen);
217                        path[prefixlen] = '/';
218                        memcpy(path + prefixlen + 1, file, filelen);
219                    }
220                    path[totallen] = '\0';
221                    if (access(path, X_OK) >= 0) {
222                        break;
223                    }
224                    lmt_memory_free(path);
225                    path = NULL;
226                    index = esp + 1;
227                } while (esp);
228            }
229            lmt_memory_free(searchpath);
230            if (path) {
231                return path;
232            } else {
233                return lmt_memory_strdup("."); /* ok? */
234            }
235        }
236    }
237
238    /*tex We alwways return a copy so that we're consistent with windows/unix. */
239
240    char *aux_utf8_readlink(const char *file)
241    {
242        int size = 256;
243        while (1) {
244            char *target = lmt_memory_malloc(size);
245            if (! target) {
246                break;
247            } else {
248                int tsize = readlink(file, target, size);
249                if (tsize <= 0) {
250                    lmt_memory_free(target);
251                    break;
252                } else if (tsize < size) {
253                    target[tsize] = '\0';
254                    return target;
255                } else {
256                    size *= 2;
257                }
258            }
259        }
260        return lmt_memory_strdup(file);
261    }
262
263# endif
264
265# ifndef S_ISREG
266    # define S_ISREG(mode) (mode & _S_IFREG)
267# endif
268
269# ifdef _WIN32
270
271    char *aux_basename(const char *name) {
272        char base[256+1];
273        char suff[256+1];
274        _splitpath(name,NULL,NULL,base,suff);
275        {
276            size_t b = strlen((const char*)base);
277            size_t s = strlen((const char*)suff);
278            char *result = (char *) lmt_memory_malloc(sizeof(char) * (b+s+1));
279            if (result) {
280                memcpy(&result[0], &base[0], b);
281                memcpy(&result[b], &suff[0], s);
282                result[b + s] = '\0';
283            }
284            return result;
285        }
286    }
287
288    char *aux_dirname(const char *name) {
289        char driv[256 + 1];
290        char path[256 + 1];
291        _splitpath(name,driv,path,NULL,NULL);
292        {
293            size_t d = strlen((const char*)driv);
294            size_t p = strlen((const char*)path);
295            char *result = (char *) lmt_memory_malloc(sizeof(char) * (d+p+1));
296            if (result) {
297                if (path[p - 1] == '/' || path[p - 1] == '\\') {
298                    --p;
299                }
300                memcpy(&result[0], &driv[0], d);
301                memcpy(&result[d], &path[0], p);
302                result[d + p] = '\0';
303            }
304            return result;
305        }
306    }
307
308    int aux_is_readable(const char *filename)
309    {
310        struct _stati64 info;
311        LPWSTR w = aux_utf8_to_wide(filename);
312        int r = _wstati64(w, &info);
313        FILE *f;
314        lmt_memory_free(w);
315        return (r == 0)
316            && (S_ISREG(info.st_mode))
317            && ((f = aux_utf8_fopen(filename, "r")) != NULL)
318            && ! fclose(f);
319    }
320
321# else
322
323    # include <libgen.h>
324
325    int aux_is_readable(const char *filename)
326    {
327        struct stat finfo;
328        FILE *f;
329        return (stat(filename, &finfo) == 0)
330            && S_ISREG(finfo.st_mode)
331            && ((f = fopen(filename, "r")) != NULL)
332            && ! fclose(f);
333    }
334
335# endif
336