2
0

json.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
  2. // Copyright 2011, SIL International, All rights reserved.
  3. // JSON debug logging
  4. // Author: Tim Eves
  5. #if !defined GRAPHITE2_NTRACING
  6. #include <cstdio>
  7. #include <limits>
  8. #include "inc/json.h"
  9. #if defined(_MSC_VER)
  10. #define FORMAT_INTMAX "%lli"
  11. #define FORMAT_UINTMAX "%llu"
  12. #else
  13. #define FORMAT_INTMAX "%ji"
  14. #define FORMAT_UINTMAX "%ju"
  15. #endif
  16. using namespace graphite2;
  17. namespace
  18. {
  19. enum
  20. {
  21. seq = ',',
  22. obj='}', member=':', empty_obj='{',
  23. arr=']', empty_arr='['
  24. };
  25. }
  26. const std::nullptr_t json::null = nullptr;
  27. inline
  28. void json::context(const char current) throw()
  29. {
  30. fprintf(_stream, "%c", *_context);
  31. indent();
  32. *_context = current;
  33. }
  34. void json::indent(const int d) throw()
  35. {
  36. if (*_context == member || (_flatten && _flatten < _context))
  37. fputc(' ', _stream);
  38. else
  39. fprintf(_stream, "\n%*s", 4*int(_context - _contexts + d), "");
  40. }
  41. inline
  42. void json::push_context(const char prefix, const char suffix) throw()
  43. {
  44. assert(_context - _contexts < ptrdiff_t(sizeof _contexts));
  45. if (_context == _contexts)
  46. *_context = suffix;
  47. else
  48. context(suffix);
  49. *++_context = prefix;
  50. }
  51. void json::pop_context() throw()
  52. {
  53. assert(_context > _contexts);
  54. if (*_context == seq) indent(-1);
  55. else fputc(*_context, _stream);
  56. fputc(*--_context, _stream);
  57. if (_context == _contexts) fputc('\n', _stream);
  58. fflush(_stream);
  59. if (_flatten >= _context) _flatten = 0;
  60. *_context = seq;
  61. }
  62. // These four functions cannot be inlined as pointers to these
  63. // functions are needed for operator << (_context_t) to work.
  64. void json::flat(json & j) throw() { if (!j._flatten) j._flatten = j._context; }
  65. void json::close(json & j) throw() { j.pop_context(); }
  66. void json::object(json & j) throw() { j.push_context('{', '}'); }
  67. void json::array(json & j) throw() { j.push_context('[', ']'); }
  68. void json::item(json & j) throw()
  69. {
  70. while (j._context > j._contexts+1 && j._context[-1] != arr)
  71. j.pop_context();
  72. }
  73. json & json::operator << (json::string s) throw()
  74. {
  75. const char ctxt = _context[-1] == obj ? *_context == member ? seq : member : seq;
  76. context(ctxt);
  77. fprintf(_stream, "\"%s\"", s);
  78. if (ctxt == member) fputc(' ', _stream);
  79. return *this;
  80. }
  81. json & json::operator << (json::number f) throw()
  82. {
  83. context(seq);
  84. if (std::numeric_limits<json::number>::infinity() == f)
  85. fputs("Infinity", _stream);
  86. else if (-std::numeric_limits<json::number>::infinity() == f)
  87. fputs("-Infinity", _stream);
  88. else if (std::numeric_limits<json::number>::quiet_NaN() == f ||
  89. std::numeric_limits<json::number>::signaling_NaN() == f)
  90. fputs("NaN", _stream);
  91. else
  92. fprintf(_stream, "%g", f);
  93. return *this;
  94. }
  95. json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, FORMAT_INTMAX, intmax_t(d)); return *this; }
  96. json & json::operator << (json::integer_u d) throw() { context(seq); fprintf(_stream, FORMAT_UINTMAX, uintmax_t(d)); return *this; }
  97. json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
  98. json & json::operator << (std::nullptr_t) throw() { context(seq); fputs("null",_stream); return *this; }
  99. #endif