00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "comma/basic/TextProvider.h"
00010 #include <ostream>
00011 #include <cstdlib>
00012 #include <cstring>
00013 #include <cassert>
00014
00015 using namespace comma;
00016
00017 TextProvider::TextProvider(const llvm::sys::Path &path)
00018 {
00019 memBuffer = llvm::MemoryBuffer::getFileOrSTDIN(path.c_str());
00020
00021
00022
00023 if (!memBuffer) abort();
00024
00025 buffer = memBuffer->getBufferStart();
00026
00027 identity = path.getLast();
00028
00029
00030 if (identity.compare("-") == 0)
00031 identity = "<stdin>";
00032
00033 initializeLinevec();
00034 }
00035
00036 TextProvider::TextProvider(const char *raw, size_t length)
00037 {
00038 memBuffer = llvm::MemoryBuffer::getMemBufferCopy(raw, raw + length);
00039 buffer = memBuffer->getBufferStart();
00040 initializeLinevec();
00041 }
00042
00043 TextProvider::TextProvider(const std::string &str)
00044 {
00045 const char *start = str.c_str();
00046 const char *end = start + str.size();
00047 memBuffer = llvm::MemoryBuffer::getMemBufferCopy(start, end);
00048 buffer = memBuffer->getBufferStart();
00049 initializeLinevec();
00050 }
00051
00052 TextProvider::~TextProvider()
00053 {
00054 delete memBuffer;
00055 }
00056
00057 Location TextProvider::getLocation(const TextIterator &ti) const
00058 {
00059 return indexOf(ti.cursor);
00060 }
00061
00062 SourceLocation TextProvider::getSourceLocation(const TextIterator &ti) const
00063 {
00064 unsigned line = getLine(ti);
00065 unsigned column = getColumn(ti);
00066 return SourceLocation(line, column, this);
00067 }
00068
00069 SourceLocation TextProvider::getSourceLocation(const Location loc) const
00070 {
00071 unsigned line = getLine(loc);
00072 unsigned column = getColumn(loc);
00073 return SourceLocation(line, column, this);
00074 }
00075
00076 TextIterator TextProvider::begin() const
00077 {
00078 return TextIterator(buffer);
00079 }
00080
00081 TextIterator TextProvider::end() const
00082 {
00083 return TextIterator(memBuffer->getBufferEnd());
00084 }
00085
00086 std::string TextProvider::extract(Location start, Location end) const
00087 {
00088 std::string str;
00089 unsigned x = start.getOffset();
00090 unsigned y = end.getOffset();
00091 assert(x <= y && "Inconsistent Location range!");
00092 assert(y < indexOf(memBuffer->getBufferEnd()) && "Locations out of range!");
00093 str.insert(0, &buffer[x], y - x + 1);
00094 return str;
00095 }
00096
00097 std::string TextProvider::extract(const TextIterator &s,
00098 const TextIterator &e) const
00099 {
00100 std::string str;
00101 unsigned length = e.cursor - s.cursor;
00102 str.insert(0, s.cursor, length);
00103 return str;
00104 }
00105
00106 std::string TextProvider::extract(const SourceLocation &sloc) const
00107 {
00108 assert(sloc.getTextProvider() == this &&
00109 "SourceLocation not associated with this TextProvider!");
00110
00111 std::string str;
00112 unsigned line = sloc.getLine();
00113 unsigned start = lines[line - 1];
00114 unsigned end = lines[line];
00115 str.insert(0, &buffer[start], end - start);
00116 return str;
00117 }
00118
00119 unsigned TextProvider::extract(const TextIterator &s,
00120 const TextIterator &e,
00121 char *buff, size_t size) const
00122 {
00123 unsigned length = e.cursor - s.cursor;
00124
00125 if (buff == 0) return length;
00126
00127 if (length >= size) {
00128 ::memcpy(buff, s.cursor, size);
00129 return size;
00130 }
00131
00132 ::memcpy(buff, s.cursor, length);
00133 buff[length] = 0;
00134 return length;
00135 }
00136
00137 void TextProvider::initializeLinevec()
00138 {
00139 lines.push_back(0);
00140 maxLineIndex = 0;
00141 }
00142
00143 unsigned TextProvider::getLine(Location loc) const
00144 {
00145 assert(loc < indexOf(memBuffer->getBufferEnd()));
00146
00147
00148
00149 if (loc >= maxLineIndex) {
00150 unsigned line;
00151 const char* cursor = &buffer[lines.back()];
00152 while (cursor != &buffer[loc]) {
00153 switch (*cursor++) {
00154 case '\r':
00155 if (*cursor == '\n')
00156 cursor++;
00157 case '\n':
00158 case '\f':
00159 lines.push_back(indexOf(cursor));
00160 }
00161 }
00162
00163
00164 line = lines.size();
00165
00166
00167 while (cursor != memBuffer->getBufferEnd()) {
00168 switch (*cursor++) {
00169 case '\r':
00170 if (*cursor == '\n')
00171 cursor++;
00172 case '\n':
00173 case '\f':
00174 lines.push_back(indexOf(cursor));
00175 maxLineIndex = indexOf(cursor);
00176 return line;
00177 }
00178 }
00179
00180 lines.push_back(indexOf(cursor));
00181 maxLineIndex = indexOf(cursor);
00182 return line;
00183 }
00184
00185
00186 int max = lines.size();
00187 int start = 0;
00188 int end = max - 1;
00189 while (start <= end) {
00190 int mid = (start + end) >> 1;
00191 Location candidate = lines[mid];
00192 if (candidate <= loc) {
00193 if (mid + 1 < max) {
00194 if (lines[mid + 1] <= loc) {
00195 start = ++mid;
00196 continue;
00197 }
00198 return ++mid;
00199 }
00200 return mid;
00201 }
00202 end = --mid;
00203 }
00204 assert(false && "Bad offset into chunk map.");
00205 return 0;
00206 }
00207
00208 unsigned TextProvider::getColumn(Location loc) const
00209 {
00210 unsigned start = lines[getLine(loc) - 1];
00211 return loc - start;
00212 }
00213
00214 std::pair<unsigned, unsigned> TextProvider::getLineOf(Location loc) const
00215 {
00216 unsigned line = getLine(loc) - 1;
00217 unsigned start = lines[line];
00218 unsigned end = lines[line + 1];
00219
00220 return std::pair<unsigned, unsigned>(start, end);
00221 }
00222