Added ifdef for Zeta build
[pwlib.git] / tools / configure / configure.cpp
blob161b1d5e3a616bac6656777e0e04d5028a465ffd
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.20 2004/08/13 01:08:09 csoutheren
28 * Changed to look for configure.ac, then configure.in
30 * Revision 1.19 2004/07/12 02:32:58 csoutheren
31 * Fixed problem when more than two elements in env var
33 * Revision 1.18 2004/04/29 02:02:25 csoutheren
34 * Removed debugging (oops)
36 * Revision 1.17 2004/04/29 02:00:49 csoutheren
37 * Fixed problem with checking for NULL error return from FindFirstFile rather than INVALID_HANDLE_VALUE
39 * Revision 1.16 2004/04/04 01:30:37 csoutheren
40 * Added ability to specify exclude environment variable on configure command line which allows easy switching between MSVC and VS.net 2003
42 * Revision 1.15 2004/03/23 06:32:01 csoutheren
43 * Fixed problems with multiple directories in exclude spec
45 * Revision 1.14 2004/03/16 01:45:17 rjongbloed
46 * Fixed locating lbrary in pre-defined search directories.
47 * Added version number to configure program.
48 * Tidied the --help display.
50 * Revision 1.13 2004/03/13 02:50:56 rjongbloed
51 * Fixed anomalous message where even though a feature was disabled, a "Located "
52 * directiory message is still displayed causing confusion.
53 * Added --disable-<feature> as synonym to existing --no-<feature> to be compatible
54 * with autoconf.
55 * Added default value to defines of 1 rather than blank.
57 * Revision 1.12 2004/01/30 02:33:58 csoutheren
58 * More fixups
60 * Revision 1.11 2004/01/30 01:43:41 csoutheren
61 * Added excludedir options and environment variable
63 * Revision 1.10 2003/11/25 08:21:37 rjongbloed
64 * Fixed display of configured items
66 * Revision 1.9 2003/11/06 09:13:20 rjongbloed
67 * Improved the Windows configure system to allow multiple defines based on file existence. Needed for SDL support of two different distros.
69 * Revision 1.8 2003/10/30 01:17:15 dereksmithies
70 * Add fix from Jose Luis Urien. Many thanks.
72 * Revision 1.7 2003/10/23 21:49:51 dereksmithies
73 * Add very sensible fix to limit extent of search. Thanks Ben Lear.
75 * Revision 1.6 2003/08/04 05:13:17 dereksmithies
76 * Reinforce the disablement if the command lines specifies --no-XXXX to a feature.
78 * Revision 1.5 2003/08/04 05:07:08 dereksmithies
79 * Command line option now disables feature when feature found on disk.
81 * Revision 1.4 2003/05/16 02:03:07 rjongbloed
82 * Fixed being able to manually disable a "feature" when does a full disk search.
84 * Revision 1.3 2003/05/05 08:39:52 robertj
85 * Added ability to explicitly disable a feature, or tell configure exactly
86 * where features library is so it does not need to search for it.
88 * Revision 1.2 2003/04/17 03:32:06 robertj
89 * Improved windows configure program to use lines out of configure.in
91 * Revision 1.1 2003/04/16 08:00:19 robertj
92 * Windoes psuedo autoconf support
96 #pragma warning(disable:4786)
98 #include <iostream>
99 #include <fstream>
100 #include <iomanip>
101 #include <string>
102 #include <list>
103 #include <algorithm>
104 #include <stdlib.h>
105 #include <windows.h>
108 #define VERSION "1.3.3"
111 using namespace std;
114 class Feature
116 public:
117 Feature() : enabled(true) { }
118 Feature(const string & featureName, const string & optionName, const string & optionValue);
120 void Parse(const string & optionName, const string & optionValue);
121 void Adjust(string & line);
122 bool Locate(const char * testDir);
124 string featureName;
125 string displayName;
126 string directorySymbol;
127 string simpleDefineName;
128 string simpleDefineValue;
130 struct CheckFileInfo {
131 CheckFileInfo() : found(false), defineName("1") { }
133 bool Locate(const string & testDir);
135 bool found;
136 string fileName;
137 string fileText;
138 string defineName;
139 string defineValue;
141 list<CheckFileInfo> checkFiles;
142 list<string> checkDirectories;
144 string directory;
145 bool enabled;
149 list<Feature> features;
150 list<string> excludeDirList;
152 ///////////////////////////////////////////////////////////////////////
154 Feature::Feature(const string & featureNameParam,
155 const string & optionName,
156 const string & optionValue)
157 : featureName(featureNameParam),
158 enabled(true)
160 Parse(optionName, optionValue);
164 void Feature::Parse(const string & optionName, const string & optionValue)
166 if (optionName == "DISPLAY")
167 displayName = optionValue;
168 else if (optionName == "DEFINE") {
169 int equal = optionValue.find('=');
170 if (equal == string::npos)
171 simpleDefineName = optionValue;
172 else {
173 simpleDefineName.assign(optionValue, 0, equal);
174 simpleDefineValue.assign(optionValue, equal+1, INT_MAX);
177 else if (optionName == "CHECK_FILE") {
178 int comma = optionValue.find(',');
179 if (comma == string::npos)
180 return;
182 CheckFileInfo check;
183 int pipe = optionValue.find('|');
184 if (pipe < 0 || pipe > comma)
185 check.fileName.assign(optionValue, 0, comma);
186 else {
187 check.fileName.assign(optionValue, 0, pipe);
188 check.fileText.assign(optionValue, pipe+1, comma-pipe-1);
191 int equal = optionValue.find('=', comma);
192 if (equal == string::npos)
193 check.defineName.assign(optionValue, comma+1, INT_MAX);
194 else {
195 check.defineName.assign(optionValue, comma+1, equal-comma-1);
196 check.defineValue.assign(optionValue, equal+1, INT_MAX);
199 checkFiles.push_back(check);
201 else if (optionName == "DIR_SYMBOL")
202 directorySymbol = '@' + optionValue + '@';
203 else if (optionName == "CHECK_DIR")
204 checkDirectories.push_back(optionValue);
208 static bool CompareName(const string & line, const string & name)
210 int pos = line.find(name);
211 if (pos == string::npos)
212 return false;
214 pos += name.length();
215 return !isalnum(line[pos]) && line[pos] != '_';
218 void Feature::Adjust(string & line)
220 if (enabled && line.find("#undef") != string::npos) {
221 if (!simpleDefineName.empty() && CompareName(line, simpleDefineName)) {
222 line = "#define " + simpleDefineName + ' ';
223 if (simpleDefineValue.empty())
224 line += '1';
225 else
226 line += simpleDefineValue;
229 for (list<CheckFileInfo>::iterator file = checkFiles.begin(); file != checkFiles.end(); file++) {
230 if (file->found && CompareName(line, file->defineName)) {
231 line = "#define " + file->defineName + ' ' + file->defineValue;
232 break;
237 if (directorySymbol[0] != '\0') {
238 int pos = line.find(directorySymbol);
239 if (pos != string::npos)
240 line.replace(pos, directorySymbol.length(), directory);
245 bool Feature::Locate(const char * testDir)
247 if (!enabled)
248 return true;
250 if (!directory.empty())
251 return true;
253 if (checkFiles.empty())
254 return true;
256 string testDirectory = testDir;
257 if (testDirectory[testDirectory.length()-1] != '\\')
258 testDirectory += '\\';
260 list<CheckFileInfo>::iterator file = checkFiles.begin();
261 if (!file->Locate(testDirectory))
262 return false;
264 while (++file != checkFiles.end())
265 file->Locate(testDirectory);
267 char buf[_MAX_PATH];
268 _fullpath(buf, testDirectory.c_str(), _MAX_PATH);
269 directory = buf;
271 cout << "Located " << displayName << " at " << directory << endl;
273 int pos;
274 while ((pos = directory.find('\\')) != string::npos)
275 directory[pos] = '/';
276 pos = directory.length()-1;
277 if (directory[pos] == '/')
278 directory.erase(pos);
280 return true;
284 bool Feature::CheckFileInfo::Locate(const string & testDirectory)
286 string filename = testDirectory + fileName;
287 ifstream file(filename.c_str(), ios::in);
288 if (!file.is_open())
289 return false;
291 if (fileText.empty())
292 found = true;
293 else {
294 while (file.good()) {
295 string line;
296 getline(file, line);
297 if (line.find(fileText) != string::npos) {
298 found = true;
299 break;
304 return found;
308 bool TreeWalk(const string & directory)
310 bool foundAll = false;
312 string wildcard = directory;
313 wildcard += "*.*";
315 WIN32_FIND_DATA fileinfo;
316 HANDLE hFindFile = FindFirstFile(wildcard.c_str(), &fileinfo);
317 if (hFindFile != INVALID_HANDLE_VALUE) {
318 do {
319 string subdir = directory;
320 subdir += fileinfo.cFileName;
321 list<string>::const_iterator r = find(excludeDirList.begin(), excludeDirList.end(), subdir);
322 if (r == excludeDirList.end()) {
323 if ((fileinfo.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0 &&
324 fileinfo.cFileName[0] != '.' &&
325 stricmp(fileinfo.cFileName, "RECYCLER") != 0) {
326 subdir += '\\';
328 foundAll = true;
329 list<Feature>::iterator feature;
330 for (feature = features.begin(); feature != features.end(); feature++) {
331 if (!feature->Locate(subdir.c_str()))
332 foundAll = false;
335 if (foundAll)
336 break;
337 TreeWalk(subdir);
340 } while (FindNextFile(hFindFile, &fileinfo));
342 FindClose(hFindFile);
345 return foundAll;
349 bool ProcessHeader(const string & headerFilename)
351 string inFilename = headerFilename;
352 inFilename += ".in";
354 ifstream in(inFilename.c_str(), ios::in);
355 if (!in.is_open()) {
356 cerr << "Could not open " << inFilename << endl;
357 return false;
360 ofstream out(headerFilename.c_str(), ios::out);
361 if (!out.is_open()) {
362 cerr << "Could not open " << headerFilename << endl;
363 return false;
366 while (in.good()) {
367 string line;
368 getline(in, line);
370 list<Feature>::iterator feature;
371 for (feature = features.begin(); feature != features.end(); feature++)
372 feature->Adjust(line);
374 out << line << '\n';
377 return !in.bad() && !out.bad();
381 int main(int argc, char* argv[])
383 ifstream conf("configure.ac", ios::in);
384 if (conf.is_open()) {
385 cout << "Opened " << "configure.ac" << endl;
386 } else {
387 conf.clear();
388 conf.open("configure.in", ios::in);
389 if (conf.is_open()) {
390 cout << "Opened " << "configure.in" << endl;
391 } else {
392 cerr << "Could not open configure.ac/configure.in" << endl;
393 return 1;
397 list<string> headers;
398 list<Feature>::iterator feature;
400 while (conf.good()) {
401 string line;
402 getline(conf, line);
403 int pos;
404 if ((pos = line.find("AC_CONFIG_HEADERS")) != string::npos) {
405 pos = line.find('(', pos);
406 if (pos != string::npos) {
407 int end = line.find(')', pos);
408 if (pos != string::npos)
409 headers.push_back(line.substr(pos+1, end-pos-1));
412 else if (line.find("dnl MSWIN_") == 0) {
413 int space = line.find(' ', 10);
414 if (space != string::npos) {
415 string optionName(line, 10, space-10);
416 while (line[space] == ' ')
417 space++;
418 int comma = line.find(',', space);
419 if (comma != string::npos) {
420 string optionValue(line, comma+1, INT_MAX);
421 if (!optionValue.empty()) {
422 string featureName(line, space, comma-space);
423 bool found = false;
424 for (feature = features.begin(); feature != features.end(); feature++) {
425 if (feature->featureName == featureName) {
426 found = true;
427 break;
430 if (found)
431 feature->Parse(optionName, optionValue);
432 else
433 features.push_back(Feature(featureName, optionName, optionValue));
440 const char EXTERN_DIR[] = "--extern-dir=";
441 const char EXCLUDE_DIR[] = "--exclude-dir=";
442 const char EXCLUDE_ENV[] = "--exclude-env=";
444 bool searchDisk = true;
445 char *externDir = NULL;
446 char *externEnv = NULL;
447 for (int i = 1; i < argc; i++) {
448 if (stricmp(argv[i], "--no-search") == 0 || stricmp(argv[i], "--disable-search") == 0)
449 searchDisk = false;
450 else if (strnicmp(argv[i], EXCLUDE_ENV, sizeof(EXCLUDE_ENV) - 1) == 0){
451 externEnv = argv[i] + sizeof(EXCLUDE_ENV) - 1;
453 else if (strnicmp(argv[i], EXTERN_DIR, sizeof(EXTERN_DIR) - 1) == 0){
454 externDir = argv[i] + sizeof(EXTERN_DIR) - 1;
456 else if (strnicmp(argv[i], EXCLUDE_DIR, sizeof(EXCLUDE_DIR) - 1) == 0) {
457 string dir(argv[i] + sizeof(EXCLUDE_DIR) - 1);
458 excludeDirList.push_back(dir);
459 cout << "Excluding " << dir << " from feature search" << endl;
461 else if (stricmp(argv[i], "-v") == 0 || stricmp(argv[i], "--version") == 0) {
462 cout << "configure version " VERSION "\n";
463 return 1;
465 else if (stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "--help") == 0) {
466 cout << "configure version " VERSION "\n"
467 "usage: configure args\n"
468 " --no-search Do not search disk for libraries.\n"
469 " --extern-dir=dir Specify where to search disk for libraries.\n"
470 " --exclude-dir=dir Exclude dir from search path.\n";
471 " --exclude-env=var Exclude dirs decribed by specified env var from search path.\n";
472 for (feature = features.begin(); feature != features.end(); feature++) {
473 if (feature->featureName[0] != '\0') {
474 cout << " --disable-" << feature->featureName
475 << setw(20-feature->featureName.length()) << "Disable " << feature->displayName << '\n';
476 if (!feature->checkFiles.empty())
477 cout << " --" << feature->featureName << "-dir=dir"
478 << setw(30-feature->featureName.length()) << "Set directory for " << feature->displayName << '\n';
481 return 1;
483 else {
484 for (feature = features.begin(); feature != features.end(); feature++) {
485 if (stricmp(argv[i], ("--no-" +feature->featureName).c_str()) == 0 ||
486 stricmp(argv[i], ("--disable-"+feature->featureName).c_str()) == 0)
487 feature->enabled = false;
488 else if (strstr(argv[i], ("--" + feature->featureName+"-dir=").c_str()) == argv[i])
489 if (!feature->Locate(argv[i] + strlen(("--" + feature->featureName + "-dir=").c_str())))
490 cerr << feature->displayName << " not found in "
491 << argv[i] + strlen(("--" + feature->featureName+"-dir=").c_str()) << endl;
496 for (i = 0; i < 2; i++) {
497 char * env = NULL;
498 switch (i) {
499 case 0:
500 env = getenv("PWLIB_CONFIGURE_EXCLUDE_DIRS");
501 break;
502 case 1:
503 if (externEnv != NULL)
504 env = getenv(externEnv);
505 break;
507 if (env != NULL) {
508 string str(env);
509 string::size_type offs = 0;
510 while (offs < str.length()) {
511 string::size_type n = str.find(';', offs);
512 string dir;
513 if (n != string::npos) {
514 dir = str.substr(offs, n-offs);
515 offs = n+1;
516 } else {
517 dir = str.substr(offs);
518 offs += str.length();
520 excludeDirList.push_back(dir);
521 cout << "Excluding " << dir << " from feature search" << endl;
526 bool foundAll = true;
527 for (feature = features.begin(); feature != features.end(); feature++) {
528 if (feature->enabled && !feature->checkFiles.empty()) {
529 bool foundOne = false;
530 list<string>::iterator dir;
531 for (dir = feature->checkDirectories.begin(); dir != feature->checkDirectories.end(); dir++) {
532 if (feature->Locate(dir->c_str())) {
533 foundOne = true;
534 break;
537 if (!foundOne)
538 foundAll = false;
542 if (searchDisk && !foundAll) {
543 // Do search of entire system
544 char drives[100];
545 if (!externDir){
546 if (!GetLogicalDriveStrings(sizeof(drives), drives))
547 strcpy(drives, "C:\\");
549 else {
550 strcpy(drives, externDir);
553 const char * drive = drives;
554 while (*drive != '\0') {
555 if (GetDriveType(drive) == DRIVE_FIXED) {
556 cout << "Searching " << drive << endl;
557 if (TreeWalk(drive))
558 break;
560 drive += strlen(drive)+1;
564 for (feature = features.begin(); feature != features.end(); feature++) {
565 cout << " " << feature->displayName << ' ';
566 if (feature->checkFiles.empty() && !feature->simpleDefineValue.empty())
567 cout << "set to " << feature->simpleDefineValue;
568 else if (feature->enabled && (feature->checkFiles.empty() || feature->checkFiles.begin()->found))
569 cout << "enabled";
570 else
571 cout << "disabled";
572 cout << '\n';
574 cout << endl;
576 for (list<string>::iterator hdr = headers.begin(); hdr != headers.end(); hdr++)
577 ProcessHeader(*hdr);
579 cout << "Configuration completed.\n";
581 return 0;