xref: /src/usr.bin/dtc/input_buffer.cc (revision 8d9c80995077820e5a4c361c739eed618513847f)
1af0dd31fSDavid Chisnall /*-
2af0dd31fSDavid Chisnall  * Copyright (c) 2013 David Chisnall
3af0dd31fSDavid Chisnall  * All rights reserved.
4af0dd31fSDavid Chisnall  *
5af0dd31fSDavid Chisnall  * This software was developed by SRI International and the University of
6af0dd31fSDavid Chisnall  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7af0dd31fSDavid Chisnall  * ("CTSRD"), as part of the DARPA CRASH research programme.
8af0dd31fSDavid Chisnall  *
9af0dd31fSDavid Chisnall  * Redistribution and use in source and binary forms, with or without
10af0dd31fSDavid Chisnall  * modification, are permitted provided that the following conditions
11af0dd31fSDavid Chisnall  * are met:
12af0dd31fSDavid Chisnall  * 1. Redistributions of source code must retain the above copyright
13af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer.
14af0dd31fSDavid Chisnall  * 2. Redistributions in binary form must reproduce the above copyright
15af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer in the
16af0dd31fSDavid Chisnall  *    documentation and/or other materials provided with the distribution.
17af0dd31fSDavid Chisnall  *
18af0dd31fSDavid Chisnall  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19af0dd31fSDavid Chisnall  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20af0dd31fSDavid Chisnall  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21af0dd31fSDavid Chisnall  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22af0dd31fSDavid Chisnall  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23af0dd31fSDavid Chisnall  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24af0dd31fSDavid Chisnall  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25af0dd31fSDavid Chisnall  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26af0dd31fSDavid Chisnall  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27af0dd31fSDavid Chisnall  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28af0dd31fSDavid Chisnall  * SUCH DAMAGE.
29af0dd31fSDavid Chisnall  *
30af0dd31fSDavid Chisnall  * $FreeBSD$
31af0dd31fSDavid Chisnall  */
32af0dd31fSDavid Chisnall 
33af0dd31fSDavid Chisnall #include "input_buffer.hh"
34009f7b42SDavid Chisnall #include <ctype.h>
35009f7b42SDavid Chisnall #include <limits.h>
36af0dd31fSDavid Chisnall #include <stdint.h>
37009f7b42SDavid Chisnall #include <stdio.h>
38009f7b42SDavid Chisnall #include <stdlib.h>
39009f7b42SDavid Chisnall #include <string.h>
40009f7b42SDavid Chisnall 
41af0dd31fSDavid Chisnall 
42af0dd31fSDavid Chisnall #include <sys/stat.h>
43af0dd31fSDavid Chisnall #include <sys/mman.h>
44af0dd31fSDavid Chisnall #include <assert.h>
45af0dd31fSDavid Chisnall 
46eaef137cSUlrich Spörlein #ifndef MAP_PREFAULT_READ
47eaef137cSUlrich Spörlein #define MAP_PREFAULT_READ 0
48eaef137cSUlrich Spörlein #endif
49eaef137cSUlrich Spörlein 
50af0dd31fSDavid Chisnall namespace dtc
51af0dd31fSDavid Chisnall {
52af0dd31fSDavid Chisnall 
53af0dd31fSDavid Chisnall void
54af0dd31fSDavid Chisnall input_buffer::skip_spaces()
55af0dd31fSDavid Chisnall {
56af0dd31fSDavid Chisnall 	if (cursor >= size) { return; }
57af0dd31fSDavid Chisnall 	if (cursor < 0) { return; }
58af0dd31fSDavid Chisnall 	char c = buffer[cursor];
59af0dd31fSDavid Chisnall 	while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\f')
60af0dd31fSDavid Chisnall 	       || (c == '\v') || (c == '\r'))
61af0dd31fSDavid Chisnall 	{
62af0dd31fSDavid Chisnall 		cursor++;
63af0dd31fSDavid Chisnall 		if (cursor > size)
64af0dd31fSDavid Chisnall 		{
65af0dd31fSDavid Chisnall 			c = '\0';
66af0dd31fSDavid Chisnall 		}
67af0dd31fSDavid Chisnall 		else
68af0dd31fSDavid Chisnall 		{
69af0dd31fSDavid Chisnall 			c = buffer[cursor];
70af0dd31fSDavid Chisnall 		}
71af0dd31fSDavid Chisnall 	}
72af0dd31fSDavid Chisnall }
73af0dd31fSDavid Chisnall 
74af0dd31fSDavid Chisnall input_buffer
75af0dd31fSDavid Chisnall input_buffer::buffer_from_offset(int offset, int s)
76af0dd31fSDavid Chisnall {
77af0dd31fSDavid Chisnall 	if (s == 0)
78af0dd31fSDavid Chisnall 	{
79af0dd31fSDavid Chisnall 		s = size - offset;
80af0dd31fSDavid Chisnall 	}
81af0dd31fSDavid Chisnall 	if (offset > size)
82af0dd31fSDavid Chisnall 	{
83af0dd31fSDavid Chisnall 		return input_buffer();
84af0dd31fSDavid Chisnall 	}
85af0dd31fSDavid Chisnall 	if (s > (size-offset))
86af0dd31fSDavid Chisnall 	{
87af0dd31fSDavid Chisnall 		return input_buffer();
88af0dd31fSDavid Chisnall 	}
89af0dd31fSDavid Chisnall 	return input_buffer(&buffer[offset], s);
90af0dd31fSDavid Chisnall }
91af0dd31fSDavid Chisnall 
92af0dd31fSDavid Chisnall bool
93af0dd31fSDavid Chisnall input_buffer::consume(const char *str)
94af0dd31fSDavid Chisnall {
95af0dd31fSDavid Chisnall 	int len = strlen(str);
96af0dd31fSDavid Chisnall 	if (len > size - cursor)
97af0dd31fSDavid Chisnall 	{
98af0dd31fSDavid Chisnall 		return false;
99af0dd31fSDavid Chisnall 	}
100af0dd31fSDavid Chisnall 	else
101af0dd31fSDavid Chisnall 	{
102af0dd31fSDavid Chisnall 		for (int i=0 ; i<len ; ++i)
103af0dd31fSDavid Chisnall 		{
104af0dd31fSDavid Chisnall 			if (str[i] != buffer[cursor + i])
105af0dd31fSDavid Chisnall 			{
106af0dd31fSDavid Chisnall 				return false;
107af0dd31fSDavid Chisnall 			}
108af0dd31fSDavid Chisnall 		}
109af0dd31fSDavid Chisnall 		cursor += len;
110af0dd31fSDavid Chisnall 		return true;
111af0dd31fSDavid Chisnall 	}
112af0dd31fSDavid Chisnall 	return false;
113af0dd31fSDavid Chisnall }
114af0dd31fSDavid Chisnall 
115af0dd31fSDavid Chisnall bool
116af0dd31fSDavid Chisnall input_buffer::consume_integer(long long &outInt)
117af0dd31fSDavid Chisnall {
118af0dd31fSDavid Chisnall 	// The first character must be a digit.  Hex and octal strings
119af0dd31fSDavid Chisnall 	// are prefixed by 0 and 0x, respectively.
120af0dd31fSDavid Chisnall 	if (!isdigit((*this)[0]))
121af0dd31fSDavid Chisnall 	{
122af0dd31fSDavid Chisnall 		return false;
123af0dd31fSDavid Chisnall 	}
124af0dd31fSDavid Chisnall 	char *end=0;
125af0dd31fSDavid Chisnall 	outInt = strtoll(&buffer[cursor], &end, 0);
126af0dd31fSDavid Chisnall 	if (end == &buffer[cursor])
127af0dd31fSDavid Chisnall 	{
128af0dd31fSDavid Chisnall 		return false;
129af0dd31fSDavid Chisnall 	}
130af0dd31fSDavid Chisnall 	cursor = end - buffer;
131af0dd31fSDavid Chisnall 	return true;
132af0dd31fSDavid Chisnall }
133af0dd31fSDavid Chisnall 
134af0dd31fSDavid Chisnall bool
135af0dd31fSDavid Chisnall input_buffer::consume_hex_byte(uint8_t &outByte)
136af0dd31fSDavid Chisnall {
137af0dd31fSDavid Chisnall 	if (!ishexdigit((*this)[0]) && !ishexdigit((*this)[1]))
138af0dd31fSDavid Chisnall 	{
139af0dd31fSDavid Chisnall 		return false;
140af0dd31fSDavid Chisnall 	}
141af0dd31fSDavid Chisnall 	outByte = (digittoint((*this)[0]) << 4) | digittoint((*this)[1]);
142af0dd31fSDavid Chisnall 	cursor += 2;
143af0dd31fSDavid Chisnall 	return true;
144af0dd31fSDavid Chisnall }
145af0dd31fSDavid Chisnall 
146af0dd31fSDavid Chisnall input_buffer&
147af0dd31fSDavid Chisnall input_buffer::next_token()
148af0dd31fSDavid Chisnall {
149af0dd31fSDavid Chisnall 	int start;
150af0dd31fSDavid Chisnall 	do {
151af0dd31fSDavid Chisnall 		start = cursor;
152af0dd31fSDavid Chisnall 		skip_spaces();
153af0dd31fSDavid Chisnall 		// Parse /* comments
154af0dd31fSDavid Chisnall 		if (((*this)[0] == '/') && ((*this)[1] == '*'))
155af0dd31fSDavid Chisnall 		{
156af0dd31fSDavid Chisnall 			// eat the start of the comment
157af0dd31fSDavid Chisnall 			++(*this);
158af0dd31fSDavid Chisnall 			++(*this);
159af0dd31fSDavid Chisnall 			do {
160af0dd31fSDavid Chisnall 				// Find the ending * of */
161af0dd31fSDavid Chisnall 				while ((**this != '\0') && (**this != '*'))
162af0dd31fSDavid Chisnall 				{
163af0dd31fSDavid Chisnall 					++(*this);
164af0dd31fSDavid Chisnall 				}
165af0dd31fSDavid Chisnall 				// Eat the *
166af0dd31fSDavid Chisnall 				++(*this);
167af0dd31fSDavid Chisnall 			} while ((**this != '\0') && (**this != '/'));
168af0dd31fSDavid Chisnall 			// Eat the /
169af0dd31fSDavid Chisnall 			++(*this);
170af0dd31fSDavid Chisnall 		}
171af0dd31fSDavid Chisnall 		// Parse // comments
172af0dd31fSDavid Chisnall 		if (((*this)[0] == '/') && ((*this)[1] == '/'))
173af0dd31fSDavid Chisnall 		{
174af0dd31fSDavid Chisnall 			// eat the start of the comment
175af0dd31fSDavid Chisnall 			++(*this);
176af0dd31fSDavid Chisnall 			++(*this);
177af0dd31fSDavid Chisnall 			// Find the ending * of */
178af0dd31fSDavid Chisnall 			while (**this != '\n')
179af0dd31fSDavid Chisnall 			{
180af0dd31fSDavid Chisnall 				++(*this);
181af0dd31fSDavid Chisnall 			}
182af0dd31fSDavid Chisnall 			// Eat the \n
183af0dd31fSDavid Chisnall 			++(*this);
184af0dd31fSDavid Chisnall 		}
185af0dd31fSDavid Chisnall 	} while (start != cursor);
186af0dd31fSDavid Chisnall 	return *this;
187af0dd31fSDavid Chisnall }
188af0dd31fSDavid Chisnall 
189af0dd31fSDavid Chisnall void
190af0dd31fSDavid Chisnall input_buffer::parse_error(const char *msg)
191af0dd31fSDavid Chisnall {
192af0dd31fSDavid Chisnall 	int line_count = 1;
193af0dd31fSDavid Chisnall 	int line_start = 0;
194af0dd31fSDavid Chisnall 	int line_end = cursor;
195af0dd31fSDavid Chisnall 	for (int i=cursor ; i>0 ; --i)
196af0dd31fSDavid Chisnall 	{
197af0dd31fSDavid Chisnall 		if (buffer[i] == '\n')
198af0dd31fSDavid Chisnall 		{
199af0dd31fSDavid Chisnall 			line_count++;
200af0dd31fSDavid Chisnall 			if (line_start == 0)
201af0dd31fSDavid Chisnall 			{
202af0dd31fSDavid Chisnall 				line_start = i+1;
203af0dd31fSDavid Chisnall 			}
204af0dd31fSDavid Chisnall 		}
205af0dd31fSDavid Chisnall 	}
206af0dd31fSDavid Chisnall 	for (int i=cursor+1 ; i<size ; ++i)
207af0dd31fSDavid Chisnall 	{
208af0dd31fSDavid Chisnall 		if (buffer[i] == '\n')
209af0dd31fSDavid Chisnall 		{
210af0dd31fSDavid Chisnall 			line_end = i;
211af0dd31fSDavid Chisnall 			break;
212af0dd31fSDavid Chisnall 		}
213af0dd31fSDavid Chisnall 	}
214af0dd31fSDavid Chisnall 	fprintf(stderr, "Error on line %d: %s\n", line_count, msg);
215af0dd31fSDavid Chisnall 	fwrite(&buffer[line_start], line_end-line_start, 1, stderr);
216af0dd31fSDavid Chisnall 	putc('\n', stderr);
217af0dd31fSDavid Chisnall 	for (int i=0 ; i<(cursor-line_start) ; ++i)
218af0dd31fSDavid Chisnall 	{
2198d9c8099SDavid Chisnall 		char c = (buffer[i+line_start] == '\t') ? '\t' : ' ';
2208d9c8099SDavid Chisnall 		putc(c, stderr);
221af0dd31fSDavid Chisnall 	}
222af0dd31fSDavid Chisnall 	putc('^', stderr);
223af0dd31fSDavid Chisnall 	putc('\n', stderr);
224af0dd31fSDavid Chisnall }
225af0dd31fSDavid Chisnall void
226af0dd31fSDavid Chisnall input_buffer::dump()
227af0dd31fSDavid Chisnall {
228af0dd31fSDavid Chisnall 	fprintf(stderr, "Current cursor: %d\n", cursor);
229af0dd31fSDavid Chisnall 	fwrite(&buffer[cursor], size-cursor, 1, stderr);
230af0dd31fSDavid Chisnall }
231af0dd31fSDavid Chisnall 
232af0dd31fSDavid Chisnall mmap_input_buffer::mmap_input_buffer(int fd) : input_buffer(0, 0)
233af0dd31fSDavid Chisnall {
234af0dd31fSDavid Chisnall 	struct stat sb;
235af0dd31fSDavid Chisnall 	if (fstat(fd, &sb))
236af0dd31fSDavid Chisnall 	{
237af0dd31fSDavid Chisnall 		perror("Failed to stat file");
238af0dd31fSDavid Chisnall 	}
239af0dd31fSDavid Chisnall 	size = sb.st_size;
240af0dd31fSDavid Chisnall 	buffer = (const char*)mmap(0, size, PROT_READ,
241af0dd31fSDavid Chisnall 		MAP_PREFAULT_READ, fd, 0);
242af0dd31fSDavid Chisnall 	if (buffer == 0)
243af0dd31fSDavid Chisnall 	{
244af0dd31fSDavid Chisnall 		perror("Failed to mmap file");
245af0dd31fSDavid Chisnall 	}
246af0dd31fSDavid Chisnall }
247af0dd31fSDavid Chisnall 
248af0dd31fSDavid Chisnall mmap_input_buffer::~mmap_input_buffer()
249af0dd31fSDavid Chisnall {
250af0dd31fSDavid Chisnall 	if (buffer != 0)
251af0dd31fSDavid Chisnall 	{
252af0dd31fSDavid Chisnall 		munmap((void*)buffer, size);
253af0dd31fSDavid Chisnall 	}
254af0dd31fSDavid Chisnall }
255af0dd31fSDavid Chisnall 
256af0dd31fSDavid Chisnall stream_input_buffer::stream_input_buffer() : input_buffer(0, 0)
257af0dd31fSDavid Chisnall {
258af0dd31fSDavid Chisnall 	int c;
259af0dd31fSDavid Chisnall 	while ((c = fgetc(stdin)) != EOF)
260af0dd31fSDavid Chisnall 	{
261af0dd31fSDavid Chisnall 		b.push_back(c);
262af0dd31fSDavid Chisnall 	}
263af0dd31fSDavid Chisnall 	buffer = b.data();
264af0dd31fSDavid Chisnall 	size = b.size();
265af0dd31fSDavid Chisnall }
266af0dd31fSDavid Chisnall 
267af0dd31fSDavid Chisnall } // namespace dtc
268af0dd31fSDavid Chisnall 
269