]> git.donarmstrong.com Git - lilypond.git/blob - flower/file-path.cc
(is_dir): canonicalize file name before stat'ing.
[lilypond.git] / flower / file-path.cc
1 /*
2   file-path.cc - implement File_path
3
4   source file of the Flower Library
5
6   (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7   Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9
10 #include "file-path.hh"
11
12 #include "std-string.hh"
13
14 #include <cstdio>
15 #include <cerrno>
16
17 #include "config.hh"
18 #if HAVE_SYS_STAT_H
19 #include <sys/stat.h>
20 #endif
21
22 #ifdef __CYGWIN__
23 #include <sys/cygwin.h>
24 #endif
25
26 #include "file-name.hh"
27 #include "warn.hh"
28
29 #ifndef PATHSEP
30 #define PATHSEP ':'
31 #endif
32
33 vector<string>
34 File_path::directories () const
35 {
36   return dirs_;
37 }
38
39 #include <algorithm>
40 void
41 File_path::parse_path (string p)
42 {
43   concat (dirs_, string_split (p, PATHSEP));
44 }
45
46 bool
47 is_file (string file_name)
48 {
49 #if !STAT_MACROS_BROKEN
50   struct stat sbuf;
51   if (stat (file_name.c_str (), &sbuf) != 0)
52     return false;
53
54   return !S_ISDIR (sbuf.st_mode);
55 #endif
56
57   if (FILE *f = fopen (file_name.c_str (), "r"))
58     {
59       fclose (f);
60       return true;
61     }
62
63   return false;
64 }
65
66 bool
67 is_dir (string file_name)
68 {
69   /*
70     canonicalize; in particular, trailing slashes should disappear.
71    */
72   file_name = File_name (file_name).to_string ();
73   
74 #if !STAT_MACROS_BROKEN
75   struct stat sbuf;
76   if (stat (file_name.c_str (), &sbuf) != 0)
77     return false;
78
79   return S_ISDIR (sbuf.st_mode);
80 #endif
81
82   if (FILE *f = fopen (file_name.c_str (), "r"))
83     {
84       fclose (f);
85       return true;
86     }
87   return false;
88 }
89
90 /** Find a file.
91
92 Check absolute file name, search in the current dir (DUH! FIXME!),
93 in the construction-arg (what's that?), and in any other appended
94 directory, in this order.
95
96 @return
97 The file name if found, or empty string if not found. */
98
99 string
100 File_path::find (string name) const
101 {
102   if (!name.length () || (name == "-"))
103     return name;
104
105 #ifdef __MINGW32__
106   if (name.find ('\\') != NPOS)
107     programming_error ("file name not normalized: " + name);
108 #endif /* __MINGW32__ */
109
110   /* Handle absolute file name.  */
111   File_name file_name (name);
112   if (file_name.dir_[0] == DIRSEP && is_file (file_name.to_string ()))
113     return file_name.to_string ();
114
115   for (vsize i = 0; i < dirs_.size (); i++)
116     {
117       File_name file_name (name);
118       File_name dir = (string) dirs_[i];
119       file_name.root_ = dir.root_;
120       dir.root_ = "";
121       if (file_name.dir_.empty ())
122         file_name.dir_ = dir.to_string ();
123       else if (!dir.to_string ().empty ())
124         file_name.dir_ = dir.to_string ()
125           + ::to_string (DIRSEP) + file_name.dir_;
126       if (is_file (file_name.to_string ()))
127         return file_name.to_string ();
128     }
129   return "";
130 }
131
132 /*
133   Try to find
134
135   file.EXT,
136
137   where EXT is from EXTENSIONS.
138 */
139 string
140 File_path::find (string name, char const *extensions[])
141 {
142   if (name.empty () || name == "-")
143     return name;
144   
145   File_name file_name (name);
146   string orig_ext = file_name.ext_;
147   for (int i = 0; extensions[i]; i++)
148     {
149       file_name.ext_ = orig_ext;
150       if (*extensions[i] && !file_name.ext_.empty ())
151         file_name.ext_ += ".";
152       file_name.ext_ += extensions[i];
153       string found = find (file_name.to_string ());
154       if (!found.empty ())
155         return found;
156     }
157   
158   return "";
159 }
160
161 /** Append a directory, return false if failed.  */
162 bool
163 File_path::try_append (string s)
164 {
165   if (s == "")
166     s = ".";
167   if (is_dir (s))
168     {
169       append (s);
170       return true;
171     }
172   return false;
173 }
174
175 string
176 File_path::to_string () const
177 {
178   string s;
179   for (vsize i = 0; i < dirs_.size (); i++)
180     {
181       s = s + dirs_[i];
182       if (i < dirs_.size () - 1)
183         s += ::to_string (PATHSEP);
184     }
185   return s;
186 }
187
188 void
189 File_path::append (string str)
190 {
191   dirs_.push_back (str);
192 }
193
194 void
195 File_path::prepend (string str)
196 {
197   dirs_.insert (dirs_.begin (), str);
198 }