| 
      
      
      From: <ale...@us...> - 2013-03-27 11:45:05
      
     | 
| Revision: 57841
          http://sourceforge.net/p/firebird/code/57841
Author:   alexpeshkoff
Date:     2013-03-27 11:45:02 +0000 (Wed, 27 Mar 2013)
Log Message:
-----------
Added operator include to config files
Modified Paths:
--------------
    firebird/trunk/lang_helpers/gds_codes.ftn
    firebird/trunk/lang_helpers/gds_codes.pas
    firebird/trunk/src/common/config/ConfigCache.cpp
    firebird/trunk/src/common/config/ConfigCache.h
    firebird/trunk/src/common/config/config.cpp
    firebird/trunk/src/common/config/config.h
    firebird/trunk/src/common/config/config_file.cpp
    firebird/trunk/src/common/config/config_file.h
    firebird/trunk/src/common/db_alias.cpp
    firebird/trunk/src/common/os/path_utils.h
    firebird/trunk/src/common/os/posix/path_utils.cpp
    firebird/trunk/src/include/gen/codetext.h
    firebird/trunk/src/include/gen/iberror.h
    firebird/trunk/src/include/gen/msgs.h
    firebird/trunk/src/include/gen/sql_code.h
    firebird/trunk/src/include/gen/sql_state.h
    firebird/trunk/src/msgs/facilities2.sql
    firebird/trunk/src/msgs/messages2.sql
    firebird/trunk/src/msgs/system_errors2.sql
    firebird/trunk/src/remote/server/os/posix/inet_server.cpp
    firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp
    firebird/trunk/src/utilities/ntrace/TraceConfiguration.cpp
Modified: firebird/trunk/lang_helpers/gds_codes.ftn
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.ftn	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/lang_helpers/gds_codes.ftn	2013-03-27 11:45:02 UTC (rev 57841)
@@ -1516,6 +1516,16 @@
       PARAMETER (GDS__no_output_format                 = 335545051)
       INTEGER*4 GDS__item_finish                     
       PARAMETER (GDS__item_finish                      = 335545052)
+      INTEGER*4 GDS__miss_config                     
+      PARAMETER (GDS__miss_config                      = 335545053)
+      INTEGER*4 GDS__conf_line                       
+      PARAMETER (GDS__conf_line                        = 335545054)
+      INTEGER*4 GDS__conf_include                    
+      PARAMETER (GDS__conf_include                     = 335545055)
+      INTEGER*4 GDS__include_depth                   
+      PARAMETER (GDS__include_depth                    = 335545056)
+      INTEGER*4 GDS__include_miss                    
+      PARAMETER (GDS__include_miss                     = 335545057)
       INTEGER*4 GDS__gfix_db_name                    
       PARAMETER (GDS__gfix_db_name                     = 335740929)
       INTEGER*4 GDS__gfix_invalid_sw                 
Modified: firebird/trunk/lang_helpers/gds_codes.pas
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.pas	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/lang_helpers/gds_codes.pas	2013-03-27 11:45:02 UTC (rev 57841)
@@ -765,6 +765,11 @@
 	gds_wrong_message_length             = 335545050;
 	gds_no_output_format                 = 335545051;
 	gds_item_finish                      = 335545052;
+	gds_miss_config                      = 335545053;
+	gds_conf_line                        = 335545054;
+	gds_conf_include                     = 335545055;
+	gds_include_depth                    = 335545056;
+	gds_include_miss                     = 335545057;
 	gds_gfix_db_name                     = 335740929;
 	gds_gfix_invalid_sw                  = 335740930;
 	gds_gfix_incmp_sw                    = 335740932;
Modified: firebird/trunk/src/common/config/ConfigCache.cpp
===================================================================
--- firebird/trunk/src/common/config/ConfigCache.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/config/ConfigCache.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -28,6 +28,8 @@
 #include "../common/config/ConfigCache.h"
 #include "../common/config/config_file.h"
 
+#include "gen/iberror.h"
+
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -37,39 +39,50 @@
 #include <errno.h>
 #endif
 
-ConfigCache::ConfigCache(Firebird::MemoryPool& p, const Firebird::PathName& fName)
-	: PermanentStorage(p), fileName(getPool(), fName), fileTime(0)
-{
-}
+using namespace Firebird;
 
+ConfigCache::ConfigCache(MemoryPool& p, const PathName& fName)
+	: PermanentStorage(p), files(FB_NEW(getPool()) ConfigCache::File(getPool(), fName))
+{ }
+
 ConfigCache::~ConfigCache()
 {
+	delete files;
 }
 
 void ConfigCache::checkLoadConfig()
 {
-	time_t newTime = getTime();
-	if (fileTime == newTime)
-	{
-		return;
+	{	// scope
+		ReadLockGuard guard(rwLock, "ConfigCache::checkLoadConfig");
+		if (files->checkLoadConfig(false))
+		{
+			return;
+		}
 	}
 
-	Firebird::WriteLockGuard guard(rwLock, "ConfigCache::checkLoadConfig");
-
+	WriteLockGuard guard(rwLock, "ConfigCache::checkLoadConfig");
 	// may be someone already reloaded?
-	newTime = getTime();
-	if (fileTime == newTime)
+	if (files->checkLoadConfig(true))
 	{
 		return;
 	}
 
-	fileTime = newTime;
-
+	files->trim();
 	loadConfig();
 }
 
-time_t ConfigCache::getTime()
+void ConfigCache::addFile(const Firebird::PathName& fName)
 {
+	files->add(fName);
+}
+
+Firebird::PathName ConfigCache::getFileName()
+{
+	return files->fileName;
+}
+
+time_t ConfigCache::File::getTime()
+{
 	struct stat st;
 	if (stat(fileName.c_str(), &st) != 0)
 	{
@@ -78,7 +91,58 @@
 			// config file is missing, but this is not our problem
 			return 0;
 		}
-		Firebird::system_call_failed::raise("stat");
+		system_call_failed::raise("stat");
 	}
 	return st.st_mtime;
 }
