~mir-team/mir/in-process-egl+input-conglomeration

« back to all changes in this revision

Viewing changes to 3rd_party/android-input/android_pristine/system/core/liblog/event_tag_map.c

Merged trunk and fixed issues

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2007 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
 
#include "cutils/event_tag_map.h"
17
 
#include "cutils/log.h"
18
 
 
19
 
#include <stdlib.h>
20
 
#include <string.h>
21
 
#include <fcntl.h>
22
 
#include <sys/mman.h>
23
 
#include <errno.h>
24
 
#include <assert.h>
25
 
 
26
 
#define OUT_TAG "EventTagMap"
27
 
 
28
 
/*
29
 
 * Single entry.
30
 
 */
31
 
typedef struct EventTag {
32
 
    unsigned int    tagIndex;
33
 
    const char*     tagStr;
34
 
} EventTag;
35
 
 
36
 
/*
37
 
 * Map.
38
 
 */
39
 
struct EventTagMap {
40
 
    /* memory-mapped source file; we get strings from here */
41
 
    void*           mapAddr;
42
 
    size_t          mapLen;
43
 
 
44
 
    /* array of event tags, sorted numerically by tag index */
45
 
    EventTag*       tagArray;
46
 
    int             numTags;
47
 
};
48
 
 
49
 
/* fwd */
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);
56
 
 
57
 
 
58
 
/*
59
 
 * Open the map file and allocate a structure to manage it.
60
 
 *
61
 
 * We create a private mapping because we want to terminate the log tag
62
 
 * strings with '\0'.
63
 
 */
64
 
EventTagMap* android_openEventTagMap(const char* fileName)
65
 
{
66
 
    EventTagMap* newTagMap;
67
 
    off_t end;
68
 
    int fd = -1;
69
 
 
70
 
    newTagMap = calloc(1, sizeof(EventTagMap));
71
 
    if (newTagMap == NULL)
72
 
        return NULL;
73
 
 
74
 
    fd = open(fileName, O_RDONLY);
75
 
    if (fd < 0) {
76
 
        fprintf(stderr, "%s: unable to open map '%s': %s\n",
77
 
            OUT_TAG, fileName, strerror(errno));
78
 
        goto fail;
79
 
    }
80
 
 
81
 
    end = lseek(fd, 0L, SEEK_END);
82
 
    (void) lseek(fd, 0L, SEEK_SET);
83
 
    if (end < 0) {
84
 
        fprintf(stderr, "%s: unable to seek map '%s'\n", OUT_TAG, fileName);
85
 
        goto fail;
86
 
    }
87
 
 
88
 
    newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE,
89
 
                                fd, 0);
90
 
    if (newTagMap->mapAddr == MAP_FAILED) {
91
 
        fprintf(stderr, "%s: mmap(%s) failed: %s\n",
92
 
            OUT_TAG, fileName, strerror(errno));
93
 
        goto fail;
94
 
    }
95
 
    newTagMap->mapLen = end;
96
 
 
97
 
    if (processFile(newTagMap) != 0)
98
 
        goto fail;
99
 
 
100
 
    return newTagMap;
101
 
 
102
 
fail:
103
 
    android_closeEventTagMap(newTagMap);
104
 
    if (fd >= 0)
105
 
        close(fd);
106
 
    return NULL;
107
 
}
108
 
 
109
 
/*
110
 
 * Close the map.
111
 
 */
112
 
void android_closeEventTagMap(EventTagMap* map)
113
 
{
114
 
    if (map == NULL)
115
 
        return;
116
 
 
117
 
    munmap(map->mapAddr, map->mapLen);
118
 
    free(map);
119
 
}
120
 
 
121
 
/*
122
 
 * Look up an entry in the map.
123
 
 *
124
 
 * The entries are sorted by tag number, so we can do a binary search.
125
 
 */
126
 
const char* android_lookupEventTag(const EventTagMap* map, int tag)
127
 
{
128
 
    int hi, lo, mid;
129
 
 
130
 
    lo = 0;
131
 
    hi = map->numTags-1;
132
 
 
133
 
    while (lo <= hi) {
134
 
        int cmp;
135
 
 
136
 
        mid = (lo+hi)/2;
137
 
        cmp = map->tagArray[mid].tagIndex - tag;
138
 
        if (cmp < 0) {
139
 
            /* tag is bigger */
140
 
            lo = mid + 1;
141
 
        } else if (cmp > 0) {
142
 
            /* tag is smaller */
143
 
            hi = mid - 1;
144
 
        } else {
145
 
            /* found */
146
 
            return map->tagArray[mid].tagStr;
147
 
        }
148
 
    }
149
 
 
150
 
    return NULL;
151
 
}
152
 
 
153
 
 
154
 
 
155
 
