- Merge aicom-network-fixes up to r36740
[reactos.git] / reactos / tools / rbuild / directory.cpp
1 /*
2 * Copyright (C) 2005 Casper S. Hornstrup
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 #include "pch.h"
19 #include <assert.h>
20
21 #include "rbuild.h"
22 #ifdef _MSC_VER
23 #include <errno.h>
24 #else
25 #include <dirent.h>
26 #endif//_MSC_VER
27
28 #ifdef WIN32
29 #define MKDIR(s) mkdir(s)
30 #else
31 #define MKDIR(s) mkdir(s, 0755)
32 #endif
33
34 using std::string;
35 using std::vector;
36
37 Directory::Directory ( const string& name_ )
38 : name(name_)
39 {
40 size_t pos = name.find_first_of ( "$:" );
41 if ( pos != string::npos )
42 {
43 throw InvalidOperationException ( __FILE__,
44 __LINE__,
45 "Invalid directory name '%s'",
46 name.c_str() );
47 }
48
49 const char* p = strpbrk ( name_.c_str (), "/\\" );
50 if ( name_.c_str () == p )
51 {
52 throw InvalidOperationException ( __FILE__,
53 __LINE__,
54 "Invalid relative path '%s'",
55 name_.c_str () );
56 }
57
58 if ( p )
59 {
60 name.erase ( p - name_.c_str ());
61 Add ( p + 1 );
62 }
63 }
64
65 void
66 Directory::Add ( const char* subdir )
67 {
68 size_t i;
69 string s1 = string ( subdir );
70 if ( ( i = s1.find ( '$' ) ) != string::npos )
71 {
72 throw InvalidOperationException ( __FILE__,
73 __LINE__,
74 "No environment variables can be used here. Path was %s",
75 subdir );
76 }
77
78 const char* p = strpbrk ( subdir, "/\\" );
79 if ( subdir == p || ( *subdir && subdir[1] == ':' ) )
80 {
81 throw InvalidOperationException ( __FILE__,
82 __LINE__,
83 "Invalid relative path '%s'",
84 subdir );
85 }
86
87 if ( !p )
88 p = subdir + strlen(subdir);
89 string s ( subdir, p-subdir );
90 if ( subdirs.find(s) == subdirs.end() )
91 subdirs[s] = new Directory(s);
92 if ( *p && *++p )
93 subdirs[s]->Add ( p );
94 }
95
96 bool
97 Directory::mkdir_p ( const char* path )
98 {
99 #ifndef _MSC_VER
100 DIR *directory;
101 directory = opendir ( path );
102 if ( directory != NULL )
103 {
104 closedir ( directory );
105 return false;
106 }
107 #endif//_MSC_VER
108
109 if ( MKDIR ( path ) != 0 )
110 {
111 #ifdef _MSC_VER
112 if ( errno == EEXIST )
113 return false;
114 #endif//_MSC_VER
115 throw AccessDeniedException ( string ( path ) );
116 }
117 return true;
118 }
119
120 bool
121 Directory::CreateDirectory ( const string& path )
122 {
123 size_t index = 0;
124 size_t nextIndex;
125 if ( isalpha ( path[0] ) && path[1] == ':' && path[2] == cSep )
126 {
127 nextIndex = path.find ( cSep, 3);
128 index = path.find ( cSep );
129 }
130 else
131 nextIndex = path.find ( cSep );
132
133 bool directoryWasCreated = false;
134 while ( nextIndex != string::npos )
135 {
136 nextIndex = path.find ( cSep, index + 1 );
137 directoryWasCreated = mkdir_p ( path.substr ( 0, nextIndex ).c_str () );
138 index = nextIndex;
139 }
140 return directoryWasCreated;
141 }
142
143 void
144 Directory::GenerateTree ( DirectoryLocation root,
145 bool verbose )
146 {
147 switch ( root )
148 {
149 case IntermediateDirectory:
150 return GenerateTree ( Environment::GetIntermediatePath (), verbose );
151 case OutputDirectory:
152 return GenerateTree ( Environment::GetOutputPath (), verbose );
153 case InstallDirectory:
154 return GenerateTree ( Environment::GetInstallPath (), verbose );
155 default:
156 throw InvalidOperationException ( __FILE__,
157 __LINE__,
158 "Invalid directory %d.",
159 root );
160 }
161 }
162
163 void
164 Directory::GenerateTree ( const string& parent,
165 bool verbose )
166 {
167 string path;
168
169 if ( parent.size () > 0 )
170 {
171 if ( name.size () > 0 )
172 path = parent + sSep + name;
173 else
174 path = parent;
175 if ( CreateDirectory ( path ) && verbose )
176 printf ( "Created %s\n", path.c_str () );
177 }
178 else
179 path = name;
180
181 for ( directory_map::iterator i = subdirs.begin ();
182 i != subdirs.end ();
183 ++i )
184 {
185 i->second->GenerateTree ( path, verbose );
186 }
187 }
188
189 string
190 Directory::EscapeSpaces ( const string& path )
191 {
192 string newpath;
193 const char* p = &path[0];
194 while ( *p != 0 )
195 {
196 if ( *p == ' ' )
197 newpath = newpath + "\\ ";
198 else
199 newpath = newpath + *p;
200 *p++;
201 }
202 return newpath;
203 }
204
205 void
206 Directory::CreateRule ( FILE* f,
207 const string& parent )
208 {
209 string path;
210 string escapedName = EscapeSpaces ( name );
211
212 if ( escapedName.size() > 0 )
213 {
214 if ( ! (escapedName == "tools" &&
215 ( parent == "$(OUTPUT)" || parent == "$(INTERMEDIATE)" ) ) )
216 {
217 fprintf ( f,
218 "%s%c%s: | %s\n",
219 parent.c_str (),
220 cSep,
221 escapedName.c_str (),
222 parent.c_str () );
223
224 fprintf ( f,
225 "\t$(ECHO_MKDIR)\n" );
226
227 fprintf ( f,
228 "\t${mkdir} $@\n" );
229 }
230
231 path = parent + sSep + escapedName;
232 }
233 else
234 path = parent;
235
236 for ( directory_map::iterator i = subdirs.begin();
237 i != subdirs.end();
238 ++i )
239 {
240 i->second->CreateRule ( f, path );
241 }
242 }
243
244 Directory::~Directory()
245 {
246 std::map<std::string, Directory*>::iterator theIterator;
247 for ( theIterator = subdirs.begin (); theIterator != subdirs.end (); theIterator++ )
248 delete theIterator->second;
249 }