+
+ConfigCache::File::File(MemoryPool& p, const PathName& fName)
+	: PermanentStorage(p), fileName(getPool(), fName), fileTime(0), next(NULL)
+{ }
+
+ConfigCache::File::~File()
+{
+	delete next;
+}
+
+bool ConfigCache::File::checkLoadConfig(bool set)
+{
+	time_t newTime = getTime();
+	if (fileTime == newTime)
+	{
+		return next ? next->checkLoadConfig(set) : true;
+	}
+
+	if (set)
+	{
+		fileTime = newTime;
+		if (next)
+		{
+			next->checkLoadConfig(set);
+		}
+	}
+	return false;
+}
+
+void ConfigCache::File::add(const PathName& fName)
+{
+	if (fName == fileName)
+	{
+		return;
+	}
+
+	if (next)
+	{
+		next->add(fName);
+	}
+	else
+	{
+		next = FB_NEW(getPool()) ConfigCache::File(getPool(), fName);
+	}
+}
+
+void ConfigCache::File::trim()
+{
+	delete next;
+	next = NULL;
+}
Modified: firebird/trunk/src/common/config/ConfigCache.h
===================================================================
--- firebird/trunk/src/common/config/ConfigCache.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/config/ConfigCache.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -39,19 +39,35 @@
 	virtual ~ConfigCache();
 
 	void checkLoadConfig();
+	void addFile(const Firebird::PathName& fName);
+	Firebird::PathName getFileName();
 
 protected:
 	virtual void loadConfig() = 0;
 
 private:
-	time_t getTime();
+	class File : public Firebird::PermanentStorage
+	{
+	public:
+		File(Firebird::MemoryPool& p, const Firebird::PathName& fName);
+		~File();
 
+		bool checkLoadConfig(bool set);
+		void add(const Firebird::PathName& fName);
+		void trim();
+
+	public:
+		Firebird::PathName fileName;
+
+	private:
+		volatile time_t fileTime;
+		File* next;
+		time_t getTime();
+	};
+	File* files;
+
 public:
 	Firebird::RWLock rwLock;
-	Firebird::PathName fileName;
-
-private:
-	volatile time_t fileTime;
 };
 
 #endif // COMMON_CONFIG_CASHE_H
