Home | History | Annotate | Download | only in preprocessor
      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