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