xref: /freebsd/usr.bin/dtc/input_buffer.cc (revision 11b249f99e4d4891bd2a21ef796d40073ee15508)
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 "input_buffer.hh"
34 #include <ctype.h>
35 #include <limits.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <assert.h>
45 
46 #ifndef MAP_PREFAULT_READ
47 #define MAP_PREFAULT_READ 0
48 #endif
49 
50 namespace dtc
51 {
52 
53 void
54 input_buffer::skip_spaces()
55 {
56 	if (cursor >= size) { return; }
57 	if (cursor < 0) { return; }
58 	char c = buffer[cursor];
59 	while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\f')
60 	       || (c == '\v') || (c == '\r'))
61 	{
62 		cursor++;
63 		if (cursor > size)
64 		{
65 			c = '\0';
66 		}
67 		else
68 		{
69 			c = buffer[cursor];
70 		}
71 	}
72 }
73 
74 input_buffer
75 input_buffer::buffer_from_offset(int offset, int s)
76 {
77 	if (s == 0)
78 	{
79 		s = size - offset;
80 	}
81 	if (offset > size)
82 	{
83 		return input_buffer();
84 	}
85 	if (s > (size-offset))
86 	{
87 		return input_buffer();
88 	}
89 	return input_buffer(&buffer[offset], s);
90 }
91 
92 bool
93 input_buffer::consume(const char *str)
94 {
95 	int len = strlen(str);
96 	if (len > size - cursor)
97 	{
98 		return false;
99 	}
100 	else
101 	{
102 		for (int i=0 ; i<len ; ++i)
103 		{
104 			if (str[i] != buffer[cursor + i])
105 			{
106 				return false;
107 			}
108 		}
109 		cursor += len;
110 		return true;
111 	}
112 	return false;
113 }
114 
115 bool
116 input_buffer::consume_integer(unsigned long long &outInt)
117 {
118 	// The first character must be a digit.  Hex and octal strings
119 	// are prefixed by 0 and 0x, respectively.
120 	if (!isdigit((*this)[0]))
121 	{
122 		return false;
123 	}
124 	char *end=0;
125 	outInt = strtoull(&buffer[cursor], &end, 0);
126 	if (end == &buffer[cursor])
127 	{
128 		return false;
129 	}
130 	cursor = end - buffer;
131 	return true;
132 }
133 
134 bool
135 input_buffer::consume_hex_byte(uint8_t &outByte)
136 {
137 	if (!ishexdigit((*this)[0]) && !ishexdigit((*this)[1]))
138 	{
139 		return false;
140 	}
141 	outByte = (digittoint((*this)[0]) << 4) | digittoint((*this)[1]);
142 	cursor += 2;
143 	return true;
144 }
145 
146 input_buffer&
147 input_buffer::next_token()
148 {
149 	int start;
150 	do {
151 		start = cursor;
152 		skip_spaces();
153 		// Parse /* comments
154 		if ((*this)[0] == '/' && (*this)[1] == '*')
155 		{
156 			// eat the start of the comment
157 			++(*this);
158 			++(*this);
159 			do {
160 				// Find the ending * of */
161 				while ((**this != '\0') && (**this != '*'))
162 				{
163 					++(*this);
164 				}
165 				// Eat the *
166 				++(*this);
167 			} while ((**this != '\0') && (**this != '/'));
168 			// Eat the /
169 			++(*this);
170 		}
171 		// Parse // comments
172 		if (((*this)[0] == '/' && (*this)[1] == '/'))
173 		{
174 			// eat the start of the comment
175 			++(*this);
176 			++(*this);
177 			// Find the ending of the line
178 			while (**this != '\n')
179 			{
180 				++(*this);
181 			}
182 			// Eat the \n
183 			++(*this);
184 		}
185 	} while (start != cursor);
186 	return *this;
187 }
188 
189 void
190 input_buffer::parse_error(const char *msg)
191 {
192 	int line_count = 1;
193 	int line_start = 0;
194 	int line_end = cursor;
195 	for (int i=cursor ; i>0 ; --i)
196 	{
197 		if (buffer[i] == '\n')
198 		{
199 			line_count++;
200 			if (line_start == 0)
201 			{
202 				line_start = i+1;
203 			}
204 		}
205 	}
206 	for (int i=cursor+1 ; i<size ; ++i)
207 	{
208 		if (buffer[i] == '\n')
209 		{
210 			line_end = i;
211 			break;
212 		}
213 	}
214 	fprintf(stderr, "Error on line %d: %s\n", line_count, msg);
215 	fwrite(&buffer[line_start], line_end-line_start, 1, stderr);
216 	putc('\n', stderr);
217 	for (int i=0 ; i<(cursor-line_start) ; ++i)
218 	{
219 		char c = (buffer[i+line_start] == '\t') ? '\t' : ' ';
220 		putc(c, stderr);
221 	}
222 	putc('^', stderr);
223 	putc('\n', stderr);
224 }
225 void
226 input_buffer::dump()
227 {
228 	fprintf(stderr, "Current cursor: %d\n", cursor);
229 	fwrite(&buffer[cursor], size-cursor, 1, stderr);
230 }
231 
232 mmap_input_buffer::mmap_input_buffer(int fd) : input_buffer(0, 0)
233 {
234 	struct stat sb;
235 	if (fstat(fd, &sb))
236 	{
237 		perror("Failed to stat file");
238 	}
239 	size = sb.st_size;
240 	buffer = (const char*)mmap(0, size, PROT_READ, MAP_PRIVATE |
241 			MAP_PREFAULT_READ, fd, 0);
242 	if (buffer == MAP_FAILED)
243 	{
244 		perror("Failed to mmap file");
245 		exit(EXIT_FAILURE);
246 	}
247 }
248 
249 mmap_input_buffer::~mmap_input_buffer()
250 {
251 	if (buffer != 0)
252 	{
253 		munmap((void*)buffer, size);
254 	}
255 }
256 
257 stream_input_buffer::stream_input_buffer() : input_buffer(0, 0)
258 {
259 	int c;
260 	while ((c = fgetc(stdin)) != EOF)
261 	{
262 		b.push_back(c);
263 	}
264 	buffer = b.data();
265 	size = b.size();
266 }
267 
268 } // namespace dtc
269 
270