1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/libui/Tokenizer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,175 @@ 1.4 +/* 1.5 + * Copyright (C) 2010 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#define LOG_TAG "Tokenizer" 1.21 +#include "cutils_log.h" 1.22 + 1.23 +#include <stdlib.h> 1.24 +#include <unistd.h> 1.25 +#include <fcntl.h> 1.26 +#include <errno.h> 1.27 +#include <sys/types.h> 1.28 +#include <sys/stat.h> 1.29 +#include "Tokenizer.h" 1.30 + 1.31 +// Enables debug output for the tokenizer. 1.32 +#define DEBUG_TOKENIZER 0 1.33 + 1.34 + 1.35 +namespace android { 1.36 + 1.37 +static inline bool isDelimiter(char ch, const char* delimiters) { 1.38 + return strchr(delimiters, ch) != NULL; 1.39 +} 1.40 + 1.41 +Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, 1.42 + bool ownBuffer, size_t length) : 1.43 + mFilename(filename), mFileMap(fileMap), 1.44 + mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length), 1.45 + mCurrent(buffer), mLineNumber(1) { 1.46 +} 1.47 + 1.48 +Tokenizer::~Tokenizer() { 1.49 + if (mFileMap) { 1.50 + mFileMap->release(); 1.51 + } 1.52 + if (mOwnBuffer) { 1.53 + delete[] mBuffer; 1.54 + } 1.55 +} 1.56 + 1.57 +status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { 1.58 + *outTokenizer = NULL; 1.59 + 1.60 + int result = NO_ERROR; 1.61 + int fd = ::open(filename.string(), O_RDONLY); 1.62 + if (fd < 0) { 1.63 + result = -errno; 1.64 + ALOGE("Error opening file '%s', %s.", filename.string(), strerror(errno)); 1.65 + } else { 1.66 + struct stat stat; 1.67 + if (fstat(fd, &stat)) { 1.68 + result = -errno; 1.69 + ALOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); 1.70 + } else { 1.71 + size_t length = size_t(stat.st_size); 1.72 + 1.73 + FileMap* fileMap = new FileMap(); 1.74 + bool ownBuffer = false; 1.75 + char* buffer; 1.76 + if (fileMap->create(NULL, fd, 0, length, true)) { 1.77 + fileMap->advise(FileMap::SEQUENTIAL); 1.78 + buffer = static_cast<char*>(fileMap->getDataPtr()); 1.79 + } else { 1.80 + fileMap->release(); 1.81 + fileMap = NULL; 1.82 + 1.83 + // Fall back to reading into a buffer since we can't mmap files in sysfs. 1.84 + // The length we obtained from stat is wrong too (it will always be 4096) 1.85 + // so we must trust that read will read the entire file. 1.86 + buffer = new char[length]; 1.87 + ownBuffer = true; 1.88 + ssize_t nrd = read(fd, buffer, length); 1.89 + if (nrd < 0) { 1.90 + result = -errno; 1.91 + ALOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); 1.92 + delete[] buffer; 1.93 + buffer = NULL; 1.94 + } else { 1.95 + length = size_t(nrd); 1.96 + } 1.97 + } 1.98 + 1.99 + if (!result) { 1.100 + *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length); 1.101 + } 1.102 + } 1.103 + close(fd); 1.104 + } 1.105 + return result; 1.106 +} 1.107 + 1.108 +status_t Tokenizer::fromContents(const String8& filename, 1.109 + const char* contents, Tokenizer** outTokenizer) { 1.110 + *outTokenizer = new Tokenizer(filename, NULL, 1.111 + const_cast<char*>(contents), false, strlen(contents)); 1.112 + return OK; 1.113 +} 1.114 + 1.115 +String8 Tokenizer::getLocation() const { 1.116 + String8 result; 1.117 + result.appendFormat("%s:%d", mFilename.string(), mLineNumber); 1.118 + return result; 1.119 +} 1.120 + 1.121 +String8 Tokenizer::peekRemainderOfLine() const { 1.122 + const char* end = getEnd(); 1.123 + const char* eol = mCurrent; 1.124 + while (eol != end) { 1.125 + char ch = *eol; 1.126 + if (ch == '\n') { 1.127 + break; 1.128 + } 1.129 + eol += 1; 1.130 + } 1.131 + return String8(mCurrent, eol - mCurrent); 1.132 +} 1.133 + 1.134 +String8 Tokenizer::nextToken(const char* delimiters) { 1.135 +#if DEBUG_TOKENIZER 1.136 + ALOGD("nextToken"); 1.137 +#endif 1.138 + const char* end = getEnd(); 1.139 + const char* tokenStart = mCurrent; 1.140 + while (mCurrent != end) { 1.141 + char ch = *mCurrent; 1.142 + if (ch == '\n' || isDelimiter(ch, delimiters)) { 1.143 + break; 1.144 + } 1.145 + mCurrent += 1; 1.146 + } 1.147 + return String8(tokenStart, mCurrent - tokenStart); 1.148 +} 1.149 + 1.150 +void Tokenizer::nextLine() { 1.151 +#if DEBUG_TOKENIZER 1.152 + ALOGD("nextLine"); 1.153 +#endif 1.154 + const char* end = getEnd(); 1.155 + while (mCurrent != end) { 1.156 + char ch = *(mCurrent++); 1.157 + if (ch == '\n') { 1.158 + mLineNumber += 1; 1.159 + break; 1.160 + } 1.161 + } 1.162 +} 1.163 + 1.164 +void Tokenizer::skipDelimiters(const char* delimiters) { 1.165 +#if DEBUG_TOKENIZER 1.166 + ALOGD("skipDelimiters"); 1.167 +#endif 1.168 + const char* end = getEnd(); 1.169 + while (mCurrent != end) { 1.170 + char ch = *mCurrent; 1.171 + if (ch == '\n' || !isDelimiter(ch, delimiters)) { 1.172 + break; 1.173 + } 1.174 + mCurrent += 1; 1.175 + } 1.176 +} 1.177 + 1.178 +} // namespace android