/* $Id: jigdoconfig.hh,v 1.5 2005/04/09 14:44:50 atterer Exp $ -*- C++ -*- __ _ |_) /| Copyright (C) 2001-2002 | richard@ | \/¯| Richard Atterer | atterer.net ¯ '` ¯ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2. See the file COPYING for details. *//** @file Representation for config data in a .jigdo file - based on ConfigFile Mostly, this class just "forwards" requests by making the appropriate calls to the ConfigFile object, with one exception: It caches the labels in the [Servers] section and detects loops. */ #ifndef JIGDOCONFIG_HH #define JIGDOCONFIG_HH #include #include #include #include //______________________________________________________________________ /** Representation for config data in a .jigdo file - based on ConfigFile */ class JigdoConfig { private: /* multimap doesn't make guarantees about order of inserted values with equal key, which needs to be preserved in our case. */ typedef map > Map; //________________________________________ public: /** To be implemented by anyone who is interested in errors/info from the JigdoConfig */ class ProgressReporter { public: virtual ~ProgressReporter() { } virtual void error(const string& message); virtual void info(const string& message); }; //________________________________________ #if 0 /* Use same function from net/uri.hh */ /** Helper function: Given a string, return 0 if the string has no "Label:" prefix, otherwise return the offset of the ':'. The "Label" portion of the string can contain *any* character except '/' and whitespace/control characters */ static inline unsigned findLabelColon(const string& s); #endif //________________________________________ /** Open file for input and create a ConfigFile object */ JigdoConfig(const char* jigdoFile, ProgressReporter& pr); JigdoConfig(const string& jigdoFile, ProgressReporter& pr); /** Take over possession of existing ConfigFile - configFile will be deleted in ~JigdoConfig()! jigdoFile argument is not used except for error messages. */ JigdoConfig(const char* jigdoFile, ConfigFile* configFile, ProgressReporter& pr); JigdoConfig(const string& jigdoFile, ConfigFile* configFile, ProgressReporter& pr); ~JigdoConfig() { delete config; } ConfigFile& configFile() { return *config; } //________________________________________ /** Prepare internal map from label name to URIs. Is called automatically during JigdoConfig(), but must be called manually afterwards whenever any entry in the ConfigFile's "[Servers]" section changes. May throw an Error if the jigdo file format version is not supported. */ void rescan(); /** Change reporter for error messages */ inline void setReporter(ProgressReporter& pr); /** Given an URI-style string like "MyServer:dir/foo/file.gz", do label lookup (looking for [Servers] entries like "MyServer=...") and return the resulting strings, e.g. "ftp://mysite.com/dir/foo/file.gz". The class will enumerate all the possible URIs. NB: After a jc.rescan(), no further calls to next() of existing Lookups for that JigdoConfig are allowed. Also, query must stay valid throughout the lifetime of Lookup, since a reference to it is maintained. */ class Lookup { public: inline Lookup(const JigdoConfig& jc, const string& query); /** If true returned, result has been overwritten with next value. Otherwise, end of list has been reached and result is unchanged. */ inline bool next(string& result); // Default copy ctor and dtor private: const JigdoConfig& config; // "MyServer:dir/foo/file.gz" or null: next() returns false const string* uri; string::size_type colon; // Offset of ':' in query // Pointer in list for "MyServer" mappings; pointer to end of list vector::const_iterator cur, end; }; friend class Lookup; //________________________________________ private: /* Adds filename and line number before reporting. This is used by JigdoConfig to talk to ConfigFile. */ struct ForwardReporter : ConfigFile::ProgressReporter { inline ForwardReporter(JigdoConfig::ProgressReporter& pr, const string& file); inline ForwardReporter(JigdoConfig::ProgressReporter& pr, const char* file); virtual ~ForwardReporter() { } virtual void error(const string& message, const size_t lineNr = 0); virtual void info(const string& message, const size_t lineNr = 0); JigdoConfig::ProgressReporter* reporter; string fileName; }; //________________________________________ struct ServerLine { ConfigFile::iterator line; size_t labelStart, labelEnd, valueStart; }; Map::iterator rescan_addLabel(list& entries, const string& label, bool& printError); inline void rescan_makeSubst(list& entries, Map::iterator mapl, const ServerLine& l, bool& printError); void scanVersionInfo(); // Check for supported file format version number ConfigFile* config; Map serverMap; ForwardReporter freporter; }; //______________________________________________________________________ JigdoConfig::ForwardReporter::ForwardReporter( JigdoConfig::ProgressReporter& pr, const string& file) : reporter(&pr), fileName(file) { } JigdoConfig::ForwardReporter::ForwardReporter( JigdoConfig::ProgressReporter& pr, const char* file) : reporter(&pr), fileName(file) { } void JigdoConfig::setReporter(ProgressReporter& pr) { freporter.reporter = ≺ } //________________________________________ JigdoConfig::Lookup::Lookup(const JigdoConfig& jc, const string& query) : config(jc), uri(&query), colon(query.find(':')), cur() { /* colon == string::npos means: The URI doesn't contain a ':', or it does but the label before it ("MyServer") isn't listed in the mapping, or the label is listed but the corresponding vector is empty. In all these cases, the Lookup will only return one string - the original query. */ if (colon != string::npos) { string label(query, 0, colon); Map::const_iterator vec = config.serverMap.find(label); ++colon; if (vec != config.serverMap.end() && vec->second.size() != 0) { cur = vec->second.begin(); end = vec->second.end(); } else { colon = string::npos; } } } bool JigdoConfig::Lookup::next(string& result) { if (uri == 0) return false; if (colon == string::npos) { // Only return one value result = *uri; uri = 0; return true; } // Iterate through vector result = *cur; result.append(*uri, colon, string::npos); ++cur; if (cur == end) uri = 0; return true; } #endif