1 /* $Id: jigdoconfig.hh,v 1.5 2005/04/09 14:44:50 atterer Exp $ -*- C++ -*-
2   __   _
3   |_) /|  Copyright (C) 2001-2002  |  richard@
4   | \/�|  Richard Atterer          |  atterer.net
5   � '` �
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License, version 2. See
8   the file COPYING for details.
9 
10 *//** @file
11 
12   Representation for config data in a .jigdo file - based on ConfigFile
13 
14   Mostly, this class just "forwards" requests by making the
15   appropriate calls to the ConfigFile object, with one exception: It
16   caches the labels in the [Servers] section and detects loops.
17 
18 */
19 
20 #ifndef JIGDOCONFIG_HH
21 #define JIGDOCONFIG_HH
22 
23 #include <map>
24 #include <string>
25 #include <vector>
26 
27 #include <configfile.hh>
28 //______________________________________________________________________
29 
30 /** Representation for config data in a .jigdo file - based on ConfigFile */
31 class JigdoConfig {
32 private:
33   /* multimap doesn't make guarantees about order of inserted values
34      with equal key, which needs to be preserved in our case. */
35   typedef map<string,vector<string> > Map;
36   //________________________________________
37 
38 public:
errorAnyReporter39   /** To be implemented by anyone who is interested in errors/info from the
40       JigdoConfig */
41   class ProgressReporter {
42   public:
43     virtual ~ProgressReporter() { }
44     virtual void error(const string& message);
45     virtual void info(const string& message);
46   };
47   //________________________________________
48 
49 #if 0 /* Use same function from net/uri.hh */
50   /** Helper function: Given a string, return 0 if the string has no "Label:"
51       prefix, otherwise return the offset of the ':'. The "Label" portion of
52       the string can contain *any* character except '/' and
53       whitespace/control characters */
54   static inline unsigned findLabelColon(const string& s);
55 #endif
56   //________________________________________
57 
58   /** Open file for input and create a ConfigFile object */
59   JigdoConfig(const char* jigdoFile, ProgressReporter& pr);
60   JigdoConfig(const string& jigdoFile, ProgressReporter& pr);
61   /** Take over possession of existing ConfigFile - configFile will be
62       deleted in ~JigdoConfig()! jigdoFile argument is not used except for
63       error messages. */
64   JigdoConfig(const char* jigdoFile, ConfigFile* configFile,
65               ProgressReporter& pr);
66   JigdoConfig(const string& jigdoFile, ConfigFile* configFile,
67               ProgressReporter& pr);
68   ~JigdoConfig() { delete config; }
69   ConfigFile& configFile() { return *config; }
70   //________________________________________
71 
72   /** Prepare internal map from label name to URIs. Is called automatically
73       during JigdoConfig(), but must be called manually afterwards whenever
74       any entry in the ConfigFile's "[Servers]" section changes.  May throw
75       an Error if the jigdo file format version is not supported. */
76   void rescan();
77 
78   /** Change reporter for error messages */
79   inline void setReporter(ProgressReporter& pr);
80 
81   /** Given an URI-style string like "MyServer:dir/foo/file.gz", do
82       label lookup (looking for [Servers] entries like "MyServer=...")
83       and return the resulting strings, e.g.
84       "ftp://mysite.com/dir/foo/file.gz". The class will enumerate all
85       the possible URIs. NB: After a jc.rescan(), no further calls to
86       next() of existing Lookups for that JigdoConfig are allowed.
87       Also, query must stay valid throughout the lifetime of Lookup,
88       since a reference to it is maintained. */
89   class Lookup {
90   public:
91     inline Lookup(const JigdoConfig& jc, const string& query);
92     /** If true returned, result has been overwritten with next value.
93         Otherwise, end of list has been reached and result is
94         unchanged. */
95     inline bool next(string& result);
96     // Default copy ctor and dtor
97   private:
98     const JigdoConfig& config;
99     // "MyServer:dir/foo/file.gz" or null: next() returns false
100     const string* uri;
101     string::size_type colon; // Offset of ':' in query
102     // Pointer in list for "MyServer" mappings; pointer to end of list
103     vector<string>::const_iterator cur, end;
104   };
105   friend class Lookup;
106   //________________________________________
107 
108 private:
109 
110   /* Adds filename and line number before reporting. This is used by
111      JigdoConfig to talk to ConfigFile. */
112   struct ForwardReporter : ConfigFile::ProgressReporter {
113     inline ForwardReporter(JigdoConfig::ProgressReporter& pr,
114                            const string& file);
115     inline ForwardReporter(JigdoConfig::ProgressReporter& pr,
116                            const char* file);
117     virtual ~ForwardReporter() { }
118     virtual void error(const string& message, const size_t lineNr = 0);
119     virtual void info(const string& message, const size_t lineNr = 0);
120     JigdoConfig::ProgressReporter* reporter;
121     string fileName;
122   };
123   //________________________________________
124 
125   struct ServerLine {
126     ConfigFile::iterator line;
127     size_t labelStart, labelEnd, valueStart;
128   };
129   Map::iterator rescan_addLabel(list<ServerLine>& entries,
130                                 const string& label, bool& printError);
131   inline void rescan_makeSubst(list<ServerLine>& entries, Map::iterator mapl,
132                                const ServerLine& l, bool& printError);
133   void scanVersionInfo(); // Check for supported file format version number
134 
135   ConfigFile* config;
binName()136   Map serverMap;
137   ForwardReporter freporter;
138 };
139 //______________________________________________________________________
binName()140 
141 JigdoConfig::ForwardReporter::ForwardReporter(
142     JigdoConfig::ProgressReporter& pr, const string& file)
143   : reporter(&pr), fileName(file) { }
144 
145 JigdoConfig::ForwardReporter::ForwardReporter(
146     JigdoConfig::ProgressReporter& pr, const char* file)
147   : reporter(&pr), fileName(file) { }
148 
149 void JigdoConfig::setReporter(ProgressReporter& pr) {
150   freporter.reporter = &pr;
151 }
152 //________________________________________
153 
154 JigdoConfig::Lookup::Lookup(const JigdoConfig& jc, const string& query)
155     : config(jc), uri(&query), colon(query.find(':')), cur() {
156   /* colon == string::npos means: The URI doesn't contain a ':', or it
157      does but the label before it ("MyServer") isn't listed in the
158      mapping, or the label is listed but the corresponding
159      vector<string> is empty. In all these cases, the Lookup will only
160      return one string - the original query. */
161   if (colon != string::npos) {
162     string label(query, 0, colon);
163     Map::const_iterator vec = config.serverMap.find(label);
164     ++colon;
165     if (vec != config.serverMap.end() && vec->second.size() != 0) {
166       cur = vec->second.begin();
167       end = vec->second.end();
168     } else {
169       colon = string::npos;
170     }
171   }
172 }
173 
174 bool JigdoConfig::Lookup::next(string& result) {
175   if (uri == 0) return false;
176   if (colon == string::npos) { // Only return one value
177     result = *uri;
178     uri = 0;
179     return true;
180   }
181   // Iterate through vector
182   result = *cur;
183   result.append(*uri, colon, string::npos);
184   ++cur;
185   if (cur == end) uri = 0;
186   return true;
187 }
188 
189 #endif
190