Home | History | Annotate | Download | only in utils
      1 // Copyright 2014 The Android Open Source Project
      2 //
      3 // This software is licensed under the terms of the GNU General Public
      4 // License version 2, as published by the Free Software Foundation, and
      5 // may be copied, distributed, and modified under those terms.
      6 //
      7 // This program is distributed in the hope that it will be useful,
      8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 // GNU General Public License for more details.
     11 
     12 #include "android/utils/property_file.h"
     13 
     14 #include "android/utils/system.h"
     15 
     16 #include <string.h>
     17 #include <stdlib.h>
     18 
     19 // Return true iff |ch| is whitespace. Don't use isspace() to avoid
     20 // locale-related results and associated issues.
     21 static int isspace(int ch) {
     22     return (ch == ' ' || ch == '\t');
     23 }
     24 
     25 void propertyFileIterator_init(PropertyFileIterator* iter,
     26                                const void* propFile,
     27                                size_t propFileLen) {
     28     iter->name[0] = '\0';
     29     iter->value[0] = '\0';
     30     iter->p = propFile;
     31     iter->end = iter->p + propFileLen;
     32 }
     33 
     34 
     35 bool propertyFileIterator_next(PropertyFileIterator* iter) {
     36     const char* p = iter->p;
     37     const char* end = iter->end;
     38     while (p < end) {
     39         // Get end of line, and compute next line position.
     40         const char* line = p;
     41         const char* lineEnd = (const char*)memchr(p, '\n', end - p);
     42         if (!lineEnd) {
     43             lineEnd = end;
     44             p = end;
     45         } else {
     46             p = lineEnd + 1;
     47         }
     48 
     49         // Remove trailing \r before the \n, if any.
     50         if (lineEnd > line && lineEnd[-1] == '\r')
     51             lineEnd--;
     52 
     53         // Skip leading whitespace.
     54         while (line < lineEnd && isspace(line[0]))
     55             line++;
     56 
     57         // Skip empty lines, and those that begin with '#' for comments.
     58         if (lineEnd == line || line[0] == '#')
     59             continue;
     60 
     61         const char* name = line;
     62         const char* nameEnd =
     63                 (const char*)memchr(name, '=', lineEnd - name);
     64         if (!nameEnd) {
     65             // Skipping lines without a =
     66             continue;
     67         }
     68         const char* value = nameEnd + 1;
     69         while (nameEnd > name && isspace(nameEnd[-1]))
     70             nameEnd--;
     71 
     72         size_t nameLen = nameEnd - name;
     73         if (nameLen == 0 || nameLen >= MAX_PROPERTY_NAME_LEN) {
     74             // Skip lines without names, or with names too long.
     75             continue;
     76         }
     77 
     78         memcpy(iter->name, name, nameLen);
     79         iter->name[nameLen] = '\0';
     80 
     81         // Truncate value's length.
     82         size_t valueLen = (lineEnd - value);
     83         if (valueLen >= MAX_PROPERTY_VALUE_LEN)
     84             valueLen = (MAX_PROPERTY_VALUE_LEN - 1);
     85 
     86         memcpy(iter->value, value, valueLen);
     87         iter->value[valueLen] = '\0';
     88 
     89         iter->p = p;
     90         return true;
     91     }
     92     iter->p = p;
     93     return false;
     94 }
     95 
     96 char* propertyFile_getValue(const char* propFile,
     97                             size_t propFileLen,
     98                             const char* propName) {
     99     size_t propNameLen = strlen(propName);
    100     if (propNameLen >= MAX_PROPERTY_NAME_LEN)
    101         return NULL;
    102 
    103     char* ret = NULL;
    104     PropertyFileIterator iter[1];
    105     propertyFileIterator_init(iter, propFile, propFileLen);
    106     while (propertyFileIterator_next(iter)) {
    107         if (!strcmp(iter->name, propName)) {
    108             free(ret);
    109             ret = ASTRDUP(iter->value);
    110         }
    111     }
    112     return ret;
    113 }
    114