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