1 : /* GRAPHITE2 LICENSING
2 :
3 : Copyright 2010, SIL International
4 : All rights reserved.
5 :
6 : This library is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU Lesser General Public License as published
8 : by the Free Software Foundation; either version 2.1 of License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should also have received a copy of the GNU Lesser General Public
17 : License along with this library in the file named "LICENSE".
18 : If not, write to the Free Software Foundation, 51 Franklin Street,
19 : Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20 : internet at http://www.fsf.org/licenses/lgpl.html.
21 :
22 : Alternatively, the contents of this file may be used under the terms of the
23 : Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 : License, as published by the Free Software Foundation, either version 2
25 : of the License or (at your option) any later version.
26 : */
27 : // JSON debug logging
28 : // Author: Tim Eves
29 :
30 : #include <stdio.h>
31 : #include "inc/json.h"
32 :
33 : using namespace graphite2;
34 :
35 : namespace
36 : {
37 : enum
38 : {
39 : seq = ',',
40 : obj='}', member=':', empty_obj='{',
41 : arr=']', empty_arr='['
42 : };
43 : }
44 :
45 : const json::_null_t json::null = {};
46 :
47 : inline
48 0 : void json::context(const char current) throw()
49 : {
50 0 : fprintf(_stream, "%c", *_context);
51 0 : indent();
52 0 : *_context = current;
53 0 : }
54 :
55 :
56 0 : void json::indent(const int d) throw()
57 : {
58 0 : if (*_context == member)
59 0 : fputc(' ', _stream);
60 : else
61 0 : fprintf(_stream, _flatten && _flatten < _context ? " " : "\n%*s", 4*int(_context - _contexts + d), "");
62 0 : }
63 :
64 :
65 : inline
66 0 : void json::push_context(const char prefix, const char suffix) throw()
67 : {
68 0 : assert(_context - _contexts < std::ptrdiff_t(sizeof _contexts));
69 :
70 0 : if (_context == _contexts)
71 0 : *_context = suffix;
72 : else
73 0 : context(suffix);
74 0 : *++_context = prefix;
75 0 : }
76 :
77 :
78 0 : void json::pop_context() throw()
79 : {
80 0 : assert(_context > _contexts);
81 :
82 0 : if (*_context == seq) indent(-1);
83 0 : else fputc(*_context, _stream);
84 :
85 0 : fputc(*--_context, _stream);
86 0 : if (_context == _contexts) fputc('\n', _stream);
87 0 : fflush(_stream);
88 :
89 0 : if (_flatten >= _context) _flatten = 0;
90 0 : *_context = seq;
91 0 : }
92 :
93 :
94 : // These four functions cannot be inlined as pointers to these
95 : // functions are needed for operator << (_context_t) to work.
96 0 : void json::flat(json & j) throw() { if (!j._flatten) j._flatten = j._context; }
97 0 : void json::close(json & j) throw() { j.pop_context(); }
98 0 : void json::object(json & j) throw() { j.push_context('{', '}'); }
99 0 : void json::array(json & j) throw() { j.push_context('[', ']'); }
100 0 : void json::item(json & j) throw()
101 : {
102 0 : while (j._context > j._contexts+1 && j._context[-1] != arr)
103 0 : j.pop_context();
104 0 : }
105 :
106 :
107 0 : json & json::operator << (json::string s) throw()
108 : {
109 0 : const char ctxt = _context[-1] == obj ? *_context == member ? seq : member : seq;
110 0 : context(ctxt);
111 0 : fprintf(_stream, "\"%s\"", s);
112 0 : if (ctxt == member) fputc(' ', _stream);
113 :
114 0 : return *this;
115 : }
116 :
117 0 : json & json::operator << (json::number f) throw() { context(seq); fprintf(_stream, "%g", f); return *this; }
118 0 : json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
119 0 : json & json::operator << (long unsigned d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
120 0 : json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
121 0 : json & json::operator << (json::_null_t) throw() { context(seq); fputs("null",_stream); return *this; }
122 :
|