gpath.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*
  2. * Portable Utility Functions
  3. *
  4. * Author:
  5. * Miguel de Icaza (miguel@novell.com)
  6. *
  7. * (C) 2006 Novell, Inc.
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining
  10. * a copy of this software and associated documentation files (the
  11. * "Software"), to deal in the Software without restriction, including
  12. * without limitation the rights to use, copy, modify, merge, publish,
  13. * distribute, sublicense, and/or sell copies of the Software, and to
  14. * permit persons to whom the Software is furnished to do so, subject to
  15. * the following conditions:
  16. *
  17. * The above copyright notice and this permission notice shall be
  18. * included in all copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. */
  28. #include <config.h>
  29. #include <stdio.h>
  30. #include <glib.h>
  31. #include <errno.h>
  32. #include <sys/stat.h>
  33. #ifdef G_OS_WIN32
  34. #include <direct.h>
  35. #endif
  36. #ifdef HAVE_UNISTD_H
  37. #include <unistd.h>
  38. #endif
  39. gchar *
  40. g_build_path (const gchar *separator, const gchar *first_element, ...)
  41. {
  42. const char *elem, *next, *endptr;
  43. gboolean trimmed;
  44. GString *path;
  45. va_list args;
  46. size_t slen;
  47. g_return_val_if_fail (separator != NULL, NULL);
  48. path = g_string_sized_new (48);
  49. slen = strlen (separator);
  50. va_start (args, first_element);
  51. for (elem = first_element; elem != NULL; elem = next) {
  52. /* trim any trailing separators from @elem */
  53. endptr = elem + strlen (elem);
  54. trimmed = FALSE;
  55. while (endptr >= elem + slen) {
  56. if (strncmp (endptr - slen, separator, slen) != 0)
  57. break;
  58. endptr -= slen;
  59. trimmed = TRUE;
  60. }
  61. /* append elem, not including any trailing separators */
  62. if (endptr > elem)
  63. g_string_append_len (path, elem, endptr - elem);
  64. /* get the next element */
  65. do {
  66. if (!(next = va_arg (args, char *)))
  67. break;
  68. /* remove leading separators */
  69. while (!strncmp (next, separator, slen))
  70. next += slen;
  71. } while (*next == '\0');
  72. if (next || trimmed)
  73. g_string_append_len (path, separator, slen);
  74. }
  75. va_end (args);
  76. return g_string_free (path, FALSE);
  77. }
  78. static gchar*
  79. strrchr_seperator (const gchar* filename)
  80. {
  81. #ifdef G_OS_WIN32
  82. char *p2;
  83. #endif
  84. char *p;
  85. p = (char*)strrchr (filename, G_DIR_SEPARATOR);
  86. #ifdef G_OS_WIN32
  87. p2 = (char*)strrchr (filename, '/');
  88. if (p2 > p)
  89. p = p2;
  90. #endif
  91. return p;
  92. }
  93. gchar *
  94. g_path_get_dirname (const gchar *filename)
  95. {
  96. char *p, *r;
  97. size_t count;
  98. g_return_val_if_fail (filename != NULL, NULL);
  99. p = strrchr_seperator (filename);
  100. if (p == NULL)
  101. return g_strdup (".");
  102. if (p == filename)
  103. return g_strdup ("/");
  104. count = p - filename;
  105. r = g_malloc (count + 1);
  106. strncpy (r, filename, count);
  107. r [count] = 0;
  108. return r;
  109. }
  110. gchar *
  111. g_path_get_basename (const char *filename)
  112. {
  113. char *r;
  114. g_return_val_if_fail (filename != NULL, NULL);
  115. /* Empty filename -> . */
  116. if (!*filename)
  117. return g_strdup (".");
  118. /* No separator -> filename */
  119. r = strrchr_seperator (filename);
  120. if (r == NULL)
  121. return g_strdup (filename);
  122. /* Trailing slash, remove component */
  123. if (r [1] == 0){
  124. char *copy = g_strdup (filename);
  125. copy [r-filename] = 0;
  126. r = strrchr_seperator (copy);
  127. if (r == NULL){
  128. g_free (copy);
  129. return g_strdup ("/");
  130. }
  131. r = g_strdup (&r[1]);
  132. g_free (copy);
  133. return r;
  134. }
  135. return g_strdup (&r[1]);
  136. }
  137. //wasm does have strtok_r even though autoconf fails to find
  138. #if !defined (HAVE_STRTOK_R) && !defined (HOST_WASM)
  139. // This is from BSD's strtok_r
  140. char *
  141. strtok_r(char *s, const char *delim, char **last)
  142. {
  143. char *spanp;
  144. int c, sc;
  145. char *tok;
  146. if (s == NULL && (s = *last) == NULL)
  147. return NULL;
  148. /*
  149. * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
  150. */
  151. cont:
  152. c = *s++;
  153. for (spanp = (char *)delim; (sc = *spanp++) != 0; ){
  154. if (c == sc)
  155. goto cont;
  156. }
  157. if (c == 0){ /* no non-delimiter characters */
  158. *last = NULL;
  159. return NULL;
  160. }
  161. tok = s - 1;
  162. /*
  163. * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
  164. * Note that delim must have one NUL; we stop if we see that, too.
  165. */
  166. for (;;){
  167. c = *s++;
  168. spanp = (char *)delim;
  169. do {
  170. if ((sc = *spanp++) == c) {
  171. if (c == 0)
  172. s = NULL;
  173. else {
  174. char *w = s - 1;
  175. *w = '\0';
  176. }
  177. *last = s;
  178. return tok;
  179. }
  180. }
  181. while (sc != 0);
  182. }
  183. /* NOTREACHED */
  184. }
  185. #endif
  186. gchar *
  187. g_find_program_in_path (const gchar *program)
  188. {
  189. char *p;
  190. char *x, *l;
  191. gchar *curdir = NULL;
  192. char *save = NULL;
  193. #ifdef G_OS_WIN32
  194. char *program_exe;
  195. static char const * const suffix_list[5] = {".exe",".cmd",".bat",".com",NULL};
  196. int listx;
  197. gboolean hasSuffix;
  198. #endif
  199. g_return_val_if_fail (program != NULL, NULL);
  200. x = p = g_getenv ("PATH");
  201. if (x == NULL || *x == '\0') {
  202. curdir = g_get_current_dir ();
  203. x = curdir;
  204. }
  205. #ifdef G_OS_WIN32
  206. /* see if program already has a suffix */
  207. listx = 0;
  208. hasSuffix = FALSE;
  209. while (!hasSuffix && suffix_list[listx]) {
  210. hasSuffix = g_str_has_suffix(program,suffix_list[listx++]);
  211. }
  212. #endif
  213. while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
  214. char *probe_path;
  215. x = NULL;
  216. probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
  217. #ifdef HAVE_ACCESS
  218. if (g_access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
  219. g_free (curdir);
  220. g_free (p);
  221. return probe_path;
  222. }
  223. #endif
  224. g_free (probe_path);
  225. #ifdef G_OS_WIN32
  226. /* check for program with a suffix attached */
  227. if (!hasSuffix) {
  228. listx = 0;
  229. while (suffix_list[listx]) {
  230. program_exe = g_strjoin (NULL, program, suffix_list [listx], (const char*)NULL);
  231. probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program_exe, (const char*)NULL);
  232. #ifdef HAVE_ACCESS
  233. if (g_access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
  234. g_free (curdir);
  235. g_free (p);
  236. g_free (program_exe);
  237. return probe_path;
  238. }
  239. #endif
  240. listx++;
  241. g_free (probe_path);
  242. g_free (program_exe);
  243. }
  244. }
  245. #endif
  246. }
  247. g_free (curdir);
  248. g_free (p);
  249. return NULL;
  250. }
  251. static char *name;
  252. void
  253. g_set_prgname (const gchar *prgname)
  254. {
  255. name = g_strdup (prgname);
  256. }
  257. gchar *
  258. g_get_prgname (void)
  259. {
  260. return name;
  261. }
  262. gboolean
  263. g_ensure_directory_exists (const gchar *filename)
  264. {
  265. #ifdef G_OS_WIN32
  266. gchar *dir_utf8 = g_path_get_dirname (filename);
  267. gunichar2 *p;
  268. gunichar2 *dir_utf16 = NULL;
  269. int retval;
  270. if (!dir_utf8 || !dir_utf8 [0])
  271. return FALSE;
  272. dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
  273. g_free (dir_utf8);
  274. if (!dir_utf16)
  275. return FALSE;
  276. p = dir_utf16;
  277. /* make life easy and only use one directory seperator */
  278. while (*p != '\0')
  279. {
  280. if (*p == '/')
  281. *p = '\\';
  282. p++;
  283. }
  284. p = dir_utf16;
  285. /* get past C:\ )*/
  286. while (*p++ != '\\')
  287. {
  288. }
  289. while (1) {
  290. p = wcschr (p, '\\');
  291. if (p)
  292. *p = '\0';
  293. retval = _wmkdir (dir_utf16);
  294. if (retval != 0 && errno != EEXIST) {
  295. g_free (dir_utf16);
  296. return FALSE;
  297. }
  298. if (!p)
  299. break;
  300. *p++ = '\\';
  301. }
  302. g_free (dir_utf16);
  303. return TRUE;
  304. #else
  305. char *p;
  306. gchar *dir = g_path_get_dirname (filename);
  307. int retval;
  308. struct stat sbuf;
  309. if (!dir || !dir [0]) {
  310. g_free (dir);
  311. return FALSE;
  312. }
  313. if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
  314. g_free (dir);
  315. return TRUE;
  316. }
  317. p = dir;
  318. while (*p == '/')
  319. p++;
  320. while (1) {
  321. p = strchr (p, '/');
  322. if (p)
  323. *p = '\0';
  324. retval = mkdir (dir, 0777);
  325. if (retval != 0 && errno != EEXIST) {
  326. g_free (dir);
  327. return FALSE;
  328. }
  329. if (!p)
  330. break;
  331. *p++ = '/';
  332. }
  333. g_free (dir);
  334. return TRUE;
  335. #endif
  336. }