widget/gonk/libui/Tokenizer.cpp

changeset 0
6474c204b198
     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

mercurial