Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / tools / configure / configure.cpp
blobed27375c358942b153872cf266e4758d6c8f23ec
1 /*
2 * configure.cxx
4 * Build options generated by the configure script.
6 * Portable Windows Library
8 * Copyright (c) 2003 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.40 2007/08/26 12:25:00 rjongbloed
28 * Changes to allow for 64 bit builds and 64 bit library linking.
30 * Revision 1.39 2007/08/22 07:00:53 rjongbloed
31 * Added new MSWIN_FIND_FILE option to locate files, eg .lib files, within the
32 * features detected directory sub-tree. Different packaging someimes has
33 * lib files in slightly different locations.
35 * Revision 1.38 2007/02/10 07:21:23 csoutheren
36 * Fixed problem with excluding directories
38 * Revision 1.37 2006/07/31 06:53:39 csoutheren
39 * Fixed problem with excluding directories
41 * Revision 1.36 2006/07/23 21:49:17 shorne
42 * Fix for exclude directories not being excluded
44 * Revision 1.35 2006/07/23 05:13:25 rjongbloed
45 * Disabled some code till get a chance to amke it work! Back to doing full disk searches all the time.
47 * Revision 1.34 2006/07/23 04:44:18 rjongbloed
48 * Fixed directory comparison to be more accurate, using Win32 API call to get absolute path.
50 * Revision 1.33 2006/07/22 06:20:55 rjongbloed
51 * Changes to configure program so will process dependencies before directory search so
52 * does not search for features it is not going to use.
53 * Added dependencies so both SSL libs cannot be included or searched for.
55 * Revision 1.32 2006/07/14 15:20:54 csoutheren
56 * Applied 1519950 - configure --extern-dir not working
57 * Thanks to Dinis Rosario
59 * Revision 1.31 2006/07/06 01:10:14 csoutheren
60 * Added parsing of version.h to configure
61 * PWLib version variables now set in ptbuildopts.h
63 * Revision 1.30 2006/07/05 13:38:17 shorne
64 * Fix compile error on MSVC6
66 * Revision 1.29 2006/07/04 00:40:16 csoutheren
67 * Added capability for multiple feature dependencies
69 * Revision 1.28 2006/06/29 02:37:23 csoutheren
70 * Fixed compile problem on VC 2005
72 * Revision 1.27 2006/06/26 01:02:55 csoutheren
73 * Improved configure.exe to ignore case when matching exclude dirs
74 * Allow exclusion of drive root directories
76 * Revision 1.26 2005/11/30 12:47:42 csoutheren
77 * Removed tabs, reformatted some code, and changed tags for Doxygen
79 * Revision 1.25 2005/08/15 09:40:58 rjongbloed
80 * Captalised the word "disabled" so more obvious.
82 * Revision 1.24 2005/08/13 19:13:49 shorne
83 * Fix so when feature not found it is marked as disabled.
85 * Revision 1.23 2004/12/09 02:05:52 csoutheren
86 * Added IF_FEATURE option to allow features dependent on existence/non-existence of
87 * other features
89 * Revision 1.22 2004/12/01 11:59:19 csoutheren
90 * Incremented version number
92 * Revision 1.21 2004/12/01 11:57:03 csoutheren
93 * Fixed problem with not finding MSWIN macros with leading spaces and added ability to enable/disable features using --name as as well as --enable-name
94 * Thank to Guilhem Tardy
96 * Revision 1.20 2004/08/13 01:08:09 csoutheren
97 * Changed to look for configure.ac, then configure.in
99 * Revision 1.19 2004/07/12 02:32:58 csoutheren
100 * Fixed problem when more than two elements in env var
102 * Revision 1.18 2004/04/29 02:02:25 csoutheren
103 * Removed debugging (oops)
105 * Revision 1.17 2004/04/29 02:00:49 csoutheren
106 * Fixed problem with checking for NULL error return from FindFirstFile rather than INVALID_HANDLE_VALUE
108 * Revision 1.16 2004/04/04 01:30:37 csoutheren
109 * Added ability to specify exclude environment variable on configure command line which allows easy switching between MSVC and VS.net 2003
111 * Revision 1.15 2004/03/23 06:32:01 csoutheren
112 * Fixed problems with multiple directories in exclude spec
114 * Revision 1.14 2004/03/16 01:45:17 rjongbloed
115 * Fixed locating lbrary in pre-defined search directories.
116 * Added version number to configure program.
117 * Tidied the --help display.
119 * Revision 1.13 2004/03/13 02:50:56 rjongbloed
120 * Fixed anomalous message where even though a feature was disabled, a "Located "
121 * directiory message is still displayed causing confusion.
122 * Added --disable-<feature> as synonym to existing --no-<feature> to be compatible
123 * with autoconf.
124 * Added default value to defines of 1 rather than blank.
126 * Revision 1.12 2004/01/30 02:33:58 csoutheren
127 * More fixups
129 * Revision 1.11 2004/01/30 01:43:41 csoutheren
130 * Added excludedir options and environment variable
132 * Revision 1.10 2003/11/25 08:21:37 rjongbloed
133 * Fixed display of configured items
135 * Revision 1.9 2003/11/06 09:13:20 rjongbloed
136 * Improved the Windows configure system to allow multiple defines based on file existence. Needed for SDL support of two different distros.
138 * Revision 1.8 2003/10/30 01:17:15 dereksmithies
139 * Add fix from Jose Luis Urien. Many thanks.
141 * Revision 1.7 2003/10/23 21:49:51 dereksmithies
142 * Add very sensible fix to limit extent of search. Thanks Ben Lear.
144 * Revision 1.6 2003/08/04 05:13:17 dereksmithies
145 * Reinforce the disablement if the command lines specifies --no-XXXX to a feature.
147 * Revision 1.5 2003/08/04 05:07:08 dereksmithies
148 * Command line option now disables feature when feature found on disk.
150 * Revision 1.4 2003/05/16 02:03:07 rjongbloed
151 * Fixed being able to manually disable a "feature" when does a full disk search.
153 * Revision 1.3 2003/05/05 08:39:52 robertj
154 * Added ability to explicitly disable a feature, or tell configure exactly
155 * where features library is so it does not need to search for it.
157 * Revision 1.2 2003/04/17 03:32:06 robertj
158 * Improved windows configure program to use lines out of configure.in
160 * Revision 1.1 2003/04/16 08:00:19 robertj
161 * Windoes psuedo autoconf support
165 #pragma warning(disable:4786)
166 #pragma warning(disable:4996)
168 #include <iostream>
169 #include <fstream>
170 #include <iomanip>
171 #include <string>
172 #include <list>
173 #include <algorithm>
174 #include <stdlib.h>
175 #include <windows.h>
176 #include <vector>
177 #include <map>
178 #include <io.h>
181 #define VERSION "1.12"
183 static char * VersionTags[] = { "MAJOR_VERSION", "MINOR_VERSION", "BUILD_NUMBER", "BUILD_TYPE" };
185 using namespace std;
187 bool DirExcluded(const string & dir);
189 string ToLower(const string & _str)
191 string str = _str;
192 string::iterator r;
193 for(r = str.begin(); r != str.end(); ++r)
194 *r = (char)tolower(*r);
195 return str;
198 string GetFullPathNameString(const string & path)
200 string fullPath;
201 DWORD len = ::GetFullPathName(path.c_str(), 0, NULL, NULL);
202 if (len > 1) {
203 fullPath.resize(len-1);
204 ::GetFullPathName(path.c_str(), len, &fullPath[0], NULL);
206 return ToLower(fullPath);
210 class Feature
212 public:
213 enum States
215 Enabled,
216 NotFound,
217 Disabled,
218 Blocked,
219 Dependency
222 Feature() : state(Enabled) { }
223 Feature(const string & featureName, const string & optionName, const string & optionValue);
225 void Parse(const string & optionName, const string & optionValue);
226 void Adjust(string & line);
227 bool Locate(const char * testDir);
229 string featureName;
230 string displayName;
231 string directorySymbol;
232 string simpleDefineName;
233 string simpleDefineValue;
234 map<string, string> defines;
235 map<string, string> defineValues;
237 struct CheckFileInfo {
238 CheckFileInfo() : found(false), defineName("1") { }
240 bool Locate(const string & testDir);
242 bool found;
243 string fileName;
244 string fileText;
245 string defineName;
246 string defineValue;
248 list<CheckFileInfo> checkFiles;
250 list<string> checkDirectories;
252 struct FindFileInfo {
253 string symbol;
254 string basename;
255 string subdir;
256 string fullname;
258 list<FindFileInfo> findFiles;
260 list<string> ifFeature;
261 list<string> ifNotFeature;
263 string breaker;
264 string directory;
265 States state;
269 vector<Feature> features;
270 list<string> excludeDirList;
272 ///////////////////////////////////////////////////////////////////////
274 Feature::Feature(const string & featureNameParam,
275 const string & optionName,
276 const string & optionValue)
277 : featureName(featureNameParam),
278 state(Enabled)
280 Parse(optionName, optionValue);
284 void Feature::Parse(const string & optionName, const string & optionValue)
286 if (optionName == "DISPLAY")
287 displayName = optionValue;
289 else if (optionName == "DEFINE") {
290 string::size_type equal = optionValue.find('=');
291 if (equal == string::npos)
292 simpleDefineName = optionValue;
293 else {
294 simpleDefineName.assign(optionValue, 0, equal);
295 simpleDefineValue.assign(optionValue, equal+1, INT_MAX);
299 else if (optionName == "VERSION") {
300 string::size_type equal = optionValue.find('=');
301 if (equal != string::npos)
302 defines.insert(pair<string,string>(optionValue.substr(0, equal), optionValue.substr(equal+1)));
305 else if (optionName == "CHECK_FILE") {
306 string::size_type comma = optionValue.find(',');
307 if (comma == string::npos)
308 return;
310 CheckFileInfo check;
311 string::size_type pipe = optionValue.find('|');
312 if (pipe < 0 || pipe > comma)
313 check.fileName.assign(optionValue, 0, comma);
314 else {
315 check.fileName.assign(optionValue, 0, pipe);
316 check.fileText.assign(optionValue, pipe+1, comma-pipe-1);
319 string::size_type equal = optionValue.find('=', comma);
320 if (equal == string::npos)
321 check.defineName.assign(optionValue, comma+1, INT_MAX);
322 else {
323 check.defineName.assign(optionValue, comma+1, equal-comma-1);
324 check.defineValue.assign(optionValue, equal+1, INT_MAX);
327 checkFiles.push_back(check);
330 else if (optionName == "DIR_SYMBOL")
331 directorySymbol = '@' + optionValue + '@';
333 else if (optionName == "CHECK_DIR")
334 checkDirectories.push_back(GetFullPathNameString(optionValue));
336 else if (optionName == "FIND_FILE") {
337 string::size_type comma1 = optionValue.find(',');
338 if (comma1 == string::npos)
339 return;
341 string::size_type comma2 = optionValue.find(',', comma1+1);
342 if (comma2 == string::npos)
343 comma2 = INT_MAX-1;
345 FindFileInfo find;
346 find.symbol.assign(optionValue, 0, comma1);
347 find.basename.assign(optionValue, comma1+1, comma2-comma1-1);
348 find.subdir.assign(optionValue, comma2+1, INT_MAX);
349 if (find.subdir.empty())
350 find.subdir = "...";
351 findFiles.push_back(find);
354 else if (optionName == "IF_FEATURE") {
355 const char * delimiters = "&";
356 string::size_type lastPos = optionValue.find_first_not_of(delimiters, 0);
357 string::size_type pos = optionValue.find_first_of(delimiters, lastPos);
358 while (string::npos != pos || string::npos != lastPos) {
359 string str = optionValue.substr(lastPos, pos - lastPos);
360 if (str[0] == '!')
361 ifNotFeature.push_back(str.substr(1));
362 else
363 ifFeature.push_back(str);
364 lastPos = optionValue.find_first_not_of(delimiters, pos);
365 pos = optionValue.find_first_of(delimiters, lastPos);
371 static bool CompareName(const string & line, const string & name)
373 string::size_type pos = line.find(name);
374 if (pos == string::npos)
375 return false;
377 pos += name.length();
378 return !isalnum(line[pos]) && line[pos] != '_';
381 void Feature::Adjust(string & line)
383 if (state == Enabled && line.find("#undef") != string::npos) {
384 if (!simpleDefineName.empty() && CompareName(line, simpleDefineName)) {
385 line = "#define " + simpleDefineName + ' ';
386 if (simpleDefineValue.empty())
387 line += '1';
388 else
389 line += simpleDefineValue;
392 map<string,string>::iterator r, s;
393 for (r = defines.begin(); r != defines.end(); ++r) {
394 if (CompareName(line, r->first)) {
395 s = defineValues.find(r->second);
396 if (s != defineValues.end())
397 line = "#define " + r->first + ' ' + s->second;
401 for (list<CheckFileInfo>::iterator file = checkFiles.begin(); file != checkFiles.end(); file++) {
402 if (file->found && CompareName(line, file->defineName)) {
403 line = "#define " + file->defineName + ' ' + file->defineValue;
404 break;
408 for (list<FindFileInfo>::iterator file = findFiles.begin(); file != findFiles.end(); file++) {
409 if (!file->fullname.empty() && CompareName(line, file->symbol)) {
410 line = "#define " + file->symbol + " \"" + file->fullname + '"';
411 break;
416 if (directorySymbol[0] != '\0') {
417 string::size_type pos = line.find(directorySymbol);
418 if (pos != string::npos)
419 line.replace(pos, directorySymbol.length(), directory);
424 bool FindFileInTree(const string & directory, string & filename)
426 bool found = false;
427 string wildcard = directory;
428 wildcard += "*.*";
430 WIN32_FIND_DATA fileinfo;
431 HANDLE hFindFile = FindFirstFile(wildcard.c_str(), &fileinfo);
432 if (hFindFile != INVALID_HANDLE_VALUE) {
433 do {
434 if (stricmp(fileinfo.cFileName, filename.c_str()) == 0) {
435 filename.insert(0, directory);
436 found = true;
437 break;
440 string subdir = GetFullPathNameString(directory + fileinfo.cFileName);
441 if ((fileinfo.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0 &&
442 fileinfo.cFileName[0] != '.' &&
443 stricmp(fileinfo.cFileName, "RECYCLER") != 0 &&
444 !DirExcluded(subdir)) {
445 subdir += '\\';
447 found = FindFileInTree(subdir, filename);
448 if (found)
449 break;
451 } while (FindNextFile(hFindFile, &fileinfo));
453 FindClose(hFindFile);
456 return found;
460 bool Feature::Locate(const char * testDir)
462 if (state != Enabled)
463 return true;
465 if (!directory.empty())
466 return true;
468 if (checkFiles.empty())
469 return true;
471 string testDirectory = testDir;
472 if (testDirectory[testDirectory.length()-1] != '\\')
473 testDirectory += '\\';
475 list<CheckFileInfo>::iterator file = checkFiles.begin();
476 if (!file->Locate(testDirectory))
477 return false;
479 while (++file != checkFiles.end())
480 file->Locate(testDirectory);
482 char buf[_MAX_PATH];
483 _fullpath(buf, testDirectory.c_str(), _MAX_PATH);
484 directory = buf;
486 if (DirExcluded(directory))
487 return false;
489 cout << "Located " << displayName << " at " << directory << endl;
491 string::size_type pos;
492 while ((pos = directory.find('\\')) != string::npos)
493 directory[pos] = '/';
494 pos = directory.length()-1;
495 if (directory[pos] == '/')
496 directory.erase(pos);
498 for (list<FindFileInfo>::iterator file = findFiles.begin(); file != findFiles.end(); file++) {
499 string::size_type elipses = file->subdir.find("...");
500 if (elipses == string::npos) {
501 string filename = directory + '/' + file->subdir + '/' + file->basename;
502 if (_access(filename.c_str(), 0) == 0)
503 file->fullname = filename;
505 else {
506 string subdir = directory + '/';
507 subdir.append(file->subdir, 0, elipses);
508 string filename = file->basename;
509 if (FindFileInTree(subdir, filename)) {
510 while ((pos = filename.find('\\')) != string::npos)
511 filename[pos] = '/';
512 file->fullname = filename;
517 return true;
521 bool Feature::CheckFileInfo::Locate(const string & testDirectory)
523 string filename = testDirectory + fileName;
524 ifstream file(filename.c_str(), ios::in);
525 if (!file.is_open())
526 return false;
528 if (fileText.empty())
529 found = true;
530 else {
531 while (file.good()) {
532 string line;
533 getline(file, line);
534 if (line.find(fileText) != string::npos) {
535 found = true;
536 break;
541 return found;
544 string ExcludeDir(const string & _dir)
546 if (_dir.length() == 0)
547 return _dir;
549 string dir(GetFullPathNameString(_dir));
551 if (dir[dir.length()-1] != '\\')
552 dir += '\\';
554 excludeDirList.push_back(dir);
556 return dir;
560 bool DirExcluded(const string & _dir)
562 if (_dir.length() == 0)
563 return false;
565 string dir(_dir);
566 if (dir[dir.length()-1] != '\\')
567 dir += "\\";
569 list<string>::const_iterator r;
571 for (r = excludeDirList.begin(); r != excludeDirList.end(); ++r) {
572 string excludeDir = *r;
573 string dirPrefix(dir.substr(0, excludeDir.length()));
574 if (dirPrefix == excludeDir)
575 return true;
578 return false;
582 bool TreeWalk(const string & directory)
584 bool foundAll = false;
586 if (DirExcluded(directory))
587 return false;
589 string wildcard = directory;
590 wildcard += "*.*";
592 WIN32_FIND_DATA fileinfo;
593 HANDLE hFindFile = FindFirstFile(wildcard.c_str(), &fileinfo);
594 if (hFindFile != INVALID_HANDLE_VALUE) {
595 do {
596 string subdir = GetFullPathNameString(directory + fileinfo.cFileName);
597 if ((fileinfo.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0 &&
598 fileinfo.cFileName[0] != '.' &&
599 stricmp(fileinfo.cFileName, "RECYCLER") != 0 &&
600 !DirExcluded(subdir)) {
601 subdir += '\\';
603 foundAll = true;
604 vector<Feature>::iterator feature;
605 for (feature = features.begin(); feature != features.end(); feature++) {
606 if (!feature->Locate(subdir.c_str()))
607 foundAll = false;
610 if (foundAll)
611 break;
612 TreeWalk(subdir);
614 } while (FindNextFile(hFindFile, &fileinfo));
616 FindClose(hFindFile);
619 return foundAll;
623 bool ProcessHeader(const string & headerFilename)
625 string inFilename = headerFilename;
626 inFilename += ".in";
628 ifstream in(inFilename.c_str(), ios::in);
629 if (!in.is_open()) {
630 cerr << "Could not open " << inFilename << endl;
631 return false;
634 ofstream out(headerFilename.c_str(), ios::out);
635 if (!out.is_open()) {
636 cerr << "Could not open " << headerFilename << endl;
637 return false;
640 while (in.good()) {
641 string line;
642 getline(in, line);
644 vector<Feature>::iterator feature;
645 for (feature = features.begin(); feature != features.end(); feature++)
646 feature->Adjust(line);
648 out << line << '\n';
651 return !in.bad() && !out.bad();
655 bool FeatureEnabled(const string & name)
657 vector<Feature>::iterator feature;
658 for (feature = features.begin(); feature != features.end(); feature++) {
659 if (feature->featureName == name && feature->state == Feature::Enabled)
660 return true;
662 return false;
666 bool AllFeaturesAre(bool state, const list<string> & features, string & breaker)
668 for (list<string>::const_iterator iter = features.begin(); iter != features.end(); ++iter) {
669 size_t pos = iter->find('|');
670 if (pos == string::npos) {
671 if (FeatureEnabled(*iter) != state) {
672 breaker = *iter;
673 return false;
676 else
678 bool anyOfState = false;
679 string str = *iter;
680 while (str.length() != 0) {
681 string key = str.substr(0, pos);
682 if (FeatureEnabled(key) == state) {
683 anyOfState = true;
684 break;
686 if (pos == string::npos)
687 break;
688 str = str.substr(pos+1);
689 pos = str.find('|');
691 if (!anyOfState) {
692 breaker = *iter;
693 return false;
697 return true;
701 int main(int argc, char* argv[])
703 // open and scan configure.ac
704 cout << "PWLib Configure " VERSION " - ";
705 ifstream conf("configure.ac", ios::in);
706 if (conf.is_open()) {
707 cout << "opened configure.ac" << endl;
708 } else {
709 conf.clear();
710 conf.open("configure.in", ios::in);
711 if (conf.is_open()) {
712 cout << "opened " << "configure.in" << endl;
713 } else {
714 cerr << "could not open configure.ac/configure.in" << endl;
715 return 1;
719 // scan for features
720 list<string> headers;
721 vector<Feature>::iterator feature;
723 while (conf.good()) {
724 string line;
725 getline(conf, line);
726 string::size_type pos;
727 if ((pos = line.find("AC_CONFIG_HEADERS")) != string::npos) {
728 if ((pos = line.find('(', pos)) != string::npos) {
729 string::size_type end = line.find(')', pos);
730 if (end != string::npos)
731 headers.push_back(line.substr(pos+1, end-pos-1));
734 else if ((pos = line.find("dnl MSWIN_")) != string::npos) {
735 string::size_type space = line.find(' ', pos+10);
736 if (space != string::npos) {
737 string optionName(line, pos+10, space-pos-10);
738 while (line[space] == ' ')
739 space++;
740 string::size_type comma = line.find(',', space);
741 if (comma != string::npos) {
742 string optionValue(line, comma+1, INT_MAX);
743 if (!optionValue.empty()) {
744 string featureName(line, space, comma-space);
745 bool found = false;
746 for (feature = features.begin(); feature != features.end(); feature++) {
747 if (feature->featureName == featureName) {
748 found = true;
749 break;
752 if (found)
753 feature->Parse(optionName, optionValue);
754 else
755 features.push_back(Feature(featureName, optionName, optionValue));
762 // scan version.h if there is a feature called version and if version.h exists
763 for (feature = features.begin(); feature != features.end(); ++feature)
764 if (feature->featureName == "version")
765 break;
766 if (feature != features.end()) {
767 ifstream version("version.h", ios::in);
768 if (version.is_open()) {
769 while (version.good()) {
770 string line;
771 getline(version, line);
772 string::size_type pos;
773 int i;
774 for (i = 0; i < (sizeof(VersionTags)/sizeof(VersionTags[0])); ++i) {
775 size_t tagLen = strlen(VersionTags[i]);
776 if ((pos = line.find(VersionTags[i])) != string::npos) {
777 string::size_type space = line.find(' ', pos+tagLen);
778 if (space != string::npos) {
779 while (line[space] == ' ')
780 space++;
781 string version = line.substr(space);
782 while (::iswspace(version[0]))
783 version.erase(0);
784 while (version.length() > 0 && ::iswspace(version[version.length()-1]))
785 version.erase(version.length()-1);
786 feature->defineValues.insert(pair<string,string>(VersionTags[i], version));
791 string version("\"");
792 map<string,string>::iterator ver;
793 if ((ver = feature->defineValues.find(VersionTags[0])) != feature->defineValues.end())
794 version += ver->second;
795 else
796 version += "0";
797 version += ".";
798 if ((ver = feature->defineValues.find(VersionTags[1])) != feature->defineValues.end())
799 version += ver->second;
800 else
801 version += "0";
802 version += ".";
803 if ((ver = feature->defineValues.find(VersionTags[2])) != feature->defineValues.end())
804 version += ver->second;
805 else
806 version += "0";
807 version += "\"";
808 feature->defineValues.insert(pair<string,string>("VERSION", version));
812 const char EXTERN_DIR[] = "--extern-dir=";
813 const char EXCLUDE_DIR[] = "--exclude-dir=";
814 const char EXCLUDE_ENV[] = "--exclude-env=";
816 bool searchDisk = true;
817 char *externDir = NULL;
818 char *externEnv = NULL;
819 int i;
820 for (i = 1; i < argc; i++) {
821 if (stricmp(argv[i], "--no-search") == 0 || stricmp(argv[i], "--disable-search") == 0)
822 searchDisk = false;
823 else if (strnicmp(argv[i], EXCLUDE_ENV, sizeof(EXCLUDE_ENV) - 1) == 0){
824 externEnv = argv[i] + sizeof(EXCLUDE_ENV) - 1;
826 else if (strnicmp(argv[i], EXTERN_DIR, sizeof(EXTERN_DIR) - 1) == 0){
827 externDir = argv[i] + sizeof(EXTERN_DIR) - 1;
829 else if (strnicmp(argv[i], EXCLUDE_DIR, sizeof(EXCLUDE_DIR) - 1) == 0) {
830 string dir(argv[i] + sizeof(EXCLUDE_DIR) - 1);
831 cout << "Excluding \"" << ExcludeDir(dir) << "\" from feature search" << endl;
833 else if (stricmp(argv[i], "-v") == 0 || stricmp(argv[i], "--version") == 0) {
834 cout << "configure version " VERSION "\n";
835 return 1;
837 else if (stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "--help") == 0) {
838 cout << "configure version " VERSION "\n"
839 "usage: configure args\n"
840 " --no-search Do not search disk for libraries.\n"
841 " --extern-dir=dir Specify where to search disk for libraries.\n"
842 " --exclude-dir=dir Exclude dir from search path.\n";
843 " --exclude-env=var Exclude dirs decribed by specified env var from search path.\n";
844 for (feature = features.begin(); feature != features.end(); feature++) {
845 if (feature->featureName[0] != '\0') {
846 cout << " --disable-" << feature->featureName
847 << setw(20-feature->featureName.length()) << "Disable " << feature->displayName << '\n';
848 if (!feature->checkFiles.empty())
849 cout << " --" << feature->featureName << "-dir=dir"
850 << setw(30-feature->featureName.length()) << "Set directory for " << feature->displayName << '\n';
853 return 1;
855 else {
856 // parse environment variable if it exists
857 std::vector<std::string> envConfigureList;
858 char * envStr = getenv("PWLIB_CONFIGURE_FEATURES");
859 if (envStr != NULL) {
860 string str(envStr);
861 string::size_type offs = 0;
862 while (offs < str.length()) {
863 string::size_type n = str.find(',', offs);
864 string xable;
865 if (n != string::npos) {
866 xable = str.substr(offs, n-offs);
867 offs = n+1;
868 } else {
869 xable = str.substr(offs);
870 offs += str.length();
872 envConfigureList.push_back(ToLower(xable));
876 // go through features and disable ones that need disabling either from command line or environment
877 for (feature = features.begin(); feature != features.end(); feature++) {
878 if (stricmp(argv[i], ("--no-" + feature->featureName).c_str()) == 0 ||
879 stricmp(argv[i], ("--disable-"+ feature->featureName).c_str()) == 0) {
880 feature->state = Feature::Disabled;
881 break;
883 else if (stricmp(argv[i], ("--enable-"+ feature->featureName).c_str()) == 0) {
884 feature->state = Feature::Enabled;
885 break;
887 else if (find(envConfigureList.begin(), envConfigureList.end(), "enable-"+ feature->featureName) != envConfigureList.end()) {
888 feature->state = Feature::Enabled;
889 break;
891 else if (find(envConfigureList.begin(), envConfigureList.end(), "disable-"+ feature->featureName) != envConfigureList.end() ||
892 find(envConfigureList.begin(), envConfigureList.end(), "no-"+ feature->featureName) != envConfigureList.end()) {
893 feature->state = Feature::Disabled;
894 break;
896 else if (strstr(argv[i], ("--" + feature->featureName + "-dir=").c_str()) == argv[i] &&
897 !feature->Locate(argv[i] + strlen(("--" + feature->featureName + "-dir=").c_str())))
898 cerr << feature->displayName << " not found in "
899 << argv[i] + strlen(("--" + feature->featureName+"-dir=").c_str()) << endl;
905 for (i = 0; i < 2; i++) {
906 char * env = NULL;
907 switch (i) {
908 case 0:
909 env = getenv("PWLIB_CONFIGURE_EXCLUDE_DIRS");
910 break;
911 case 1:
912 if (externEnv != NULL)
913 env = getenv(externEnv);
914 break;
916 if (env != NULL) {
917 string str(env);
918 string::size_type offs = 0;
919 while (offs < str.length()) {
920 string::size_type n = str.find(';', offs);
921 string dir;
922 if (n != string::npos) {
923 dir = str.substr(offs, n-offs);
924 offs = n+1;
925 } else {
926 dir = str.substr(offs);
927 offs += str.length();
929 cout << "Excluding \"" << ExcludeDir(dir) << "\" from feature search" << endl;
934 bool foundAll = true;
935 for (feature = features.begin(); feature != features.end(); feature++) {
936 #if 0 // Does not work yet
937 if (feature->state == Feature::Enabled && !AllFeaturesAre(true, feature->ifFeature, feature->breaker))
938 feature->state = Feature::Dependency;
939 if (feature->state == Feature::Enabled && !AllFeaturesAre(false, feature->ifNotFeature, feature->breaker))
940 feature->state = Feature::Blocked;
941 #endif
942 if (feature->state == Feature::Enabled && !feature->checkFiles.empty()) {
943 bool foundOne = false;
944 list<string>::iterator dir;
945 for (dir = feature->checkDirectories.begin(); dir != feature->checkDirectories.end(); dir++) {
946 if (!DirExcluded(*dir) && feature->Locate(dir->c_str())) {
947 foundOne = true;
948 break;
951 if (!foundOne)
952 foundAll = false;
956 if (searchDisk && !foundAll) {
957 // Do search of entire system
958 char drives[1024];
959 if (!externDir){
960 if (!GetLogicalDriveStrings(sizeof(drives), drives))
961 strcpy(drives, "C:\\");
963 else {
964 strcpy(drives, externDir);
965 drives[strlen(externDir)+1] = '\0';
968 const char * drive = drives;
969 while (*drive != '\0') {
970 if (externDir || GetDriveType(drive) == DRIVE_FIXED) {
971 cout << "Searching " << drive << endl;
972 if (TreeWalk(drive))
973 break;
975 drive += strlen(drive)+1;
979 for (feature = features.begin(); feature != features.end(); feature++) {
980 if (feature->state == Feature::Enabled && !AllFeaturesAre(true, feature->ifFeature, feature->breaker))
981 feature->state = Feature::Dependency;
982 if (feature->state == Feature::Enabled && !AllFeaturesAre(false, feature->ifNotFeature, feature->breaker))
983 feature->state = Feature::Blocked;
984 if (feature->state == Feature::Enabled && !feature->checkFiles.empty() && !feature->checkFiles.begin()->found)
985 feature->state = Feature::NotFound;
988 int longestNameWidth = 0;
989 for (feature = features.begin(); feature != features.end(); feature++) {
990 int length = feature->displayName.length();
991 if (length > longestNameWidth)
992 longestNameWidth = length;
995 cout << "\n\nFeatures:\n";
996 for (feature = features.begin(); feature != features.end(); feature++) {
997 cout << setw(longestNameWidth+3) << feature->displayName << ' ';
998 switch (feature->state)
1000 case Feature::Enabled:
1001 cout << "enabled";
1002 break;
1004 case Feature::Disabled :
1005 cout << "DISABLED by user";
1006 break;
1008 case Feature::Dependency :
1009 cout << "DISABLED due to absence of feature " << feature->breaker;
1010 break;
1012 case Feature::Blocked :
1013 cout << "DISABLED due to presence of feature " << feature->breaker;
1014 break;
1016 default :
1017 cout << "DISABLED";
1019 cout << '\n';
1021 cout << endl;
1023 for (list<string>::iterator hdr = headers.begin(); hdr != headers.end(); hdr++)
1024 ProcessHeader(*hdr);
1026 cout << "Configuration completed.\n";
1028 return 0;