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-2025 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 ASSERT (p1 != NO_TEXT);
114 ASSERT (p2 != NO_TEXT);
115 ASSERT (fn != NO_TEXT);
116 #if defined (BUILD_WIN32)
117 if (p2[0] == '\\') {
118 a68_bufcpy (q, p2, PATH_MAX);
119 } else {
120 a68_bufcpy (q, p1, PATH_MAX);
121 a68_bufcat (q, "\\", PATH_MAX);
122 a68_bufcat (q, p2, PATH_MAX);
123 }
124 a68_bufcat (q, "\\", PATH_MAX);
125 a68_bufcat (q, fn, PATH_MAX);
126 #else
127 if (p2[0] == '/') {
128 // Absolute path starting at root.
129 a68_bufcpy (q, p2, PATH_MAX);
130 } else if (p2[0] == '~') {
131 // "~" is a shell extension, not Unix.
132 // We handle it anyway, as a courtesy.
133 a68_bufcpy (q, getenv("HOME"), PATH_MAX);
134 a68_bufcat (q, &p2[1], PATH_MAX);
135 } else {
136 a68_bufcpy (q, p1, PATH_MAX);
137 a68_bufcat (q, "/", PATH_MAX);
138 a68_bufcat (q, p2, PATH_MAX);
139 }
140 a68_bufcat (q, "/", PATH_MAX);
141 a68_bufcat (q, fn, PATH_MAX);
142 #endif
143 // Error handling in the caller!
144 errno = 0;
145 #if defined (BUILD_WIN32)
146 char *r = win32_realpath (q, NO_TEXT);
147 #else
148 char *r = realpath (q, NO_TEXT);
149 #endif
150 if (r != NO_TEXT) {
151 size_t len = strlen (r) + 1;
152 char *rc = (char *) get_fixed_heap_space (len);
153 ABEND (rc == NO_TEXT, ERROR_OUT_OF_CORE, __func__);
154 a68_bufcpy (rc, r, len);
155 free (r);
156 return rc;
157 } else {
158 return NO_TEXT;
159 }
160 }
161
162 //! @brief PROC (STRING) STRING realpath
163
164 void genie_realpath (NODE_T * p)
165 {
166 A68_REF str;
167 POP_REF (p, &str);
168 char in[PATH_MAX + 1];
169 if (a_to_c_string (p, in, str) == NO_TEXT) {
170 PUSH_REF (p, empty_string (p));
171 } else {
172 // Note that ~ is not resolved since that is the shell, not libc.
173 #if defined (BUILD_WIN32)
174 char *out = win32_realpath (in, NO_TEXT);
175 #else
176 char *out = realpath (in, NO_TEXT);
177 #endif
178 if (out == NO_TEXT) {
179 PUSH_REF (p, empty_string (p));
180 } else {
181 PUSH_REF (p, c_to_a_string (p, out, PATH_MAX));
182 }
183 }
184 }
185
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|