@@ -143,29 +143,67 @@ nonnull_all
143
143
static int32_t open_file (
144
144
parser_t * parser , zone_file_t * file , const char * path , size_t length )
145
145
{
146
+ char * abs = NULL ;
147
+
146
148
(void )parser ;
147
149
148
150
if (!(file -> name = strndup (path , length )))
149
151
return ZONE_OUT_OF_MEMORY ;
150
152
153
+ const char * rel = file -> name ;
154
+
151
155
#if _WIN32
152
156
char buf [1 ];
153
- DWORD size = GetFullPathName (file -> name , sizeof (buf ), buf , NULL );
157
+ // relative include paths are relative to including file
158
+ if (file != & parser -> first && PathIsRelative (path )) {
159
+ assert (parser -> file -> path != not_a_file );
160
+ assert (parser -> file -> handle != NULL );
161
+ const char * dir = parser -> file -> path ;
162
+ int dirlen = 0 ;
163
+ for (int i = 0 ; i < INT32_MAX && dir [i ]; i ++ ) {
164
+ if (dir [i ] == '/' || dir [i ] == '\\' )
165
+ dirlen = i + 1 ;
166
+ }
167
+ int len ;
168
+ len = snprintf (buf , sizeof (buf ), "%.*s\\%s" , dirlen , dir , file -> name );
169
+ assert (len != -1 );
170
+ if (!(abs = malloc (len + 1 )))
171
+ return ZONE_READ_ERROR ;
172
+ (void )snprintf (abs , len + 1 , "%.*s\\%s" , dirlen , dir , file -> name );
173
+ rel = abs ;
174
+ }
175
+ DWORD size = GetFullPathName (rel , sizeof (buf ), buf , NULL );
154
176
if (!size )
155
- return ZONE_READ_ERROR ;
177
+ goto read_error ;
156
178
if (!(file -> path = malloc (size )))
157
- return ZONE_OUT_OF_MEMORY ;
158
- if (!(length = GetFullPathName (file -> name , size , file -> path , NULL )))
159
- return ZONE_READ_ERROR ;
160
- if (length != size - 1 )
161
- return ZONE_READ_ERROR ;
179
+ goto out_of_memory ;
180
+ (void )GetFullPathName (rel , size , file -> path , NULL );
162
181
#else
163
182
char buf [PATH_MAX ];
164
- if (!realpath (file -> name , buf ))
165
- return ZONE_READ_ERROR ;
183
+ if (file != & parser -> first && path [0 ] != '/' ) {
184
+ assert (parser -> file -> path != not_a_file );
185
+ assert (parser -> file -> handle != NULL );
186
+ const char * dir = parser -> file -> path ;
187
+ int dirlen = 0 ;
188
+ for (int i = 0 ; i < INT32_MAX && dir [i ]; i ++ ) {
189
+ if (dir [i ] == '/' )
190
+ dirlen = i + 1 ;
191
+ }
192
+ int len ;
193
+ len = snprintf (buf , sizeof (buf ), "%.*s/%s" , dirlen , dir , file -> name );
194
+ if (!(abs = malloc ((size_t )len + 1 )))
195
+ return ZONE_OUT_OF_MEMORY ;
196
+ (void )snprintf (abs , (size_t )len + 1 , "%.*s/%s" , dirlen , dir , file -> name );
197
+ rel = abs ;
198
+ }
199
+ if (!realpath (rel , buf ))
200
+ goto read_error ;
166
201
if (!(file -> path = strdup (buf )))
167
- return ZONE_OUT_OF_MEMORY ;
202
+ goto out_of_memory ;
168
203
#endif
204
+ if (abs )
205
+ free (abs );
206
+ abs = NULL ;
169
207
170
208
if (!(file -> handle = fopen (file -> path , "rb" )))
171
209
switch (errno ) {
@@ -192,6 +230,12 @@ static int32_t open_file(
192
230
file -> lines .head = file -> lines .tape ;
193
231
file -> lines .tail = file -> lines .tape ;
194
232
return 0 ;
233
+ read_error :
234
+ if (abs ) free (abs );
235
+ return ZONE_READ_ERROR ;
236
+ out_of_memory :
237
+ if (abs ) free (abs );
238
+ return ZONE_OUT_OF_MEMORY ;
195
239
}
196
240
197
241
diagnostic_pop ()
0 commit comments