add a CVS snapshot, to thoroughly test on the Debian side
[alioth/jupp.git] / path.c
1 /* $MirOS: contrib/code/jupp/path.c,v 1.12 2016/10/29 23:44:45 tg Exp $ */
2 /* 
3  *      Directory and path functions
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *
7  *      This file is part of JOE (Joe's Own Editor)
8  */
9 #include "config.h"
10 #include "types.h"
11
12 #include <stdio.h>
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_STAT_H
15 #include <sys/stat.h>
16 #endif
17 #include <fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
20 #ifdef HAVE_PATHS_H
21 #  include <paths.h>    /* for _PATH_TMP */
22 #endif
23 #ifdef HAVE_LIMITS_H
24 #include <limits.h>
25 #endif
26 #ifdef HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif
29
30 #ifdef HAVE_BSD_STRING_H
31 #include <bsd/string.h>
32 #endif
33
34 #include "path.h"
35 #include "vs.h"
36 #include "va.h"
37
38 #ifdef TIME_WITH_SYS_TIME
39 # include <sys/time.h>
40 # include <time.h>
41 #else
42 # ifdef HAVE_SYS_TIME_H
43 #  include <sys/time.h>
44 # else
45 #  include <time.h>
46 # endif
47 #endif
48
49 #ifdef HAVE_DIRENT_H
50 #  include <dirent.h>
51 #  define NAMLEN(dirent) strlen((dirent)->d_name)
52 #else
53 #  ifdef HAVE_SYS_DIRENT_H
54 #    include <sys/dirent.h>
55 #    define NAMLEN(dirent) strlen((dirent)->d_name)
56 #  else
57 #    define direct dirent
58 #    define NAMLEN(dirent) (dirent)->d_namlen
59 #    ifdef HAVE_SYS_NDIR_H
60 #      include <sys/ndir.h>
61 #    else
62 #      ifdef HAVE_SYS_DIR_H
63 #        include <sys/dir.h>
64 #      else
65 #        ifdef HAVE_NDIR_H
66 #          include <ndir.h>
67 #        else
68 #          ifndef __MSDOS__
69 #            include "dir.c"
70 #          endif
71 #        endif
72 #      endif
73 #    endif
74 #  endif
75 #endif
76
77 #if HAVE_DRIVE_LETTERS
78 #define do_if_drive_letter(path, command) do {          \
79         if ((path)[1] == ':' && (                       \
80             ((path)[0] >= 'a' && (path)[0] <= 'z') ||   \
81             ((path)[0] >= 'A' && (path)[0] <= 'Z'))) {  \
82                 command;                                \
83         }                                               \
84 } while (/* CONSTCOND */ 0)
85 #else
86 #define do_if_drive_letter(path, command) do { } while (/* CONSTCOND */ 0)
87 #endif
88 #define skip_drive_letter(path) do_if_drive_letter((path), (path) += 2)
89
90 #ifndef         _PATH_TMP
91 #  ifdef __MSDOS__
92 #    define     _PATH_TMP       ""
93 #  else
94 #    define     _PATH_TMP       "/tmp/"
95 #  endif
96 #endif
97
98 #if !defined(PATH_MAX) && !defined(HAVE_GET_CURRENT_DIR_NAME)
99 #warning What should we include to have PATH_MAX defined?
100 #define PATH_MAX        4096
101 #endif
102
103 /********************************************************************/
104 #if HAVE_BACKSLASH_PATHS
105 unsigned char *joesep(unsigned char *path)
106 {
107         int x;
108
109         for (x = 0; path[x]; ++x)
110                 if (path[x] == '\\')
111                         path[x] = '/';
112         return path;
113 }
114 #endif
115 /********************************************************************/
116 unsigned char *namprt(unsigned char *path)
117 {
118         unsigned char *z;
119
120         skip_drive_letter(path);
121         z = path + slen(path);
122         while ((z != path) && (z[-1] != '/'))
123                 --z;
124         return vsncpy(NULL, 0, sz(z));
125 }
126 /********************************************************************/
127 unsigned char *namepart(unsigned char *tmp, unsigned char *path)
128 {
129         unsigned char *z;
130
131         skip_drive_letter(path);
132         z = path + strlen((char *)path);
133         while ((z != path) && (z[-1] != '/'))
134                 --z;
135         strlcpy((char *)tmp, (char *)z, 1024);
136         return (tmp);
137 }
138 /********************************************************************/
139 unsigned char *dirprt_ptr(unsigned char *path)
140 {
141         unsigned char *b = path;
142         unsigned char *z = path + slen(path);
143
144         skip_drive_letter(b);
145         while ((z != b) && (z[-1] != '/'))
146                 --z;
147         return (z);
148 }
149 unsigned char *dirprt(unsigned char *path)
150 {
151         return vsncpy(NULL, 0, path, dirprt_ptr(path) - path);
152 }
153 /********************************************************************/
154 unsigned char *begprt(unsigned char *path)
155 {
156         unsigned char *z = path + slen(path);
157         int drv = 0;
158
159         do_if_drive_letter(path, drv = 2);
160         while ((z != path + drv) && (z[-1] == '/'))
161                 --z;
162         if (z == path + drv)
163                 return vsncpy(NULL, 0, sz(path));
164         else {
165                 while ((z != path + drv) && (z[-1] != '/'))
166                         --z;
167                 return vsncpy(NULL, 0, path, z - path);
168         }
169 }
170 /********************************************************************/
171 unsigned char *endprt(unsigned char *path)
172 {
173         unsigned char *z = path + slen(path);
174         int drv = 0;
175
176         do_if_drive_letter(path, drv = 2);
177         while ((z != path + drv) && (z[-1] == '/'))
178                 --z;
179         if (z == path + drv)
180                 return vsncpy(NULL, 0, sc(""));
181         else {
182                 while (z != path + drv && z[-1] != '/')
183                         --z;
184                 return vsncpy(NULL, 0, sz(z));
185         }
186 }
187 /********************************************************************/
188 int mkpath(unsigned char *path)
189 {
190         unsigned char *s;
191
192         if (path[0] == '/') {
193                 if (chddir("/"))
194                         return 1;
195                 s = path;
196                 goto in;
197         }
198
199         while (path[0]) {
200                 int c;
201
202                 for (s = path; (*s) && (*s != '/'); s++) ;
203                 c = *s;
204                 *s = 0;
205                 if (chddir((char *)path)) {
206                         if (mkdir((char *)path, 0777))
207                                 return 1;
208                         if (chddir((char *)path))
209                                 return 1;
210                 }
211                 *s = c;
212               in:
213                 while (*s == '/')
214                         ++s;
215                 path = s;
216         }
217         return 0;
218 }
219 /********************************************************************/
220 /* Create a temporary file */
221 /********************************************************************/
222 unsigned char *mktmp(unsigned char *where, int *fdp)
223 {
224 #ifndef HAVE_MKSTEMP
225         static unsigned seq = 0;
226 #endif
227         unsigned char *name;
228         int fd;
229         unsigned namesize;
230
231         if (!where)
232                 where = (unsigned char *)getenv("TMPDIR");
233         if (!where)
234                 where = (unsigned char *)getenv("TEMP");
235         if (!where)
236                 where = US _PATH_TMP;
237
238         namesize = strlen((char *)where) + 20;
239         name = vsmk(namesize);  /* [G.Ghibo'] we need to use vsmk() and not malloc() as
240                                    area returned by mktmp() is destroyed later with
241                                    vsrm(); */
242 #ifdef HAVE_MKSTEMP
243         joe_snprintf_1((char *)name, namesize, "%s/joe.tmp.XXXXXXXXXX", where);
244         if ((fd = mkstemp((char *)name)) == -1)
245                 return (NULL);  /* FIXME: vflsh() and vflshf() */
246                                 /* expect mktmp() always succeed!!! */
247         fchmod(fd, 0600);       /* Linux glibc 2.0 mkstemp() creates it with */
248                                 /* 0666 mode --> change it to 0600, so nobody */
249                                 /* else sees content of temporary file */
250 #else
251 #warning "Waah, this is insane! Consider getting mkstemp!"
252  loop:
253         seq = (seq + 1) % 10000;
254         joe_snprintf_3(name, namesize, "%s/joe.tmp.%04u%05u", where, seq,
255             (unsigned)(time(NULL) % 100000));
256         if ((fd = open(name, O_RDONLY)) != -1) {
257                 close(fd);
258                 goto loop;      /* FIXME: possible endless loop --> DoS attack */
259         }
260         if ((fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600)) == -1)
261                 return (NULL);  /* FIXME: see above */
262 #endif
263         if (fdp)
264                 *fdp = fd;
265         else
266                 close(fd);
267         return (name);
268 }
269 /********************************************************************/
270 int rmatch(unsigned char *a, unsigned char *b)
271 {
272         int flag, inv, c;
273
274         for (;;)
275                 switch (*a) {
276                 case '*':
277                         ++a;
278                         do {
279                                 if (rmatch(a, b))
280                                         return 1;
281                         } while (*b++);
282                         return 0;
283                 case '[':
284                         ++a;
285                         flag = 0;
286                         if (*a == '^') {
287                                 ++a;
288                                 inv = 1;
289                         } else
290                                 inv = 0;
291                         if (*a == ']')
292                                 if (*b == *a++)
293                                         flag = 1;
294                         while (*a && (c = *a++) != ']')
295                                 if ((c == '-') && (a[-2] != '[') && (*a)) {
296                                         if ((*b >= a[-2]) && (*b <= *a))
297                                                 flag = 1;
298                                 } else if (*b == c)
299                                         flag = 1;
300                         if ((!flag && !inv) || (flag && inv) || (!*b))
301                                 return 0;
302                         ++b;
303                         break;
304                 case '?':
305                         ++a;
306                         if (!*b)
307                                 return 0;
308                         ++b;
309                         break;
310                 case 0:
311                         if (!*b)
312                                 return 1;
313                         else
314                                 return 0;
315                 default:
316                         if (*a++ != *b++)
317                                 return 0;
318                 }
319 }
320 /********************************************************************/
321 int isreg(unsigned char *s)
322 {
323         int x;
324
325         for (x = 0; s[x]; ++x)
326                 if ((s[x] == '*') || (s[x] == '?') || (s[x] == '['))
327                         return 1;
328         return 0;
329 }
330 /********************************************************************/
331 #ifdef __MSDOS__
332 #include <dos.h>
333 #include <dir.h>
334
335 struct direct {
336         unsigned char d_name[16];
337 } direc;
338 int dirstate = 0;
339 struct ffblk ffblk;
340 unsigned char *dirpath = NULL;
341
342 void *opendir(unsigned char *path)
343 {
344         dirstate = 0;
345         return &direc;
346 }
347
348 void closedir()
349 {
350 }
351
352 struct direct *readdir()
353 {
354         int x;
355
356         if (dirstate) {
357                 if (findnext(&ffblk))
358                         return NULL;
359         } else {
360                 if (findfirst("*.*", &ffblk, FA_DIREC))
361                         return NULL;
362                 dirstate = 1;
363         }
364
365         strcpy(direc.d_name, ffblk.ff_name);
366         for (x = 0; direc.d_name[x]; ++x)
367                 direc.d_name[x] = tolower(direc.d_name[x]);
368         return &direc;
369 }
370 #endif
371 /********************************************************************/
372 unsigned char **rexpnd(unsigned char *word)
373 {
374         void *dir;
375         unsigned char **lst = NULL;
376
377         struct dirent *de;
378         dir = opendir(".");
379         if (dir) {
380                 while ((de = readdir(dir)) != NULL)
381                         if (strcmp(".", de->d_name))
382                                 if (rmatch(word, (unsigned char *)de->d_name))
383                                         lst = vaadd(lst, vsncpy(NULL, 0, sz((unsigned char *)de->d_name)));
384                 closedir(dir);
385         }
386         return lst;
387 }
388 /********************************************************************/
389 int chJpwd(const unsigned char *path)
390 {
391         unsigned char *fullpath;
392         int rv;
393
394         if (!has_JOERC)
395                 return (-1);
396         fullpath = vsncpy(NULL, 0, sz(get_JOERC));
397         fullpath = vsncpy(sv(fullpath), sz(path));
398         rv = chpwd(fullpath);
399         vsrm(fullpath);
400         return (rv);
401 }
402
403 int chpwd(const unsigned char *path)
404 {
405 #ifdef __MSDOS__
406         unsigned char buf[256];
407         int x;
408
409         if (!path)
410                 return 0;
411         if ((path[0]) && (path[1] == ':')) {
412                 if (_chdrive(path[0] & 0x1F))
413                         return -1;
414                 path += 2;
415         }
416         if (!path[0])
417                 return 0;
418         strcpy(buf, path);
419         x = strlen(buf);
420         while (x > 1) {
421                 --x;
422                 if ((buf[x] == '/') || (buf[x] == '\\'))
423                         buf[x] = 0;
424                 else
425                         break;
426         }
427         return chdir(buf);
428 #else
429         if ((!path) || (!path[0]))
430                 return 0;
431         return chdir((char *)path);
432 #endif
433 }
434
435 /* The pwd function */
436 unsigned char *pwd(void)
437 {
438 #if defined(PATH_MAX) || !defined(HAVE_GET_CURRENT_DIR_NAME)
439         static unsigned char buf[PATH_MAX];
440         unsigned char   *ret;
441
442 #ifdef HAVE_GETCWD
443         ret = (unsigned char *)getcwd((char *)buf, PATH_MAX - 1);
444 #else
445         ret = (unsigned char *)getwd((char *)buf);
446 #endif
447         buf[PATH_MAX - 1] = '\0';
448
449         return ret;
450 #else
451         /* Hurd */
452         static char *wd = NULL;
453
454         free(wd);
455         wd = get_current_dir_name();
456         return ((void *)wd);
457 #endif
458 }
459
460 #if JUPP_WIN32RELOC
461 unsigned char has_JOERC = 0;
462 unsigned char *get_JOERC = NULL;
463
464 extern char *cygwin32_argv0(void);
465
466 void init_JOERC(void)
467 {
468         struct stat sb;
469         char *sep;
470
471         if ((get_JOERC = (unsigned char *)cygwin32_argv0()) == NULL)
472                 return;
473         joesep(get_JOERC);
474         if ((sep = strrchr((char *)get_JOERC, '/')) == NULL)
475                 return;
476         if (stat(get_JOERC, &sb))
477                 return;
478         sep[1] = '\0';
479         has_JOERC = 1;
480 }
481 #endif