string.cc revision 245803
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: head/usr.bin/dtc/string.cc 245803 2013-01-22 17:49:51Z theraven $
31 */
32
33#include "string.hh"
34
35namespace
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 */
42struct 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 */
54struct 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 */
73struct 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
91namespace dtc
92{
93
94template<class T> string
95string::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
103string::string(input_buffer &s) : start((const char*)s), length(0)
104{
105	while(s[length] != '\0')
106	{
107		length++;
108	}
109}
110
111string
112string::parse_node_name(input_buffer &s)
113{
114	return parse<is_node_name_character>(s);
115}
116
117string
118string::parse_property_name(input_buffer &s)
119{
120	return parse<is_property_name_character>(s);
121}
122string
123string::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
145bool
146string::operator==(const string& other) const
147{
148	return (length == other.length) &&
149	       (memcmp(start, other.start, length) == 0);
150}
151
152bool
153string::operator==(const char *other) const
154{
155	return strncmp(other, start, length) == 0;
156}
157
158bool
159string::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
166void
167string::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
243void
244string::print(FILE *file)
245{
246	fwrite(start, length, 1, file);
247}
248
249void
250string::dump()
251{
252	print(stderr);
253}
254
255} // namespace dtc
256
257