input_buffer.cc revision 245839
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: head/usr.bin/dtc/input_buffer.cc 245839 2013-01-23 08:54:34Z theraven $
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
46namespace dtc
47{
48
49void
50input_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
70input_buffer
71input_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
88bool
89input_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
111bool
112input_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
130bool
131input_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
142input_buffer&
143input_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
185void
186input_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}
220void
221input_buffer::dump()
222{
223	fprintf(stderr, "Current cursor: %d\n", cursor);
224	fwrite(&buffer[cursor], size-cursor, 1, stderr);
225}
226
227mmap_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
243mmap_input_buffer::~mmap_input_buffer()
244{
245	if (buffer != 0)
246	{
247		munmap((void*)buffer, size);
248	}
249}
250
251stream_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