1 /*****************************************************************************
2  * Copyright (c) 2019 FrontISTR Commons
3  * This software is released under the MIT License, see LICENSE.txt
4  *****************************************************************************/
5 
6 #include <stdio.h>
7 #include <ctype.h>
8 #include <string.h>
9 #include <errno.h>
10 #include "hecmw_config.h"
11 #include "hecmw_path.h"
12 #include "hecmw_util.h"
13 
14 #ifdef __MINGW32__
15 #define PATH_SEPARATOR '/'
16 #elif __MINGW64__
17 #define PATH_SEPARATOR '/'
18 #elif __CYGWIN__
19 #define PATH_SEPARATOR '/'
20 #elif __WIN32__
21 #define PATH_SEPARATOR '\\'
22 #else
23 #define PATH_SEPARATOR '/'
24 #endif
25 
26 #ifdef __WIN32__
27 #define isslash(c) ((c) == '/' || (c) == '\\')
28 #elif __CYGWIN__
29 #define isslash(c) ((c) == '/' || (c) == '\\')
30 #else
31 #define isslash(c) ((c) == '/')
32 #endif
33 
HECMW_get_path_separator(void)34 int HECMW_get_path_separator(void) { return PATH_SEPARATOR; }
35 
has_drive(const char * path)36 static int has_drive(const char *path) {
37   const char *p = path;
38 
39   if (path == NULL) return 0;
40   if (!*p || !isalpha(*p)) return 0;
41   p++;
42   return (*p == ':');
43 }
44 
HECMW_is_absolute_path(const char * path)45 int HECMW_is_absolute_path(const char *path) {
46   if (path == NULL) return 0;
47 
48 #ifdef __WIN32__
49   if (*path && isslash(*path)) return 1;
50   return has_drive(path);
51 #elif __CYGWIN__
52   if (*path && isslash(*path)) return 1;
53   return has_drive(path);
54 #else
55   return (*path && isslash(*path));
56 #endif
57 }
58 
dir_name(const char * path)59 static char *dir_name(const char *path) {
60   const char *p;
61   static char dname[HECMW_FILENAME_LEN + 1];
62 
63   if (path == NULL || strlen(path) == 0) {
64     strcpy(dname, ".");
65     return dname;
66   }
67 
68   p = path + strlen(path) - 1;
69   while (p > path && isslash(*p)) {
70     p--;
71   }
72 
73   while (p > path && !isslash(*p)) {
74     p--;
75   }
76 
77   if (p == path) {
78     sprintf(dname, "%c", isslash(*p) ? PATH_SEPARATOR : '.');
79     return dname;
80   } else {
81     do {
82       p--;
83     } while (p > path && isslash(*p));
84   }
85 
86   if (p - path + 1 > HECMW_FILENAME_LEN) {
87     errno = ENAMETOOLONG;
88     return NULL;
89   }
90   strncpy(dname, path, p - path + 1);
91   dname[p - path + 1] = '\0';
92 
93   return dname;
94 }
95 
base_name(const char * path)96 static char *base_name(const char *path) {
97   const char *sp, *ep;
98   static char bname[HECMW_FILENAME_LEN + 1];
99 
100   if (path == NULL || strlen(path) == 0) {
101     strcpy(bname, ".");
102     return bname;
103   }
104 
105   ep = path + strlen(path) - 1;
106   while (ep > path && isslash(*ep)) {
107     ep--;
108   }
109 
110   if (ep == path && isslash(*ep)) {
111     sprintf(bname, "%c", PATH_SEPARATOR);
112     return bname;
113   }
114 
115   sp = ep;
116   while (sp > path && !isslash(*(sp - 1))) {
117     sp--;
118   }
119 
120   if (ep - sp + 1 > HECMW_FILENAME_LEN) {
121     errno = ENAMETOOLONG;
122     return NULL;
123   }
124   strncpy(bname, sp, ep - sp + 1);
125   bname[ep - sp + 1] = '\0';
126 
127   return bname;
128 }
129 
get_bdname(const char * path,int type)130 static char *get_bdname(const char *path, int type) {
131   const char *p, *q;
132   static char bname[HECMW_FILENAME_LEN + 1];
133   char drive[10] = "";
134 
135   if (has_drive(path)) {
136     p = path + 2;
137     sprintf(drive, "%.2s", path);
138   } else {
139     p = path;
140   }
141   if (type == 'B') { /* basename */
142     q = base_name(p);
143   } else { /* dirname */
144     q = dir_name(p);
145   }
146   if (q == NULL) return NULL;
147   if (strlen(drive) > 0 && isslash(*q)) {
148     if (strlen(drive) + strlen(q) > HECMW_FILENAME_LEN) {
149       errno = ENAMETOOLONG;
150       return NULL;
151     }
152     sprintf(bname, "%s%s", drive, q);
153   } else {
154     sprintf(bname, "%s", q);
155   }
156   return bname;
157 }
158 
HECMW_basename(const char * path)159 char *HECMW_basename(const char *path) {
160   char *bname = get_bdname(path, 'B');
161   if (bname == NULL) {
162     HECMW_set_error(errno, "");
163   }
164   return bname;
165 }
166 
HECMW_dirname(const char * path)167 char *HECMW_dirname(const char *path) {
168   char *dname = get_bdname(path, 'D');
169   if (dname == NULL) {
170     HECMW_set_error(errno, "");
171   }
172   return dname;
173 }
174