Modified: firebird/trunk/src/common/config/config.cpp
===================================================================
--- firebird/trunk/src/common/config/config.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/config/config.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -45,15 +45,25 @@
 {
 public:
 	explicit ConfigImpl(Firebird::MemoryPool& p)
-		: Firebird::PermanentStorage(p), confMessage(getPool())
+		: Firebird::PermanentStorage(p), missConf(false)
 	{
-		ConfigFile file(fb_utils::getPrefix(fb_utils::FB_DIR_CONF, CONFIG_FILE));
-		defaultConfig = new Config(file);
-
-		if (file.getMessage())
+		try
 		{
-			confMessage = file.getMessage();
+			ConfigFile file(fb_utils::getPrefix(fb_utils::FB_DIR_CONF, CONFIG_FILE));
+			defaultConfig = new Config(file);
 		}
+		catch (const Firebird::status_exception& ex)
+		{
+			if (ex.value()[1] != isc_miss_config)
+			{
+				throw;
+			}
+
+			missConf = true;
+
+			ConfigFile file(ConfigFile::USE_TEXT, "");
+			defaultConfig = new Config(file);
+		}
 	}
 
 /*	void changeDefaultConfig(Config* newConfig)
@@ -66,9 +76,9 @@
 		return defaultConfig;
 	}
 
-	const char* getMessage()
+	bool missFirebirdConf()
 	{
-		return confMessage.nullStr();
+		return missConf;
 	}
 
 private:
@@ -77,7 +87,7 @@
     ConfigImpl(const ConfigImpl&);
     void operator=(const ConfigImpl&);
 
-	Firebird::string confMessage;
+	bool missConf;
 };
 
 /******************************************************************************
@@ -196,7 +206,7 @@
 		if (entries[i].data_type == TYPE_STRING && values[i])
 		{
 			ConfigFile::String expand((const char*)values[i]);
-			if (file.macroParse(expand) && expand != (const char*) values[i])
+			if (file.macroParse(expand, NULL) && expand != (const char*) values[i])
 			{
 				ConfigFile::String& saved(tempStrings.add());
 				saved = expand;
@@ -313,9 +323,9 @@
 	return firebirdConf().getDefaultConfig();
 }
 
-const char* Config::getMessage()
+bool Config::missFirebirdConf()
 {
-	return firebirdConf().getMessage();
+	return firebirdConf().missFirebirdConf();
 }
 
 const char* Config::getInstallDirectory()
Modified: firebird/trunk/src/common/config/config.h
===================================================================
--- firebird/trunk/src/common/config/config.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/config/config.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -185,9 +185,9 @@
 	Config(const ConfigFile& file, const Config& base);		// use to build db-specific config
 	~Config();
 
-	// Check for errors in .conf file
+	// Check for missing firebird.conf
 
-	static const char* getMessage();
+	static bool missFirebirdConf();
 
 	// Interface to support command line root specification.
 	// This ugly solution was required to make it possible to specify root
Modified: firebird/trunk/src/common/config/config_file.cpp
===================================================================
--- firebird/trunk/src/common/config/config_file.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/config/config_file.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -26,7 +26,9 @@
 #include "../common/classes/auto.h"
 #include "../common/config/config_file.h"
 #include "../common/config/config.h"
+#include "../common/config/ConfigCache.h"
 #include "../common/os/path_utils.h"
+#include "../common/ScanDir.h"
 #include <stdio.h>
 
 #ifdef HAVE_STDLIB_H
@@ -37,16 +39,36 @@
 
 namespace {
 
+bool hasWildCards(const PathName& s)
+{
+	return s.find_first_of("?*") != PathName::npos;
+}
+
+void strip2slashes(ConfigFile::String& to)
+{
+	// strip double slashes
+	char sep2[3];
+	sep2[0] = PathUtils::dir_sep;
+	sep2[1] = sep2[0];
+	sep2[2] = 0;
+
+	size_t pos = 0;
+	while((pos = to.find(sep2, pos)) != PathName::npos)
+	{
+		to.erase(pos, 1);
+	}
+}
+
 class MainStream : public ConfigFile::Stream
 {
 public:
-	MainStream(const char* fname, PathName& errString)
-		: file(fopen(fname, "rt")), l(0)
+	MainStream(const char* fname)
+		: file(fopen(fname, "rt")), fileName(fname), l(0)
 	{
 		if (!file)
 		{
 			// config file does not exist
-			errString.printf("Missing configuration file: %s", fname);
+			(Arg::Gds(isc_miss_config) << fname << Arg::OsError()).raise();
 		}
 	}
 
@@ -65,7 +87,10 @@
 			{
 				return false;
 			}
-			input.LoadFromFile(file);
+			if (!input.LoadFromFile(file))
+			{
+				return false;
+			}
 			++l;
 			input.alltrim(" \t\r");
 		} while (input.isEmpty() || input[0] == '#');
@@ -74,8 +99,19 @@
 		return true;
 	}
 
+	bool active()
+	{
+		return file.hasData();
+	}
+
+	const char* getFileName() const
+	{
+		return fileName.c_str();
+	}
+
 private:
 	AutoPtr<FILE, FileClose> file;
+	Firebird::PathName fileName;
 	unsigned int l;
 };
 
@@ -125,6 +161,11 @@
 		return true;
 	}
 
+	const char* getFileName() const
+	{
+		return NULL;
+	}
+
 private:
 	const char* s;
 	unsigned int l;
@@ -133,8 +174,8 @@
 class SubStream : public ConfigFile::Stream
 {
 public:
-	SubStream()
-		: cnt(0)
+	SubStream(const char* fName)
+		: fileName(fName), cnt(0)
 	{ }
 
 	bool getLine(ConfigFile::String& input, unsigned int& line)
@@ -157,65 +198,71 @@
 		data.push(Line(input, line));
 	}
 
+	const char* getFileName() const
+	{
+		return fileName;
+	}
+
 private:
 	typedef Pair<Left<ConfigFile::String, unsigned int> > Line;
 	ObjectsArray<Line> data;
+	const char* fileName;
 	size_t cnt;
 };
 
 } // anonymous namespace
 
 
-ConfigFile::ConfigFile(const Firebird::PathName& file, USHORT fl)
+ConfigFile::ConfigFile(const Firebird::PathName& file, USHORT fl, ConfigCache* cache)
 	: AutoStorage(),
-	  configFile(getPool(), file),
 	  parameters(getPool()),
 	  flags(fl),
-	  lastMessage(getPool())
+	  includeLimit(0),
+	  filesCache(cache)
 {
-	MainStream s(configFile.c_str(), lastMessage);
+	MainStream s(file.c_str());
 	parse(&s);
 }
 
-ConfigFile::ConfigFile(const char* file, USHORT fl)
+ConfigFile::ConfigFile(const char* file, USHORT fl, ConfigCache* cache)
 	: AutoStorage(),
-	  configFile(getPool(), String(file)),
 	  parameters(getPool()),
 	  flags(fl),
-	  lastMessage(getPool())
+	  includeLimit(0),
+	  filesCache(cache)
 {
-	MainStream s(configFile.c_str(), lastMessage);
+	MainStream s(file);
 	parse(&s);
 }
 
 ConfigFile::ConfigFile(UseText, const char* configText, USHORT fl)
 	: AutoStorage(),
-	  configFile(getPool()),
 	  parameters(getPool()),
 	  flags(fl),
-	  lastMessage(getPool())
+	  includeLimit(0),
+	  filesCache(NULL)
 {
 	TextStream s(configText);
 	parse(&s);
 }
 
-ConfigFile::ConfigFile(MemoryPool& p, const Firebird::PathName& file, USHORT fl)
+ConfigFile::ConfigFile(MemoryPool& p, const Firebird::PathName& file, USHORT fl, ConfigCache* cache)
 	: AutoStorage(p),
-	  configFile(getPool(), file),
 	  parameters(getPool()),
 	  flags(fl),
-	  lastMessage(getPool())
+	  includeLimit(0),
+	  filesCache(cache)
 {
-	MainStream s(configFile.c_str(), lastMessage);
+	MainStream s(file.c_str());
 	parse(&s);
 }
 
-ConfigFile::ConfigFile(MemoryPool& p, ConfigFile::Stream* s, USHORT fl, const Firebird::PathName& file)
+ConfigFile::ConfigFile(MemoryPool& p, ConfigFile::Stream* s, USHORT fl)
 	: AutoStorage(p),
-	  configFile(getPool(), file),
 	  parameters(getPool()),
 	  flags(fl),
-	  lastMessage(getPool())
+	  includeLimit(0),
+	  filesCache(NULL)
 {
 	parse(s);
 }
@@ -229,12 +276,14 @@
  *	Parse line, taking quotes into account
  */
 
-ConfigFile::LineType ConfigFile::parseLine(const String& input, KeyType& key, String& value)
+ConfigFile::LineType ConfigFile::parseLine(const char* fileName, const String& input, KeyType& key, String& value)
 {
 	int inString = 0;
 	String::size_type valStart = 0;
 	String::size_type eol = String::npos;
 	bool hasSub = false;
+	const char* include = "include";
+	const unsigned incLen = strlen(include);
 
 	for (String::size_type n = 0; n < input.length(); ++n)
 	{
@@ -271,6 +320,22 @@
 
 		case ' ':
 		case '\t':
+			if (n == incLen && key.isEmpty())
+			{
+				KeyType inc = input.substr(0, n).ToNoCaseString();
+				if (inc == include)
+				{
+					value = input.substr(n);
+					value.alltrim(" \t\r");
+
+					if (!macroParse(value, fileName))
+					{
+						return LINE_BAD;
+					}
+					return LINE_INCLUDE;
+				}
+			}
+			// fall down ...
 		case '\r':
 			break;
 
@@ -317,7 +382,7 @@
 	}
 
 	// Now expand macros in value
-	if (!macroParse(value))
+	if (!macroParse(value, fileName))
 	{
 		return LINE_BAD;
 	}
@@ -330,7 +395,7 @@
  *	Substitute macro values in a string
  */
 
-bool ConfigFile::macroParse(String& value) const
+bool ConfigFile::macroParse(String& value, const char* fileName) const
 {
 	String::size_type subFrom;
 
@@ -341,7 +406,7 @@
 		{
 			String macro;
 			String m = value.substr(subFrom + 2, subTo - (subFrom + 2));
-			if (! translate(m, macro))
+			if (! translate(fileName, m, macro))
 			{
 				return false;
 			}
@@ -353,6 +418,7 @@
 		}
 	}
 
+	strip2slashes(value);
 	return true;
 }
 
@@ -361,7 +427,7 @@
  *	Find macro value
  */
 
-bool ConfigFile::translate(const String& from, String& to) const
+bool ConfigFile::translate(const char* fileName, const String& from, String& to) const
 {
 	if (from == "root")
 	{
@@ -373,28 +439,28 @@
 	}
 	else if (from == "this")
 	{
-		if (configFile.isEmpty())
+		if (!fileName)
 		{
 			return false;
 		}
 
-		PathName tempPath = configFile;
+		PathName tempPath(fileName);
 
 #ifdef UNIX
 		if (PathUtils::isSymLink(tempPath))
 		{
 			// If $(this) is a symlink, expand it.
 			TEXT temp[MAXPATHLEN];
-			const int n = readlink(configFile.c_str(), temp, sizeof(temp));
+			const int n = readlink(fileName, temp, sizeof(temp));
 
-			if (n != -1 && n < sizeof(temp))
+			if (n != -1 && unsigned(n) < sizeof(temp))
 			{
 				tempPath = temp;
 
 				if (PathUtils::isRelative(tempPath))
 				{
 					PathName parent;
-					PathUtils::splitLastComponent(parent, tempPath, configFile);
+					PathUtils::splitLastComponent(parent, tempPath, fileName);
 					PathUtils::concatPath(tempPath, parent, temp);
 				}
 			}
@@ -460,10 +526,9 @@
  *	Take into an account fault line
  */
 
-void ConfigFile::badLine(const String& line)
+void ConfigFile::badLine(const char* fileName, const String& line)
 {
-	lastMessage.printf("%s: illegal line <%s>",
-		(configFile.hasData() ? configFile.c_str() : "Passed text"), line.c_str());
+	(Arg::Gds(isc_conf_line) << (fileName ? fileName : "Passed text") << line).raise();
 }
 
 /******************************************************************************
@@ -476,28 +541,33 @@
 	String inputLine;
 	Parameter* previous = NULL;
 	unsigned int line;
+	const char* streamName = stream->getFileName();
 
 	while (stream->getLine(inputLine, line))
 	{
 		Parameter current;
 		current.line = line;
 
-		switch (parseLine(inputLine, current.name, current.value))
+		switch (parseLine(streamName, inputLine, current.name, current.value))
 		{
 		case LINE_BAD:
-			badLine(inputLine);
+			badLine(streamName, inputLine);
 			return;
 
 		case LINE_REGULAR:
 			if (current.name.isEmpty())
 			{
-				badLine(inputLine);
+				badLine(streamName, inputLine);
 				return;
 			}
 
 			previous = ¶meters[parameters.add(current)];
 			break;
 
+		case LINE_INCLUDE:
+			include(streamName, current.value.ToPathName());
+			break;
+
 		case LINE_START_SUB:
 			if (current.name.hasData())
 			{
@@ -506,7 +576,7 @@
 			}
 
 			{ // subconf scope
-				SubStream subStream;
+				SubStream subStream(stream->getFileName());
 				while (stream->getLine(inputLine, line))
 				{
 					if (inputLine[0] == '}')
@@ -515,7 +585,7 @@
 						s.ltrim(" \t\r");
 						if (s.hasData() && s[0] != '#')
 						{
-							badLine(s);
+							badLine(streamName, s);
 							return;
 						}
 						break;
@@ -523,20 +593,128 @@
 					subStream.putLine(inputLine, line);
 				}
 
-				previous->sub = FB_NEW(getPool()) ConfigFile(getPool(), &subStream,
-															 flags & ~HAS_SUB_CONF, configFile);
+				previous->sub = FB_NEW(getPool())
+					ConfigFile(getPool(), &subStream, flags & ~HAS_SUB_CONF);
 			}
 			break;
 		}
 	}
 }
 
+//#define DEBUG_INCLUDES
+
 /******************************************************************************
  *
- *	Check for parse/load error
+ *	Parse include operator
  */
 
-const char* ConfigFile::getMessage() const
+void ConfigFile::include(const char* currentFileName, const PathName& parPath)
 {
-	return lastMessage.nullStr();
+	// We should better limit include depth
+	AutoSetRestore<unsigned> depth(&includeLimit, includeLimit + 1);
+	if (includeLimit > INCLUDE_LIMIT)
+	{
+		(Arg::Gds(isc_conf_include) << currentFileName << parPath << Arg::Gds(isc_include_depth)).raise();
+	}
+
+	// for relative paths first of all prepend with current path (i.e. path of current conf file)
+	PathName path;
+	if (PathUtils::isRelative(parPath))
+	{
+		PathName curPath;
+		PathUtils::splitLastComponent(curPath, path /*dummy*/, currentFileName);
+		PathUtils::concatPath(path, curPath, parPath);
+	}
+	else
+	{
+		path = parPath;
+	}
+
+	// split path into components
+	PathName pathPrefix;
+	PathUtils::splitPrefix(path, pathPrefix);
+	PathName savedPath(path);		// Expect no *? in prefix
+	FilesArray components;
+	while (path.hasData())
+	{
+		PathName cur, tmp;
+		PathUtils::splitLastComponent(tmp, cur, path);
+
+#ifdef DEBUG_INCLUDES
+		fprintf(stderr, "include: path=%s cur=%s tmp=%s\n", path.c_str(), cur.c_str(), tmp.c_str());
+#endif
+
+		components.push(cur);
+		path = tmp;
+	}
+
+	// analyze components for wildcards
+	if (!wildCards(currentFileName, pathPrefix, components))
+	{
+		// no matches found - check for presence of wild symbols in path
+		if (!hasWildCards(savedPath))
+		{
+			(Arg::Gds(isc_conf_include) << currentFileName << parPath << Arg::Gds(isc_include_miss)).raise();
+		}
+	}
 }
+
+/******************************************************************************
+ *
+ *	Parse wildcards
+ *		- calls parse for found files
+ *		- fills filesCache
+ *		- returns true if some match was found
+ */
+
+bool ConfigFile::wildCards(const char* currentFileName, const PathName& pathPrefix, FilesArray& components)
+{
+	// Any change in directory can cause config change
+	PathName prefix(pathPrefix);
+	if(!pathPrefix.hasData())
+		prefix = ".";
+
+	bool found = false;
+	PathName next(components.pop());
+
+#ifdef DEBUG_INCLUDES
+	fprintf(stderr, "wildCards: prefix=%s next=%s left=%d\n",
+		prefix.c_str(), next.c_str(), components.getCount());
+#endif
+
+	ScanDir list(prefix.c_str(), next.c_str());
+	while (list.next())
+	{
+		PathName name;
+		const PathName fileName = list.getFileName();
+		if (fileName == ".")
+			continue;
+		if (fileName[0] == '.' && next[0] != '.')
+			continue;
+		PathUtils::concatPath(name, pathPrefix, fileName);
+
+#ifdef DEBUG_INCLUDES
+		fprintf(stderr, "in Scan: name=%s pathPrefix=%s list.fileName=%s\n",
+			name.c_str(), pathPrefix.c_str(), fileName.c_str());
+#endif
+
+		if (filesCache)
+			filesCache->addFile(name);
+
+		if (components.hasData())	// should be directory
+		{
+			found = found || wildCards(currentFileName, name, components);
+		}
+		else
+		{
+			MainStream include(name.c_str());
+			if (include.active())
+			{
+				found = true;
+				parse(&include);
+			}
+		}
+	}
+
+	return found;
+}
Modified: firebird/trunk/src/common/config/config_file.h
===================================================================
--- firebird/trunk/src/common/config/config_file.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/config/config_file.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -46,6 +46,8 @@
 	(common/config/config.cpp) and server-side alias manager (common/db_alias.cpp).
 **/
 
+class ConfigCache;
+
 class ConfigFile : public Firebird::AutoStorage, public Firebird::RefCounted
 {
 public:
@@ -65,6 +67,7 @@
 	public:
 		virtual ~Stream();
 		virtual bool getLine(String&, unsigned int&) = 0;
+		virtual const char* getFileName() const = 0;
 	};
 
 	struct Parameter : public AutoStorage
@@ -90,15 +93,16 @@
 
     typedef Firebird::SortedObjectsArray<Parameter, Firebird::InlineStorage<Parameter*, 100>,
 										 KeyType, Parameter> Parameters;
+	typedef Firebird::ObjectsArray<Firebird::PathName> FilesArray;
 
-	ConfigFile(const Firebird::PathName& file, USHORT fl = 0);
-	ConfigFile(const char* file, USHORT fl = 0);
+	ConfigFile(const Firebird::PathName& file, USHORT fl = 0, ConfigCache* cache = NULL);
+	ConfigFile(const char* file, USHORT fl = 0, ConfigCache* cache = NULL);
 	ConfigFile(UseText, const char* configText, USHORT fl = 0);
 
-	ConfigFile(MemoryPool& p, const Firebird::PathName& file, USHORT fl = 0);
+	ConfigFile(MemoryPool& p, const Firebird::PathName& file, USHORT fl = 0, ConfigCache* cache = NULL);
 
 private:
-	ConfigFile(MemoryPool& p, ConfigFile::Stream* s, USHORT fl, const Firebird::PathName& file);
+	ConfigFile(MemoryPool& p, ConfigFile::Stream* s, USHORT fl);
 
 public:
 	// key and value management
@@ -111,26 +115,25 @@
 		return parameters;
 	}
 
-	// was there some error parsing config file?
-	const char* getMessage() const;
-
 	// Substitute macro values in a string
-	bool macroParse(String& value) const;
+	bool macroParse(String& value, const char* fileName) const;
 
 private:
-	enum LineType {LINE_BAD, LINE_REGULAR, LINE_START_SUB};
+	enum LineType {LINE_BAD, LINE_REGULAR, LINE_START_SUB, LINE_INCLUDE};
 
-    Firebird::PathName configFile;
     Parameters parameters;
 	USHORT flags;
-	USHORT badLinesCount;
-	Firebird::PathName lastMessage;
+	unsigned includeLimit;
+	ConfigCache* filesCache;
+	static const unsigned INCLUDE_LIMIT = 64;
 
 	// utilities
 	void parse(Stream* stream);
-	LineType parseLine(const String& input, KeyType& key, String& value);
-	bool translate(const String& from, String& to) const;
-	void badLine(const String& line);
+	LineType parseLine(const char* fileName, const String& input, KeyType& key, String& value);
+	bool translate(const char* fileName, const String& from, String& to) const;
+	void badLine(const char* fileName, const String& line);
+	void include(const char* currentFileName, const Firebird::PathName& path);
+	bool wildCards(const char* currentFileName, const Firebird::PathName& pathPrefix, FilesArray& components);
 };
 
 #endif	// CONFIG_CONFIG_FILE_H
Modified: firebird/trunk/src/common/db_alias.cpp
===================================================================
--- firebird/trunk/src/common/db_alias.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/db_alias.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -198,7 +198,7 @@
 			}
 			databases.clear();
 
-			ConfigFile aliasConfig(fileName, ConfigFile::HAS_SUB_CONF);
+			ConfigFile aliasConfig(getFileName(), ConfigFile::HAS_SUB_CONF, this);
 			const ConfigFile::Parameters& params = aliasConfig.getParameters();
 
 			for (n = 0; n < params.getCount(); ++n)
Modified: firebird/trunk/src/common/os/path_utils.h
===================================================================
--- firebird/trunk/src/common/os/path_utils.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/os/path_utils.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -147,6 +147,13 @@
 	static void splitLastComponent(Firebird::PathName&, Firebird::PathName&,
 									const Firebird::PathName&);
 
+	/**	splitPrefix takes a path as the first argument, splits OS-dependent prefix
+		from it (something like C:\, D: or \ in windows or / in posix),
+		and returns stripped path inplace, i.e. as first argument.
+		Prefix is returned as the second argument.
+	**/
+	static void splitPrefix(Firebird::PathName& path, Firebird::PathName& prefix);
+
 	/** This is the factory method for allocating dir_iterator objects.
 		It takes a reference to a memory pool to use for all heap allocations,
 		and the path of the directory to iterate (in that order).  It is the
Modified: firebird/trunk/src/common/os/posix/path_utils.cpp
===================================================================
--- firebird/trunk/src/common/os/posix/path_utils.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/common/os/posix/path_utils.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -118,6 +118,16 @@
 	file.append(orgPath, pos + 1, orgPath.length() - pos - 1);
 }
 
+void PathUtils::splitPrefix(Firebird::PathName& path, Firebird::PathName& prefix)
+{
+	prefix.erase();
+	while (path[0] == dir_sep)
+	{
+		prefix = dir_sep;
+		path.erase(0, 1);
+	}
+}
+
 void PathUtils::concatPath(Firebird::PathName& result,
 		const Firebird::PathName& first,
 		const Firebird::PathName& second)
Modified: firebird/trunk/src/include/gen/codetext.h
===================================================================
--- firebird/trunk/src/include/gen/codetext.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/include/gen/codetext.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -754,6 +754,11 @@
 	{"wrong_message_length", 335545050},
 	{"no_output_format", 335545051},
 	{"item_finish", 335545052},
+	{"miss_config", 335545053},
+	{"conf_line", 335545054},
+	{"conf_include", 335545055},
+	{"include_depth", 335545056},
+	{"include_miss", 335545057},
 	{"gfix_db_name", 335740929},
 	{"gfix_invalid_sw", 335740930},
 	{"gfix_incmp_sw", 335740932},
Modified: firebird/trunk/src/include/gen/iberror.h
===================================================================
--- firebird/trunk/src/include/gen/iberror.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/include/gen/iberror.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -788,6 +788,11 @@
 const ISC_STATUS isc_wrong_message_length             = 335545050L;
 const ISC_STATUS isc_no_output_format                 = 335545051L;
 const ISC_STATUS isc_item_finish                      = 335545052L;
+const ISC_STATUS isc_miss_config                      = 335545053L;
+const ISC_STATUS isc_conf_line                        = 335545054L;
+const ISC_STATUS isc_conf_include                     = 335545055L;
+const ISC_STATUS isc_include_depth                    = 335545056L;
+const ISC_STATUS isc_include_miss                     = 335545057L;
 const ISC_STATUS isc_gfix_db_name                     = 335740929L;
 const ISC_STATUS isc_gfix_invalid_sw                  = 335740930L;
 const ISC_STATUS isc_gfix_incmp_sw                    = 335740932L;
@@ -1232,7 +1237,7 @@
 const ISC_STATUS isc_trace_switch_param_miss          = 337182758L;
 const ISC_STATUS isc_trace_param_act_notcompat        = 337182759L;
 const ISC_STATUS isc_trace_mandatory_switch_miss      = 337182760L;
-const ISC_STATUS isc_err_max                          = 1176;
+const ISC_STATUS isc_err_max                          = 1181;
 
 #else /* c definitions */
 
@@ -1990,6 +1995,11 @@
 #define isc_wrong_message_length             335545050L
 #define isc_no_output_format                 335545051L
 #define isc_item_finish                      335545052L
+#define isc_miss_config                      335545053L
+#define isc_conf_line                        335545054L
+#define isc_conf_include                     335545055L
+#define isc_include_depth                    335545056L
+#define isc_include_miss                     335545057L
 #define isc_gfix_db_name                     335740929L
 #define isc_gfix_invalid_sw                  335740930L
 #define isc_gfix_incmp_sw                    335740932L
@@ -2434,7 +2444,7 @@
 #define isc_trace_switch_param_miss          337182758L
 #define isc_trace_param_act_notcompat        337182759L
 #define isc_trace_mandatory_switch_miss      337182760L
-#define isc_err_max                          1176
+#define isc_err_max                          1181
 
 #endif
 
Modified: firebird/trunk/src/include/gen/msgs.h
===================================================================
--- firebird/trunk/src/include/gen/msgs.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/include/gen/msgs.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -757,6 +757,11 @@
 	{335545050, "Message length passed from user application does not match set of columns"},		/* wrong_message_length */
 	{335545051, "Resultset is missing output format information"},		/* no_output_format */
 	{335545052, "Message metadata not ready - item @1 is not finished"},		/* item_finish */
+	{335545053, "Missing configuration file: @1"},		/* miss_config */
+	{335545054, "@1: illegal line <@2>"},		/* conf_line */
+	{335545055, "Invalid include operator in @1 for <@2>"},		/* conf_include */
+	{335545056, "Include depth too big"},		/* include_depth */
+	{335545057, "File to include not found"},		/* include_miss */
 	{335740929, "data base file name (@1) already given"},		/* gfix_db_name */
 	{335740930, "invalid switch @1"},		/* gfix_invalid_sw */
 	{335740932, "incompatible switch combination"},		/* gfix_incmp_sw */
Modified: firebird/trunk/src/include/gen/sql_code.h
===================================================================
--- firebird/trunk/src/include/gen/sql_code.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/include/gen/sql_code.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -753,6 +753,11 @@
 	{335545050, -804}, /* 730 wrong_message_length */
 	{335545051, -804}, /* 731 no_output_format */
 	{335545052, -804}, /* 732 item_finish */
+	{335545053, -902}, /* 733 miss_config */
+	{335545054, -902}, /* 734 conf_line */
+	{335545055, -902}, /* 735 conf_include */
+	{335545056, -902}, /* 736 include_depth */
+	{335545057, -902}, /* 737 include_miss */
 	{335740929, -901}, /*   1 gfix_db_name */
 	{335740930, -901}, /*   2 gfix_invalid_sw */
 	{335740932, -901}, /*   4 gfix_incmp_sw */
Modified: firebird/trunk/src/include/gen/sql_state.h
===================================================================
--- firebird/trunk/src/include/gen/sql_state.h	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/include/gen/sql_state.h	2013-03-27 11:45:02 UTC (rev 57841)
@@ -753,6 +753,11 @@
 	{335545050, "07000"}, // 730 wrong_message_length
 	{335545051, "07000"}, // 731 no_output_format
 	{335545052, "HY021"}, // 732 item_finish
+	{335545053, "XX000"}, // 733 miss_config
+	{335545054, "XX000"}, // 734 conf_line
+	{335545055, "XX000"}, // 735 conf_include
+	{335545056, "XX000"}, // 736 include_depth
+	{335545057, "XX000"}, // 737 include_miss
 	{335740929, "00000"}, //   1 gfix_db_name
 	{335740930, "00000"}, //   2 gfix_invalid_sw
 	{335740932, "00000"}, //   4 gfix_incmp_sw
Modified: firebird/trunk/src/msgs/facilities2.sql
===================================================================
--- firebird/trunk/src/msgs/facilities2.sql	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/msgs/facilities2.sql	2013-03-27 11:45:02 UTC (rev 57841)
@@ -1,7 +1,7 @@
 /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
 set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
 --
-('2013-02-21 18:12:38', 'JRD', 0, 733)
+('2013-03-26 17:52:41', 'JRD', 0, 738)
 ('2012-01-23 20:10:30', 'QLI', 1, 532)
 ('2009-07-16 05:26:11', 'GFIX', 3, 121)
 ('1996-11-07 13:39:40', 'GPRE', 4, 1)
Modified: firebird/trunk/src/msgs/messages2.sql
===================================================================
--- firebird/trunk/src/msgs/messages2.sql	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/msgs/messages2.sql	2013-03-27 11:45:02 UTC (rev 57841)
@@ -840,6 +840,11 @@
 ('wrong_message_length', NULL, 'why.cpp', NULL, 0, 730, NULL, 'Message length passed from user application does not match set of columns', NULL, NULL);
 ('no_output_format', NULL, 'why.cpp', NULL, 0, 731, NULL, 'Resultset is missing output format information', NULL, NULL);
 ('item_finish', NULL, 'MsgMetadata.cpp', NULL, 0, 732, NULL, 'Message metadata not ready - item @1 is not finished', NULL, NULL);
+('miss_config', NULL, 'config_file.cpp', NULL, 0, 733, NULL, 'Missing configuration file: @1', NULL, NULL);
+('conf_line', NULL, 'config_file.cpp', NULL, 0, 734, NULL, '@1: illegal line <@2>', NULL, NULL);
+('conf_include', NULL, 'config_file.cpp', NULL, 0, 735, NULL, 'Invalid include operator in @1 for <@2>', NULL, NULL);
+('include_depth', NULL, 'config_file.cpp', NULL, 0, 736, NULL, 'Include depth too big', NULL, NULL);
+('include_miss', NULL, 'config_file.cpp', NULL, 0, 737, NULL, 'File to include not found', NULL, NULL);
 -- QLI
 (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
 (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
Modified: firebird/trunk/src/msgs/system_errors2.sql
===================================================================
--- firebird/trunk/src/msgs/system_errors2.sql	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/msgs/system_errors2.sql	2013-03-27 11:45:02 UTC (rev 57841)
@@ -739,6 +739,11 @@
 (-804, '07', '000', 0, 730, 'wrong_message_length', NULL, NULL)
 (-804, '07', '000', 0, 731, 'no_output_format', NULL, NULL)
 (-804, 'HY', '021', 0, 732, 'item_finish', NULL, NULL)
+(-902, 'XX', '000', 0, 733, 'miss_config', NULL, NULL)
+(-902, 'XX', '000', 0, 734, 'conf_line', NULL, NULL)
+(-902, 'XX', '000', 0, 735, 'conf_include', NULL, NULL)
+(-902, 'XX', '000', 0, 736, 'include_depth', NULL, NULL)
+(-902, 'XX', '000', 0, 737, 'include_miss', NULL, NULL)
 -- GFIX
 (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
 (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
Modified: firebird/trunk/src/remote/server/os/posix/inet_server.cpp
===================================================================
--- firebird/trunk/src/remote/server/os/posix/inet_server.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/remote/server/os/posix/inet_server.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -39,6 +39,7 @@
 #include "../jrd/ibase.h"
 #include "../common/classes/init.h"
 #include "../common/config/config.h"
+#include "../common/os/fbsyslog.h"
 #include <sys/param.h>
 
 #ifdef HAVE_SYS_TYPES_H
@@ -156,6 +157,8 @@
  *	Run the server with apollo mailboxes.
  *
  **************************************/
+  try
+  {
 	RemPortPtr port;
 
 // 01 Sept 2003, Nickolay Samofatov
@@ -339,6 +342,13 @@
 		divorce_terminal(mask);
 	}
 
+	// check firebird.conf presence - must be for server
+	if (Config::missFirebirdConf())
+	{
+		Firebird::Syslog::Record(Firebird::Syslog::Error, "Missing master config file firebird.conf");
+		exit(STARTUP_ERROR);
+	}
+
 	if (super || standaloneClassic)
 	{
 		try
@@ -424,6 +434,21 @@
 	fb_shutdown(10000, fb_shutrsn_exit_called);
 
 	return FINI_OK;
+  }
+  catch(const Firebird::Exception& ex)
+  {
+    ISC_STATUS_ARRAY status;
+    ex.stuff_exception(status);
+
+    char s[100];
+    const ISC_STATUS* st = status;
+    fb_interpret(s, sizeof(s), &st);
+
+    Firebird::Syslog::Record(Firebird::Syslog::Error, "Firebird startup error");
+    Firebird::Syslog::Record(Firebird::Syslog::Error, s);
+
+  	exit(STARTUP_ERROR);
+  }
 }
 
 } // extern "C"
Modified: firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp
===================================================================
--- firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -206,10 +206,10 @@
 		return STARTUP_ERROR; // see /common/common.h
 	}
 
-	// Check for errors/missing firebird.conf
-	const char* anyError = Config::getMessage();
-	if (anyError)
+	// Check for missing firebird.conf
+	if (Config::missFirebirdConf())
 	{
+		const char* anyError = "Missing master config file firebird.conf";
 		Syslog::Record(Syslog::Error, anyError);
 		MessageBox(NULL, anyError, "Firebird server failure",
 			MB_OK | MB_ICONHAND | MB_SYSTEMMODAL  | MB_DEFAULT_DESKTOP_ONLY);
Modified: firebird/trunk/src/utilities/ntrace/TraceConfiguration.cpp
===================================================================
--- firebird/trunk/src/utilities/ntrace/TraceConfiguration.cpp	2013-03-27 01:34:44 UTC (rev 57840)
+++ firebird/trunk/src/utilities/ntrace/TraceConfiguration.cpp	2013-03-27 11:45:02 UTC (rev 57841)
@@ -92,10 +92,6 @@
 void TraceCfgReader::readConfig()
 {
 	ConfigFile cfgFile(ConfigFile::USE_TEXT, m_text, ConfigFile::HAS_SUB_CONF);
-	if (cfgFile.getMessage())
-	{
-		fatal_exception::raiseFmt(ERROR_PREFIX"%s", cfgFile.getMessage());
-	}
 
 	m_subpatterns[0].start = 0;
 	m_subpatterns[0].end = m_databaseName.length();
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
 |