source: head/obuild/cpp/obuild_find.cpp@ 3

Last change on this file since 3 was 3, checked in by barrand, 19 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.