source: git/src/filename.c @ a0b076f

RELEASE/1.0RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectstereostereo-2025walls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since a0b076f was a0b076f, checked in by Olly Betts <olly@…>, 24 years ago

decree that safe_fopen() is for writing, fopenWithPthAndExt() for reading
(and possibly appending)

git-svn-id: file:///home/survex-svn/survex/trunk@693 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

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