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