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
14namespace angle
15{
16
17namespace pp
18{
19
20Input::Input() : mCount(0), mString(0) {}
21
22Input::~Input() {}
23
24Input::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
35const 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
52size_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