1 /************************************************************************/
2 /* */
3 /* Maniputaion of file names. */
4 /* */
5 /* The routines do not consult the file system to find out whether */
6 /* strings refer to a particular kind of thing on the file system. */
7 /* The current directory is however retrieved to resolve relative */
8 /* names. */
9 /* */
10 /************************************************************************/
11
12 # include "appUtilConfig.h"
13
14 # include <string.h>
15
16 # include "appSystem.h"
17
18 # include <appDebugon.h>
19
20 /************************************************************************/
21 /* */
22 /* Return a pointer to the beginning of the extension part in a file */
23 /* name. The pointer points IN the input string. */
24 /* */
25 /************************************************************************/
26
appFileGetFileExtension(MemoryBuffer * extension,const MemoryBuffer * filename)27 int appFileGetFileExtension( MemoryBuffer * extension,
28 const MemoryBuffer * filename )
29 {
30 const char * all= utilMemoryBufferGetString( filename );
31 const char * slash;
32 const char * dot;
33
34 slash= strrchr( all, '/' );
35 if ( slash )
36 { dot= strrchr( slash+ 1, '.' ); }
37 else{ dot= strrchr( all, '.' ); }
38
39 if ( ! dot )
40 { utilEmptyMemoryBuffer( extension ); }
41 else{
42 int off= dot- all+ 1;
43 int len= filename->mbSize- off;
44
45 if ( utilMemoryBufferGetRange( extension, filename, off, len ) )
46 { LDEB(1); return -1; }
47 }
48
49 return 0;
50 }
51
appFileSetExtensionX(MemoryBuffer * filename,const char * extension,int replace)52 static int appFileSetExtensionX( MemoryBuffer * filename,
53 const char * extension,
54 int replace )
55 {
56 const char * all= utilMemoryBufferGetString( filename );
57 const char * dot= (const char *)0;
58
59 int from;
60 int extlen= 0;
61
62 if ( utilMemoryBufferIsEmpty( filename ) )
63 { LDEB(filename->mbSize); return -1; }
64
65 if ( replace )
66 {
67 const char * slash;
68
69 slash= strrchr( all, '/' );
70
71 if ( slash )
72 { dot= strrchr( slash+ 1, '.' ); }
73 else{ dot= strrchr( all, '.' ); }
74 }
75
76 if ( ! dot )
77 {
78 if ( extension && extension[0] )
79 {
80 if ( utilMemoryBufferAppendBytes( filename, (unsigned char *)".", 1 ) )
81 { LDEB(1); return -1; }
82
83 extlen= strlen( extension );
84 }
85
86 from= filename->mbSize;
87 }
88 else{
89 if ( extension && extension[0] )
90 {
91 from= dot- all+ 1;
92 extlen= strlen( extension );
93 }
94 else{ from= dot- all; }
95 }
96
97 if ( utilMemoryBufferReplaceBytes( filename, from, filename->mbSize,
98 (const unsigned char *)extension, extlen ) )
99 { LDEB(1); return -1; }
100
101 return 0;
102 }
103
appFileSetExtension(MemoryBuffer * filename,const char * extension)104 int appFileSetExtension( MemoryBuffer * filename,
105 const char * extension )
106 {
107 return appFileSetExtensionX( filename, extension, 1 );
108 }
109
appFileAddExtension(MemoryBuffer * filename,const char * extension)110 int appFileAddExtension( MemoryBuffer * filename,
111 const char * extension )
112 {
113 return appFileSetExtensionX( filename, extension, 0 );
114 }
115
appFileGetRelativeName(MemoryBuffer * relative,const MemoryBuffer * filename)116 int appFileGetRelativeName( MemoryBuffer * relative,
117 const MemoryBuffer * filename )
118 {
119 const char * all= utilMemoryBufferGetString( filename );
120 const char * slash;
121
122 slash= strrchr( all, '/' );
123
124 if ( ! slash )
125 {
126 if ( utilCopyMemoryBuffer( relative, filename ) )
127 { LDEB(1); return -1; }
128 }
129 else{
130 int off= slash- all+ 1;
131 int len= filename->mbSize- off;
132
133 if ( utilMemoryBufferGetRange( relative, filename, off, len ) )
134 { LDEB(1); return -1; }
135 }
136
137 return 0;
138 }
139
appDirectoryOfFileName(MemoryBuffer * dir,const MemoryBuffer * name)140 int appDirectoryOfFileName( MemoryBuffer * dir,
141 const MemoryBuffer * name )
142 {
143 const char * all= utilMemoryBufferGetString( name );
144 const char * slash= strrchr( all, '/' );
145
146 if ( ! slash )
147 { utilEmptyMemoryBuffer( dir ); }
148 else{
149 if ( utilMemoryBufferGetRange( dir, name, 0, slash- all ) )
150 { LDEB(1); return -1; }
151 }
152
153 return 0;
154 }
155
appFileNameIsAbsolute(const char * filename)156 int appFileNameIsAbsolute( const char * filename )
157 { return filename[0] == '/'; }
158
159 /************************************************************************/
160 /* */
161 /* Translate a file name to an absolute name. */
162 /* */
163 /* a) Utility routine: append a path fragment to an already existing */
164 /* piece of path. */
165 /* b) Make some attempts to remove silly intermediate fragments */
166 /* from the path. This can give unexpected results when there are */
167 /* symbolic links to directories, or the ../ go below the root of */
168 /* the file system. The results of not removing ./ and ../ can be */
169 /* as unexpected, but has the advantage not to attach any meaning */
170 /* to the structure of file names in application code. */
171 /* */
172 /* 1) If the name is an absolute one, just copy it to the */
173 /* destination. */
174 /* 2) See whether the file the name has to be relative to has a */
175 /* directory part. If so, determine its length, including the */
176 /* slash that separates it from the relative part. */
177 /* 3) If the file the name has to be relative to is an absolute one, */
178 /* append the relative name to the absolute one. */
179 /* 4) Both names are relative.. Determine the current directory. */
180 /* 5) Append a final slash to the name of the current directory. */
181 /* 6) Build one absolute name of the collected path elements. */
182 /* */
183 /************************************************************************/
184
185 /* a */
utilFileNameCatenate(MemoryBuffer * path,const MemoryBuffer * relative,int relLen)186 static int utilFileNameCatenate( MemoryBuffer * path,
187 const MemoryBuffer * relative,
188 int relLen )
189 {
190 const char * r= utilMemoryBufferGetString( relative );
191 const char * p= utilMemoryBufferGetString( path );
192 int rOff= 0;
193 int pLen= path->mbSize;
194
195 /* b */
196 while( rOff < relLen )
197 {
198 if ( ! strncmp( r, "./", 2 ) )
199 { r += 2; rOff += 2; continue; }
200
201 if ( ! strncmp( r, "../", 3 ) )
202 {
203 int lastSlash= -1;
204 int i;
205
206 for ( i= 0; i < pLen- 1; i++ )
207 {
208 if ( p[i] == '/' )
209 { lastSlash= i; }
210 }
211
212 if ( lastSlash < 0 )
213 { break; }
214
215 pLen= lastSlash+ 1;
216 r += 3; rOff += 3;
217 continue;
218 }
219
220 break;
221 }
222
223 if ( pLen > 0 && p[pLen- 1] != '/' )
224 {
225 if ( utilMemoryBufferReplaceBytes( path, pLen, path->mbSize,
226 (unsigned char *)"/", 1 ) )
227 { LDEB(1); return -1; }
228
229 pLen= path->mbSize;
230 }
231
232 if ( utilMemoryBufferReplaceBytes( path, pLen, path->mbSize,
233 relative->mbBytes+ rOff, relLen- rOff ) )
234 { LDEB(relLen); return -1; }
235
236 return path->mbSize;
237 }
238
appAbsoluteName(MemoryBuffer * absolute,const MemoryBuffer * relative,int relativeIsFile,const MemoryBuffer * nameRelativeTo)239 extern int appAbsoluteName( MemoryBuffer * absolute,
240 const MemoryBuffer * relative,
241 int relativeIsFile,
242 const MemoryBuffer * nameRelativeTo )
243 {
244 int rval= -1;
245 int relLen= 0;
246
247 if ( ! relative || utilMemoryBufferIsEmpty( relative ) )
248 { XDEB(relative); rval= -1; goto ready; }
249
250 /* 1 */
251 if ( relative->mbBytes[0] == '/' )
252 {
253 if ( utilCopyMemoryBuffer( absolute, relative ) )
254 { LDEB(1); rval= -1; goto ready; }
255
256 rval= absolute->mbSize; goto ready;
257 }
258
259 /* 2 */
260 if ( nameRelativeTo && ! utilMemoryBufferIsEmpty( nameRelativeTo ) )
261 {
262 if ( relativeIsFile )
263 {
264 int slash= utilMemoryBufferLastIndexOf( nameRelativeTo, '/' );
265
266 if ( slash >= 0 )
267 { relLen= slash; }
268 }
269 else{
270 relLen= nameRelativeTo->mbSize;
271 }
272
273 /* 3 */
274 if ( relLen > 0 && nameRelativeTo->mbBytes[0] == '/' )
275 {
276 if ( utilMemoryBufferSetBytes( absolute,
277 nameRelativeTo->mbBytes, relLen ) )
278 { LDEB(relLen); rval= -1; goto ready; }
279
280 if ( utilFileNameCatenate( absolute,
281 relative, relative->mbSize ) < 0 )
282 { LDEB(1); rval= -1; goto ready; }
283
284 rval= absolute->mbSize; goto ready;
285 }
286 }
287
288 /* 4 */
289 if ( appCurrentDirectory( absolute ) < 0 )
290 { LDEB(1); rval= -1; goto ready; }
291
292 /* 6 */
293 if ( relLen > 0 )
294 {
295 if ( utilFileNameCatenate( absolute, nameRelativeTo, relLen ) < 0 )
296 { LDEB(relLen); rval= -1; goto ready; }
297 }
298
299 if ( utilFileNameCatenate( absolute, relative, relative->mbSize ) < 0 )
300 { LDEB(1); rval= -1; goto ready; }
301
302 rval= absolute->mbSize;
303
304 ready:
305
306 return rval;
307 }
308
309 # if 0
310
311 static void xx( const char * filename,
312 const char * fileRelativeTo )
313 {
314 char absolute[1000+1];
315
316 if ( appAbsoluteName( absolute, sizeof( absolute )- 1,
317 filename, fileRelativeTo ) < 0 )
318 { SSDEB( filename, fileRelativeTo ); }
319 else{ SSSDEB( filename, fileRelativeTo, absolute ); }
320
321 return;
322 }
323
324 void xxx()
325 {
326
327 xx( "in.gif", "out.rtf" );
328 xx( "../in.gif", "out.rtf" );
329 xx( "../../in.gif", "out.rtf" );
330
331 xx( "in.gif", "../out.rtf" );
332 xx( "in.gif", "../../out.rtf" );
333 xx( "../in.gif", "../../out.rtf" );
334
335 xx( "/in.gif", "../../out.rtf" );
336 xx( "/tmp/in.gif", "../../out.rtf" );
337
338 xx( "in.gif", "/out.rtf" );
339 xx( "in.gif", "/etc/out.rtf" );
340 xx( "../in.gif", "/etc/out.rtf" );
341 xx( "../../in.gif", "/etc/out.rtf" );
342
343 return;
344 }
345
346 # endif
347
348