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