2
* Copyright (C) 2007 The Android Open Source Project
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
16
#include "cutils/event_tag_map.h"
17
#include "cutils/log.h"
26
#define OUT_TAG "EventTagMap"
31
typedef struct EventTag {
32
unsigned int tagIndex;
40
/* memory-mapped source file; we get strings from here */
44
/* array of event tags, sorted numerically by tag index */
50
static int processFile(EventTagMap* map);
51
static int countMapLines(const EventTagMap* map);
52
static int parseMapLines(EventTagMap* map);
53
static int scanTagLine(char** pData, EventTag* tag, int lineNum);
54
static int sortTags(EventTagMap* map);
55
static void dumpTags(const EventTagMap* map);
59
* Open the map file and allocate a structure to manage it.
61
* We create a private mapping because we want to terminate the log tag
64
EventTagMap* android_openEventTagMap(const char* fileName)
66
EventTagMap* newTagMap;
70
newTagMap = calloc(1, sizeof(EventTagMap));
71
if (newTagMap == NULL)
74
fd = open(fileName, O_RDONLY);
76
fprintf(stderr, "%s: unable to open map '%s': %s\n",
77
OUT_TAG, fileName, strerror(errno));
81
end = lseek(fd, 0L, SEEK_END);
82
(void) lseek(fd, 0L, SEEK_SET);
84
fprintf(stderr, "%s: unable to seek map '%s'\n", OUT_TAG, fileName);
88
newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE,
90
if (newTagMap->mapAddr == MAP_FAILED) {
91
fprintf(stderr, "%s: mmap(%s) failed: %s\n",
92
OUT_TAG, fileName, strerror(errno));
95
newTagMap->mapLen = end;
97
if (processFile(newTagMap) != 0)
103
android_closeEventTagMap(newTagMap);
112
void android_closeEventTagMap(EventTagMap* map)
117
munmap(map->mapAddr, map->mapLen);
122
* Look up an entry in the map.
124
* The entries are sorted by tag number, so we can do a binary search.
126
const char* android_lookupEventTag(const EventTagMap* map, int tag)
137
cmp = map->tagArray[mid].tagIndex - tag;
141
} else if (cmp > 0) {
146
return map->tagArray[mid].tagStr;
156
* Determine whether "c" is a whitespace char.
158
static inline int isCharWhitespace(char c)
160
return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
164
* Determine whether "c" is a valid tag char.
166
static inline int isCharValidTag(char c)
168
return ((c >= 'A' && c <= 'Z') ||
169
(c >= 'a' && c <= 'z') ||
170
(c >= '0' && c <= '9') ||
175
* Determine whether "c" is a valid decimal digit.
177
static inline int isCharDigit(char c)
179
return (c >= '0' && c <= '9');
184
* Crunch through the file, parsing the contents and creating a tag index.
186
static int processFile(EventTagMap* map)
188
EventTag* tagArray = NULL;
190
/* get a tag count */
191
map->numTags = countMapLines(map);
192
if (map->numTags < 0)
195
//printf("+++ found %d tags\n", map->numTags);
197
/* allocate storage for the tag index array */
198
map->tagArray = calloc(1, sizeof(EventTag) * map->numTags);
199
if (map->tagArray == NULL)
202
/* parse the file, null-terminating tag strings */
203
if (parseMapLines(map) != 0) {
204
fprintf(stderr, "%s: file parse failed\n", OUT_TAG);
208
/* sort the tags and check for duplicates */
209
if (sortTags(map) != 0)
216
* Run through all lines in the file, determining whether they're blank,
217
* comments, or possibly have a tag entry.
219
* This is a very "loose" scan. We don't try to detect syntax errors here.
220
* The later pass is more careful, but the number of tags found there must
221
* match the number of tags found here.
223
* Returns the number of potential tag entries found.
225
static int countMapLines(const EventTagMap* map)
227
int numTags, unknown;
231
cp = (const char*) map->mapAddr;
232
endp = cp + map->mapLen;
239
} else if (unknown) {
240
if (isCharDigit(*cp)) {
241
/* looks like a tag to me */
244
} else if (isCharWhitespace(*cp)) {
245
/* might be leading whitespace before tag num, keep going */
247
/* assume comment; second pass can complain in detail */
251
/* we've made up our mind; just scan to end of line */
260
* Parse the tags out of the file.
262
static int parseMapLines(EventTagMap* map)
264
int tagNum, lineStart, lineNum;
268
cp = (char*) map->mapAddr;
269
endp = cp + map->mapLen;
271
/* insist on EOL at EOF; simplifies parsing and null-termination */
272
if (*(endp-1) != '\n') {
273
fprintf(stderr, "%s: map file missing EOL on last line\n", OUT_TAG);
281
//printf("{%02x}", *cp); fflush(stdout);
285
} else if (lineStart) {
287
/* comment; just scan to end */
289
} else if (isCharDigit(*cp)) {
290
/* looks like a tag; scan it out */
291
if (tagNum >= map->numTags) {
293
"%s: more tags than expected (%d)\n", OUT_TAG, tagNum);
296
if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0)
299
lineNum++; // we eat the '\n'
300
/* leave lineStart==1 */
301
} else if (isCharWhitespace(*cp)) {
302
/* looks like leading whitespace; keep scanning */
305
"%s: unexpected chars (0x%02x) in tag number on line %d\n",
306
OUT_TAG, *cp, lineNum);
310
/* this is a blank or comment line */
315
if (tagNum != map->numTags) {
316
fprintf(stderr, "%s: parsed %d tags, expected %d\n",
317
OUT_TAG, tagNum, map->numTags);
327
* "*pData" should be pointing to the first digit in the tag number. On
328
* successful return, it will be pointing to the last character in the
329
* tag line (i.e. the character before the start of the next line).
331
* Returns 0 on success, nonzero on failure.
333
static int scanTagLine(char** pData, EventTag* tag, int lineNum)
341
while (isCharDigit(*++cp))
345
val = strtoul(startp, &endp, 10);
348
fprintf(stderr, "ARRRRGH\n");
352
while (*++cp != '\n' && isCharWhitespace(*cp))
357
"%s: missing tag string on line %d\n", OUT_TAG, lineNum);
363
while (isCharValidTag(*++cp))
367
/* null terminate and return */
369
} else if (isCharWhitespace(*cp)) {
370
/* CRLF or trailin spaces; zap this char, then scan for the '\n' */
373
/* just ignore the rest of the line till \n
374
TODO: read the tag description that follows the tag name
376
while (*++cp != '\n') {
380
"%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
386
//printf("+++ Line %d: got %d '%s'\n", lineNum, tag->tagIndex, tag->tagStr);
391
* Compare two EventTags.
393
static int compareEventTags(const void* v1, const void* v2)
395
const EventTag* tag1 = (const EventTag*) v1;
396
const EventTag* tag2 = (const EventTag*) v2;
398
return tag1->tagIndex - tag2->tagIndex;
402
* Sort the EventTag array so we can do fast lookups by tag index. After
403
* the sort we do a quick check for duplicate tag indices.
405
* Returns 0 on success.
407
static int sortTags(EventTagMap* map)
411
qsort(map->tagArray, map->numTags, sizeof(EventTag), compareEventTags);
413
for (i = 1; i < map->numTags; i++) {
414
if (map->tagArray[i].tagIndex == map->tagArray[i-1].tagIndex) {
415
fprintf(stderr, "%s: duplicate tag entries (%d:%s and %d:%s)\n",
417
map->tagArray[i].tagIndex, map->tagArray[i].tagStr,
418
map->tagArray[i-1].tagIndex, map->tagArray[i-1].tagStr);
427
* Dump the tag array for debugging.
429
static void dumpTags(const EventTagMap* map)
433
for (i = 0; i < map->numTags; i++) {
434
const EventTag* tag = &map->tagArray[i];
435
printf(" %3d: %6d '%s'\n", i, tag->tagIndex, tag->tagStr);