~ubuntu-branches/ubuntu/wily/aspectc++/wily

« back to all changes in this revision

Viewing changes to Puma/gen-release/step1/src/PathManager.cc

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2005-12-23 10:49:40 UTC
  • Revision ID: james.westby@ubuntu.com-20051223104940-ig4klhoi991zs7km
Tags: upstream-0.99+1.0pre2
ImportĀ upstreamĀ versionĀ 0.99+1.0pre2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// This file is part of PUMA.
 
2
// Copyright (C) 1999-2003  The PUMA developer team.
 
3
//                                                                
 
4
// This program is free software;  you can redistribute it and/or 
 
5
// modify it under the terms of the GNU General Public License as 
 
6
// published by the Free Software Foundation; either version 2 of 
 
7
// the License, or (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      
 
15
// License along with this program; if not, write to the Free     
 
16
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 
17
// MA  02111-1307  USA                                            
 
18
 
 
19
#include "Puma/Config.h"
 
20
#include "Puma/PathIterator.h"
 
21
#include "Puma/ErrorStream.h"
 
22
#include "Puma/PathManager.h"
 
23
#include "Puma/FileUnit.h"
 
24
#include "Puma/MacroUnit.h"
 
25
#include "Puma/RegComp.h"
 
26
#include "Puma/SysCall.h"
 
27
#include <string.h>
 
28
#include <stdlib.h>
 
29
#ifdef _MSC_VER
 
30
#define PATH_MAX _MAX_PATH
 
31
#endif
 
