diff options
Diffstat (limited to 'libutils/Tokenizer.cpp')
-rw-r--r-- | libutils/Tokenizer.cpp | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp new file mode 100644 index 000000000..7067533b1 --- /dev/null +++ b/libutils/Tokenizer.cpp | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #define LOG_TAG "Tokenizer" | ||
18 | |||
19 | #include <stdlib.h> | ||
20 | #include <unistd.h> | ||
21 | #include <fcntl.h> | ||
22 | #include <errno.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <utils/Log.h> | ||
26 | #include <utils/Tokenizer.h> | ||
27 | |||
28 | // Enables debug output for the tokenizer. | ||
29 | #define DEBUG_TOKENIZER 0 | ||
30 | |||
31 | |||
32 | namespace android { | ||
33 | |||
34 | static inline bool isDelimiter(char ch, const char* delimiters) { | ||
35 | return strchr(delimiters, ch) != NULL; | ||
36 | } | ||
37 | |||
38 | Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, | ||
39 | bool ownBuffer, size_t length) : | ||
40 | mFilename(filename), mFileMap(fileMap), | ||
41 | mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length), | ||
42 | mCurrent(buffer), mLineNumber(1) { | ||
43 | } | ||
44 | |||
45 | Tokenizer::~Tokenizer() { | ||
46 | if (mFileMap) { | ||
47 | mFileMap->release(); | ||
48 | } | ||
49 | if (mOwnBuffer) { | ||
50 | delete[] mBuffer; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { | ||
55 | *outTokenizer = NULL; | ||
56 | |||
57 | int result = NO_ERROR; | ||
58 | int fd = ::open(filename.string(), O_RDONLY); | ||
59 | if (fd < 0) { | ||
60 | result = -errno; | ||
61 | ALOGE("Error opening file '%s', %s.", filename.string(), strerror(errno)); | ||
62 | } else { | ||
63 | struct stat stat; | ||
64 | if (fstat(fd, &stat)) { | ||
65 | result = -errno; | ||
66 | ALOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); | ||
67 | } else { | ||
68 | size_t length = size_t(stat.st_size); | ||
69 | |||
70 | FileMap* fileMap = new FileMap(); | ||
71 | bool ownBuffer = false; | ||
72 | char* buffer; | ||
73 | if (fileMap->create(NULL, fd, 0, length, true)) { | ||
74 | fileMap->advise(FileMap::SEQUENTIAL); | ||
75 | buffer = static_cast<char*>(fileMap->getDataPtr()); | ||
76 | } else { | ||
77 | fileMap->release(); | ||
78 | fileMap = NULL; | ||
79 | |||
80 | // Fall back to reading into a buffer since we can't mmap files in sysfs. | ||
81 | // The length we obtained from stat is wrong too (it will always be 4096) | ||
82 | // so we must trust that read will read the entire file. | ||
83 | buffer = new char[length]; | ||
84 | ownBuffer = true; | ||
85 | ssize_t nrd = read(fd, buffer, length); | ||
86 | if (nrd < 0) { | ||
87 | result = -errno; | ||
88 | ALOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); | ||
89 | delete[] buffer; | ||
90 | buffer = NULL; | ||
91 | } else { | ||
92 | length = size_t(nrd); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | if (!result) { | ||
97 | *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length); | ||
98 | } | ||
99 | } | ||
100 | close(fd); | ||
101 | } | ||
102 | return result; | ||
103 | } | ||
104 | |||
105 | status_t Tokenizer::fromContents(const String8& filename, | ||
106 | const char* contents, Tokenizer** outTokenizer) { | ||
107 | *outTokenizer = new Tokenizer(filename, NULL, | ||
108 | const_cast<char*>(contents), false, strlen(contents)); | ||
109 | return OK; | ||
110 | } | ||
111 | |||
112 | String8 Tokenizer::getLocation() const { | ||
113 | String8 result; | ||
114 | result.appendFormat("%s:%d", mFilename.string(), mLineNumber); | ||
115 | return result; | ||
116 | } | ||
117 | |||
118 | String8 Tokenizer::peekRemainderOfLine() const { | ||
119 | const char* end = getEnd(); | ||
120 | const char* eol = mCurrent; | ||
121 | while (eol != end) { | ||
122 | char ch = *eol; | ||
123 | if (ch == '\n') { | ||
124 | break; | ||
125 | } | ||
126 | eol += 1; | ||
127 | } | ||
128 | return String8(mCurrent, eol - mCurrent); | ||
129 | } | ||
130 | |||
131 | String8 Tokenizer::nextToken(const char* delimiters) { | ||
132 | #if DEBUG_TOKENIZER | ||
133 | ALOGD("nextToken"); | ||
134 | #endif | ||
135 | const char* end = getEnd(); | ||
136 | const char* tokenStart = mCurrent; | ||
137 | while (mCurrent != end) { | ||
138 | char ch = *mCurrent; | ||
139 | if (ch == '\n' || isDelimiter(ch, delimiters)) { | ||
140 | break; | ||
141 | } | ||
142 | mCurrent += 1; | ||
143 | } | ||
144 | return String8(tokenStart, mCurrent - tokenStart); | ||
145 | } | ||
146 | |||
147 | void Tokenizer::nextLine() { | ||
148 | #if DEBUG_TOKENIZER | ||
149 | ALOGD("nextLine"); | ||
150 | #endif | ||
151 | const char* end = getEnd(); | ||
152 | while (mCurrent != end) { | ||
153 | char ch = *(mCurrent++); | ||
154 | if (ch == '\n') { | ||
155 | mLineNumber += 1; | ||
156 | break; | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | void Tokenizer::skipDelimiters(const char* delimiters) { | ||
162 | #if DEBUG_TOKENIZER | ||
163 | ALOGD("skipDelimiters"); | ||
164 | #endif | ||
165 | const char* end = getEnd(); | ||
166 | while (mCurrent != end) { | ||
167 | char ch = *mCurrent; | ||
168 | if (ch == '\n' || !isDelimiter(ch, delimiters)) { | ||
169 | break; | ||
170 | } | ||
171 | mCurrent += 1; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | } // namespace android | ||