source: git/src/filename.c @ affaeee

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since affaeee was affaeee, checked in by Olly Betts <olly@…>, 18 years ago

Rework the OS== mechanism as defining WIN32 and UNIX causes problems with
third party headers which test for these defines and assume the wrong OS!

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@3072 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/* OS dependent filename manipulation routines
2 * Copyright (c) Olly Betts 1998-2003,2004,2005
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include "filename.h"
24#include "debug.h"
25
26#include <ctype.h>
27#include <string.h>
28
29typedef struct filelist {
30   char *fnm;
31   FILE *fh;
32   struct filelist *next;
33} filelist;
34
35static filelist *flhead = NULL;
36
37static void filename_register_output_with_fh(const char *fnm, FILE *fh);
38
39/* safe_fopen should be used when writing a file
40 * fopenWithPthAndExt should be used when reading a file
41 */
42
43/* Wrapper for fopen which throws a fatal error if it fails.
44 * Some versions of fopen() are quite happy to open a directory.
45 * We aren't, so catch this case. */
46extern FILE *
47safe_fopen(const char *fnm, const char *mode)
48{
49   FILE *f;
50   SVX_ASSERT(mode[0] == 'w'); /* only expect to be used for writing */
51   if (fDirectory(fnm))
52      fatalerror(/*Filename `%s' refers to directory*/44, fnm);
53
54   f = fopen(fnm, mode);
55   if (!f) fatalerror(/*Failed to open output file `%s'*/47, fnm);
56
57   filename_register_output_with_fh(fnm, f);
58   return f;
59}
60
61/* Wrapper for fclose which throws a fatal error if there's been a write
62 * error.
63 */
64extern void
65safe_fclose(FILE *f)
66{
67   SVX_ASSERT(f);
68   /* NB: use of | rather than || - we always want to call fclose() */
69   if (ferror(f) | (fclose(f) == EOF)) {
70      filelist *p;
71      for (p = flhead; p != NULL; p = p->next)
72         if (p->fh == f) break;
73
74      if (p && p->fnm) {
75         const char *fnm = p->fnm;
76         p->fnm = NULL;
77         p->fh = NULL;
78         (void)remove(fnm);
79         fatalerror(/*Error writing to file `%s'*/110, fnm);
80      }
81      /* FIXME: this case should never happen... */
82      fatalerror(/*Error writing to file*/111);
83   }
84}
85
86extern FILE *
87safe_fopen_with_ext(const char *fnm, const char *ext, const char *mode)
88{
89   FILE *f;
90   char *p;
91   p = add_ext(fnm, ext);
92   f = safe_fopen(p, mode);
93   osfree(p);
94   return f;
95}
96
97static FILE *
98fopen_not_dir(const char *fnm, const char *mode)
99{
100   if (fDirectory(fnm)) return NULL;
101   return fopen(fnm, mode);
102}
103
104extern char * Far
105path_from_fnm(const char *fnm)
106{
107   char *pth;
108   const char *lf;
109   int lenpth = 0;
110
111   lf = strrchr(fnm, FNM_SEP_LEV);
112#ifdef FNM_SEP_LEV2
113   {
114      const char *lf2 = strrchr(lf ? lf + 1 : fnm, FNM_SEP_LEV2);
115      if (lf2) lf = lf2;
116   }
117#endif
118#ifdef FNM_SEP_DRV
119   if (!lf) lf = strrchr(fnm, FNM_SEP_DRV);
120#endif
121   if (lf) lenpth = lf - fnm + 1;
122
123   pth = osmalloc(lenpth + 1);
124   memcpy(pth, fnm, lenpth);
125   pth[lenpth] = '\0';
126
127   return pth;
128}
129
130extern char *
131base_from_fnm(const char *fnm)
132{
133   char *p;
134
135   p = strrchr(fnm, FNM_SEP_EXT);
136   /* Trim off any leaf extension, but dirs can have extensions too */
137   if (p && !strchr(p, FNM_SEP_LEV)
138#ifdef FNM_SEP_LEV2
139       && !strchr(p, FNM_SEP_LEV2)
140#endif
141       ) {
142      size_t len = (const char *)p - fnm;
143
144      p = osmalloc(len + 1);
145      memcpy(p, fnm, len);
146      p[len] = '\0';
147      return p;
148   }
149
150   return osstrdup(fnm);
151}
152
153extern char *
154baseleaf_from_fnm(const char *fnm)
155{
156   const char *p;
157   char *q;
158   size_t len;
159
160   p = fnm;
161   q = strrchr(p, FNM_SEP_LEV);
162   if (q) p = q + 1;
163#ifdef FNM_SEP_LEV2
164   q = strrchr(p, FNM_SEP_LEV2);
165   if (q) p = q + 1;
166#endif
167
168   q = strrchr(p, FNM_SEP_EXT);
169   if (q) len = (const char *)q - p; else len = strlen(p);
170
171   q = osmalloc(len + 1);
172   memcpy(q, p, len);
173   q[len] = '\0';
174   return q;
175}
176
177extern char * Far
178leaf_from_fnm(const char *fnm)
179{
180   const char *lf;
181   lf = strrchr(fnm, FNM_SEP_LEV);
182   if (lf) fnm = lf + 1;
183#ifdef FNM_SEP_LEV2
184   lf = strrchr(fnm, FNM_SEP_LEV2);
185   if (lf) fnm = lf + 1;
186#endif
187#ifdef FNM_SEP_DRV
188   lf = strrchr(fnm, FNM_SEP_DRV);
189   if (lf) fnm = lf + 1;
190#endif
191   return osstrdup(fnm);
192}
193
194/* Make fnm from pth and lf, inserting an FNM_SEP_LEV if appropriate */
195extern char * Far
196use_path(const char *pth, const char *lf)
197{
198   char *fnm;
199   int len, len_total;
200   bool fAddSep = fFalse;
201
202   len = strlen(pth);
203   len_total = len + strlen(lf) + 1;
204
205   /* if there's a path and it doesn't end in a separator, insert one */
206   if (len && pth[len - 1] != FNM_SEP_LEV) {
207#ifdef FNM_SEP_LEV2
208      if (pth[len - 1] != FNM_SEP_LEV2) {
209#endif
210#ifdef FNM_SEP_DRV
211         if (pth[len - 1] != FNM_SEP_DRV) {
212#endif
213            fAddSep = fTrue;
214            len_total++;
215#ifdef FNM_SEP_DRV
216         }
217#endif
218#ifdef FNM_SEP_LEV2
219      }
220#endif
221   }
222
223   fnm = osmalloc(len_total);
224   strcpy(fnm, pth);
225   if (fAddSep) fnm[len++] = FNM_SEP_LEV;
226   strcpy(fnm + len, lf);
227   return fnm;
228}
229
230/* Add ext to fnm, inserting an FNM_SEP_EXT if appropriate */
231extern char * Far
232add_ext(const char *fnm, const char *ext)
233{
234   char * fnmNew;
235   int len, len_total;
236#ifdef FNM_SEP_EXT
237   bool fAddSep = fFalse;
238#endif
239
240   len = strlen(fnm);
241   len_total = len + strlen(ext) + 1;
242#ifdef FNM_SEP_EXT
243   if (ext[0] != FNM_SEP_EXT) {
244      fAddSep = fTrue;
245      len_total++;
246   }
247#endif
248
249   fnmNew = osmalloc(len_total);
250   strcpy(fnmNew, fnm);
251#ifdef FNM_SEP_EXT
252   if (fAddSep) fnmNew[len++] = FNM_SEP_EXT;
253#endif
254   strcpy(fnmNew + len, ext);
255   return fnmNew;
256}
257
258/* fopen file, found using pth and fnm
259 * fnmUsed is used to return filename used to open file (ignored if NULL)
260 * or NULL if file didn't open
261 */
262extern FILE Far *
263fopenWithPthAndExt(const char *pth, const char *fnm, const char *ext,
264                   const char *mode, char **fnmUsed)
265{
266   char *fnmFull = NULL;
267   FILE *fh = NULL;
268   bool fAbs;
269
270   /* if no pth treat fnm as absolute */
271   fAbs = (pth == NULL || *pth == '\0' || fAbsoluteFnm(fnm));
272
273   /* if appropriate, try it without pth */
274   if (fAbs) {
275      fh = fopen_not_dir(fnm, mode);
276      if (fh) {
277         if (fnmUsed) fnmFull = osstrdup(fnm);
278      } else {
279         if (ext && *ext) {
280            /* we've been given an extension so try using it */
281            fnmFull = add_ext(fnm, ext);
282            fh = fopen_not_dir(fnmFull, mode);
283         }
284      }
285   } else {
286      /* try using path given - first of all without the extension */
287      fnmFull = use_path(pth, fnm);
288      fh = fopen_not_dir(fnmFull, mode);
289      if (!fh) {
290         if (ext && *ext) {
291            /* we've been given an extension so try using it */
292            char *fnmTmp;
293            fnmTmp = fnmFull;
294            fnmFull = add_ext(fnmFull, ext);
295            osfree(fnmTmp);
296            fh = fopen_not_dir(fnmFull, mode);
297         }
298      }
299   }
300
301   /* either it opened or didn't. If not, fh == NULL from fopen_not_dir() */
302
303   /* free name if it didn't open or name isn't wanted */
304   if (fh == NULL || fnmUsed == NULL) osfree(fnmFull);
305   if (fnmUsed) *fnmUsed = (fh ? fnmFull : NULL);
306   return fh;
307}
308
309/* Like fopenWithPthAndExt except that "foreign" paths are translated to
310 * native ones (e.g. on Unix dir\file.ext -> dir/file.ext) */
311FILE *
312fopen_portable(const char *pth, const char *fnm, const char *ext,
313               const char *mode, char **fnmUsed)
314{
315   FILE *fh = fopenWithPthAndExt(pth, fnm, ext, mode, fnmUsed);
316   if (fh == NULL) {
317#if OS_UNIX
318      int f_changed = 0;
319      char *fnm_trans, *p;
320      fnm_trans = osstrdup(fnm);
321      for (p = fnm_trans; *p; p++) {
322         switch (*p) {
323         case '\\': /* swap a backslash to a forward slash */
324            *p = '/';
325            f_changed = 1;
326            break;
327         }
328      }
329      if (f_changed)
330         fh = fopenWithPthAndExt(pth, fnm_trans, ext, mode, fnmUsed);
331
332      /* as a last ditch measure, try lowercasing the filename */
333      if (fh == NULL) {
334         f_changed = 0;
335         for (p = fnm_trans; *p ; p++) {
336            unsigned char ch = *p;
337            if (isupper(ch)) {
338               *p = tolower(ch);
339               f_changed = 1;
340            }
341         }
342         if (f_changed)
343            fh = fopenWithPthAndExt(pth, fnm_trans, ext, mode, fnmUsed);
344      }
345      osfree(fnm_trans);
346#endif
347   }
348   return fh;
349}
350
351void
352filename_register_output(const char *fnm)
353{
354   filelist *p = osnew(filelist);
355   SVX_ASSERT(fnm);
356   p->fnm = osstrdup(fnm);
357   p->fh = NULL;
358   p->next = flhead;
359   flhead = p;
360}
361
362static void
363filename_register_output_with_fh(const char *fnm, FILE *fh)
364{
365   filelist *p = osnew(filelist);
366   SVX_ASSERT(fnm);
367   p->fnm = osstrdup(fnm);
368   p->fh = fh;
369   p->next = flhead;
370   flhead = p;
371}
372
373void
374filename_delete_output(void)
375{
376   while (flhead) {
377      filelist *p = flhead;
378      flhead = flhead->next;
379      if (p->fnm) {
380         (void)remove(p->fnm);
381         osfree(p->fnm);
382      }
383      osfree(p);
384   }
385}
Note: See TracBrowser for help on using the repository browser.