input_buffer.cc revision 247006
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 247006 2013-02-19 18:28:25Z uqs $
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
50namespace dtc
51{
52
53void
54input_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
74input_buffer
75input_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
92bool
93input_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
115bool
116input_buffer::consume_integer(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 = strtoll(&buffer[cursor], &end, 0);
126	if (end == &buffer[cursor])
127	{
128		return false;
129	}
130	cursor = end - buffer;
131	return true;
132}
133
134bool
135input_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
146input_buffer&
147input_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 */
178			while (**this != '\n')
179			{
180				++(*this);
181			}
182			// Eat the \n
183			++(*this);
184		}
185	} while (start != cursor);
186	return *this;
187}
188
189void
190input_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		putc(' ', stderr);
220	}
221	putc('^', stderr);
222	putc('\n', stderr);
223}
224void
225input_buffer::dump()
226{
227	fprintf(stderr, "Current cursor: %d\n", cursor);
228	fwrite(&buffer[cursor], size-cursor, 1, stderr);
229}
230
231mmap_input_buffer::mmap_input_buffer(int fd) : input_buffer(0, 0)
232{
233	struct stat sb;
234	if (fstat(fd, &sb))
235	{
236		perror("Failed to stat file");
237	}
238	size = sb.st_size;
239	buffer = (const char*)mmap(0, size, PROT_READ,
240		MAP_PREFAULT_READ, fd, 0);
241	if (buffer == 0)
242	{
243		perror("Failed to mmap file");
244	}
245}
246
247mmap_input_buffer::~mmap_input_buffer()
248{
249	if (buffer != 0)
250	{
251		munmap((void*)buffer, size);
252	}
253}
254
255stream_input_buffer::stream_input_buffer() : input_buffer(0, 0)
256{
257	int c;
258	while ((c = fgetc(stdin)) != EOF)
259	{
260		b.push_back(c);
261	}
262	buffer = b.data();
263	size = b.size();
264}
265
266} // namespace dtc
267
268