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