/*
156
 
 * Determine whether "c" is a whitespace char.
157
 
 */
158
 
static inline int isCharWhitespace(char c)
159
 
{
160
 
    return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
161
 
}
162
 
 
163
 
/*
164
 
 * Determine whether "c" is a valid tag char.
165
 
 */
166
 
static inline int isCharValidTag(char c)
167
 
{
168
 
    return ((c >= 'A' && c <= 'Z') ||
169
 
            (c >= 'a' && c <= 'z') ||
170
 
            (c >= '0' && c <= '9') ||
171
 
            (c == '_'));
172
 
}
173
 
 
174
 
/*
175
 
 * Determine whether "c" is a valid decimal digit.
176
 
 */
177
 
static inline int isCharDigit(char c)
178
 
{
179
 
    return (c >= '0' && c <= '9');
180
 
}
181
 
 
182
 
 
183
 
/*
184
 
 * Crunch through the file, parsing the contents and creating a tag index.
185
 
 */
186
 
static int processFile(EventTagMap* map)
187
 
{
188
 
    EventTag* tagArray = NULL;
189
 
 
190
 
    /* get a tag count */
191
 
    map->numTags = countMapLines(map);
192
 
    if (map->numTags < 0)
193
 
        return -1;
194
 
 
195
 
    //printf("+++ found %d tags\n", map->numTags);
196
 
 
197
 
    /* allocate storage for the tag index array */
198
 
    map->tagArray = calloc(1, sizeof(EventTag) * map->numTags);
199
 
    if (map->tagArray == NULL)
200
 
        return -1;
201
 
 
202
 
    /* parse the file, null-terminating tag strings */
203
 
    if (parseMapLines(map) != 0) {
204
 
        fprintf(stderr, "%s: file parse failed\n", OUT_TAG);
205
 
        return -1;
206
 
    }
207
 
 
208
 
    /* sort the tags and check for duplicates */
209
 
    if (sortTags(map) != 0)
210
 
        return -1;
211
 
 
212
 
    return 0;
213
 
}
214
 
 
215
 
/*
216
 
 * Run through all lines in the file, determining whether they're blank,
217
 
 * comments, or possibly have a tag entry.
218
 
 *
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.
222
 
 *
223
 
 * Returns the number of potential tag entries found.
224
 
 */
225
 
static int countMapLines(const EventTagMap* map)
226
 
{
227
 
    int numTags, unknown;
228
 
    const char* cp;
229
 
    const char* endp;
230
 
 
231
 
    cp = (const char*) map->mapAddr;
232
 
    endp = cp + map->mapLen;
233
 
 
234
 
    numTags = 0;
235
 
    unknown = 1;
236
 
    while (cp < endp) {
237
 
        if (*cp == '\n') {
238
 
            unknown = 1;
239
 
        } else if (unknown) {
240
 
            if (isCharDigit(*cp)) {
241
 
                /* looks like a tag to me */
242
 
                numTags++;
243
 
                unknown = 0;
244
 
            } else if (isCharWhitespace(*cp)) {
245
 
                /* might be leading whitespace before tag num, keep going */
246
 
            } else {
247
 
                /* assume comment; second pass can complain in detail */
248
 
                unknown = 0;
249
 
            }
250
 
        } else {
251
 
            /* we've made up our mind; just scan to end of line */
252
 
        }
253
 
        cp++;
254
 
    }
255
 
 
256
 
    return numTags;
257
 
}
258
 
 
259
 
/*
260
 
 * Parse the tags out of the file.
261
 
 */
262
 
static int parseMapLines(EventTagMap* map)
263
 
{
264
 
    int tagNum, lineStart, lineNum;
265
 
    char* cp;
266
 
    char* endp;
267
 
 
268
 
    cp = (char*) map->mapAddr;
269
 
    endp = cp + map->mapLen;
270
 
 
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);
274
 
        return -1;
275
 
    }
276
 
 
277
 
    tagNum = 0;
278
 
    lineStart = 1;
279
 
    lineNum = 1;
