1 | // |
2 | // Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. |
3 | // Use of this source code is governed by a BSD-style license that can be |
4 | // found in the LICENSE file. |
5 | // |
6 | |
7 | #include "compiler/preprocessor/Input.h" |
8 | |
9 | #include <algorithm> |
10 | #include <cstring> |
11 | |
12 | #include "common/debug.h" |
13 | |
14 | namespace angle |
15 | { |
16 | |
17 | namespace pp |
18 | { |
19 | |
20 | Input::Input() : mCount(0), mString(0) {} |
21 | |
22 | Input::~Input() {} |
23 | |
24 | Input::Input(size_t count, const char *const string[], const int length[]) |
25 | : mCount(count), mString(string) |
26 | { |
27 | mLength.reserve(mCount); |
28 | for (size_t i = 0; i < mCount; ++i) |
29 | { |
30 | int len = length ? length[i] : -1; |
31 | mLength.push_back(len < 0 ? std::strlen(mString[i]) : len); |
32 | } |
33 | } |
34 | |
35 | const char *Input::skipChar() |
36 | { |
37 | // This function should only be called when there is a character to skip. |
38 | ASSERT(mReadLoc.cIndex < mLength[mReadLoc.sIndex]); |
39 | ++mReadLoc.cIndex; |
40 | if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) |
41 | { |
42 | ++mReadLoc.sIndex; |
43 | mReadLoc.cIndex = 0; |
44 | } |
45 | if (mReadLoc.sIndex >= mCount) |
46 | { |
47 | return nullptr; |
48 | } |
49 | return mString[mReadLoc.sIndex] + mReadLoc.cIndex; |
50 | } |
51 | |
52 | size_t Input::read(char *buf, size_t maxSize, int *lineNo) |
53 | { |
54 | size_t nRead = 0; |
55 | // The previous call to read might have stopped copying the string when encountering a line |
56 | // continuation. Check for this possibility first. |
57 | if (mReadLoc.sIndex < mCount && maxSize > 0) |
58 | { |
59 | const char *c = mString[mReadLoc.sIndex] + mReadLoc.cIndex; |
60 | if ((*c) == '\\') |
61 | { |
62 | c = skipChar(); |
63 | if (c != nullptr && (*c) == '\n') |
64 | { |
65 | // Line continuation of backslash + newline. |
66 | skipChar(); |
67 | // Fake an EOF if the line number would overflow. |
68 | if (*lineNo == INT_MAX) |
69 | { |
70 | return 0; |
71 | } |
72 | ++(*lineNo); |
73 | } |
74 | else if (c != nullptr && (*c) == '\r') |
75 | { |
76 | // Line continuation. Could be backslash + '\r\n' or just backslash + '\r'. |
77 | c = skipChar(); |
78 | if (c != nullptr && (*c) == '\n') |
79 | { |
80 | skipChar(); |
81 | } |
82 | // Fake an EOF if the line number would overflow. |
83 | if (*lineNo == INT_MAX) |
84 | { |
85 | return 0; |
86 | } |
87 | ++(*lineNo); |
88 | } |
89 | else |
90 | { |
91 | // Not line continuation, so write the skipped backslash to buf. |
92 | *buf = '\\'; |
93 | ++nRead; |
94 | } |
95 | } |
96 | } |
97 | |
98 | size_t maxRead = maxSize; |
99 | while ((nRead < maxRead) && (mReadLoc.sIndex < mCount)) |
100 | { |
101 | size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; |
102 | size = std::min(size, maxSize); |
103 | for (size_t i = 0; i < size; ++i) |
104 | { |
105 | // Stop if a possible line continuation is encountered. |
106 | // It will be processed on the next call on input, which skips it |
107 | // and increments line number if necessary. |
108 | if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\') |
109 | { |
110 | size = i; |
111 | maxRead = nRead + size; // Stop reading right before the backslash. |
112 | } |
113 | } |
114 | std::memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size); |
115 | nRead += size; |
116 | mReadLoc.cIndex += size; |
117 | |
118 | // Advance string if we reached the end of current string. |
119 | if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) |
120 | { |
121 | ++mReadLoc.sIndex; |
122 | mReadLoc.cIndex = 0; |
123 | } |
124 | } |
125 | return nRead; |
126 | } |
127 | |
128 | } // namespace pp |
129 | |
130 | } // namespace angle |
131 | |