1 /*
2  Copyright (c) 2018, MIPI Alliance, Inc.
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions
7  are met:
8 
9  * Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 
12  * Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in
14    the documentation and/or other materials provided with the
15    distribution.
16 
17  * Neither the name of the copyright holder nor the names of its
18    contributors may be used to endorse or promote products derived
19    from this software without specific prior written permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 /*
35  * Contributors:
36  * Norbert Schulz (Intel Corporation) - Initial API and implementation
37  */
38 
39 #ifndef MIPI_SYST_PRINTF_H_included
40 #define MIPI_SYST_PRINTF_H_included
41 
42 #include <string>
43 #include <stdint.h>
44 #include <vector>
45 
46 #include "mipi_syst_printer.h"
47 
48 MIPI_SYST_NAMESPACE_BEGIN
49 
50 /// Finite state machine parser to parse printf format strings used in catalog
51 /// and printf messages. It detects if we got a string embedded with formats like
52 /// this:
53 ///            %[flags][width][.precision][length]specifier
54 ///
55 ///    flags:      - + (space) # 0
56 ///    width:      (number)  *
57 ///    precision:  .(number) .*
58 ///    length:     hh h l ll j z t L
59 ///    specifier:  d i u o x X f F e E g G a A c s p n
60 ///
61 /// details: http://www.cplusplus.com/reference/cstdio/printf/
62 ///
63 class fmtscanner
64 {
65 public:
fmtscanner(bool is32Bit)66 	fmtscanner(bool is32Bit) :
67 		SIZEOF_PTR(is32Bit ? 4 : 8),
68 		SIZEOF_INT(4),
69 		SIZEOF_LONG(is32Bit ? 4 : 8),
70 		SIZEOF_SIZEOF(is32Bit ? 4 : 8),
71 		SIZEOF_LONGLONG(8)
72 	{}
73 
~fmtscanner()74 	~fmtscanner() {}
75 
76 	/// argument variants
77 	//
78 	enum ArgType {
79 		INTEGER,     ///< 32/64 bit integer
80 		POINTER,     ///< 32/64 bit pointer
81 		DOUBLE,      ///< floating point number
82 		TEXT,        ///< text portion in format
83 		STRING,      ///< pointer to string %s
84 		PERCENT_N,   ///< the odd %n format
85 		STAR,        ///< an int from a %* arg
86 		UNKNOWN      ///< invalid format
87 	};
88 
89 	enum Result {
90 		OK = 0,
91 		UNKNOWN_FORMAT = (1 << 1),
92 		INCOMPLETE_FORMAT = (1 << 2)
93 	};
94 
95 	/// Helper class to store information for one printf format fragment
96 	///
97 	class ArgFragment {
98 	public:
99 		ArgFragment(ArgType type, size_t size, const std::string& text);
100 
type()101 		ArgType            type() const { return _type; }
size()102 		size_t             size() const { return _size; }
text()103 		const std::string& text() const { return _text; }
104 
105 	private:
106 		ArgType _type;               ///< arg type
107 		size_t _size;                ///< arg buffer space usage
108 		std::string _text;           ///< argument string fragment
109 	};
110 
111 	typedef std::vector<ArgFragment> Args;
112 
113 protected:
114 
115 	/// Finite state machine states of the argument parser
116 	///
117 	enum FmtScanState {
118 		START,
119 		PLAINTEXT,
120 		PERCENT,
121 		FLAGS,
122 		WIDTH, WIDTH_NUMBER,
123 		PRECISION_DOT, PRECISION_VAL, PRECISION_NUMBER,
124 		MODIFIER,
125 		MODIFIER_HALF,
126 		MODIFIER_LONG,
127 		SPECIFIER
128 	};
129 
130 	/// Format modifier types
131 	///
132 	enum Modifier {
133 		MOD_NONE, MOD_HH, MOD_H, MOD_L, MOD_LL, MOD_J, MOD_Z, MOD_T, MOD_LD
134 	};
135 
136 public:
137 	/// Parse a printf argument string into a vector of argument fragments
138 	/// @eturn OK if no error, or bitmask of errors from Result enumeration.
139 	///
140 	uint32_t parse(const std::string& fmt, Args& args);
141 
142 	const uint32_t SIZEOF_PTR;
143 	const uint32_t SIZEOF_INT;
144 	const uint32_t SIZEOF_LONG;
145 	const uint32_t SIZEOF_SIZEOF;
146 	const uint32_t SIZEOF_LONGLONG;
147 };
148 
149 
150 /// Printf style formatter for events
151 ///
152 /// This class does printf style formatting using a format string
153 /// and memory buffer for the printf arguments. The code assumes
154 /// that all arguments are stored in the buffer without any padding
155 /// bytes. Strings are embedded as byte sequences into the buffer,
156 /// including their terminating null byte.
157 ///
158 /// Here is an example of how the buffer is expected
159 /// to be setup for the given printf call:
160 ///
161 ///  printf("the %s jumped over the %s, %d times", "cow", "moon", 2);
162 ///
163 /// Argument buffer layout, following the format string:
164 ///
165 /// +-----------------------------------------------------------------+
166 /// | 'c' | 'o' | 'w' | 0 | 'm' | 'o' | 'o' | 'n' | 0 | 2 | 0 | 0 | 0 |
167 /// +-----------------------------------------------------------------+
168 ///   |<---    P1   --->|    |<---      P2       -->|   |<--- P3 -->|
169 ///
170 /// It will print "the cow jumped over the moon, 2 times".
171 ///
172 class msgprintf
173 {
174 public:
msgprintf(bool is32bit)175 	msgprintf(bool is32bit) :
176 		_scanner(is32bit)
177 	{}
178 
179 	///  Initialize a printf formatter based on fmt and argument buffer
180 	///
181 	/// @param fmt a C99 language compliant printf format string
182 	/// @param args the argument buffer
183 	/// @param size number of bytes in argument buffer
184 	/// @param result ougoing string result or error message
185 	///
186 	/// @ return true if formatting succeeded, false if not.
187 	///
188 	bool format(const std::string& fmt,
189 		const void * args, uint32_t size,
190 		std::string& result);
191 
192 private:
193 
194 	fmtscanner _scanner;
195 	fmtscanner::Args _args;
196 
197 	msgprintf(const msgprintf&) = delete;
198 	msgprintf operator=(const msgprintf&) = delete;
199 };
200 
201 MIPI_SYST_NAMESPACE_END
202 
203 #endif // MIPI_SYST_PRINTER_H_included
204