xref: /freebsd/usr.bin/dtc/string.cc (revision af0dd31fc469cac25e441ff350ccda958ea5c8df)
1*af0dd31fSDavid Chisnall /*-
2*af0dd31fSDavid Chisnall  * Copyright (c) 2013 David Chisnall
3*af0dd31fSDavid Chisnall  * All rights reserved.
4*af0dd31fSDavid Chisnall  *
5*af0dd31fSDavid Chisnall  * This software was developed by SRI International and the University of
6*af0dd31fSDavid Chisnall  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7*af0dd31fSDavid Chisnall  * ("CTSRD"), as part of the DARPA CRASH research programme.
8*af0dd31fSDavid Chisnall  *
9*af0dd31fSDavid Chisnall  * Redistribution and use in source and binary forms, with or without
10*af0dd31fSDavid Chisnall  * modification, are permitted provided that the following conditions
11*af0dd31fSDavid Chisnall  * are met:
12*af0dd31fSDavid Chisnall  * 1. Redistributions of source code must retain the above copyright
13*af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer.
14*af0dd31fSDavid Chisnall  * 2. Redistributions in binary form must reproduce the above copyright
15*af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer in the
16*af0dd31fSDavid Chisnall  *    documentation and/or other materials provided with the distribution.
17*af0dd31fSDavid Chisnall  *
18*af0dd31fSDavid Chisnall  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*af0dd31fSDavid Chisnall  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*af0dd31fSDavid Chisnall  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*af0dd31fSDavid Chisnall  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*af0dd31fSDavid Chisnall  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*af0dd31fSDavid Chisnall  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*af0dd31fSDavid Chisnall  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*af0dd31fSDavid Chisnall  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*af0dd31fSDavid Chisnall  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*af0dd31fSDavid Chisnall  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*af0dd31fSDavid Chisnall  * SUCH DAMAGE.
29*af0dd31fSDavid Chisnall  *
30*af0dd31fSDavid Chisnall  * $FreeBSD$
31*af0dd31fSDavid Chisnall  */
32*af0dd31fSDavid Chisnall 
33*af0dd31fSDavid Chisnall #include "string.hh"
34*af0dd31fSDavid Chisnall 
35*af0dd31fSDavid Chisnall namespace
36*af0dd31fSDavid Chisnall {
37*af0dd31fSDavid Chisnall /**
38*af0dd31fSDavid Chisnall  * The source files are ASCII, so we provide a non-locale-aware version of
39*af0dd31fSDavid Chisnall  * isalpha.  This is a class so that it can be used with a template function
40*af0dd31fSDavid Chisnall  * for parsing strings.
41*af0dd31fSDavid Chisnall  */
42*af0dd31fSDavid Chisnall struct is_alpha
43*af0dd31fSDavid Chisnall {
44*af0dd31fSDavid Chisnall 	static inline bool check(const char c)
45*af0dd31fSDavid Chisnall 	{
46*af0dd31fSDavid Chisnall 		return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') &&
47*af0dd31fSDavid Chisnall 			(c <= 'Z'));
48*af0dd31fSDavid Chisnall 	}
49*af0dd31fSDavid Chisnall };
50*af0dd31fSDavid Chisnall /**
51*af0dd31fSDavid Chisnall  * Check whether a character is in the set allowed for node names.  This is a
52*af0dd31fSDavid Chisnall  * class so that it can be used with a template function for parsing strings.
53*af0dd31fSDavid Chisnall  */
54*af0dd31fSDavid Chisnall struct is_node_name_character
55*af0dd31fSDavid Chisnall {
56*af0dd31fSDavid Chisnall 	static inline bool check(const char c)
57*af0dd31fSDavid Chisnall 	{
58*af0dd31fSDavid Chisnall 		switch(c)
59*af0dd31fSDavid Chisnall 		{
60*af0dd31fSDavid Chisnall 			default:
61*af0dd31fSDavid Chisnall 				return false;
62*af0dd31fSDavid Chisnall 			case 'a'...'z': case 'A'...'Z': case '0'...'9':
63*af0dd31fSDavid Chisnall 			case ',': case '.': case '+': case '-':
64*af0dd31fSDavid Chisnall 			case '_':
65*af0dd31fSDavid Chisnall 				return true;
66*af0dd31fSDavid Chisnall 		}
67*af0dd31fSDavid Chisnall 	}
68*af0dd31fSDavid Chisnall };
69*af0dd31fSDavid Chisnall /**
70*af0dd31fSDavid Chisnall  * Check whether a character is in the set allowed for property names.  This is
71*af0dd31fSDavid Chisnall  * a class so that it can be used with a template function for parsing strings.
72*af0dd31fSDavid Chisnall  */
73*af0dd31fSDavid Chisnall struct is_property_name_character
74*af0dd31fSDavid Chisnall {
75*af0dd31fSDavid Chisnall 	static inline bool check(const char c)
76*af0dd31fSDavid Chisnall 	{
77*af0dd31fSDavid Chisnall 		switch(c)
78*af0dd31fSDavid Chisnall 		{
79*af0dd31fSDavid Chisnall 			default:
80*af0dd31fSDavid Chisnall 				return false;
81*af0dd31fSDavid Chisnall 			case 'a'...'z': case 'A'...'Z': case '0'...'9':
82*af0dd31fSDavid Chisnall 			case ',': case '.': case '+': case '-':
83*af0dd31fSDavid Chisnall 			case '_': case '#':
84*af0dd31fSDavid Chisnall 				return true;
85*af0dd31fSDavid Chisnall 		}
86*af0dd31fSDavid Chisnall 	}
87*af0dd31fSDavid Chisnall };
88*af0dd31fSDavid Chisnall 
89*af0dd31fSDavid Chisnall }
90*af0dd31fSDavid Chisnall 
91*af0dd31fSDavid Chisnall namespace dtc
92*af0dd31fSDavid Chisnall {
93*af0dd31fSDavid Chisnall 
94*af0dd31fSDavid Chisnall template<class T> string
95*af0dd31fSDavid Chisnall string::parse(input_buffer &s)
96*af0dd31fSDavid Chisnall {
97*af0dd31fSDavid Chisnall 	const char *start = s;
98*af0dd31fSDavid Chisnall 	int l=0;
99*af0dd31fSDavid Chisnall 	while (T::check(*s)) { l++; ++s; }
100*af0dd31fSDavid Chisnall 	return string(start, l);
101*af0dd31fSDavid Chisnall }
102*af0dd31fSDavid Chisnall 
103*af0dd31fSDavid Chisnall string::string(input_buffer &s) : start((const char*)s), length(0)
104*af0dd31fSDavid Chisnall {
105*af0dd31fSDavid Chisnall 	while(s[length] != '\0')
106*af0dd31fSDavid Chisnall 	{
107*af0dd31fSDavid Chisnall 		length++;
108*af0dd31fSDavid Chisnall 	}
109*af0dd31fSDavid Chisnall }
110*af0dd31fSDavid Chisnall 
111*af0dd31fSDavid Chisnall string
112*af0dd31fSDavid Chisnall string::parse_node_name(input_buffer &s)
113*af0dd31fSDavid Chisnall {
114*af0dd31fSDavid Chisnall 	return parse<is_node_name_character>(s);
115*af0dd31fSDavid Chisnall }
116*af0dd31fSDavid Chisnall 
117*af0dd31fSDavid Chisnall string
118*af0dd31fSDavid Chisnall string::parse_property_name(input_buffer &s)
119*af0dd31fSDavid Chisnall {
120*af0dd31fSDavid Chisnall 	return parse<is_property_name_character>(s);
121*af0dd31fSDavid Chisnall }
122*af0dd31fSDavid Chisnall string
123*af0dd31fSDavid Chisnall string::parse_node_or_property_name(input_buffer &s, bool &is_property)
124*af0dd31fSDavid Chisnall {
125*af0dd31fSDavid Chisnall 	if (is_property)
126*af0dd31fSDavid Chisnall 	{
127*af0dd31fSDavid Chisnall 		return parse_property_name(s);
128*af0dd31fSDavid Chisnall 	}
129*af0dd31fSDavid Chisnall 	const char *start = s;
130*af0dd31fSDavid Chisnall 	int l=0;
131*af0dd31fSDavid Chisnall 	while (is_node_name_character::check(*s))
132*af0dd31fSDavid Chisnall 	{
133*af0dd31fSDavid Chisnall 		l++;
134*af0dd31fSDavid Chisnall 		++s;
135*af0dd31fSDavid Chisnall 	}
136*af0dd31fSDavid Chisnall 	while (is_property_name_character::check(*s))
137*af0dd31fSDavid Chisnall 	{
138*af0dd31fSDavid Chisnall 		l++;
139*af0dd31fSDavid Chisnall 		++s;
140*af0dd31fSDavid Chisnall 		is_property = true;
141*af0dd31fSDavid Chisnall 	}
142*af0dd31fSDavid Chisnall 	return string(start, l);
143*af0dd31fSDavid Chisnall }
144*af0dd31fSDavid Chisnall 
145*af0dd31fSDavid Chisnall bool
146*af0dd31fSDavid Chisnall string::operator==(const string& other) const
147*af0dd31fSDavid Chisnall {
148*af0dd31fSDavid Chisnall 	return (length == other.length) &&
149*af0dd31fSDavid Chisnall 	       (memcmp(start, other.start, length) == 0);
150*af0dd31fSDavid Chisnall }
151*af0dd31fSDavid Chisnall 
152*af0dd31fSDavid Chisnall bool
153*af0dd31fSDavid Chisnall string::operator==(const char *other) const
154*af0dd31fSDavid Chisnall {
155*af0dd31fSDavid Chisnall 	return strncmp(other, start, length) == 0;
156*af0dd31fSDavid Chisnall }
157*af0dd31fSDavid Chisnall 
158*af0dd31fSDavid Chisnall bool
159*af0dd31fSDavid Chisnall string::operator<(const string& other) const
160*af0dd31fSDavid Chisnall {
161*af0dd31fSDavid Chisnall 	if (length < other.length) { return true; }
162*af0dd31fSDavid Chisnall 	if (length > other.length) { return false; }
163*af0dd31fSDavid Chisnall 	return memcmp(start, other.start, length) < 0;
164*af0dd31fSDavid Chisnall }
165*af0dd31fSDavid Chisnall 
166*af0dd31fSDavid Chisnall void
167*af0dd31fSDavid Chisnall string::push_to_buffer(byte_buffer &buffer, bool escapes)
168*af0dd31fSDavid Chisnall {
169*af0dd31fSDavid Chisnall 	for (int i=0 ; i<length ; ++i)
170*af0dd31fSDavid Chisnall 	{
171*af0dd31fSDavid Chisnall 		uint8_t c = start[i];
172*af0dd31fSDavid Chisnall 		if (escapes && c == '\\' && i+1 < length)
173*af0dd31fSDavid Chisnall 		{
174*af0dd31fSDavid Chisnall 			c = start[++i];
175*af0dd31fSDavid Chisnall 			switch (c)
176*af0dd31fSDavid Chisnall 			{
177*af0dd31fSDavid Chisnall 				// For now, we just ignore invalid escape sequences.
178*af0dd31fSDavid Chisnall 				default:
179*af0dd31fSDavid Chisnall 				case '"':
180*af0dd31fSDavid Chisnall 				case '\'':
181*af0dd31fSDavid Chisnall 				case '\\':
182*af0dd31fSDavid Chisnall 					break;
183*af0dd31fSDavid Chisnall 				case 'a':
184*af0dd31fSDavid Chisnall 					c = '\a';
185*af0dd31fSDavid Chisnall 					break;
186*af0dd31fSDavid Chisnall 				case 'b':
187*af0dd31fSDavid Chisnall 					c = '\b';
188*af0dd31fSDavid Chisnall 					break;
189*af0dd31fSDavid Chisnall 				case 't':
190*af0dd31fSDavid Chisnall 					c = '\t';
191*af0dd31fSDavid Chisnall 					break;
192*af0dd31fSDavid Chisnall 				case 'n':
193*af0dd31fSDavid Chisnall 					c = '\n';
194*af0dd31fSDavid Chisnall 					break;
195*af0dd31fSDavid Chisnall 				case 'v':
196*af0dd31fSDavid Chisnall 					c = '\v';
197*af0dd31fSDavid Chisnall 					break;
198*af0dd31fSDavid Chisnall 				case 'f':
199*af0dd31fSDavid Chisnall 					c = '\f';
200*af0dd31fSDavid Chisnall 					break;
201*af0dd31fSDavid Chisnall 				case 'r':
202*af0dd31fSDavid Chisnall 					c = '\r';
203*af0dd31fSDavid Chisnall 					break;
204*af0dd31fSDavid Chisnall 				case '0'...'7':
205*af0dd31fSDavid Chisnall 				{
206*af0dd31fSDavid Chisnall 					int v = digittoint(c);
207*af0dd31fSDavid Chisnall 					if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0')
208*af0dd31fSDavid Chisnall 					{
209*af0dd31fSDavid Chisnall 						v <<= 3;
210*af0dd31fSDavid Chisnall 						v |= digittoint(start[i+1]);
211*af0dd31fSDavid Chisnall 						i++;
212*af0dd31fSDavid Chisnall 						if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0')
213*af0dd31fSDavid Chisnall 						{
214*af0dd31fSDavid Chisnall 							v <<= 3;
215*af0dd31fSDavid Chisnall 							v |= digittoint(start[i+1]);
216*af0dd31fSDavid Chisnall 						}
217*af0dd31fSDavid Chisnall 					}
218*af0dd31fSDavid Chisnall 					c = (uint8_t)v;
219*af0dd31fSDavid Chisnall 					break;
220*af0dd31fSDavid Chisnall 				}
221*af0dd31fSDavid Chisnall 				case 'x':
222*af0dd31fSDavid Chisnall 				{
223*af0dd31fSDavid Chisnall 					++i;
224*af0dd31fSDavid Chisnall 					if (i >= length)
225*af0dd31fSDavid Chisnall 					{
226*af0dd31fSDavid Chisnall 						break;
227*af0dd31fSDavid Chisnall 					}
228*af0dd31fSDavid Chisnall 					int v = digittoint(start[i]);
229*af0dd31fSDavid Chisnall 					if (i+1 < length && ishexdigit(start[i+1]))
230*af0dd31fSDavid Chisnall 					{
231*af0dd31fSDavid Chisnall 						v <<= 4;
232*af0dd31fSDavid Chisnall 						v |= digittoint(start[++i]);
233*af0dd31fSDavid Chisnall 					}
234*af0dd31fSDavid Chisnall 					c = (uint8_t)v;
235*af0dd31fSDavid Chisnall 					break;
236*af0dd31fSDavid Chisnall 				}
237*af0dd31fSDavid Chisnall 			}
238*af0dd31fSDavid Chisnall 		}
239*af0dd31fSDavid Chisnall 		buffer.push_back(c);
240*af0dd31fSDavid Chisnall 	}
241*af0dd31fSDavid Chisnall }
242*af0dd31fSDavid Chisnall 
243*af0dd31fSDavid Chisnall void
244*af0dd31fSDavid Chisnall string::print(FILE *file)
245*af0dd31fSDavid Chisnall {
246*af0dd31fSDavid Chisnall 	fwrite(start, length, 1, file);
247*af0dd31fSDavid Chisnall }
248*af0dd31fSDavid Chisnall 
249*af0dd31fSDavid Chisnall void
250*af0dd31fSDavid Chisnall string::dump()
251*af0dd31fSDavid Chisnall {
252*af0dd31fSDavid Chisnall 	print(stderr);
253*af0dd31fSDavid Chisnall }
254*af0dd31fSDavid Chisnall 
255*af0dd31fSDavid Chisnall } // namespace dtc
256*af0dd31fSDavid Chisnall 
257