michael@0: /* GRAPHITE2 LICENSING michael@0: michael@0: Copyright 2011, SIL International michael@0: All rights reserved. michael@0: michael@0: This library is free software; you can redistribute it and/or modify michael@0: it under the terms of the GNU Lesser General Public License as published michael@0: by the Free Software Foundation; either version 2.1 of License, or michael@0: (at your option) any later version. michael@0: michael@0: This program is distributed in the hope that it will be useful, michael@0: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: Lesser General Public License for more details. michael@0: michael@0: You should also have received a copy of the GNU Lesser General Public michael@0: License along with this library in the file named "LICENSE". michael@0: If not, write to the Free Software Foundation, 51 Franklin Street, michael@0: Suite 500, Boston, MA 02110-1335, USA or visit their web page on the michael@0: internet at http://www.fsf.org/licenses/lgpl.html. michael@0: michael@0: Alternatively, the contents of this file may be used under the terms of the michael@0: Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public michael@0: License, as published by the Free Software Foundation, either version 2 michael@0: of the License or (at your option) any later version. michael@0: */ michael@0: // JSON debug logging michael@0: // Author: Tim Eves michael@0: michael@0: #if !defined GRAPHITE2_NTRACING michael@0: michael@0: #include michael@0: #include "inc/json.h" michael@0: michael@0: using namespace graphite2; michael@0: michael@0: namespace michael@0: { michael@0: enum michael@0: { michael@0: seq = ',', michael@0: obj='}', member=':', empty_obj='{', michael@0: arr=']', empty_arr='[' michael@0: }; michael@0: } michael@0: michael@0: const json::_null_t json::null = {}; michael@0: michael@0: inline michael@0: void json::context(const char current) throw() michael@0: { michael@0: fprintf(_stream, "%c", *_context); michael@0: indent(); michael@0: *_context = current; michael@0: } michael@0: michael@0: michael@0: void json::indent(const int d) throw() michael@0: { michael@0: if (*_context == member || (_flatten && _flatten < _context)) michael@0: fputc(' ', _stream); michael@0: else michael@0: fprintf(_stream, "\n%*s", 4*int(_context - _contexts + d), ""); michael@0: } michael@0: michael@0: michael@0: inline michael@0: void json::push_context(const char prefix, const char suffix) throw() michael@0: { michael@0: assert(_context - _contexts < ptrdiff_t(sizeof _contexts)); michael@0: michael@0: if (_context == _contexts) michael@0: *_context = suffix; michael@0: else michael@0: context(suffix); michael@0: *++_context = prefix; michael@0: } michael@0: michael@0: michael@0: void json::pop_context() throw() michael@0: { michael@0: assert(_context > _contexts); michael@0: michael@0: if (*_context == seq) indent(-1); michael@0: else fputc(*_context, _stream); michael@0: michael@0: fputc(*--_context, _stream); michael@0: if (_context == _contexts) fputc('\n', _stream); michael@0: fflush(_stream); michael@0: michael@0: if (_flatten >= _context) _flatten = 0; michael@0: *_context = seq; michael@0: } michael@0: michael@0: michael@0: // These four functions cannot be inlined as pointers to these michael@0: // functions are needed for operator << (_context_t) to work. michael@0: void json::flat(json & j) throw() { if (!j._flatten) j._flatten = j._context; } michael@0: void json::close(json & j) throw() { j.pop_context(); } michael@0: void json::object(json & j) throw() { j.push_context('{', '}'); } michael@0: void json::array(json & j) throw() { j.push_context('[', ']'); } michael@0: void json::item(json & j) throw() michael@0: { michael@0: while (j._context > j._contexts+1 && j._context[-1] != arr) michael@0: j.pop_context(); michael@0: } michael@0: michael@0: michael@0: json & json::operator << (json::string s) throw() michael@0: { michael@0: const char ctxt = _context[-1] == obj ? *_context == member ? seq : member : seq; michael@0: context(ctxt); michael@0: fprintf(_stream, "\"%s\"", s); michael@0: if (ctxt == member) fputc(' ', _stream); michael@0: michael@0: return *this; michael@0: } michael@0: michael@0: json & json::operator << (json::number f) throw() { context(seq); fprintf(_stream, "%g", f); return *this; } michael@0: json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; } michael@0: json & json::operator << (long unsigned d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; } michael@0: json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; } michael@0: json & json::operator << (json::_null_t) throw() { context(seq); fputs("null",_stream); return *this; } michael@0: michael@0: #endif michael@0: