line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* |
2
|
|
|
|
|
|
|
* File: builtin_findfile.c |
3
|
|
|
|
|
|
|
* Author: Igor Vlasenko |
4
|
|
|
|
|
|
|
* Created: Tue Jul 14 22:47:11 2009 |
5
|
|
|
|
|
|
|
*/ |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#include /* for isalpha */ |
8
|
|
|
|
|
|
|
#include /* for getenv */ |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
/* TODO: support CYGWIN |
11
|
|
|
|
|
|
|
* see |
12
|
|
|
|
|
|
|
* http://sourceware.org/autobook/autobook/autobook_249.html |
13
|
|
|
|
|
|
|
*/ |
14
|
|
|
|
|
|
|
#if defined __CYGWIN32__ && !defined __CYGWIN__ |
15
|
|
|
|
|
|
|
/* For backwards compatibility with Cygwin b19 and |
16
|
|
|
|
|
|
|
earlier, we define __CYGWIN__ here, so that |
17
|
|
|
|
|
|
|
we can rely on checking just for that macro. */ |
18
|
|
|
|
|
|
|
# define __CYGWIN__ __CYGWIN32__ |
19
|
|
|
|
|
|
|
#endif |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#if defined _WIN32 && !defined __CYGWIN__ |
22
|
|
|
|
|
|
|
/* Use Windows separators on all _WIN32 defining |
23
|
|
|
|
|
|
|
environments, except Cygwin. */ |
24
|
|
|
|
|
|
|
# define DIR_SEPARATOR_CHAR '\\' |
25
|
|
|
|
|
|
|
#endif |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
#if defined (DIR_SEPARATOR_CHAR) |
28
|
|
|
|
|
|
|
# define IS_FILE_SEP(X) ((X=='/') || (X==DIR_SEPARATOR_CHAR)) |
29
|
|
|
|
|
|
|
#else |
30
|
|
|
|
|
|
|
# define IS_FILE_SEP(X) (X=='/') |
31
|
|
|
|
|
|
|
#endif |
32
|
|
|
|
|
|
|
|
33
|
343
|
|
|
|
|
|
static int _ff_exists(const char* path) { |
34
|
343
|
|
|
|
|
|
FILE *file_p = fopen(path, "r"); |
35
|
343
|
100
|
|
|
|
|
if (file_p) { |
36
|
310
|
|
|
|
|
|
fclose(file_p); |
37
|
310
|
50
|
|
|
|
|
if (debuglevel>=TMPL_LOG_DEBUG2) tmpl_log(TMPL_LOG_DEBUG2,"_ff_exists: found [%s]\n",path); |
38
|
310
|
|
|
|
|
|
return 1; |
39
|
|
|
|
|
|
|
} |
40
|
33
|
50
|
|
|
|
|
if (debuglevel>=TMPL_LOG_DEBUG2) tmpl_log(TMPL_LOG_ERROR,"_ff_exists: not found [%s]\n",path); |
41
|
33
|
|
|
|
|
|
return 0; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
/* lame dirname implementation */ |
45
|
68
|
|
|
|
|
|
static PSTRING _ff_dirname(const char* path) { |
46
|
68
|
|
|
|
|
|
PSTRING retval={(char*)path,(char*)path}; |
47
|
68
|
|
|
|
|
|
char c=0; |
48
|
68
|
50
|
|
|
|
|
if (path!=NULL) retval.endnext += strlen(path); |
49
|
0
|
|
|
|
|
|
else return retval; |
50
|
993
|
100
|
|
|
|
|
while (retval.endnext > retval.begin && (c=*(--retval.endnext)) && ! IS_FILE_SEP(c)); |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
51
|
|
|
|
|
|
|
/*fprintf(stderr,"built-in _ff_dirname: dir = %.*s\n",(int)(retval.endnext-retval.begin),retval.begin);*/ |
52
|
68
|
|
|
|
|
|
return retval; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
/* |
55
|
|
|
|
|
|
|
Windows Relative Paths |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
For functions that manipulate files, the file names can be relative to the current directory. A file name is relative to the current directory if it does not begin with one of the following: |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
* A UNC name of any format. |
60
|
|
|
|
|
|
|
* A disk designator with a backslash, for example "C:\". |
61
|
|
|
|
|
|
|
* A backslash, for example, "\directory"). |
62
|
|
|
|
|
|
|
*/ |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
/* remember about \\?\ and \\?\UNC\ prefixes on WIN platform. |
65
|
|
|
|
|
|
|
* see "File Names, Paths, and Namespaces" |
66
|
|
|
|
|
|
|
* http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx |
67
|
|
|
|
|
|
|
*/ |
68
|
310
|
|
|
|
|
|
int _ff_is_absolute(const char * filename) { |
69
|
310
|
|
|
|
|
|
unsigned char c0 = *filename; |
70
|
|
|
|
|
|
|
#if defined _WIN32 || defined __CYGWIN__ |
71
|
|
|
|
|
|
|
unsigned char c1; |
72
|
|
|
|
|
|
|
unsigned char c2; |
73
|
|
|
|
|
|
|
#endif |
74
|
310
|
50
|
|
|
|
|
if ('\0' == c0) return 0; |
75
|
|
|
|
|
|
|
/* \\?\ and \\?\UNC\ prefixes are included too */ |
76
|
310
|
50
|
|
|
|
|
if (IS_FILE_SEP(c0)) return 1; |
77
|
|
|
|
|
|
|
#if defined _WIN32 || defined __CYGWIN__ |
78
|
|
|
|
|
|
|
c1 = *(++filename); |
79
|
|
|
|
|
|
|
if ('\0' == c1) return 0; |
80
|
|
|
|
|
|
|
c2 = *(++filename); |
81
|
|
|
|
|
|
|
if (isalpha(c0) && ':'==c1 && IS_FILE_SEP(c2)) return 1; |
82
|
|
|
|
|
|
|
#endif |
83
|
310
|
|
|
|
|
|
return 0; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
#if defined _WIN32 || defined __CYGWIN__ |
87
|
|
|
|
|
|
|
int _ff_is_win_fully_qualified_path(const char * filename) { |
88
|
|
|
|
|
|
|
unsigned char c0 = *filename; |
89
|
|
|
|
|
|
|
unsigned char c1; |
90
|
|
|
|
|
|
|
unsigned char c2; |
91
|
|
|
|
|
|
|
if ('\0' == c0) return 0; |
92
|
|
|
|
|
|
|
c1 = *(++filename); |
93
|
|
|
|
|
|
|
if ('\0' == c1) return 0; |
94
|
|
|
|
|
|
|
c2 = *(++filename); |
95
|
|
|
|
|
|
|
/* \\?\ and \\?\UNC\ prefixes are included too */ |
96
|
|
|
|
|
|
|
if (isalpha(c0) && ':'==c1 && IS_FILE_SEP(c2)) return 1; |
97
|
|
|
|
|
|
|
if ('\\'==c0 && '\\'==c1 && '?'==c2 && '\\'==*filename) return 1; |
98
|
|
|
|
|
|
|
return 0; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
#endif |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
#define _ff_canonical_path(X) (X) |
103
|
|
|
|
|
|
|
|
104
|
6
|
|
|
|
|
|
static MPSTRING _shift_back_pstring_at(MPSTRING buf, char* pos, long shift) { |
105
|
6
|
50
|
|
|
|
|
if (pos >= buf.begin && (pos+shift) <=buf.endnext) { |
|
|
50
|
|
|
|
|
|
106
|
6
|
|
|
|
|
|
buf.endnext -= shift; |
107
|
176
|
100
|
|
|
|
|
while (pos
|
108
|
170
|
|
|
|
|
|
*pos=*(pos+shift); |
109
|
170
|
|
|
|
|
|
pos++; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
6
|
|
|
|
|
|
*buf.endnext='\0'; |
113
|
6
|
|
|
|
|
|
return buf; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
230
|
|
|
|
|
|
static MPSTRING _filepath_remove_multiple_slashes(MPSTRING buf) { |
117
|
230
|
|
|
|
|
|
char* pos = buf.begin; |
118
|
|
|
|
|
|
|
#if defined _WIN32 |
119
|
|
|
|
|
|
|
/* due to \\?\ and \\?\UNC\ prefixes on WIN platform. |
120
|
|
|
|
|
|
|
* see "File Names, Paths, and Namespaces" |
121
|
|
|
|
|
|
|
* http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx |
122
|
|
|
|
|
|
|
* we skip first 2 bytes of path |
123
|
|
|
|
|
|
|
*/ |
124
|
|
|
|
|
|
|
if (((buf.endnext-pos)>1) && ('\\'==*pos && '\\'==*(pos+1))) pos += 2; |
125
|
|
|
|
|
|
|
#endif |
126
|
5170
|
100
|
|
|
|
|
while (pos
|
127
|
4940
|
100
|
|
|
|
|
if (IS_FILE_SEP(*pos) && IS_FILE_SEP(*(pos+1))) buf=_shift_back_pstring_at(buf, pos, 1); |
|
|
50
|
|
|
|
|
|
128
|
4940
|
|
|
|
|
|
else pos++; |
129
|
|
|
|
|
|
|
} |
130
|
230
|
|
|
|
|
|
return buf; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
115
|
|
|
|
|
|
static const char* _ff_canonical_path_from_buf(MPSTRING buf) { |
134
|
|
|
|
|
|
|
char* pos; |
135
|
|
|
|
|
|
|
char* prev_slash_next; |
136
|
|
|
|
|
|
|
char* slash_begin; |
137
|
|
|
|
|
|
|
/* /./ <-- shift -2 */ |
138
|
115
|
|
|
|
|
|
pos = buf.begin; |
139
|
2478
|
100
|
|
|
|
|
while (pos
|
140
|
2363
|
100
|
|
|
|
|
if (IS_FILE_SEP(*pos) && ('.'==*(pos+1)) && IS_FILE_SEP(*(pos+2))) buf=_shift_back_pstring_at(buf, pos, 2); |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
141
|
2363
|
|
|
|
|
|
pos++; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
/* // <-- shift -1 */ |
145
|
115
|
|
|
|
|
|
buf=_filepath_remove_multiple_slashes(buf); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
/* /.* /../ shift (scan from prevslash to slash back) */ |
148
|
115
|
|
|
|
|
|
pos = buf.begin; |
149
|
115
|
|
|
|
|
|
slash_begin = buf.begin; |
150
|
|
|
|
|
|
|
#if defined _WIN32 |
151
|
|
|
|
|
|
|
/* check for C: */ |
152
|
|
|
|
|
|
|
if (((buf.endnext-pos)>1) && isalpha((unsigned char) *pos) && ':'==*(pos+1)) { |
153
|
|
|
|
|
|
|
pos += 2; |
154
|
|
|
|
|
|
|
slash_begin += 2; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
#endif |
157
|
115
|
|
|
|
|
|
prev_slash_next = slash_begin; |
158
|
2361
|
100
|
|
|
|
|
while (pos
|
159
|
|
|
|
|
|
|
/*printf("debug: %s pos=%c[%ld] fsn=%c[%ld]\n",buf.begin,*pos, pos-buf.begin, *prev_slash_next,prev_slash_next-buf.begin);*/ |
160
|
2246
|
100
|
|
|
|
|
if (IS_FILE_SEP(*pos)) { |
161
|
110
|
100
|
|
|
|
|
if (('.'==*(pos+1)) && ('.'==*(pos+2)) && IS_FILE_SEP(*(pos+3))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
162
|
|
|
|
|
|
|
/*printf("debug: do shift pos=%ld fsn=%ld shift=%ld\n", pos-buf.begin, prev_slash_next-buf.begin, pos-prev_slash_next+4);*/ |
163
|
1
|
50
|
|
|
|
|
if (pos == prev_slash_next && prev_slash_next==slash_begin) { |
|
|
0
|
|
|
|
|
|
164
|
|
|
|
|
|
|
/* begining of the string ("/../") -> leave one slash */ |
165
|
0
|
|
|
|
|
|
buf=_shift_back_pstring_at(buf, prev_slash_next, pos-prev_slash_next+3); |
166
|
0
|
|
|
|
|
|
pos=prev_slash_next-1;/* 1 to compensate pos++ */ |
167
|
|
|
|
|
|
|
} else { |
168
|
1
|
|
|
|
|
|
buf=_shift_back_pstring_at(buf, prev_slash_next, pos-prev_slash_next+4); |
169
|
1
|
|
|
|
|
|
pos=prev_slash_next-2;/* 2 to compensate / and pos++ */ |
170
|
|
|
|
|
|
|
/* 2 to step back slashnext char and 'slash' char, if any */ |
171
|
1
|
50
|
|
|
|
|
if (prev_slash_next>slash_begin) prev_slash_next--; |
172
|
1
|
50
|
|
|
|
|
if (prev_slash_next>slash_begin) prev_slash_next--; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
/* old prev_slash_next now current, so we need to recalculate it */ |
175
|
|
|
|
|
|
|
/* first find a 'slash' char */ |
176
|
10
|
100
|
|
|
|
|
while (prev_slash_next>=slash_begin && !IS_FILE_SEP(*prev_slash_next)) prev_slash_next--; |
|
|
50
|
|
|
|
|
|
177
|
1
|
50
|
|
|
|
|
if (prev_slash_next>slash_begin) prev_slash_next++;/* step next to slash */ |
178
|
|
|
|
|
|
|
} else { |
179
|
109
|
|
|
|
|
|
prev_slash_next=pos+1; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
} |
182
|
2246
|
|
|
|
|
|
pos++; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
/* // <-- shift -1 */ |
186
|
115
|
|
|
|
|
|
buf=_filepath_remove_multiple_slashes(buf); |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
/* offset 0: if ./ shift -2 */ |
189
|
115
|
50
|
|
|
|
|
if ((buf.endnext-buf.begin)<2) return buf.begin; |
190
|
115
|
|
|
|
|
|
pos = buf.begin; |
191
|
115
|
100
|
|
|
|
|
if (('.'==*pos) && IS_FILE_SEP(*(pos+1))) buf=_shift_back_pstring_at(buf, pos, 2); |
|
|
50
|
|
|
|
|
|
192
|
115
|
|
|
|
|
|
return buf.begin; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
68
|
|
|
|
|
|
static MPSTRING _ff_add_pstr_to_buffer(MPSTRING buf, PSTRING pstr) { |
196
|
68
|
|
|
|
|
|
MPSTRING ret = buf; |
197
|
|
|
|
|
|
|
const char* s; |
198
|
|
|
|
|
|
|
//tmpl_log(TMPL_LOG_ERROR,"_ff_add_pstr_to_buffer: called as [%p,%p]+[%p,%p]\n",buf.begin,buf.endnext, pstr.begin,pstr.endnext); |
199
|
423
|
100
|
|
|
|
|
for (s=pstr.begin;s
|
200
|
|
|
|
|
|
|
//tmpl_log(TMPL_LOG_ERROR,"_ff_add_pstr_to_buffer: ret = [%p,%p]\n",ret.begin,ret.endnext); |
201
|
68
|
|
|
|
|
|
return ret; |
202
|
|
|
|
|
|
|
} |
203
|
227
|
|
|
|
|
|
static MPSTRING _ff_add_str_to_buffer(MPSTRING buf, const char* str) { |
204
|
227
|
|
|
|
|
|
MPSTRING ret = buf; |
205
|
227
|
|
|
|
|
|
const char* s=str; |
206
|
|
|
|
|
|
|
//tmpl_log(TMPL_LOG_ERROR,"_ff_add_str_to_buffer: called as [%p,%p]+[%s]\n",buf.begin,buf.endnext, str); |
207
|
3010
|
100
|
|
|
|
|
while ('\0'!=*s) {*(ret.endnext++)=*s++;} |
208
|
|
|
|
|
|
|
//tmpl_log(TMPL_LOG_ERROR,"_ff_add_str_to_buffer: ret = [%p,%p]\n",ret.begin,ret.endnext); |
209
|
227
|
|
|
|
|
|
return ret; |
210
|
|
|
|
|
|
|
} |
211
|
112
|
|
|
|
|
|
static MPSTRING _ff_add_sep_to_buffer(MPSTRING buf) { |
212
|
112
|
|
|
|
|
|
MPSTRING ret = buf; |
213
|
112
|
50
|
|
|
|
|
if (ret.endnext>ret.begin && IS_FILE_SEP(*(ret.endnext-1))) return ret; |
|
|
100
|
|
|
|
|
|
214
|
|
|
|
|
|
|
#ifdef DIR_SEPARATOR_CHAR |
215
|
|
|
|
|
|
|
*(ret.endnext++)=DIR_SEPARATOR_CHAR; |
216
|
|
|
|
|
|
|
#else |
217
|
105
|
|
|
|
|
|
*(ret.endnext++)='/'; |
218
|
|
|
|
|
|
|
#endif |
219
|
112
|
|
|
|
|
|
return ret; |
220
|
|
|
|
|
|
|
} |
221
|
147
|
|
|
|
|
|
static MPSTRING _ff_add_0_to_buffer(MPSTRING buf) { |
222
|
147
|
|
|
|
|
|
*(buf.endnext++)='\0'; |
223
|
147
|
|
|
|
|
|
return buf; |
224
|
|
|
|
|
|
|
} |
225
|
310
|
|
|
|
|
|
static const char* get_template_root(struct tmplpro_param* param) { |
226
|
310
|
|
|
|
|
|
const char* retval = param->template_root; |
227
|
310
|
50
|
|
|
|
|
if (NULL==retval) retval = getenv("HTML_TEMPLATE_ROOT"); |
228
|
310
|
|
|
|
|
|
return retval; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
310
|
|
|
|
|
|
static const char* _find_file (struct tmplpro_param* param, const char* filename, PSTRING extra_dir) { |
232
|
|
|
|
|
|
|
// TODO: finish it |
233
|
310
|
|
|
|
|
|
const char* HTML_TEMPLATE_ROOT = get_template_root(param); |
234
|
310
|
|
|
|
|
|
size_t HTML_TEMPLATE_ROOT_length=0; |
235
|
310
|
|
|
|
|
|
size_t buffsize=0; |
236
|
310
|
|
|
|
|
|
char** pathlist=param->path; |
237
|
|
|
|
|
|
|
MPSTRING pbuf_begin, filepath; |
238
|
|
|
|
|
|
|
|
239
|
310
|
50
|
|
|
|
|
if (param->debug >= TMPL_LOG_DEBUG2) { |
240
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_DEBUG2,"built-in _find_file: looking for %s extra dir = %.*s\n",filename, (int)(extra_dir.endnext-extra_dir.begin),extra_dir.begin); |
241
|
0
|
0
|
|
|
|
|
if (HTML_TEMPLATE_ROOT) tmpl_log(TMPL_LOG_DEBUG2,"built-in _find_file: HTML_TEMPLATE_ROOT = %s\n",HTML_TEMPLATE_ROOT); |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
/* first check for a full path */ |
245
|
310
|
50
|
|
|
|
|
if (_ff_is_absolute(filename) && _ff_exists(filename)) return _ff_canonical_path(filename); |
|
|
0
|
|
|
|
|
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
#if defined _WIN32 || defined __CYGWIN__ |
248
|
|
|
|
|
|
|
/* no sense of prefixing C:\ or \\?\ */ |
249
|
|
|
|
|
|
|
if (_ff_is_win_fully_qualified_path(filename)) { |
250
|
|
|
|
|
|
|
tmpl_log(TMPL_LOG_DEBUG2,"built-in _ff_is_win_fully_qualified_path: rejected %s: is_absolute=%d exists=%d\n",filename,_ff_is_absolute(filename),_ff_exists(filename)); |
251
|
|
|
|
|
|
|
return NULL; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
#endif |
254
|
|
|
|
|
|
|
|
255
|
310
|
100
|
|
|
|
|
if (HTML_TEMPLATE_ROOT!=NULL) HTML_TEMPLATE_ROOT_length=strlen(HTML_TEMPLATE_ROOT); |
256
|
310
|
100
|
|
|
|
|
if (pathlist!=NULL) { |
257
|
179
|
100
|
|
|
|
|
while (NULL!=*pathlist) { |
258
|
99
|
|
|
|
|
|
size_t pathentrylen=strlen(*pathlist); |
259
|
99
|
100
|
|
|
|
|
if (buffsize
|
260
|
99
|
|
|
|
|
|
pathlist++; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
/* bufsize is max possible length path of path considered |
264
|
|
|
|
|
|
|
* min is max_len(foreach pathlist)+HTML_TEMPLATE_ROOT_length+strlen(filename)+len(extra_dir)+1) |
265
|
|
|
|
|
|
|
* but we malloc an extra space to avoid frequent reallocing |
266
|
|
|
|
|
|
|
*/ |
267
|
310
|
|
|
|
|
|
buffsize+=HTML_TEMPLATE_ROOT_length+strlen(filename)+(extra_dir.endnext-extra_dir.begin)+4+1; /* 4 - for slashes */ |
268
|
310
|
|
|
|
|
|
pbuffer_resize(¶m->builtin_findfile_buffer, buffsize); |
269
|
310
|
|
|
|
|
|
pbuf_begin.begin=pbuffer_string(¶m->builtin_findfile_buffer); |
270
|
310
|
|
|
|
|
|
pbuf_begin.endnext=pbuf_begin.begin; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
/* try the extra_path if one was specified */ |
273
|
310
|
100
|
|
|
|
|
if (extra_dir.begin!=NULL) { |
274
|
68
|
|
|
|
|
|
filepath=_ff_add_pstr_to_buffer(pbuf_begin,extra_dir); |
275
|
68
|
100
|
|
|
|
|
if (extra_dir.endnext-extra_dir.begin >0) |
276
|
32
|
|
|
|
|
|
filepath=_ff_add_sep_to_buffer(filepath); |
277
|
68
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(filepath,filename); |
278
|
68
|
|
|
|
|
|
filepath=_ff_add_0_to_buffer(filepath); |
279
|
68
|
100
|
|
|
|
|
if (_ff_exists(filepath.begin)) return _ff_canonical_path_from_buf(filepath); |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
/* try pre-prending HTML_Template_Root */ |
283
|
258
|
100
|
|
|
|
|
if (HTML_TEMPLATE_ROOT!=NULL) { |
284
|
1
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(pbuf_begin,HTML_TEMPLATE_ROOT); |
285
|
1
|
50
|
|
|
|
|
if (HTML_TEMPLATE_ROOT_length >0) |
286
|
1
|
|
|
|
|
|
filepath=_ff_add_sep_to_buffer(filepath); |
287
|
1
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(filepath,filename); |
288
|
1
|
|
|
|
|
|
filepath=_ff_add_0_to_buffer(filepath); |
289
|
1
|
50
|
|
|
|
|
if (_ff_exists(filepath.begin)) return _ff_canonical_path_from_buf(filepath); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
/* try "path" option list.. */ |
293
|
258
|
|
|
|
|
|
pathlist=param->path; |
294
|
258
|
100
|
|
|
|
|
if (pathlist!=NULL) { |
295
|
82
|
100
|
|
|
|
|
while (NULL!=*pathlist) { |
296
|
|
|
|
|
|
|
//tmpl_log(TMPL_LOG_ERROR,"try 'path' option list..: looking in [%s]\n",*pathlist); |
297
|
77
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(pbuf_begin,*pathlist); |
298
|
|
|
|
|
|
|
/* add separator only if *pathlist non-empty */ |
299
|
77
|
50
|
|
|
|
|
if (0!=**pathlist) filepath=_ff_add_sep_to_buffer(filepath); |
300
|
77
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(filepath,filename); |
301
|
77
|
|
|
|
|
|
filepath=_ff_add_0_to_buffer(filepath); |
302
|
77
|
100
|
|
|
|
|
if (_ff_exists(filepath.begin)) return _ff_canonical_path_from_buf(filepath); |
303
|
15
|
|
|
|
|
|
pathlist++; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
/* try even a relative path from the current directory...*/ |
308
|
196
|
100
|
|
|
|
|
if (_ff_exists(filename)) return _ff_canonical_path(filename); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
/* try "path" option list with HTML_TEMPLATE_ROOT prepended... */ |
311
|
1
|
50
|
|
|
|
|
if (HTML_TEMPLATE_ROOT!=NULL) { |
312
|
1
|
|
|
|
|
|
pathlist=param->path; |
313
|
1
|
50
|
|
|
|
|
if (pathlist!=NULL) { |
314
|
1
|
50
|
|
|
|
|
while (NULL!=*pathlist) { |
315
|
1
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(pbuf_begin,HTML_TEMPLATE_ROOT); |
316
|
1
|
50
|
|
|
|
|
if (HTML_TEMPLATE_ROOT_length >0) |
317
|
1
|
|
|
|
|
|
filepath=_ff_add_sep_to_buffer(filepath); |
318
|
1
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(filepath,*pathlist); |
319
|
|
|
|
|
|
|
/* add separator only if *pathlist non-empty */ |
320
|
1
|
50
|
|
|
|
|
if (0!=**pathlist) filepath=_ff_add_sep_to_buffer(filepath); |
321
|
1
|
|
|
|
|
|
filepath=_ff_add_str_to_buffer(filepath,filename); |
322
|
1
|
|
|
|
|
|
filepath=_ff_add_0_to_buffer(filepath); |
323
|
1
|
50
|
|
|
|
|
if (_ff_exists(filepath.begin)) return _ff_canonical_path_from_buf(filepath); |
324
|
0
|
|
|
|
|
|
pathlist++; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
310
|
|
|
|
|
|
return NULL; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
310
|
|
|
|
|
|
static const char* BACKCALL stub_find_file_func(ABSTRACT_FINDFILE* param,const char* filename, const char* last_visited_file) { |
333
|
|
|
|
|
|
|
const char* filepath; |
334
|
310
|
|
|
|
|
|
PSTRING extra_path ={NULL,NULL}; |
335
|
|
|
|
|
|
|
|
336
|
310
|
50
|
|
|
|
|
if (filename == last_visited_file) tmpl_log(TMPL_LOG_ERROR,"built-in find_file: internal error: buffer clash for %s\n",filename); |
337
|
|
|
|
|
|
|
|
338
|
310
|
50
|
|
|
|
|
if (((struct tmplpro_param*)param)->debug>= TMPL_LOG_DEBUG) |
339
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_DEBUG,"built-in find_file: looking for %s last_visited_file = %s\n",filename, last_visited_file); |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
// look for the included file... |
342
|
310
|
100
|
|
|
|
|
if (last_visited_file!=NULL && ! ((struct tmplpro_param*) param)->search_path_on_include) { |
|
|
100
|
|
|
|
|
|
343
|
68
|
|
|
|
|
|
extra_path = _ff_dirname(last_visited_file); |
344
|
|
|
|
|
|
|
} |
345
|
310
|
|
|
|
|
|
filepath = _find_file((struct tmplpro_param*)param,filename,extra_path); |
346
|
310
|
50
|
|
|
|
|
if (filepath==NULL) { |
347
|
0
|
|
|
|
|
|
char** path=((struct tmplpro_param*)param)->path; |
348
|
0
|
|
|
|
|
|
const char* HTML_TEMPLATE_ROOT = get_template_root((struct tmplpro_param*)param); |
349
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_ERROR,"built-in find_file: can't find file %s", filename); |
350
|
0
|
0
|
|
|
|
|
if (NULL!=last_visited_file) tmpl_log(TMPL_LOG_ERROR," (included from %s)", last_visited_file); |
351
|
0
|
0
|
|
|
|
|
if(HTML_TEMPLATE_ROOT!=NULL) { |
352
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_ERROR," with HTML_TEMPLATE_ROOT = '%s'",HTML_TEMPLATE_ROOT); |
353
|
|
|
|
|
|
|
} |
354
|
0
|
0
|
|
|
|
|
if (NULL!=path) { |
355
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_ERROR," with path = ["); |
356
|
0
|
0
|
|
|
|
|
while (NULL!=*path) { |
357
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_ERROR," '%s'",*path); |
358
|
0
|
|
|
|
|
|
path++; |
359
|
|
|
|
|
|
|
} |
360
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_ERROR," ]"); |
361
|
|
|
|
|
|
|
} else { |
362
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_ERROR," with empty path list"); |
363
|
|
|
|
|
|
|
} |
364
|
0
|
|
|
|
|
|
tmpl_log(TMPL_LOG_ERROR,"\n"); |
365
|
0
|
|
|
|
|
|
return NULL; |
366
|
|
|
|
|
|
|
} else { |
367
|
310
|
|
|
|
|
|
return filepath; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
/* |
372
|
|
|
|
|
|
|
* Local Variables: |
373
|
|
|
|
|
|
|
* mode: c |
374
|
|
|
|
|
|
|
* End: |
375
|
|
|
|
|
|
|
*/ |