MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Properties.hpp
1 /*
2  Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 /*
19  * Properties.hpp
20  *
21  */
22 
23 #ifndef Properties_hpp
24 #define Properties_hpp
25 
26 #include <map>
27 #include <string>
28 #include <ios>
29 #include <iostream>
30 #include <istream>
31 #include <ostream>
32 #include <streambuf>
33 #include <fstream>
34 #include <cassert>
35 #include <climits>
36 
37 namespace utils {
38 
39 using std::map;
40 using std::wstring;
41 using std::ios_base;
42 using std::istream;
43 //using std::wistream;
44 using std::ostream;
45 //using std::wostream;
46 using std::streambuf;
47 //using std::wstreambuf;
48 
85 class Properties : public map<wstring, wstring>
86 {
87 public:
92  void load(const char* filename)
93  throw (ios_base::failure);
94 
99  void load(istream& is)
100  throw (ios_base::failure);
101 
111  void load(streambuf& ib)
112  throw (ios_base::failure);
113 
118  // not implemented yet
119  //void load(wistream& is)
120  // throw (ios_base::failure);
121 
130  // not implemented yet
131  //void load(wstreambuf& ib)
132  // throw (ios_base::failure);
133 
137  void store(const char* filename, const wstring* header = NULL) const
138  throw (ios_base::failure);
139 
143  void store(ostream& os, const wstring* header = NULL) const
144  throw (ios_base::failure);
145 
158  void store(streambuf& ob, const wstring* header = NULL) const
159  throw (ios_base::failure);
160 
164  // not implemented yet
165  //void store(wostream& os, const wstring* header = NULL) const
166  // throw (ios_base::failure);
167 
180  // not implemented yet
181  //void store(wstreambuf& ob, const wstring* header = NULL) const
182  // throw (ios_base::failure);
183 
184 protected:
185  static bool isWS(int c);
186  static bool isNL(int c);
187  static bool isComment(int c);
188  static bool isAssign(int c);
189  static bool isKeyTerminator(int c);
190  static bool isEsc(int c);
191  static void skipWS(streambuf& ib);
192  static void skipComment(streambuf& ib);
193  static void readIgnored(streambuf& ib);
194  static void readEsc(wstring& s, streambuf& ib);
195  static void readKey(wstring& s, streambuf& ib);
196  static void readValue(wstring& s, streambuf& ib);
197  static bool isPrintableAscii(wchar_t c);
198  static void writeAsciiEsc(streambuf& os, wchar_t c);
199  static void writeUnicodeEsc(streambuf& os, wchar_t c);
200  static void writeKey(streambuf& os, const wstring& s);
201  static void writeValue(streambuf& os, const wstring& s);
202  static void writeChar(streambuf& os, char c);
203 };
204 
205 inline istream&
206 operator>>(istream& s, Properties& p)
207 {
208  p.load(s);
209  return s;
210 }
211 
212 /*
213 // not implemented yet
214 inline wistream&
215 operator>>(wistream& s, Properties& p)
216 {
217  p.load(s);
218  return s;
219 }
220 */
221 
222 inline ostream&
223 operator<<(ostream& s, const Properties& p)
224 {
225  p.store(s);
226  return s;
227 }
228 
229 /*
230 // not implemented yet
231 inline wostream&
232 operator<<(wostream& s, const Properties& p)
233 {
234  p.store(s);
235  return s;
236 }
237 */
238 
239 
240 // ---------------------------------------------------------------------------
241 // Properties Implementation
242 // ---------------------------------------------------------------------------
243 
244 using std::cout;
245 using std::wcout;
246 using std::endl;
247 using std::ifstream;
248 using std::ofstream;
249 using std::streambuf;
250 using std::stringbuf;
251 
252 // ---------------------------------------------------------------------------
253 
254 inline bool
256 {
257  switch (c) {
258  case 0x09: // '\t' HT
259  case 0x0c: // '\f' FF
260  case 0x20: // ' ' SPACE
261  return true;
262  }
263  return false;
264 }
265 
266 inline bool
267 Properties::isNL(int c)
268 {
269  switch (c) {
270  case 0x0a: // '\n' LF
271  case 0x0d: // '\r' CR
272  return true;
273  }
274  return false;
275 }
276 
277 inline bool
278 Properties::isComment(int c)
279 {
280  switch (c) {
281  case 0x21: // '!'
282  case 0x23: // '#'
283  return true;
284  }
285  return false;
286 }
287 
288 inline bool
289 Properties::isAssign(int c)
290 {
291  switch (c) {
292  case 0x3a: // ':'
293  case 0x3d: // '='
294  return true;
295  }
296  return false;
297 }
298 
299 inline bool
300 Properties::isKeyTerminator(int c)
301 {
302  return isWS(c) || isAssign(c) || isNL(c);
303 }
304 
305 inline bool
306 Properties::isEsc(int c)
307 {
308  switch (c) {
309  case 0x5c: // '\\'
310  return true;
311  }
312  return false;
313 }
314 
315 inline void
316 Properties::skipWS(streambuf& ib)
317 {
318  int c;
319  while ((c = ib.snextc()) != EOF && isWS(c));
320 }
321 
322 inline void
323 Properties::skipComment(streambuf& ib)
324 {
325  int c;
326  // comments cannot have escaped line terminators
327  while ((c = ib.snextc()) != EOF && !isNL(c));
328  ib.sbumpc();
329 }
330 
331 inline void
332 Properties::readIgnored(streambuf& ib)
333 {
334  int c;
335  while ((c = ib.sgetc()) != EOF) {
336  if (isWS(c)) {
337  skipWS(ib);
338  c = ib.sgetc();
339  }
340  if (isNL(c)) {
341  ib.sbumpc();
342  continue;
343  }
344  if (isComment(c)) {
345  ib.sbumpc();
346  skipComment(ib);
347  continue;
348  }
349  return;
350  }
351 }
352 
353 inline void
354 Properties::readEsc(wstring& s, streambuf& ib)
355 {
356  int c = ib.sgetc();
357  switch (c) {
358  case EOF:
359  return;
360  case 0x0a: // '\n' LF
361  case 0x0d: // '\r' CR
362  // escaped EOL (CR, LF, CRLF)
363  if ((c = ib.snextc()) != 0x0a) // '\n' LF
364  ib.sungetc();
365  skipWS(ib);
366  return;
367  case 0x6e: // 'n'
368  // LF ("newline") char escape
369  c = 0x0a; // '\n'
370  break;
371  case 0x72: // 'r'
372  // CR ("return") char escape
373  c = 0x0d; // '\r'
374  break;
375  case 0x75: { // 'u'
376  // unicode escape
377  c = ib.sbumpc();
378  // store input characters in case not an escape sequence
379  wstring raw;
380  raw += c; // silently drop backslash by general rule
381  unsigned int d = 0;
382  for (int i = 0; i < 4; i++) {
383  d <<= 4;
384  c = ib.sbumpc();
385  raw += static_cast<wchar_t>(c); // exlicit cast preferred
386  switch (c) {
387  case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
388  case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
389  // '0'..'9'
390  d += c - 0x30; // - '0'
391  break;
392  case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46:
393  // 'A'..'F'
394  d += 10 + c - 0x41; // - 'A'
395  break;
396  case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66:
397  // 'a'..'f'
398  d += 10 + c - 0x61; // - 'a'
399  break;
400  case EOF:
401  default:
402  // not a unicode escape sequence, write the raw char sequence
403  s += static_cast<wchar_t>(c); // exlicit cast preferred
404  return;
405  }
406  }
407  s += static_cast<wchar_t>(d); // exlicit cast preferred
408  return;
409  }
410  default:
411  // unrecognized escape no error, silently drop preceding backslash
412  break;
413  }
414  s += static_cast<wchar_t>(c); // exlicit cast preferred
415  ib.sbumpc();
416 }
417 
418 inline void
419 Properties::readKey(wstring& s, streambuf& ib)
420 {
421  int c;
422  while ((c = ib.sgetc()) != EOF) {
423  if (isKeyTerminator(c)) {
424  if (isNL(c)) {
425  return;
426  }
427  if (isWS(c)) {
428  skipWS(ib);
429  c = ib.sgetc();
430  }
431  if (isAssign(c)) {
432  skipWS(ib);
433  }
434  return;
435  }
436 
437  ib.sbumpc();
438  if (isEsc(c)) {
439  readEsc(s, ib);
440  } else {
441  s += static_cast<wchar_t>(c); // exlicit cast preferred
442  }
443  }
444 }
445 
446 inline void
447 Properties::readValue(wstring& s, streambuf& ib)
448 {
449  int c;
450  while ((c = ib.sgetc()) != EOF) {
451  ib.sbumpc();
452  if (isNL(c)) {
453  return;
454  }
455 
456  if (isEsc(c)) {
457  readEsc(s, ib);
458  } else {
459  s += static_cast<wchar_t>(c); // exlicit cast preferred
460  }
461  }
462 }
463 
464 inline bool
465 Properties::isPrintableAscii(wchar_t c)
466 {
467  return (L'\x20' <= c && c <= L'\x7e');
468 }
469 
470 inline void
471 Properties::writeChar(streambuf& os, char c)
472 {
473  int n = os.sputc(c);
474  if (n == EOF)
475  throw ios_base::failure("Error writing to streambuf");
476 }
477 
478 inline void
479 Properties::writeAsciiEsc(streambuf& os, wchar_t c)
480 {
481  assert(L'\x20' <= c && c <= L'\x7e');
482  char d;
483  switch (c) {
484  case L'\t': // HT
485  d = '\x74'; // 't'
486  break;
487  case L'\n': // LF
488  d = '\x6e'; // 'n'
489  break;
490  case L'\f': // FF
491  d = '\x66'; // 'f'
492  break;
493  case L'\r': // CR
494  d = '\x72'; // 'r'
495  break;
496  case L' ': // SPACE
497  case L'!':
498  case L'#':
499  case L':':
500  case L'=':
501  case L'\\':
502  d = static_cast<char>(c); // exlicit cast preferred
503  break;
504  default:
505  // write the raw character
506  writeChar(os, static_cast<char>(c)); // explicit cast preferred
507  return;
508  }
509  writeChar(os, '\x5c'); // '\\'
510  writeChar(os, d);
511 }
512 
513 inline void
514 Properties::writeUnicodeEsc(streambuf& os, wchar_t c)
515 {
516  assert(c < L'\x20' || L'\x7e' < c);
517 
518  // subsequent code depends upon a UCS-2 (UTF-16) or UTF-32
519  // encoding of wide characters
520  const int w = sizeof(wchar_t);
521  assert(w == 2 || w == 4);
522  assert(CHAR_BIT == 8);
523 
524  // write unicode escape sequence as "\\unnnn" or "\Unnnnnnnn"
525  writeChar(os, '\x5c'); // '\\'
526  writeChar(os, w == 2 ? '\x75' : '\x55'); // 'u' : 'U'
527  static const char ascii[] = { '\x30', '\x31', '\x32', '\x33',
528  '\x34', '\x35', '\x36', '\x37',
529  '\x38', '\x39', '\x41', '\x42',
530  '\x43', '\x44', '\x45', '\x46' }; // '0'..'F'
531  for (unsigned int i = w * 8 - 4; i >= 0; i -= 4) {
532  writeChar(os, ascii[(c>>i) & 0xF]);
533  }
534 }
535 
536 inline void
537 Properties::writeKey(streambuf& os, const wstring& s)
538 {
539  for (wstring::const_iterator i = s.begin(); i != s.end(); ++i) {
540  const wchar_t c = *i;
541  if (isPrintableAscii(c))
542  writeAsciiEsc(os, c);
543  else
544  writeUnicodeEsc(os, c);
545  }
546 }
547 
548 inline void
549 Properties::writeValue(streambuf& os, const wstring& s)
550 {
551  wstring::const_iterator i = s.begin();
552  for (; i != s.end() && *i == L'\x20'; ++i) { // L' ' SPACE
553  // write leading spaces escaped
554  writeAsciiEsc(os, *i);
555  }
556  for (; i != s.end(); ++i) {
557  const wchar_t c = *i;
558  if (c == L'\x20') { // L' ' SPACE
559  // write embedded or tailing spaces unescaped
560  writeChar(os, '\x20'); // ' ' SPACE
561  } else if (isPrintableAscii(c)) {
562  writeAsciiEsc(os, c);
563  } else {
564  writeUnicodeEsc(os, c);
565  }
566  }
567 }
568 
569 // ---------------------------------------------------------------------------
570 
571 inline void
572 Properties::load(const char* filename)
573  throw (ios_base::failure)
574 {
575  assert(filename);
576  ifstream ifs;
577  ifs.exceptions(ifstream::failbit | ifstream::badbit);
578  ifs.open(filename);
579  assert(!ifs.bad()); // thrown ios_base::failure
580  load(ifs);
581  ifs.close();
582 }
583 
584 inline void
585 Properties::load(istream& is)
586  throw (ios_base::failure)
587 {
588  istream::iostate exceptions = is.exceptions(); // backup
589  is.exceptions(istream::failbit | istream::badbit);
590  streambuf* ib = is.rdbuf();
591  assert(ib != NULL); // thrown ios_base::failure
592  load(*ib);
593  is.exceptions(exceptions); // restore
594 }
595 
596 inline void
597 Properties::load(streambuf& ib)
598  throw (ios_base::failure)
599 {
600  while (ib.sgetc() != EOF) {
601  readIgnored(ib);
602  if (ib.sgetc() == EOF)
603  return;
604 
605  // parse property
606  wstring k;
607  readKey(k, ib);
608  wstring v;
609  readValue(v, ib);
610  //wcout << "('" << k << "', '" << v << "')" << endl;
611  (*this)[k] = v; // YYY
612  //this->operator[](k) = v;
613  }
614 }
615 
616 inline void
617 Properties::store(const char* filename, const wstring* header) const
618  throw (ios_base::failure)
619 {
620  assert(filename);
621  ofstream ofs;
622  ofs.exceptions(ifstream::failbit | ifstream::badbit);
623  ofs.open(filename);
624  assert(!ofs.bad());
625  store(ofs, header);
626  ofs.close();
627 }
628 
629 inline void
630 Properties::store(ostream& os, const wstring* header) const
631  throw (ios_base::failure)
632 {
633  ostream::iostate exceptions = os.exceptions(); // backup
634  os.exceptions(istream::failbit | istream::badbit);
635  streambuf* ob = os.rdbuf();
636  assert(ob != NULL); // thrown ios_base::failure
637  store(*ob, header);
638  os.exceptions(exceptions); // restore
639 }
640 
641 inline void
642 Properties::store(streambuf& os, const wstring* header) const
643  throw (ios_base::failure)
644 {
645  // subsequent code for writing the header, keys and values
646  // depends upon UCS-2 (UTF-16) or UTF-32 character encoding
647  const int w = sizeof(wchar_t);
648  assert(w == 2 || w == 4);
649  assert(CHAR_BIT == 8);
650  assert(L'!' == '\x21');
651  assert(L'A' == '\x41');
652  assert(L'a' == '\x61');
653  assert(L'~' == '\x7e');
654  (void)w;
655 
656  if (header != NULL) {
657  writeChar(os, '\x23'); // '#'
658  writeKey(os, *header);
659  writeChar(os, '\x0a'); // '\n'
660  }
661 
662  for (const_iterator i = begin(); i != end(); ++i) {
663  const wstring& key = i->first;
664  const wstring& value = i->second;
665  writeKey(os, key);
666  writeChar(os, '\x3d'); // '='
667  writeValue(os, value);
668  writeChar(os, '\x0a'); // '\n'
669  }
670 }
671 
672 // ---------------------------------------------------------------------------
673 
674 } // utils
675 
676 #endif // Properties_hpp