a68g-path.c
1 //! @file a68g-path.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Low-level file path routines.
25
26 #include "a68g.h"
27 #include "a68g-prelude.h"
28 #include "a68g-genie.h"
29
30 #if defined (BUILD_WIN32)
31 #include <windows.h>
32 #endif
33
34 //! @brief Safely get dir name from path.
35
36 char *a68_dirname (char *src)
37 {
38 int len = (int) strlen (src) + 1;
39 char *cpy = (char *) get_fixed_heap_space (len + 1);
40 char *dst = (char *) get_fixed_heap_space (len + 1);
41 ABEND (cpy == NO_TEXT, ERROR_OUT_OF_CORE, __func__);
42 ABEND (dst == NO_TEXT, ERROR_OUT_OF_CORE, __func__);
43 a68_bufcpy (cpy, src, len);
44 a68_bufcpy (dst, dirname (cpy), len);
45 return dst;
46 }
47
48 //! @brief Safely get basename from path.
49
50 char *a68_basename (char *src)
51 {
52 int len = (int) strlen (src) + 1;
53 char *cpy = (char *) get_fixed_heap_space (len + 1);
54 char *dst = (char *) get_fixed_heap_space (len + 1);
55 ABEND (cpy == NO_TEXT, ERROR_OUT_OF_CORE, __func__);
56 ABEND (dst == NO_TEXT, ERROR_OUT_OF_CORE, __func__);
57 a68_bufcpy (cpy, src, len);
58 a68_bufcpy (dst, basename (cpy), len);
59 return dst;
60 }
61
62 //! @brief Compute relative path.
63
64 #if defined (BUILD_WIN32)
65
66 static char *win32_slash (char *p)
67 {
68 char *q = p;
69 while (*p != '\0') {
70 if (*p == '\\') {
71 *p = '/';
72 }
73 p++;
74 }
75 return q;
76 }
77
78 static char *win32_realpath (char *name, char *resolved)
79 {
80 char *res = NO_TEXT;
81 if (name == NO_TEXT || name[0] == '\0') {
82 return NO_TEXT;
83 }
84 if (resolved == NO_TEXT) {
85 res = (char *) get_fixed_heap_space (PATH_MAX + 1);
86 if (res == NO_TEXT) {
87 return NO_TEXT;
88 }
89 } else {
90 res = resolved;
91 }
92 int ret = GetFullPathName (name, PATH_MAX, res, (char **) NO_TEXT);
93 if (ret == 0) {
94 return NO_TEXT;
95 } else {
96 win32_slash (res);
97 struct stat st;
98 if (stat (res, &st) < 0) { // Should be 'lstat', but mingw does not have that.
99 if (resolved == NO_TEXT) {
100 free (res);
101 return NO_TEXT;
102 }
103 }
104 }
105 return res;
106 }
107
108 #endif
109
110 char *a68_relpath (char *p1, char *p2, char *fn)
111 {
112 char q[PATH_MAX + 1];
113 a68_bufcpy (q, p1, PATH_MAX);
114 a68_bufcat (q, "/", PATH_MAX);
115 a68_bufcat (q, p2, PATH_MAX);
116 a68_bufcat (q, "/", PATH_MAX);
117 a68_bufcat (q, fn, PATH_MAX);
118 // Home directory shortcut ~ is a shell extension.
119 if (strchr (q, '~') != NO_TEXT) {
120 return NO_TEXT;
121 }
122 char *r = (char *) get_fixed_heap_space (PATH_MAX + 1);
123 ABEND (r == NO_TEXT, ERROR_OUT_OF_CORE, __func__);
124 // Error handling in the caller!
125 errno = 0;
126 #if defined (BUILD_WIN32)
127 r = win32_realpath (q, NO_TEXT);
128 #else
129 r = realpath (q, NO_TEXT);
130 #endif
131 return r;
132 }
133
134 //! @brief PROC (STRING) STRING realpath
135
136 void genie_realpath (NODE_T * p)
137 {
138 A68_REF str;
139 POP_REF (p, &str);
140 char in[PATH_MAX + 1];
141 if (a_to_c_string (p, in, str) == NO_TEXT) {
142 PUSH_REF (p, empty_string (p));
143 } else {
144 // Note that ~ is not resolved since that is the shell, not libc.
145 #if defined (BUILD_WIN32)
146 char *out = win32_realpath (in, NO_TEXT);
147 #else
148 char *out = realpath (in, NO_TEXT);
149 #endif
150 if (out == NO_TEXT) {
151 PUSH_REF (p, empty_string (p));
152 } else {
153 PUSH_REF (p, c_to_a_string (p, out, PATH_MAX));
154 }
155 }
156 }
157
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|