source: git/src/filename.c @ fc4b814

RELEASE/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 fc4b814 was 64d37a3, checked in by Olly Betts <olly@…>, 21 years ago

Sync with 1.0 branch.

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

  • Property mode set to 100644
File size: 9.1 KB
RevLine 
[846746e]1/* OS dependent filename manipulation routines
[64d37a3]2 * Copyright (c) Olly Betts 1998-2003
[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"
[13a1bd16]24#include "debug.h"
[47c7a94]25
26#include <ctype.h>
[9af1d7a9]27#include <string.h>
28
[908298d]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
[a0b076f]39/* safe_fopen should be used when writing a file
40 * fopenWithPthAndExt should be used when reading a file
41 */
[ce5b43c]42
[a420b49]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;
[4c07c51]50   SVX_ASSERT(mode[0] == 'w'); /* only expect to be used for writing */
[a420b49]51   if (fDirectory(fnm))
[759fb47]52      fatalerror(/*Filename `%s' refers to directory*/44, fnm);
[a420b49]53
54   f = fopen(fnm, mode);
[a0b076f]55   if (!f) fatalerror(/*Failed to open output file `%s'*/47, fnm);
56
[908298d]57   filename_register_output_with_fh(fnm, f);
[a420b49]58   return f;
59}
60
[f1067a2]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{
[4c07c51]67   SVX_ASSERT(f);
[f1067a2]68   /* NB: use of | rather than || - we always want to call fclose() */
[908298d]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_in_file(fnm, 0, /*Error writing to file*/111);
80      }
[f1067a2]81      fatalerror(/*Error writing to file*/111);
[908298d]82   }
[f1067a2]83}
84
[ce5b43c]85extern FILE *
86safe_fopen_with_ext(const char *fnm, const char *ext, const char *mode)
87{
88   FILE *f;
89   char *p;
90   p = add_ext(fnm, ext);
91   f = safe_fopen(p, mode);
92   osfree(p);
93   return f;
94}
95
96static FILE *
[a420b49]97fopen_not_dir(const char *fnm, const char *mode)
98{
99   if (fDirectory(fnm)) return NULL;
100   return fopen(fnm, mode);
[9af1d7a9]101}
102
[64d37a3]103extern char * Far
[ce5b43c]104path_from_fnm(const char *fnm)
[a420b49]105{
[9af1d7a9]106   char *pth;
107   const char *lf;
108   int lenpth = 0;
109
[a420b49]110   lf = strrchr(fnm, FNM_SEP_LEV);
[9af1d7a9]111#ifdef FNM_SEP_LEV2
[029824d]112   {
[eee67ab]113      const char *lf2 = strrchr(lf ? lf + 1 : fnm, FNM_SEP_LEV2);
[029824d]114      if (lf2) lf = lf2;
115   }
[9af1d7a9]116#endif
117#ifdef FNM_SEP_DRV
[a420b49]118   if (!lf) lf = strrchr(fnm, FNM_SEP_DRV);
[9af1d7a9]119#endif
120   if (lf) lenpth = lf - fnm + 1;
121
[908298d]122   pth = osmalloc(lenpth + 1);
[a420b49]123   memcpy(pth, fnm, lenpth);
[9af1d7a9]124   pth[lenpth] = '\0';
125
126   return pth;
127}
128
[ce5b43c]129extern char *
130base_from_fnm(const char *fnm)
131{
132   char *p;
[cb3d1e2]133
[ce5b43c]134   p = strrchr(fnm, FNM_SEP_EXT);
135   /* Trim off any leaf extension, but dirs can have extensions too */
[029824d]136   if (p && !strchr(p, FNM_SEP_LEV)
[ce5b43c]137#ifdef FNM_SEP_LEV2
[029824d]138       && !strchr(p, FNM_SEP_LEV2)
[ce5b43c]139#endif
140       ) {
[e917a13]141      size_t len = (const char *)p - fnm;
[ce5b43c]142
[908298d]143      p = osmalloc(len + 1);
[ce5b43c]144      memcpy(p, fnm, len);
145      p[len] = '\0';
146      return p;
147   }
148
[908298d]149   return osstrdup(fnm);
[ce5b43c]150}
151
152extern char *
153baseleaf_from_fnm(const char *fnm)
154{
155   const char *p;
156   char *q;
157   size_t len;
[cb3d1e2]158
[ce5b43c]159   p = fnm;
160   q = strrchr(p, FNM_SEP_LEV);
161   if (q) p = q + 1;
162#ifdef FNM_SEP_LEV2
163   q = strrchr(p, FNM_SEP_LEV2);
164   if (q) p = q + 1;
165#endif
[cb3d1e2]166
[ce5b43c]167   q = strrchr(p, FNM_SEP_EXT);
[e917a13]168   if (q) len = (const char *)q - p; else len = strlen(p);
[ce5b43c]169
[908298d]170   q = osmalloc(len + 1);
[ce5b43c]171   memcpy(q, p, len);
172   q[len] = '\0';
173   return q;
174}
175
[64d37a3]176extern char * Far
[ce5b43c]177leaf_from_fnm(const char *fnm)
[a420b49]178{
[029824d]179   const char *lf;
[a420b49]180   lf = strrchr(fnm, FNM_SEP_LEV);
[029824d]181   if (lf) fnm = lf + 1;
[9af1d7a9]182#ifdef FNM_SEP_LEV2
[029824d]183   lf = strrchr(fnm, FNM_SEP_LEV2);
184   if (lf) fnm = lf + 1;
[9af1d7a9]185#endif
186#ifdef FNM_SEP_DRV
[029824d]187   lf = strrchr(fnm, FNM_SEP_DRV);
188   if (lf) fnm = lf + 1;
[9af1d7a9]189#endif
[908298d]190   return osstrdup(fnm);
[9af1d7a9]191}
192
193/* Make fnm from pth and lf, inserting an FNM_SEP_LEV if appropriate */
[64d37a3]194extern char * Far
[ce5b43c]195use_path(const char *pth, const char *lf)
[a420b49]196{
[9af1d7a9]197   char *fnm;
198   int len, len_total;
199   bool fAddSep = fFalse;
200
201   len = strlen(pth);
202   len_total = len + strlen(lf) + 1;
203
204   /* if there's a path and it doesn't end in a separator, insert one */
[a420b49]205   if (len && pth[len - 1] != FNM_SEP_LEV) {
[9af1d7a9]206#ifdef FNM_SEP_LEV2
[a420b49]207      if (pth[len - 1] != FNM_SEP_LEV2) {
[9af1d7a9]208#endif
209#ifdef FNM_SEP_DRV
[421b7d2]210         if (pth[len - 1] != FNM_SEP_DRV) {
[9af1d7a9]211#endif
[421b7d2]212            fAddSep = fTrue;
213            len_total++;
[9af1d7a9]214#ifdef FNM_SEP_DRV
[421b7d2]215         }
[9af1d7a9]216#endif
217#ifdef FNM_SEP_LEV2
218      }
219#endif
220   }
221
[908298d]222   fnm = osmalloc(len_total);
[a420b49]223   strcpy(fnm, pth);
[9af1d7a9]224   if (fAddSep) fnm[len++] = FNM_SEP_LEV;
[a420b49]225   strcpy(fnm + len, lf);
[9af1d7a9]226   return fnm;
227}
228
229/* Add ext to fnm, inserting an FNM_SEP_EXT if appropriate */
[64d37a3]230extern char * Far
[ce5b43c]231add_ext(const char *fnm, const char *ext)
[a420b49]232{
[9af1d7a9]233   char * fnmNew;
234   int len, len_total;
235#ifdef FNM_SEP_EXT
236   bool fAddSep = fFalse;
237#endif
238
239   len = strlen(fnm);
240   len_total = len + strlen(ext) + 1;
241#ifdef FNM_SEP_EXT
242   if (ext[0] != FNM_SEP_EXT) {
243      fAddSep = fTrue;
244      len_total++;
245   }
246#endif
247
[908298d]248   fnmNew = osmalloc(len_total);
[a420b49]249   strcpy(fnmNew, fnm);
[9af1d7a9]250#ifdef FNM_SEP_EXT
251   if (fAddSep) fnmNew[len++] = FNM_SEP_EXT;
252#endif
[a420b49]253   strcpy(fnmNew + len, ext);
[9af1d7a9]254   return fnmNew;
255}
256
257/* fopen file, found using pth and fnm
[25ab06b]258 * fnmUsed is used to return filename used to open file (ignored if NULL)
[9af1d7a9]259 * or NULL if file didn't open
260 */
[64d37a3]261extern FILE Far *
[25ab06b]262fopenWithPthAndExt(const char *pth, const char *fnm, const char *ext,
263                   const char *mode, char **fnmUsed)
[a420b49]264{
265   char *fnmFull = NULL;
266   FILE *fh = NULL;
267   bool fAbs;
268
269   /* if no pth treat fnm as absolute */
270   fAbs = (pth == NULL || *pth == '\0' || fAbsoluteFnm(fnm));
271
272   /* if appropriate, try it without pth */
273   if (fAbs) {
[25ab06b]274      fh = fopen_not_dir(fnm, mode);
[a420b49]275      if (fh) {
[908298d]276         if (fnmUsed) fnmFull = osstrdup(fnm);
[a420b49]277      } else {
[25ab06b]278         if (ext && *ext) {
[a420b49]279            /* we've been given an extension so try using it */
[25ab06b]280            fnmFull = add_ext(fnm, ext);
281            fh = fopen_not_dir(fnmFull, mode);
[a420b49]282         }
[9af1d7a9]283      }
[a420b49]284   } else {
285      /* try using path given - first of all without the extension */
[ce5b43c]286      fnmFull = use_path(pth, fnm);
[25ab06b]287      fh = fopen_not_dir(fnmFull, mode);
[a420b49]288      if (!fh) {
[25ab06b]289         if (ext && *ext) {
[a420b49]290            /* we've been given an extension so try using it */
291            char *fnmTmp;
292            fnmTmp = fnmFull;
[25ab06b]293            fnmFull = add_ext(fnmFull, ext);
[a420b49]294            osfree(fnmTmp);
[25ab06b]295            fh = fopen_not_dir(fnmFull, mode);
[a420b49]296         }
[9af1d7a9]297      }
[a420b49]298   }
299
300   /* either it opened or didn't. If not, fh == NULL from fopen_not_dir() */
301
302   /* free name if it didn't open or name isn't wanted */
[25ab06b]303   if (fh == NULL || fnmUsed == NULL) osfree(fnmFull);
304   if (fnmUsed) *fnmUsed = (fh ? fnmFull : NULL);
[a420b49]305   return fh;
[9af1d7a9]306}
[47c7a94]307
308/* Like fopenWithPthAndExt except that "foreign" paths are translated to
309 * native ones (e.g. on Unix dir\file.ext -> dir/file.ext) */
310FILE *
311fopen_portable(const char *pth, const char *fnm, const char *ext,
[25ab06b]312               const char *mode, char **fnmUsed)
[47c7a94]313{
[25ab06b]314   FILE *fh = fopenWithPthAndExt(pth, fnm, ext, mode, fnmUsed);
[47c7a94]315   if (fh == NULL) {
316#if (OS==RISCOS) || (OS==UNIX)
317      int f_changed = 0;
318      char *fnm_trans, *p;
319#if OS==RISCOS
320      char *q;
321#endif
322      fnm_trans = osstrdup(fnm);
323#if OS==RISCOS
324      q = fnm_trans;
325#endif
326      for (p = fnm_trans; *p; p++) {
327         switch (*p) {
328#if (OS==RISCOS)
[421b7d2]329         /* swap either slash to a dot, and a dot to a forward slash */
[47c7a94]330         /* but .. goes to ^ */
[421b7d2]331         case '.':
[47c7a94]332            if (p[1] == '.') {
333               *q++ = '^';
334               p++; /* skip second dot */
335            } else {
336               *q++ = '/';
337            }
338            f_changed = 1;
339            break;
[421b7d2]340         case '/': case '\\':
[47c7a94]341            *q++ = '.';
342            f_changed = 1;
343            break;
344         default:
345            *q++ = *p; break;
346#else
[421b7d2]347         case '\\': /* swap a backslash to a forward slash */
[47c7a94]348            *p = '/';
349            f_changed = 1;
350            break;
351#endif
352         }
353      }
354#if OS==RISCOS
355      *q = '\0';
356#endif
357      if (f_changed)
[25ab06b]358         fh = fopenWithPthAndExt(pth, fnm_trans, ext, mode, fnmUsed);
[47c7a94]359
360#if (OS==UNIX)
361      /* as a last ditch measure, try lowercasing the filename */
362      if (fh == NULL) {
363         f_changed = 0;
364         for (p = fnm_trans; *p ; p++)
[abd126e]365            if (isupper((unsigned char)*p)) {
[47c7a94]366               *p = tolower(*p);
367               f_changed = 1;
368            }
369         if (f_changed)
[25ab06b]370            fh = fopenWithPthAndExt(pth, fnm_trans, ext, mode, fnmUsed);
[47c7a94]371      }
372#endif
373      osfree(fnm_trans);
374#endif
375   }
376   return fh;
377}
[25ab06b]378
379void
380filename_register_output(const char *fnm)
[421b7d2]381{
[908298d]382   filelist *p = osnew(filelist);
[4c07c51]383   SVX_ASSERT(fnm);
[908298d]384   p->fnm = osstrdup(fnm);
385   p->fh = NULL;
386   p->next = flhead;
387   flhead = p;
388}
389
390static void
391filename_register_output_with_fh(const char *fnm, FILE *fh)
[25ab06b]392{
393   filelist *p = osnew(filelist);
[4c07c51]394   SVX_ASSERT(fnm);
[908298d]395   p->fnm = osstrdup(fnm);
396   p->fh = fh;
[25ab06b]397   p->next = flhead;
398   flhead = p;
399}
400
401void
402filename_delete_output(void)
403{
404   while (flhead) {
405      filelist *p = flhead;
406      flhead = flhead->next;
[908298d]407      if (p->fnm) {
408         (void)remove(p->fnm);
409         osfree(p->fnm);
410      }
[25ab06b]411      osfree(p);
412   }
413}
Note: See TracBrowser for help on using the repository browser.