]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/dtc/input_buffer.cc
MFC
[FreeBSD/FreeBSD.git] / usr.bin / dtc / input_buffer.cc
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