source: git/src/filename.c @ 13a1bd16

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 13a1bd16 was 13a1bd16, checked in by Mark Shinwell <mark>, 24 years ago

Movement controls now work properly!!

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