1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "Input.h" 16 17 #include <algorithm> 18 #include <cassert> 19 #include <cstring> 20 21 namespace pp 22 { 23 24 Input::Input() : mCount(0), mString(0) 25 { 26 } 27 28 Input::~Input() 29 { 30 } 31 32 Input::Input(size_t count, const char *const string[], const int length[]) 33 : mCount(count), mString(string) 34 { 35 mLength.reserve(mCount); 36 for (size_t i = 0; i < mCount; ++i) 37 { 38 int len = length ? length[i] : -1; 39 mLength.push_back(len < 0 ? std::strlen(mString[i]) : len); 40 } 41 } 42 43 const char *Input::skipChar() 44 { 45 // This function should only be called when there is a character to skip. 46 assert(mReadLoc.cIndex < mLength[mReadLoc.sIndex]); 47 ++mReadLoc.cIndex; 48 if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) 49 { 50 ++mReadLoc.sIndex; 51 mReadLoc.cIndex = 0; 52 } 53 if (mReadLoc.sIndex >= mCount) 54 { 55 return nullptr; 56 } 57 return mString[mReadLoc.sIndex] + mReadLoc.cIndex; 58 } 59 60 size_t Input::read(char *buf, size_t maxSize, int *lineNo) 61 { 62 size_t nRead = 0; 63 // The previous call to read might have stopped copying the string when encountering a line 64 // continuation. Check for this possibility first. 65 if (mReadLoc.sIndex < mCount && maxSize > 0) 66 { 67 const char *c = mString[mReadLoc.sIndex] + mReadLoc.cIndex; 68 if ((*c) == '\\') 69 { 70 c = skipChar(); 71 if (c != nullptr && (*c) == '\n') 72 { 73 // Line continuation of backslash + newline. 74 skipChar(); 75 // Fake an EOF if the line number would overflow. 76 if (*lineNo == INT_MAX) 77 { 78 return 0; 79 } 80 ++(*lineNo); 81 } 82 else if (c != nullptr && (*c) == '\r') 83 { 84 // Line continuation. Could be backslash + '\r\n' or just backslash + '\r'. 85 c = skipChar(); 86 if (c != nullptr && (*c) == '\n') 87 { 88 skipChar(); 89 } 90 // Fake an EOF if the line number would overflow. 91 if (*lineNo == INT_MAX) 92 { 93 return 0; 94 } 95 ++(*lineNo); 96 } 97 else 98 { 99 // Not line continuation, so write the skipped backslash to buf. 100 *buf = '\\'; 101 ++nRead; 102 } 103 } 104 } 105 106 size_t maxRead = maxSize; 107 while ((nRead < maxRead) && (mReadLoc.sIndex < mCount)) 108 { 109 size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; 110 size = std::min(size, maxSize); 111 for (size_t i = 0; i < size; ++i) 112 { 113 // Stop if a possible line continuation is encountered. 114 // It will be processed on the next call on input, which skips it 115 // and increments line number if necessary. 116 if (*(mString[mReadLoc.sIndex] + mReadLoc.cIndex + i) == '\\') 117 { 118 size = i; 119 maxRead = nRead + size; // Stop reading right before the backslash. 120 } 121 } 122 std::memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size); 123 nRead += size; 124 mReadLoc.cIndex += size; 125 126 // Advance string if we reached the end of current string. 127 if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) 128 { 129 ++mReadLoc.sIndex; 130 mReadLoc.cIndex = 0; 131 } 132 } 133 return nRead; 134 } 135 136 } // namespace pp 137 138