Fix typo
[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 }
129 else
130 nextIndex = path.find ( cSep );
131
132 bool directoryWasCreated = false;
133 while ( nextIndex != string::npos )
134 {
135 nextIndex = path.find ( cSep, index + 1 );
136 directoryWasCreated = mkdir_p ( path.substr ( 0, nextIndex ).c_str () );
137 index = nextIndex;
138 }
139 return directoryWasCreated;
140 }
141
142 void
143 Directory::GenerateTree ( DirectoryLocation root,
144 bool verbose )
145 {
146 switch ( root )
147 {
148 case IntermediateDirectory:
149 return GenerateTree ( Environment::GetIntermediatePath (), verbose );
150 case OutputDirectory:
151 return GenerateTree ( Environment::GetOutputPath (), verbose );
152 case InstallDirectory:
153 return GenerateTree ( Environment::GetInstallPath (), verbose );
154 default:
155 throw InvalidOperationException ( __FILE__,
156 __LINE__,
157 "Invalid directory %d.",
158 root );
159 }
160 }
161
162 void
163 Directory::GenerateTree ( const string& parent,
164 bool verbose )
165 {
166 string path;
167
168 if ( parent.size () > 0 )
169 {
170 if ( name.size () > 0 )
171 path = parent + sSep + name;
172 else
173 path = parent;
174 if ( CreateDirectory ( path ) && verbose )
175 printf ( "Created %s\n", path.c_str () );
176 }
177 else
178 path = name;
179
180 for ( directory_map::iterator i = subdirs.begin ();
181 i != subdirs.end ();
182 ++i )
183 {
184 i->second->GenerateTree ( path, verbose );
185 }
186 }
187
188 string
189 Directory::EscapeSpaces ( const string& path )
190 {
191 string newpath;
192 const char* p = &path[0];
193 while ( *p != 0 )
194 {
195 if ( *p == ' ' )
196 newpath = newpath + "\\ ";
197 else
198 newpath = newpath + *p;
199 *p++;
200 }
201 return newpath;
202 }
203
204 void
205 Directory::CreateRule ( FILE* f,
206 const string& parent )
207 {
208 string path;
209 string escapedName = EscapeSpaces ( name );
210
211 if ( escapedName.size() > 0 )
212 {
213 fprintf ( f,
214 "%s%c%s: | %s\n",
215 parent.c_str (),
216 cSep,
217 escapedName.c_str (),
218 parent.c_str () );
219
220 fprintf ( f,
221 "\t$(ECHO_MKDIR)\n" );
222
223 fprintf ( f,
224 "\t${mkdir} $@\n" );
225
226 path = parent + sSep + escapedName;
227 }
228 else
229 path = parent;
230
231 for ( directory_map::iterator i = subdirs.begin();
232 i != subdirs.end();
233 ++i )
234 {
235 i->second->CreateRule ( f, path );
236 }
237 }