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