source: snovis/head/obuild/cpp/obuild_find.cpp @ 9

Last change on this file since 9 was 6, checked in by barrand, 17 years ago
File size: 16.2 KB
Line 
1//
2//  This program is and should be standalone so that :
3//     UNIX> c++ obuild_find.cxx
4//      DOS> cl.exe obuild_find.cxx
5// builds at first shoot.
6//
7
8#include <string>
9#include <vector>
10#include <stdlib.h>
11
12// From Lib :
13static bool Lib_System_getenv(const std::string&,std::string&);
14static std::string Lib_System_pathSeparator();
15static std::string Lib_System_fileSeparator();
16static std::vector<std::string> Lib_smanip_words(const std::string&,
17                                                 const std::string&,
18                                                 bool = false);
19static bool Lib_smanip_match(const std::string&,const std::string&);
20static bool Lib_smanip_printf(std::string&,int,const char*,...);
21
22static bool Lib_dirmanip_entries(const std::string&,
23                                 std::vector<std::string>&,bool = true);
24static bool Lib_dirmanip_isAnEntry(const std::string&,const std::string&,
25                                 bool&);
26static bool Lib_dirmanip_find(const std::vector<std::string>& aPaths,
27                   const std::string& aPackage,
28                   const std::string& aVersion,
29                   std::string& aPath,
30                   std::string& aError); 
31
32//////////////////////////////////////////////////////////////////////////////
33//////////////////////////////////////////////////////////////////////////////
34//////////////////////////////////////////////////////////////////////////////
35int main(
36 int aArgc
37,char** aArgv
38) 
39//////////////////////////////////////////////////////////////////////////////
40//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
41{
42  std::vector<std::string> args;
43 {for(int index=0;index<aArgc;index++) args.push_back(aArgv[index]);}
44 
45  std::string pack;
46  std::string vers;
47  if(args.size()==2) {
48    pack = args[1];
49  } else if(args.size()==3) {
50    pack = args[1];
51    vers = args[2];
52  } else {
53    fprintf(stderr,"obuild_find : one or two arguments expected.\n");
54    printf("\n");
55    return EXIT_FAILURE;
56  }
57
58  //fprintf(stderr,"obuild_find : \"%s\" vers \"%s\"\n",pack.c_str(),vers.c_str());
59
60  std::string::size_type star = vers.find('*');
61  bool vers_wildcard = (star==std::string::npos?false:true);
62
63  std::string opath;
64  if(!Lib_System_getenv("OBUILD_PATH",opath)) {
65    fprintf(stderr,"\
66obuild_find : environment variable OBUILD_PATH not defined.\n\
67\n\
68  OBUILD_PATH is a list of head directories\n\
69 containing packages. Directories are ':' separated on a UNIX\n\
70 and ';' separated on a Windows.\n\
71\n\
72  For example, on a UNIX, if /work/project1 contains package pack1\n\
73 and /usr/project2 contains the package pack2 ; then\n\
74 having for the obuild directories the directory hierachies :\n\
75    /work/project1/pack1/<version>/obuild\n\
76    /usr/project2/pack2/<version>/obuild\n\
77 someone set the OBUILD_PATH variable under a csh flavoured\n\
78 shell with :\n\
79    csh> setenv OBUILD_PATH \"/work/project1:/usr/project2\"\n\
80 and under a sh flavoured shell with :\n\
81     sh> OBUILD_PATH=\"/work/project1:/usr/project2\"\n\
82     sh> export OBUILD_PATH\n\
83 Under DOS :\n\
84    DOS> SET OBUILD_PATH=C:\\work\\project1;D:\\usr\\project2\"\n\
85\n\
86");
87    printf("\n");
88    return EXIT_FAILURE;
89  }
90   
91  std::string sep = Lib_System_pathSeparator();
92  std::vector<std::string> paths = Lib_smanip_words(opath,sep);
93
94  std::string path,serr;
95  std::string dir;
96  if(!Lib_dirmanip_find(paths,pack,vers,dir,serr)) {
97    fprintf(stderr,"%s\n",serr.c_str());
98    printf("\n");
99    return EXIT_FAILURE;
100  }
101  if(dir=="") {
102    printf("\n");
103    return EXIT_FAILURE; //Not found.
104  }
105  printf("%s\n",dir.c_str());         
106  return EXIT_SUCCESS; 
107}
108
109//////////////////////////////////////////////////////////////////////////////
110//////////////////////////////////////////////////////////////////////////////
111//////////////////////////////////////////////////////////////////////////////
112//////////////////////////////////////////////////////////////////////////////
113bool Lib_System_getenv(
114 const std::string& aString
115,std::string& aValue
116)
117//////////////////////////////////////////////////////////////////////////////
118//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
119{
120  const char* env = ::getenv(aString.c_str());
121  if(env) {
122    aValue = std::string(env?env:"");
123    return true;
124  } else {
125    aValue = "";
126    return false;
127  }
128}
129//////////////////////////////////////////////////////////////////////////////
130std::string Lib_System_fileSeparator(
131)
132//////////////////////////////////////////////////////////////////////////////
133//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
134{
135#ifdef WIN32
136  return "\\";
137#else
138  return "/";
139#endif
140}
141//////////////////////////////////////////////////////////////////////////////
142std::string Lib_System_pathSeparator(
143)
144//////////////////////////////////////////////////////////////////////////////
145//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
146{
147#ifdef WIN32
148  return ";";
149#else
150  return ":";
151#endif
152}
153//////////////////////////////////////////////////////////////////////////////
154#include <string.h> /* strcpy */
155#include <stdlib.h> /* malloc,free */
156
157#define Lib_strdup(str)  ((str) != NULL ? (::strcpy((char*)::malloc((unsigned)::strlen(str) + 1), str)) : (char*)NULL)
158#define Lib_strdel(str) {if((str)!=NULL) {::free(str);str=NULL;}}
159//////////////////////////////////////////////////////////////////////////////
160bool Lib_smanip_match(
161 const std::string& aString   
162,const std::string& aPattern
163)
164//////////////////////////////////////////////////////////////////////////////
165//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
166{
167  int lpattern = aPattern.length();
168  int lstring  = aString.length();
169  if ((lpattern==0)&&(lstring==0)) return true;
170  if ((lpattern==0)&&(lstring!=0)) return true;
171  if ((lpattern!=0)&&(lstring==0)) return false;
172  // pattern is * :
173  if(aPattern=="*") return true;
174  int wcount = 0;
175  int count;
176  for(count=0;count<lpattern;count++) {
177    if(aPattern[count]=='*') wcount++;
178  }
179  // no wildcard :
180  if(wcount==0) {
181    return (aPattern==aString ? true : false );
182  }
183
184  // complex pattern :
185#define PACKET 32
186  char** words = (char**)::malloc(PACKET * sizeof(char*));
187  if(words==NULL) return false;
188  int wmax = PACKET;
189  int wnumber= 0;
190  char* s = Lib_strdup(aPattern.c_str());
191  char* token = s;
192  while(1) { 
193    char* pos = ::strstr (token,"*");
194    if(pos) {
195      *pos = '\0';
196      if(*token!='\0') {
197        if(wnumber>=wmax) {
198          words = (char**)::realloc(words,(wmax+PACKET) * sizeof(char*));
199          if(words==NULL) {
200            Lib_strdel(s);
201            return false;
202          }
203          wmax += PACKET;
204        }
205        words[wnumber] = token;
206        wnumber++;
207      }
208      token = pos + 1;
209    } else { // last word :
210      if(*token!='\0') {
211        if(wnumber>=wmax) {
212          words = (char**)::realloc(words,(wmax+PACKET) * sizeof(char*));
213          if(words==NULL) {
214            Lib_strdel(s);
215            return false;
216          }
217          wmax += PACKET;
218        }
219        words[wnumber] = token;
220        wnumber++;
221      }
222      break;
223    }
224  }
225  // check that at least one word is not empty :
226  bool ok = false;
227  for(count=0;count<wnumber;count++) { 
228    if(*(words[count])!='\0') {
229      ok = true;
230      break;
231    }
232  }
233  if(!ok) { // only wildcards :
234    Lib_strdel(s);
235    if(words) ::free(words);
236    return true;
237  } 
238
239  // loop on words :
240  bool match = true;
241  token = (char*)aString.c_str();
242  for(count=0;count<wnumber;count++) { 
243    int   lword;
244    lword = ::strlen(words[count]); 
245    if(lword>0) { 
246      char* pos;
247      if(count==0) {
248        if(aPattern[0]!='*') {
249          // Begin of pattern (words[0]) and aString must match :
250          if(::strncmp(token,words[count],lword)!=0) {
251            match = false; // Different.
252            break;     
253          }
254          token = token + lword;
255          continue;
256        }
257      }
258      pos = ::strstr (token,words[count]);
259      if(!pos) {
260        match = false;
261        break;
262      }
263      if((count==(wnumber-1)) && (aPattern[lpattern-1]!='*') ) {
264        // Last word :
265        if(::strcmp(aString.c_str()+lstring-lword,words[count])!=0) 
266          match = false; // Compare last word and end of aString.
267        break;
268      } else {
269        token = pos + lword;
270      }
271    }
272  }
273  Lib_strdel(s);
274  if(words) ::free(words);
275  return match;
276}
277//////////////////////////////////////////////////////////////////////////////
278std::vector<std::string> Lib_smanip_words(
279 const std::string& aString
280,const std::string& aLimiter
281,bool aTakeEmpty // false
282)
283//////////////////////////////////////////////////////////////////////////////
284//  If aLimiter is for exa "|" and for "xxx||xxx" :
285//  - aTakeEmpty false : {"xxx","xxx"} will be created (and NOT {"xxx","","xxx"}).
286//  - aTakeEmpty true : {"xxx","","xxx"} will be created.
287//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
288{
289  std::vector<std::string> words;
290  if(aString=="") return words;
291  std::string::size_type lim = (aTakeEmpty?0:1);
292  if(aLimiter=="") {
293    words.push_back(aString);
294  } else {
295    std::string::size_type l = aString.length();
296    std::string::size_type llimiter = aLimiter.length();
297    std::string::size_type pos = 0;
298    while(1) {
299      std::string::size_type index = aString.find(aLimiter,pos);
300      if(index==std::string::npos){ // Last word.
301        if((l-pos)>=lim) words.push_back(aString.substr(pos,l-pos));
302        break;
303      } else {
304        //     abcxxxef
305        //     0  3  67
306        if((index-pos)>=lim) words.push_back(aString.substr(pos,index-pos));
307        pos = index + llimiter;
308      }
309    }
310  }
311  return words;
312}
313#include <stdarg.h>
314//////////////////////////////////////////////////////////////////////////////
315bool Lib_smanip_printf(
316 std::string& aString
317,int aLength
318,const char* aFormat
319,...
320)
321//////////////////////////////////////////////////////////////////////////////
322//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
323{
324  aString = "";
325  if(aLength<0) return false;
326  if(!aFormat) return false;
327  char* s = new char[aLength+1];
328  if(!s) return false;
329  s[aLength] = '\0';
330  va_list args;
331  va_start (args,aFormat);
332  vsprintf (s,aFormat,args);
333  va_end   (args);
334  if(s[aLength]!='\0') {
335    delete [] s;
336    return false;
337  }
338  aString = s;
339  delete [] s;
340  return true;
341}
342
343#ifdef WIN32
344#include <windows.h>
345#include <direct.h>
346#else //UNIX
347#include <dirent.h>
348#if defined(_POSIX_SOURCE)
349#define REAL_DIR_ENTRY(dp) 1
350#else
351#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
352#endif
353#include <unistd.h>
354#endif
355
356#include <sys/stat.h>
357//////////////////////////////////////////////////////////////////////////////
358bool Lib_dirmanip_entries(
359 const std::string& aPath
360,std::vector<std::string>& aList
361,bool aFullPath
362)
363//////////////////////////////////////////////////////////////////////////////
364//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
365{
366  aList.clear();
367  struct stat finfo;
368  if (::stat(aPath.c_str(),&finfo) < 0)  return false;
369#ifdef WIN32
370  if (!(finfo.st_mode & S_IFDIR)) return false;
371  std::string entry = aPath;
372  if (!(entry[entry.size()] == '/' || entry[entry.size()] == '\\' ))
373    entry += "\\";
374  entry += "*";
375  WIN32_FIND_DATA findFileData;
376  HANDLE dir = ::FindFirstFile(entry.c_str(),&findFileData);
377  if(dir == INVALID_HANDLE_VALUE) return false;
378  // Get file names :
379  for (;;) {
380    if(!::FindNextFile(dir,&findFileData)) break;
381    std::string name = (const char*)findFileData.cFileName;
382    if(aFullPath)
383      aList.push_back(aPath+"\\"+name);
384    else
385      aList.push_back(name);
386  }
387  ::FindClose(dir);
388#else
389  if (!S_ISDIR(finfo.st_mode)) return false;
390  DIR* dir = ::opendir(aPath.c_str());
391  if(!dir) return false;
392  // Get file names :
393  for (;;) {
394    struct dirent* dp = ::readdir(dir);
395    //struct direct* dp;
396    if (dp==NULL) break;
397    if (REAL_DIR_ENTRY(dp)) {
398      std::string name = dp->d_name;
399      // Be sure we can work on the file :
400      std::string fname = aPath+"/"+name;
401      if (::stat(fname.c_str(),&finfo) < 0)  continue;
402      if(aFullPath)
403        aList.push_back(fname);
404      else
405        aList.push_back(name);
406    }
407  }
408  ::closedir(dir);
409#endif
410  return true;
411}
412//////////////////////////////////////////////////////////////////////////////
413bool Lib_dirmanip_isAnEntry(
414 const std::string& aPath
415,const std::string& aName
416,bool& aFound
417)
418//////////////////////////////////////////////////////////////////////////////
419//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
420{
421  aFound = false;
422  struct stat finfo;
423  if (::stat(aPath.c_str(),&finfo) < 0)  return false;
424#ifdef WIN32
425  if (!(finfo.st_mode & S_IFDIR)) return false;
426  std::string entry = aPath;
427  if (!(entry[entry.size()] == '/' || entry[entry.size()] == '\\' ))
428    entry += "\\";
429  entry += "*";
430  WIN32_FIND_DATA findFileData;
431  HANDLE dir = ::FindFirstFile(entry.c_str(),&findFileData);
432  if(dir == INVALID_HANDLE_VALUE) return false;
433  // Get file names :
434  for (;;) {
435    if(!::FindNextFile(dir,&findFileData)) break;
436    std::string name = (const char*)findFileData.cFileName;
437    if(name==aName) {
438      aFound = true;
439      ::FindClose(dir);
440      return true;
441    }
442  }
443  ::FindClose(dir);
444#else
445  if (!S_ISDIR(finfo.st_mode)) return false;
446  DIR* dir = ::opendir(aPath.c_str());
447  if(!dir) return false;
448  // Get file names :
449  for (;;) {
450    struct dirent* dp = ::readdir(dir);
451    //struct direct* dp;
452    if (dp==NULL) break;
453    if (REAL_DIR_ENTRY(dp)) {
454      std::string name = dp->d_name;
455      if(name==aName) {
456        aFound = true;
457        ::closedir(dir);
458        return true;
459      }
460    }
461  }
462  ::closedir(dir);
463#endif
464  return true;
465}
466//////////////////////////////////////////////////////////////////////////////
467bool Lib_dirmanip_find(
468 const std::vector<std::string>& aPaths
469,const std::string& aPackage
470,const std::string& aVersion
471,std::string& aPath
472,std::string& aError
473) 
474//////////////////////////////////////////////////////////////////////////////
475// aVersion could be empty and can contain woldcards.
476// The list of paths is searched first to last.
477// return true and aPath="" mean not found.
478// return false : something went wrong in directory manipulation.
479//                aError contains then an error message.
480//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
481{
482  if(aPackage=="") {
483    aError = "Lib::dirmanip::find : empty package name.";
484    return false;
485  }
486
487  std::string sep = Lib_System_fileSeparator();
488
489  std::string::size_type star = aVersion.find('*');
490  bool vers_wildcard = (star==std::string::npos?false:true);
491
492  unsigned int pathn = aPaths.size();
493  //fprintf(stderr,"obuild_find : number of path %d\n",pathn);
494  for(unsigned int pathi=0;pathi<pathn;pathi++) {
495    std::string dir = aPaths[pathi];
496    //fprintf(stderr,"Lib::dirmanip::find : look directory \"%s\"\n",
497    //  dir.c_str());
498    bool found;
499    if(!Lib_dirmanip_isAnEntry(dir,aPackage,found)) {
500      aPath = "";
501      Lib_smanip_printf(aError,128+dir.size(),
502        "Lib::dirmanip::find : can't open directory \"%s\"\n",dir.c_str());
503      return false;
504    }
505    if(found) {
506      if(aVersion=="") {
507        dir += sep+aPackage;
508        aPath = dir;
509        aError = "";
510        return true;
511      }
512      // Look version :
513      dir += sep+aPackage;
514      if(vers_wildcard) {
515        std::vector<std::string> files;
516        if(Lib_dirmanip_entries(dir,files,false)) {
517          unsigned int number = files.size();
518          for(unsigned int index=0;index<number;index++) {
519            const std::string& file = files[index];
520            //std::string p,n,s;
521            //Lib::smanip::pathNameSuffix(file,p,n,s);
522            if(Lib_smanip_match(file,aVersion)) {
523              dir += sep+file;
524              aPath = dir;
525              aError = "";
526              return true;
527            }
528          } 
529        } 
530      } else {
531        bool found;
532        if(!Lib_dirmanip_isAnEntry(dir,aVersion,found)) {
533          aPath = "";
534          Lib_smanip_printf(aError,128+dir.size(),
535            "Lib::dirmanip::find : can't open directory \"%s\"\n",dir.c_str());
536          return false;
537        }
538        dir += sep+aVersion;
539        aPath = dir;
540        aError = "";
541        return true;
542      }
543    }
544  }
545
546  aPath = ""; // return true and aPath="" mean not found.
547  aError = "";
548  return true;
549}
Note: See TracBrowser for help on using the repository browser.