]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/dtc/string.cc
Import new (BSDL) device tree compiler. Now built by default, so that it can't
[FreeBSD/FreeBSD.git] / usr.bin / dtc / string.cc
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