1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2008 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
20 /*******************************************************
21 * This file contains classes and templates that deal
22 * with the comparison and hashing of 'irc strings'.
23 * An 'irc string' is a string which compares in a
24 * case insensitive manner, and as per RFC 1459 will
25 * treat [ identical to {, ] identical to }, and \
28 * Our hashing functions are designed to accept
29 * std::string and compare/hash them as type irc::string
30 * by converting them internally. This makes them
31 * backwards compatible with other code which is not
32 * aware of irc::string.
33 *******************************************************/
38 /** A mapping of uppercase to lowercase, including scandinavian
39 * 'oddities' as specified by RFC1459, e.g. { -> [, and | -> \
41 unsigned const char rfc_case_insensitive_map[256] = {
42 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 0-19 */
43 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, /* 20-39 */
44 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, /* 40-59 */
45 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, /* 60-79 */
46 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 94, 95, 96, 97, 98, 99, /* 80-99 */
47 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, /* 100-119 */
48 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, /* 120-139 */
49 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, /* 140-159 */
50 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, /* 160-179 */
51 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, /* 180-199 */
52 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, /* 200-219 */
53 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, /* 220-239 */
54 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 /* 240-255 */
57 /** Seperate from the other casemap tables so that code *can* still exclusively rely on RFC casemapping
60 * This is provided as a pointer so that modules can change it to their custom mapping tables,
61 * e.g. for national character support.
63 extern unsigned const char *national_case_insensitive_map;
65 /** Case insensitive map, ASCII rules.
69 unsigned const char ascii_case_insensitive_map[256] = {
70 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 0-19 */
71 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, /* 20-39 */
72 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, /* 40-59 */
73 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, /* 60-79 */
74 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, /* 80-99 */
75 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, /* 100-119 */
76 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, /* 120-139 */
77 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, /* 140-159 */
78 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, /* 160-179 */
79 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, /* 180-199 */
80 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, /* 200-219 */
81 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, /* 220-239 */
82 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 /* 240-255 */
85 /** Case sensitive map.
86 * Can technically also be used for ASCII case sensitive comparisons, as [ != {, etc.
88 unsigned const char rfc_case_sensitive_map[256] = {
89 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
90 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
91 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
92 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
93 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
94 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
95 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
96 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
97 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
98 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
99 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
100 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
101 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
106 /** The irc namespace contains a number of helper classes.
111 /** This class returns true if two strings match.
112 * Case sensitivity is ignored, and the RFC 'character set'
117 /** The operator () does the actual comparison in hash_map
119 bool operator()(const std::string& s1, const std::string& s2) const;
122 /** The irc_char_traits class is used for RFC-style comparison of strings.
123 * This class is used to implement irc::string, a case-insensitive, RFC-
124 * comparing string class.
126 struct irc_char_traits : std::char_traits<char> {
128 /** Check if two chars match.
129 * @param c1st First character
130 * @param c2nd Second character
131 * @return true if the characters are equal
133 static bool eq(char c1st, char c2nd);
135 /** Check if two chars do NOT match.
136 * @param c1st First character
137 * @param c2nd Second character
138 * @return true if the characters are unequal
140 static bool ne(char c1st, char c2nd);
142 /** Check if one char is less than another.
143 * @param c1st First character
144 * @param c2nd Second character
145 * @return true if c1st is less than c2nd
147 static bool lt(char c1st, char c2nd);
149 /** Compare two strings of size n.
150 * @param str1 First string
151 * @param str2 Second string
152 * @param n Length to compare to
153 * @return similar to strcmp, zero for equal, less than zero for str1
154 * being less and greater than zero for str1 being greater than str2.
156 static CoreExport int compare(const char* str1, const char* str2, size_t n);
158 /** Find a char within a string up to position n.
159 * @param s1 String to find in
160 * @param n Position to search up to
161 * @param c Character to search for
162 * @return Pointer to the first occurance of c in s1
164 static CoreExport const char* find(const char* s1, int n, char c);
167 /** Compose a hex string from raw data.
168 * @param raw The raw data to compose hex from
169 * @pram rawsz The size of the raw data buffer
170 * @return The hex string.
172 CoreExport std::string hex(const unsigned char *raw, size_t rawsz);
174 /** This typedef declares irc::string based upon irc_char_traits.
176 typedef std::basic_string<char, irc_char_traits, std::allocator<char> > string;
178 /** irc::stringjoiner joins string lists into a string, using
179 * the given seperator string.
180 * This class can join a vector of std::string, a deque of
181 * std::string, or a const char* const* array, using overloaded
184 class CoreExport stringjoiner : public classbase
194 /** Join elements of a vector, between (and including) begin and end
195 * @param seperator The string to seperate values with
196 * @param sequence One or more items to seperate
197 * @param begin The starting element in the sequence to be joined
198 * @param end The ending element in the sequence to be joined
200 stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end);
202 /** Join elements of a deque, between (and including) begin and end
203 * @param seperator The string to seperate values with
204 * @param sequence One or more items to seperate
205 * @param begin The starting element in the sequence to be joined
206 * @param end The ending element in the sequence to be joined
208 stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end);
210 /** Join elements of an array of char arrays, between (and including) begin and end
211 * @param seperator The string to seperate values with
212 * @param sequence One or more items to seperate
213 * @param begin The starting element in the sequence to be joined
214 * @param end The ending element in the sequence to be joined
216 stringjoiner(const std::string &seperator, const char* const* sequence, int begin, int end);
218 /** Get the joined sequence
219 * @return A reference to the joined string
221 std::string& GetJoined();
224 /** irc::modestacker stacks mode sequences into a list.
225 * It can then reproduce this list, clamped to a maximum of MAXMODES
228 class CoreExport modestacker : public classbase
231 InspIRCd* ServerInstance;
233 /** The mode sequence and its parameters
235 std::deque<std::string> sequence;
237 /** True if the mode sequence is initially adding
238 * characters, false if it is initially removing
244 /** Construct a new modestacker.
245 * @param add True if the stack is adding modes,
246 * false if it is removing them
248 modestacker(InspIRCd* Instance, bool add);
250 /** Push a modeletter and its parameter onto the stack.
251 * No checking is performed as to if this mode actually
252 * requires a parameter. If you stack invalid mode
253 * sequences, they will be tidied if and when they are
254 * passed to a mode parser.
255 * @param modeletter The mode letter to insert
256 * @param parameter The parameter for the mode
258 void Push(char modeletter, const std::string ¶meter);
260 /** Push a modeletter without parameter onto the stack.
261 * No checking is performed as to if this mode actually
262 * requires a parameter. If you stack invalid mode
263 * sequences, they will be tidied if and when they are
264 * passed to a mode parser.
265 * @param modeletter The mode letter to insert
267 void Push(char modeletter);
269 /** Push a '+' symbol onto the stack.
273 /** Push a '-' symbol onto the stack.
277 /** Return zero or more elements which form the
278 * mode line. This will be clamped to a max of
279 * MAXMODES items (MAXMODES-1 mode parameters and
280 * one mode sequence string), and max_line_size
281 * characters. As specified below, this function
282 * should be called in a loop until it returns zero,
283 * indicating there are no more modes to return.
284 * @param result The deque to populate. This will
285 * be cleared before it is used.
286 * @param max_line_size The maximum size of the line
287 * to build, in characters, seperate to MAXMODES.
288 * @return The number of elements in the deque.
289 * The function should be called repeatedly until it
290 * returns 0, in case there are multiple lines of
291 * mode changes to be obtained.
293 int GetStackedLine(std::deque<std::string> &result, int max_line_size = 360);
296 /** irc::tokenstream reads a string formatted as per RFC1459 and RFC2812.
297 * It will split the string into 'tokens' each containing one parameter
299 * For instance, if it is instantiated with the string:
300 * "PRIVMSG #test :foo bar baz qux"
301 * then each successive call to tokenstream::GetToken() will return
302 * "PRIVMSG", "#test", "foo bar baz qux", "".
303 * Note that if the whole string starts with a colon this is not taken
304 * to mean the string is all one parameter, and the first item in the
305 * list will be ":item". This is to allow for parsing 'source' fields
308 class CoreExport tokenstream : public classbase
316 /** Last position of a seperator token
318 std::string::iterator last_starting_position;
320 /** Current string position
322 std::string::iterator n;
324 /** True if the last value was an ending value
329 /** Create a tokenstream and fill it with the provided data
331 tokenstream(const std::string &source);
337 /** Fetch the next token from the stream as a std::string
338 * @param token The next token available, or an empty string if none remain
339 * @return True if tokens are left to be read, false if the last token was just retrieved.
341 bool GetToken(std::string &token);
343 /** Fetch the next token from the stream as an irc::string
344 * @param token The next token available, or an empty string if none remain
345 * @return True if tokens are left to be read, false if the last token was just retrieved.
347 bool GetToken(irc::string &token);
349 /** Fetch the next token from the stream as an integer
350 * @param token The next token available, or undefined if none remain
351 * @return True if tokens are left to be read, false if the last token was just retrieved.
353 bool GetToken(int &token);
355 /** Fetch the next token from the stream as a long integer
356 * @param token The next token available, or undefined if none remain
357 * @return True if tokens are left to be read, false if the last token was just retrieved.
359 bool GetToken(long &token);
362 /** irc::sepstream allows for splitting token seperated lists.
363 * Each successive call to sepstream::GetToken() returns
364 * the next token, until none remain, at which point the method returns
367 class CoreExport sepstream : public classbase
373 /** Last position of a seperator token
375 std::string::iterator last_starting_position;
376 /** Current string position
378 std::string::iterator n;
383 /** Create a sepstream and fill it with the provided data
385 sepstream(const std::string &source, char seperator);
389 virtual ~sepstream();
391 /** Fetch the next token from the stream
392 * @param token The next token from the stream is placed here
393 * @return True if tokens still remain, false if there are none left
395 virtual bool GetToken(std::string &token);
397 /** Fetch the entire remaining stream, without tokenizing
398 * @return The remaining part of the stream
400 virtual const std::string GetRemaining();
402 /** Returns true if the end of the stream has been reached
403 * @return True if the end of the stream has been reached, otherwise false
405 virtual bool StreamEnd();
408 /** A derived form of sepstream, which seperates on commas
410 class CoreExport commasepstream : public sepstream
413 /** Initialize with comma seperator
415 commasepstream(const std::string &source) : sepstream(source, ',')
420 /** A derived form of sepstream, which seperates on spaces
422 class CoreExport spacesepstream : public sepstream
425 /** Initialize with space seperator
427 spacesepstream(const std::string &source) : sepstream(source, ' ')
432 /** The portparser class seperates out a port range into integers.
433 * A port range may be specified in the input string in the form
434 * "6660,6661,6662-6669,7020". The end of the stream is indicated by
435 * a return value of 0 from portparser::GetToken(). If you attempt
436 * to specify an illegal range (e.g. one where start >= end, or
437 * start or end < 0) then GetToken() will return the first element
438 * of the pair of numbers.
440 class CoreExport portparser : public classbase
444 /** Used to split on commas
448 /** Current position in a range of ports
452 /** Starting port in a range of ports
456 /** Ending port in a range of ports
460 /** Allow overlapped port ranges
464 /** Used to determine overlapping of ports
465 * without O(n) algorithm being used
467 std::map<long, bool> overlap_set;
469 /** Returns true if val overlaps an existing range
471 bool Overlaps(long val);
474 /** Create a portparser and fill it with the provided data
475 * @param source The source text to parse from
476 * @param allow_overlapped Allow overlapped ranges
478 portparser(const std::string &source, bool allow_overlapped = true);
480 /** Frees the internal commasepstream object
484 /** Fetch the next token from the stream
485 * @return The next port number is returned, or 0 if none remain
490 /** Turn _ characters in a string into spaces
491 * @param n String to translate
492 * @return The new value with _ translated to space.
494 CoreExport const char* Spacify(const char* n);
497 /* Define operators for using >> and << with irc::string to an ostream on an istream. */
498 /* This was endless fun. No. Really. */
499 /* It was also the first core change Ommeh made, if anyone cares */
501 /** Operator << for irc::string
503 inline std::ostream& operator<<(std::ostream &os, const irc::string &str) { return os << str.c_str(); }
505 /** Operator >> for irc::string
507 inline std::istream& operator>>(std::istream &is, irc::string &str)
515 /* Define operators for + and == with irc::string to std::string for easy assignment
520 inline std::string operator+ (std::string& leftval, irc::string& rightval)
522 return leftval + std::string(rightval.c_str());
525 /* Define operators for + and == with irc::string to std::string for easy assignment
530 inline irc::string operator+ (irc::string& leftval, std::string& rightval)
532 return leftval + irc::string(rightval.c_str());
535 /* Define operators for + and == with irc::string to std::string for easy assignment
540 inline bool operator== (const std::string& leftval, const irc::string& rightval)
542 return (leftval.c_str() == rightval);
545 /* Define operators for + and == with irc::string to std::string for easy assignment
550 inline bool operator== (const irc::string& leftval, const std::string& rightval)
552 return (leftval == rightval.c_str());
555 /* Define operators != for irc::string to std::string for easy comparison
557 inline bool operator!= (const irc::string& leftval, const std::string& rightval)
559 return !(leftval == rightval.c_str());
562 /* Define operators != for std::string to irc::string for easy comparison
564 inline bool operator!= (const std::string& leftval, const irc::string& rightval)
566 return !(leftval.c_str() == rightval);
569 // FIXME MAXBUF messes up these
571 template<std::size_t N>
572 static inline bool operator == (std::string const &lhs, char const (&rhs)[N])
574 return lhs.length() == N - 1 && !std::memcmp(lhs.data(), rhs, N - 1);
577 template<std::size_t N>
578 static inline bool operator != (std::string const &lhs, char const (&rhs)[N])
580 return !(lhs == rhs);
584 /** Assign an irc::string to a std::string.
586 inline std::string assign(const irc::string &other) { return other.c_str(); }
588 /** Assign a std::string to an irc::string.
590 inline irc::string assign(const std::string &other) { return other.c_str(); }
592 /** Trim the leading and trailing spaces from a std::string.
594 inline std::string& trim(std::string &str)
596 std::string::size_type start = str.find_first_not_of(" ");
597 std::string::size_type end = str.find_last_not_of(" ");
598 if (start == std::string::npos || end == std::string::npos)
601 str = str.substr(start, end-start+1);
606 /** Hashing stuff is totally different on vc++'s hash_map implementation, so to save a buttload of
607 * #ifdefs we'll just do it all at once
609 BEGIN_HASHMAP_NAMESPACE
611 /** Hashing function to hash irc::string
614 template<> class CoreExport hash_compare<irc::string, std::less<irc::string> >
617 enum { bucket_size = 4, min_buckets = 8 }; /* Got these numbers from the CRT source, if anyone wants to change them feel free. */
619 /** Compare two irc::string values for hashing in hash_map
621 bool operator()(const irc::string & s1, const irc::string & s2) const
623 if(s1.length() != s2.length()) return true;
624 return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), (size_t)s1.length()) < 0);
627 /** Hash an irc::string value for hash_map
629 size_t operator()(const irc::string & s) const;
632 template<> class CoreExport hash_compare<std::string, std::less<std::string> >
635 enum { bucket_size = 4, min_buckets = 8 }; /* Again, from the CRT source */
637 /** Compare two std::string values for hashing in hash_map
639 bool operator()(const std::string & s1, const std::string & s2) const
641 if(s1.length() != s2.length()) return true;
642 return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), (size_t)s1.length()) < 0);
645 /** Hash a std::string using RFC1459 case sensitivity rules
646 * @param s A string to hash
647 * @return The hash value
649 size_t operator()(const std::string & s) const;
653 template<> struct hash<irc::string>
655 /** Hash an irc::string using RFC1459 case sensitivity rules
656 * @param s A string to hash
657 * @return The hash value
659 size_t operator()(const irc::string &s) const;
662 /* XXX FIXME: Implement a hash function overriding std::string's that works with TR1! */
664 #ifdef HASHMAP_DEPRECATED
667 template<> struct hash<std::string>
670 size_t operator()(const std::string &s) const;
675 /** Convert a string to lower case respecting RFC1459
676 * @param n A string to lowercase
678 void strlower(char *n);
680 END_HASHMAP_NAMESPACE