ucx/properties.c

Fri, 12 Jul 2013 20:50:18 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 12 Jul 2013 20:50:18 +0200
changeset 108
d2b1e67b2b48
child 109
75cb6590358b
permissions
-rw-r--r--

new properties parser

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013 Olaf Wintermann. All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  */
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <string.h>
    33 #include "properties.h"
    35 UcxPropParser *ucx_prop_new() {
    36     UcxPropParser *parser = (UcxPropParser*)malloc(
    37             sizeof(UcxPropParser));
    38     if(!parser) {
    39         return NULL;
    40     }
    42     parser->buffer = NULL;
    43     parser->buflen = 0;
    44     parser->pos = 0;
    45     parser->tmp = NULL;
    46     parser->tmplen = 0;
    47     parser->tmpcap = 0;
    48     parser->delimiter = '=';
    49     parser->comment1 = '#';
    50     parser->comment2 = 0;
    51     parser->comment3 = 0;   
    53     return parser;
    54 }
    56 void ucx_prop_free(UcxPropParser *parser) {
    57     if(parser->tmp) {
    58         free(parser->tmp);
    59     }
    60     free(parser);
    61 }
    63 void ucx_prop_fill(UcxPropParser *parser, char *buf, size_t len) {
    64     parser->buffer = buf;
    65     parser->buflen = len;
    66     parser->pos = 0;
    67 }
    69 static void parser_tmp_append(UcxPropParser *parser, char *buf, size_t len) {
    70     if(parser->tmpcap - parser->tmplen < len) {
    71         size_t newcap = parser->tmpcap + len + 64;
    72         parser->tmp = (char*)realloc(parser->tmp, newcap);
    73         parser->tmpcap = newcap;
    74     }
    75     memcpy(parser->tmp + parser->tmplen, buf, len);
    76     parser->tmplen += len;
    77 }
    79 int ucx_prop_parse(UcxPropParser *parser, sstr_t *name, sstr_t *value)  {   
    80     if(parser->tmplen > 0) {
    81         char *buf = parser->buffer + parser->pos;
    82         size_t len = parser->buflen - parser->pos;
    83         sstr_t str = sstrn(buf, len);
    84         sstr_t nl = sstrchr(str, '\n');
    85         if(nl.ptr) {
    86             size_t newlen = (size_t)(nl.ptr - buf) + 1;
    87             parser_tmp_append(parser, buf, newlen);
    88             // the tmp buffer contains exactly one line now
    90             char *orig_buf = parser->buffer;
    91             size_t orig_len = parser->buflen;
    93             parser->buffer = parser->tmp;
    94             parser->buflen = parser->tmplen;
    95             parser->pos = 0;    
    96             parser->tmp = NULL;
    97             parser->tmpcap = 0;
    98             parser->tmplen = 0;
    99             // run parse with the tmp buffer as main buffer
   100             int ret = ucx_prop_parse(parser, name, value);
   102             // restore original buffer
   103             parser->tmp = parser->buffer;
   104             parser->buffer = orig_buf;
   105             parser->buflen = orig_len;
   106             parser->pos = newlen;
   108             /*
   109              * if ret == 0 the tmp buffer contained just space or comment
   110              * we parse again with the original buffer to get a name/value
   111              * or a new tmp buffer
   112              */
   113             return ret ? ret : ucx_prop_parse(parser, name, value);
   114         } else {
   115             parser_tmp_append(parser, buf, len);
   116             return 0;
   117         }
   118     } else if(parser->tmp) {
   119         free(parser->tmp);
   120         parser->tmp = NULL;
   121     }
   123     char comment1 = parser->comment1;
   124     char comment2 = parser->comment2;
   125     char comment3 = parser->comment3;
   126     char delimiter = parser->delimiter;
   128     // get one line and parse it
   129     while(1) {
   130         if(parser->pos >= parser->buflen) {
   131             return 0;
   132         }
   133         char *buf = parser->buffer + parser->pos;
   134         size_t len = parser->buflen - parser->pos;
   136         /*
   137          * First we check if we have at least one line. We also get indices of
   138          * delimiter and comment chars
   139          */
   140         size_t delimiter_index = 0;
   141         size_t comment_index = 0;
   142         int has_comment = 0;
   144         size_t i = 0;
   145         char c = 0;
   146         for(;i<len;i++) {
   147             c = buf[i];
   148             if(c == comment1 || c == comment2 || c == comment3) {
   149                 if(comment_index == 0) {
   150                     comment_index = i;
   151                     has_comment = 1;
   152                 }
   153             } else if(c == delimiter) {
   154                 if(delimiter_index == 0 && !has_comment) {
   155                     delimiter_index = i;
   156                 }
   157             } else if(c == '\n') {
   158                 break;
   159             }
   160         }
   162         if(c != '\n') {
   163             // we have not enough data for a line
   164             // store remaining bytes in temporary buffer for next round
   165             parser->tmpcap = len + 128;
   166             parser->tmp = (char*)malloc(parser->tmpcap);
   167             parser->tmplen = len;
   168             memcpy(parser->tmp, buf, len);
   169             return 0;
   170         }
   172         sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i);
   173         // check line
   174         if(delimiter_index == 0) {
   175             line = sstrtrim(line);
   176             if(line.length != 0) {
   177                 // syntax error
   178                 // TODO
   179             }
   180             parser->pos += i + 1;
   181             continue;
   182         }
   184         sstr_t n = sstrn(buf, delimiter_index);
   185         sstr_t v = sstrn(buf + delimiter_index + 1, i - delimiter_index - 1); 
   186         n = sstrtrim(n);
   187         v = sstrtrim(v);      
   188         if(n.length == 0 || v.length == 0) {
   189             // syntax error
   190             // TODO
   191             parser->pos += i + 1;
   192             continue;
   193         }
   195         *name = n;
   196         *value = v;
   198         parser->pos += i + 1;
   199         break;
   200     }
   202     return 1;
   203 }

mercurial