280
 
    while (cp < endp) {
281
 
        //printf("{%02x}", *cp); fflush(stdout);
282
 
        if (*cp == '\n') {
283
 
            lineStart = 1;
284
 
            lineNum++;
285
 
        } else if (lineStart) {
286
 
            if (*cp == '#') {
287
 
                /* comment; just scan to end */
288
 
                lineStart = 0;
289
 
            } else if (isCharDigit(*cp)) {
290
 
                /* looks like a tag; scan it out */
291
 
                if (tagNum >= map->numTags) {
292
 
                    fprintf(stderr,
293
 
                        "%s: more tags than expected (%d)\n", OUT_TAG, tagNum);
294
 
                    return -1;
295
 
                }
296
 
                if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0)
297
 
                    return -1;
298
 
                tagNum++;
299
 
                lineNum++;      // we eat the '\n'
300
 
                /* leave lineStart==1 */
301
 
            } else if (isCharWhitespace(*cp)) {
302
 
                /* looks like leading whitespace; keep scanning */
303
 
            } else {
304
 
                fprintf(stderr,
305
 
                    "%s: unexpected chars (0x%02x) in tag number on line %d\n",
306
 
                    OUT_TAG, *cp, lineNum);
307
 
                return -1;
308
 
            }
309
 
        } else {
310
 
            /* this is a blank or comment line */
311
 
        }
312
 
        cp++;
313
 
    }
314
 
 
315
 
    if (tagNum != map->numTags) {
316
 
        fprintf(stderr, "%s: parsed %d tags, expected %d\n",
317
 
            OUT_TAG, tagNum, map->numTags);
318
 
        return -1;
319
 
    }
320
 
 
321
 
    return 0;
322
 
}
323
 
 
324
 
/*
325
 
 * Scan one tag line.
326
 
 *
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).
330
 
 *
331
 
 * Returns 0 on success, nonzero on failure.
332
 
 */
333
 
static int scanTagLine(char** pData, EventTag* tag, int lineNum)
334
 
{
335
 
    char* cp = *pData;
336
 
    char* startp;
337
 
    char* endp;
338
 
    unsigned long val;
339
 
 
340
 
    startp = cp;
341
 
    while (isCharDigit(*++cp))
342
 
        ;
343
 
    *cp = '\0';
344
 
 
345
 
    val = strtoul(startp, &endp, 10);
346
 
    assert(endp == cp);
347
 
    if (endp != cp)
348
 
        fprintf(stderr, "ARRRRGH\n");
349
 
 
350
 
    tag->tagIndex = val;
351
 
 
352
 
    while (*++cp != '\n' && isCharWhitespace(*cp))
353
 
        ;
354
 
 
355
 
    if (*cp == '\n') {
356
 
        fprintf(stderr,
357
 
            "%s: missing tag string on line %d\n", OUT_TAG, lineNum);
358
 
        return -1;
359
 
    }
360
 
 
361
 
    tag->tagStr = cp;
362
 
 
363
 
    while (isCharValidTag(*++cp))
364
 
        ;
365
 
 
366
 
    if (*cp == '\n') {
367
 
        /* null terminate and return */
368
 
        *cp = '\0';
369
 
    } else if (isCharWhitespace(*cp)) {
370
 
        /* CRLF or trailin spaces; zap this char, then scan for the '\n' */
371
 
        *cp = '\0';
372
 
 
373
 
        /* just ignore the rest of the line till \n
374
 
        TODO: read the tag description that follows the tag name
375
 
        */
376
 
        while (*++cp != '\n') {
377
 
        }
378
 
    } else {
379
 
        fprintf(stderr,
380
 
            "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
381
 
        return -1;
382
 
    }
383
 
 
384
 
    *pData = cp;
385
 
 
386
 
    //printf("+++ Line %d: got %d '%s'\n", lineNum, tag->tagIndex, tag->tagStr);
387
 
    return 0;
388
 
}
389
 
 
390
 
/*
391
 
 * Compare two EventTags.
392
 
 */
393
 
static int compareEventTags(const void* v1, const void* v2)
394
 
{
395
 
    const EventTag* tag1 = (const EventTag*) v1;
396
 
    const EventTag* tag2 = (const EventTag*) v2;
397
 
 
398
 
    return tag1->tagIndex - tag2->tagIndex;
399
 
}
400
 
 
401
 
/*
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.
404
 
 *
405
 
 * Returns 0 on success.
406
 
 */
407
 
static int sortTags(EventTagMap* map)
408
 
{
409
 
    int i;
410
 
 
411
 
    qsort(map->tagArray, map->numTags, sizeof(EventTag), compareEventTags);
412
 
 
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",
416
 
                OUT_TAG,
417
 
                map->tagArray[i].tagIndex, map->tagArray[i].tagStr,
418
 
                map->tagArray[i-1].tagIndex, map->tagArray[i-1].tagStr);
419
 
            return -1;
420
 
        }
421
 
    }
422
 
 
423
 
    return 0;
424
 
}
425
 
 
426
 
/*
427
 
 * Dump the tag array for debugging.
428
 
 */
429
 
static void dumpTags(const EventTagMap* map)
430
 
{
431
 
    int i;
432
 
 
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);
436
 
    }
437
 
}
438