32
 
 
33
namespace Puma {
 
34
 
 
35
 
 
36
PathManager::~PathManager () {
 
37
  for (int i = numProts () - 1; i >= 0; i--)
 
38
    delete _protected[i];
 
39
}
 
40
 
 
41
 
 
42
// Join the paths of the given manager with the paths 
 
43
// of this path manager.
 
44
void PathManager::join (PathManager &pm) {
 
45
  for (int i = 0; i < pm.numPaths (); i++)
 
46
    addPath (pm.src (i), pm.dest (i));   
 
47
  for (int i = 0; i < pm.numProts (); i++)
 
48
    _protected.append (new RegComp (*pm.prot (i)));
 
49
}
 
50
 
 
51
 
 
52
// Add the separator '/' to the copy of the given string.
 
53
char *PathManager::addSeparator (const char *s) const {
 
54
  if (! s) return (char*) 0;
 
55
  int pos = strlen (s);
 
56
 
 
57
  char *str = new char[pos + 2];
 
58
  strcpy (str, s);
 
59
  if (str[pos - 1] != '/') // Add a trailing '/'.
 
60
    strcat (str, "/");
 
61
  return str;
 
62
}
 
63
 
 
64
 
 
65
// Add a new source directory.
 
66
void PathManager::addPath (const char *source, const char *destination) {
 
67
  if (source) {        
 
68
    char *newsrc = addSeparator (source);
 
69
 
 
70
    // Don't add a source directory twice.
 
71
    // Don't add a sub-directory of an existing source directory.
 
72
    for (int pos = numPaths () - 1; pos >= 0; pos--)
 
73
      if (strncmp (src (pos), newsrc, strlen (src (pos))) == 0) {
 
74
        delete[] newsrc;
 
75
        return;
 
76
      }
 
77
        
 
78
    // Add the source path.
 
79
    _paths[numPaths ()].src (newsrc);
 
80
        
 
81
    if (destination) {   
 
82
      // Add the destination path.
 
83
      char *newdest = addSeparator (destination);
 
84
      _paths[numPaths () - 1].dest (newdest);
 
85
      delete[] newdest;
 
86
    }
 
87
 
 
88
    // add the files to iterator file list
 
89
    traverse (newsrc);
 
90
 
 
91
    delete[] newsrc;
 
92
  }
 
93
  else if (destination) {
 
94
    // Add the destination path.
 
95
    char *newdest = addSeparator (destination);
 
96
    _paths[numPaths ()].dest (newdest);
 
97
    delete[] newdest;
 
98
    _paths[numPaths () - 1].src (0);
 
99
  }
 
100
}
 
101
 
 
102
 
 
103
// find the canonical filename representation for a file
 
104
bool PathManager::canonFilename (Filename name, Filename &abs_name) const {
 
105
 
 
106
  string file_abs = "";
 
107
  const char *path = name.path ();
 
108
  if (strcmp (path, "") == 0)
 
109
    path = ".";
 
110
    
 
111
  Filename canon_file, canon_dir;
 
112
  if (SysCall::canonical (name, canon_file))
 
113
    file_abs = canon_file.name ();
 
114
  else if (SysCall::canonical (name.path (), canon_dir)) {
 
115
    file_abs = canon_dir.name ();
 
116
    const char *nodir = strrchr (name.name (), '/');
 
117
    if (!nodir) nodir = strrchr (name.name (), '\\');
 
118
    if (nodir)
 
119
    file_abs += nodir;
 
120
  }
 
121
  else
 
122
    return false; // neither file nor directory exist
 
123
 
 
124
  abs_name.name (file_abs.c_str ());
 
125
  return true;
 
126
}
 
127
 
 
128
 
 
129
// checks if a give file (by name) is a registered file of this path manager
 
130
// In case of success (found!) the an iterator is returned, which can be
 
131
// used to access more information about the file.
 
132
bool PathManager::isBelow (const char *file, PFMConstIter &iter) const {
 
133
 
 
134
  // determine the canonical name (which has to exist)
 
135
  Filename file_abs;
 
136
  if (!canonFilename (file, file_abs))
 
137
    return false;
 
138
 
 
139
  // search for the name and return the result
 
140
  iter = _files.find (string (file_abs.name ()));
 
141
  return iter != _files.end ();
 
142
}
 
143
 
 
144
 
 
145
// Add a new file to the project file list
 
146
PFMConstIter PathManager::addFile (const ProjectFile &file) {
 
147
 
 
148
  Filename file_abs;
 
149
  bool have_canon = canonFilename (file.name (), file_abs);
 
150
  if (!have_canon) {
 
151
    assert (false);
 
152
    return _files.end ();
 
153
  }
 
154
 
 
155
  // insert the file with its canonical name as the key
 
156
  pair<PFMConstIter, bool> insert_result =
 
157
    _files.insert (PFMPair (string (file_abs.name ()), file));
 
158
    
 
159
  // return the iterator
 
160
  return insert_result.first; 
 
161
}
 
162
 
 
163
 
 
164
// Add a new file to the project file list
 
165
PFMConstIter PathManager::addFile (Filename file) {
 
166
  // determine the destination path and call addFile with two args
 
167
  std::ostringstream path;
 
168
  bool have_dest = getDestinationPath (file.name (), path);
 
169
  path << std::ends;
 
170
  string dest_path = path.str ();
 
171
  return addFile (file, have_dest ? dest_path.c_str () : "<unused-dest-name>");
 
172
}
 
173
 
 
174
 
 
175
// Add a new file to the project file list with destination path
 
176
PFMConstIter PathManager::addFile (Filename name, Filename dest) {
 
177
  return addFile (ProjectFile (name, dest));
 
178
}
 
179
 
 
180
 
 
181
// Set the destination directory of the given source directory.
 
182
void PathManager::setDest (const char *source, const char *destination) {
 
183
  if (! source) return;
 
184
    
 
185
  // Search the corresponding path info object.
 
186
  int pos;
 
187
  for (pos = numPaths () - 1; pos >= 0; pos--)
 
188
    if (strcmp (src (pos), source) == 0) 
 
189
      break;
 
190
  if (pos < 0) return; // Source path doesn't exist.
 
191
  if (destination) {   
 
192
    // Set the destination path.
 
193
    char *newdest = addSeparator (destination);
 
194
    _paths[pos].dest (newdest);
 
195
    delete[] newdest;
 
196
  } else 
 
197
    _paths[pos].dest (destination);
 
198
}
 
199
 
 
200
 
 
201
// Configure the project from the command line or a file.
 
202
void PathManager::configure (const Config &c) {
 
203
  const ConfOption *d = 0, *p = 0;
 
204
 
 
205
  for (unsigned i = 0; i < c.Options (); i++) {
 
206
    const ConfOption *o = c.Option (i);
 
207
    bool new_p = false, new_d = false;
 
208
    
 
209
    if (! strcmp (o->Name (), "-w")) {
 
210
      if (o->Arguments () != 1) continue;
 
211
      protect (o->Argument (0));
 
212
    } else if (! strcmp (o->Name (), "-p")) {
 
213
      if (o->Arguments () != 1) continue;
 
214
      new_p = true;
 
215
    } else if (! strcmp (o->Name (), "-d")) {
 
216
      if (o->Arguments () != 1) continue;
 
217
      new_d = true;
 
218
    }
 
219
    
 
220
    if (new_p) {
 
221
      if (p) {
 
222
        addPath (p->Argument (0), d ? d->Argument (0): 0);
 
223
        if (d) d = 0;
 
224
      }
 
225
      p = o;
 
226
    }
 
227
    
 
228
    if (new_d) {
 
229
      if (d) {
 
230
        addPath (p ? p->Argument (0) : 0, d->Argument (0));
 
231
        if (p) p = 0;
 
232
      }
 
233
      d = o;
 
234
    }
 
235
  }
 
236
  
 
237
  if (p || d)
 
238
    addPath (p ? p->Argument (0) : 0, d ? d->Argument (0) : 0);
 
239
}
 
240
 
 
241
 
 
242
// Initial globbing implementation.
 
243
void PathManager::glob (char *pattern) {
 
244
  // Explore the source directories of the manager and for 
 
245
  // any file matching the given pattern call the method 
 
246
  // action(filename). The default pattern is ".*".
 
247
  PathIterator iter (pattern);
 
248
  while (iterate (iter))
 
249
    action (iter);
 
250
}
 
251
 
 
252
 
 
253
// Iterate the contents of the paths.
 
254
const char *PathManager::iterate (PathIterator &iter) const {
 
255
 
 
256
  // a new iterator should start at the beginning
 
257
  if (!iter.in_use ()) {
 
258
    iter.init (_files.begin ());
 
259
  }
 
260
  else
 
261
    ++iter;
 
262
    
 
263
  // search for the next matching element
 
264
  while (iter != _files.end () &&
 
265
         ! iter._regexp->match (iter->second.name ().name ())) {
 
266
    ++iter;
 
267
  }
 
268
 
 
269
  // end or element
 
270
  if (iter == _files.end ()) {
 
271
    iter.done ();
 
272
    return 0;
 
273
  }
 
274
  else {
 
275
    return iter->second.name ().name ();
 
276
  }
 
277
}
 
278
 
 
279
 
 
280
// find all files of a directory tree and add them to _files
 
281
void PathManager::traverse (const char *path) {
 
282
  // open the current directory
 
283
  DirHandle dp = SysCall::opendir (path, &err ());
 
284
  if (! dp) { // Skip the directory, may be an access problem.
 
285
    err () << sev_error << "Couldn't open directory `" 
 
286
           << path << "'." << endMessage;
 
287
    return;
 
288
  }
 
289
  
 
290
  // Read the current directory entries.
 
291
  const char *entry;
 
292
  while ((entry = SysCall::readdir (dp, &err()))) {
 
293
    // Create the full name of the current entry, e.g. /tmp/file.c.
 
294
    char *name = new char[strlen (path) + strlen (entry) + 2];
 
295
    strcpy (name, path);
 
296
    if (name[strlen (name) - 1] != '/') 
 
297
      strcat (name, "/");
 
298
    strcat (name, entry);
 
299
    
 
300
    // Read the attributes of the current entry.
 
301
    FileInfo fi;
 
302
    if (! SysCall::stat (name, fi, &err())) continue;
 
303
    
 
304
    // Test whether entry is a directory.
 
305
    if (fi.is_dir ())
 
306
      traverse (name); // Dive into the sub-directory.
 
307
    else
 
308
      // File entry found.
 
309
      addFile (name);
 
310
    delete[] name;
 
311
  }
 
312
  
 
313
  // Close the current directory and go one up.
 
314
  SysCall::closedir (dp, &err());        
 
315
}
 
316
 
 
317
 
 
318
// Add a regular pattern specifying a path that has to be
 
319
// protected from writing.
 
320
void PathManager::protect (const char *path) {
 
321
  if (path) 
 
322
    _protected.append (new RegComp (path));
 
323
}
 
324
 
 
325
 
 
326
// Return true if the given file or path is protected
 
327
// from writing or if it isn't located within one of the 
 
328
// source directories, because then it's protected, too.
 
329
bool PathManager::isProtected (const char *file) const {
 
330
  if (! file) return false;
 
331
  
 
332
  // Protected by protect patterns?
 
333
  for (int i = numProts () - 1; i >= 0; i--) {
 
334
    if (prot (i)->match (file)) 
 
335
      return true;
 
336
  }
 
337
  
 
338
  // From outside the source directories?
 
339
  return ! isBelow (file);
 
340
}
 
341
 
 
342
 
 
343
const char *PathManager::getDestination (Filename file, ostream *name) const {
 
344
 
 
345
  // determine the canonical name (which has to exist)
 
346
  Filename file_abs;
 
347
  if (!canonFilename (file, file_abs))
 
348
    return 0;
 
349
  
 
350
  for (int i = numPaths () - 1; i >= 0; i--) {
 
351
    // TODO: don't determine the canonical directory names every time
 
352
    Filename dir_abs;
 
353
    if (!canonFilename (src (i), dir_abs)) {
 
354
      assert (false);
 
355
      return 0;
 
356
    }
 
357
    // is the canonical dir name a prefix of the filename?
 
358
    int len = strlen (dir_abs.name ());
 
359
    if (strncmp (dir_abs.name (), file_abs.name (), len) == 0 &&
 
360
        *(file_abs.name () + len) == '/') {
 
361
      if (name)
 
362
        *name << file_abs.name () + len + 1;
 
363
      return dest (i);
 
364
    }
 
365
  }
 
366
  return 0;
 
367
}
 
368
 
 
369
 
 
370
bool PathManager::getDestinationPath (const char *filename, ostream &out) const {
 
371
  std::ostringstream rest;
 
372
  const char *dir = getDestination (filename, &rest);
 
373
  rest << std::ends;
 
374
  if (dir) {
 
375
    out << dir;
 
376
    if (dir [strlen (dir) - 1] != '/')
 
377
      out << "/";
 
378
    out << rest.str ().c_str ();
 
379
    return true;
 
380
  }
 
381
  return false;
 
382
}
 
383
 
 
384
 
 
385
} // namespace Puma