PengZheng commented on code in PR #692:
URL: https://github.com/apache/celix/pull/692#discussion_r1421711752


##########
libs/utils/src/filter.c:
##########
@@ -463,367 +555,327 @@ static celix_status_t 
celix_filter_compile(celix_filter_t* filter) {
     return CELIX_SUCCESS;
 }
 
-celix_status_t filter_match(celix_filter_t * filter, celix_properties_t 
*properties, bool *out) {
+celix_status_t filter_match(celix_filter_t* filter, celix_properties_t* 
properties, bool* out) {
     bool result = celix_filter_match(filter, properties);
     if (out != NULL) {
         *out = result;
     }
     return CELIX_SUCCESS;
 }
 
-static int celix_filter_compareAttributeValue(const celix_filter_t* filter, 
const char* propertyValue) {
-    if (!filter->internal->convertedToLong && 
!filter->internal->convertedToDouble && !filter->internal->convertedToVersion) {
-        return strcmp(propertyValue, filter->value);
+static int celix_filter_cmpLong(long a, long b) {
+    if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    } else {
+        return 0;
     }
+}
 
-    if (filter->internal->convertedToLong) {
-        bool propertyValueIsLong = false;
-        long value = celix_utils_convertStringToLong(propertyValue, 0, 
&propertyValueIsLong);
-        if (propertyValueIsLong) {
-            if (value < filter->internal->longValue)
-                return -1;
-            else if (value > filter->internal->longValue)
-                return 1;
-            else
-                return 0;
-        }
-    }
-
-    if (filter->internal->convertedToDouble) {
-        bool propertyValueIsDouble = false;
-        double value = celix_utils_convertStringToDouble(propertyValue, 0.0, 
&propertyValueIsDouble);
-        if (propertyValueIsDouble) {
-            if (value < filter->internal->doubleValue) {
-                return -1;
-            } else if (value > filter->internal->doubleValue) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
+static int celix_filter_cmpDouble(double a, double b) {
+    if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static int celix_filter_cmpBool(bool a, bool b) {
+    if (a == b) {
+        return 0;
+    } else if (a) {
+        return 1;
+    } else {
+        return -1;
+    }
+}
+
+static int celix_filter_compareAttributeValue(const celix_filter_t* filter, 
const celix_properties_entry_t* entry) {
+    // not converted, fallback on string compare
+    if (!filter->internal->convertedToLong && 
!filter->internal->convertedToDouble &&
+        !filter->internal->convertedToBool && 
!filter->internal->convertedToVersion) {
+        return strcmp(entry->value, filter->value);
     }
 
-    if (filter->internal->convertedToVersion) {
-        bool propertyValueIsVersion = false;
-        celix_version_t *value = 
celix_utils_convertStringToVersion(propertyValue, NULL, 
&propertyValueIsVersion);
-        if (propertyValueIsVersion) {
-            int cmp = celix_version_compareTo(value, 
filter->internal->versionValue);
-            celix_version_destroy(value);
+    // compare typed values
+    if (filter->internal->convertedToLong && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_LONG) {
+        return celix_filter_cmpLong(entry->typed.longValue, 
filter->internal->longValue);
+    } else if (filter->internal->convertedToDouble && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_DOUBLE) {
+        return celix_filter_cmpDouble(entry->typed.doubleValue, 
filter->internal->doubleValue);
+    } else if (filter->internal->convertedToBool && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_BOOL) {
+        return celix_filter_cmpBool(entry->typed.boolValue, 
filter->internal->boolValue);
+    } else if (filter->internal->convertedToVersion && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_VERSION) {
+        return celix_version_compareTo(entry->typed.versionValue, 
filter->internal->versionValue);
+    }
+
+    // check if the property string value can be converted to the filter value 
type
+    bool propertyConverted;
+    if (filter->internal->convertedToLong) {
+        long val = celix_utils_convertStringToLong(entry->value, 0, 
&propertyConverted);
+        if (propertyConverted) {
+            return celix_filter_cmpLong(val, filter->internal->longValue);
+        }
+    } else if (filter->internal->convertedToDouble) {
+        double val = celix_utils_convertStringToDouble(entry->value, 0.0, 
&propertyConverted);
+        if (propertyConverted) {
+            return celix_filter_cmpDouble(val, filter->internal->doubleValue);
+        }
+    } else if (filter->internal->convertedToBool) {
+        bool val = celix_utils_convertStringToBool(entry->value, false, 
&propertyConverted);
+        if (propertyConverted) {
+            return celix_filter_cmpBool(val, filter->internal->boolValue);
+        }
+    } else if (filter->internal->convertedToVersion) {
+        celix_version_t* val = 
celix_utils_convertStringToVersion(entry->value, NULL, &propertyConverted);
+        if (propertyConverted) {
+            int cmp = celix_version_compareTo(val, 
filter->internal->versionValue);
+            celix_version_destroy(val);
             return cmp;
         }
     }
 
-    //fallback on string compare
-    return strcmp(propertyValue, filter->value);
+    // fallback on string compare
+    return strcmp(entry->value, filter->value);
 }
 
-static celix_status_t filter_compare(const celix_filter_t* filter, const char 
*propertyValue, bool *out) {
-    celix_status_t  status = CELIX_SUCCESS;
-    bool result = false;
+static bool celix_filter_matchSubString(const celix_filter_t* filter, const 
celix_properties_entry_t* entry) {
+    assert(filter->children && celix_arrayList_size(filter->children) >= 2);
 
-    if (filter == NULL || propertyValue == NULL) {
-        *out = false;
-        return status;
-    }
+    size_t strLen = celix_utils_strlen(entry->value);
+    const char* initial = celix_arrayList_get(filter->children, 0);
+    const char* final = celix_arrayList_get(filter->children, 
celix_arrayList_size(filter->children) - 1);
 
-    switch (filter->operand) {
-        case CELIX_FILTER_OPERAND_SUBSTRING: {
-            int pos = 0;
-            int size = celix_arrayList_size(filter->children);
-            for (int i = 0; i < size; i++) {
-                char * substr = (char *) celix_arrayList_get(filter->children, 
i);
-
-                if (i + 1 < size) {
-                    if (substr == NULL) {
-                        unsigned int index;
-                        char * substr2 = (char *) 
celix_arrayList_get(filter->children, i + 1);
-                        if (substr2 == NULL) {
-                            continue;
-                        }
-                        index = strcspn(propertyValue+pos, substr2);
-                        if (index == strlen(propertyValue+pos)) {
-                            *out = false;
-                            return CELIX_SUCCESS;
-                        }
-
-                        pos = index + strlen(substr2);
-                        if (i + 2 < size) {
-                            i++;
-                        }
-                    } else {
-                        unsigned int len = strlen(substr);
-                        char * region = (char *)calloc(1, len+1);
-                        strncpy(region, propertyValue+pos, len);
-                        region[len]    = '\0';
-                        if (strcmp(region, substr) == 0) {
-                            pos += len;
-                        } else {
-                            free(region);
-                            *out = false;
-                            return CELIX_SUCCESS;
-                        }
-                        free(region);
-                    }
-                } else {
-                    unsigned int len;
-                    int begin;
+    const char* currentValue = entry->value;
 
-                    if (substr == NULL) {
-                        *out = true;
-                        return CELIX_SUCCESS;
-                    }
-                    len = strlen(substr);
-                    begin = strlen(propertyValue)-len;
-                    *out = (strcmp(propertyValue+begin, substr) == 0);
-                    return CELIX_SUCCESS;
-                }
-            }
-            *out = true;
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_APPROX: {
-            *out = strcasecmp(propertyValue, filter->value) == 0;
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_EQUAL: {
-            *out = (celix_filter_compareAttributeValue(filter, propertyValue) 
== 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_GREATER: {
-            *out = (celix_filter_compareAttributeValue(filter, propertyValue) 
> 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_GREATEREQUAL: {
-            *out = (celix_filter_compareAttributeValue(filter, propertyValue) 
>= 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_LESS: {
-            *out = (celix_filter_compareAttributeValue(filter, propertyValue) 
< 0);
-            return CELIX_SUCCESS;
+    if (initial) {
+        const char* found = strstr(entry->value, initial);
+        currentValue = found + celix_utils_strlen(initial);
+        if (!found || found != entry->value) {
+            return false;
         }
-        case CELIX_FILTER_OPERAND_LESSEQUAL: {
-            *out = (celix_filter_compareAttributeValue(filter, propertyValue) 
<= 0);
-            return CELIX_SUCCESS;
+    }
+
+    for (int i = 1; i < celix_arrayList_size(filter->children) - 1; i++) {
+        const char* substr = celix_arrayList_get(filter->children, i);
+        const char* found = strstr(currentValue, substr);
+        if (!found || found <= currentValue) {
+            return false;
         }
-        case CELIX_FILTER_OPERAND_AND:
-        case CELIX_FILTER_OPERAND_NOT:
-        case CELIX_FILTER_OPERAND_OR:
-        case CELIX_FILTER_OPERAND_PRESENT: {
+        currentValue = found + celix_utils_strlen(substr);
+    }
+
+    if (final) {
+        const char* found = strstr(currentValue, final);
+        if (!found || found <= currentValue || found + 
celix_utils_strlen(final) != entry->value + strLen) {
+            return false;
         }
-            /* no break */
     }
 
-    if (out != NULL) {
-        *out = result;
+    return true;
+}
+
+static bool celix_filter_matchPropertyEntry(const celix_filter_t* filter, 
const celix_properties_entry_t* entry) {
+    switch (filter->operand) {
+    case CELIX_FILTER_OPERAND_SUBSTRING:
+        return celix_filter_matchSubString(filter, entry);
+    case CELIX_FILTER_OPERAND_APPROX:
+        return strcasecmp(entry->value, filter->value) == 0;
+    case CELIX_FILTER_OPERAND_EQUAL:
+        return celix_filter_compareAttributeValue(filter, entry) == 0;
+    case CELIX_FILTER_OPERAND_GREATER:
+        return celix_filter_compareAttributeValue(filter, entry) > 0;
+    case CELIX_FILTER_OPERAND_GREATEREQUAL:
+        return celix_filter_compareAttributeValue(filter, entry) >= 0;
+    case CELIX_FILTER_OPERAND_LESS:
+        return celix_filter_compareAttributeValue(filter, entry) < 0;
+    default:
+        assert(filter->operand == CELIX_FILTER_OPERAND_LESSEQUAL);
+        return celix_filter_compareAttributeValue(filter, entry) <= 0;
     }
-    return status;
 }
 
-celix_status_t filter_getString(celix_filter_t * filter, const char 
**filterStr) {
+celix_status_t filter_getString(celix_filter_t* filter, const char** 
filterStr) {
     if (filter != NULL) {
         *filterStr = filter->filterStr;
     }
     return CELIX_SUCCESS;
 }
 
-celix_status_t filter_match_filter(celix_filter_t *src, celix_filter_t *dest, 
bool *out) {
-    bool result = celix_filter_matchFilter(src, dest);
+celix_status_t filter_match_filter(celix_filter_t* src, celix_filter_t* dest, 
bool* out) {
+    bool result = celix_filter_equals(src, dest);
     if (out != NULL) {
         *out = result;
     }
     return CELIX_SUCCESS;
 }
 
+celix_filter_t* celix_filter_create(const char* filterString) {
+    if (!filterString || filterString[0] == '\0') {
+        filterString = "(|)";
+    }
 
-celix_filter_t* celix_filter_create(const char *filterString) {
-    celix_filter_t * filter = NULL;
-    char* filterStr = string_ndup(filterString, 1024*1024);
     int pos = 0;
-    filter = filter_parseFilter(filterStr, &pos);
-    if (filter != NULL && pos != strlen(filterStr)) {
-        fprintf(stderr, "Filter Error: Extraneous trailing characters.\n");
-        filter_destroy(filter);
-        filter = NULL;
-    } else if (filter != NULL) {
-        if (filter->operand != CELIX_FILTER_OPERAND_OR && filter->operand != 
CELIX_FILTER_OPERAND_AND &&
-            filter->operand != CELIX_FILTER_OPERAND_NOT && filter->operand != 
CELIX_FILTER_OPERAND_SUBSTRING &&
-            filter->operand != CELIX_FILTER_OPERAND_PRESENT) {
-            if (filter->attribute == NULL || filter->value == NULL) {
-                filter_destroy(filter);
-                filter = NULL;
-            }
-        }
+    celix_autoptr(celix_filter_t) filter = 
celix_filter_parseFilter(filterString, &pos);
+    if (!filter) {
+        celix_err_push("Failed to parse filter string");
+        return NULL;
     }
-
-    if (filter == NULL) {
-        free(filterStr);
-    } else {
-        filter->filterStr = filterStr;
-        celix_status_t status = celix_filter_compile(filter);
-        if (status != CELIX_SUCCESS) {
-            celix_filter_destroy(filter);
-            filter = NULL;
-        }
+    if (pos != strlen(filterString)) {
+        celix_err_push("Filter Error: Extraneous trailing characters.");
+        return NULL;
     }
-
-    return filter;
+    if (celix_filter_compile(filter) != CELIX_SUCCESS) {
+        celix_err_push("Failed to compile filter");
+        return NULL;
+    }
+    filter->filterStr = celix_utils_strdup(filterString);
+    if (NULL == filter->filterStr) {
+        celix_err_push("Failed to create filter string");
+        return NULL;
+    }
+    return celix_steal_ptr(filter);
 }
 
-void celix_filter_destroy(celix_filter_t *filter) {
-    if (filter != NULL) {
-        if(filter->children != NULL) {
-            if (filter->operand == CELIX_FILTER_OPERAND_SUBSTRING) {
-                int size = celix_arrayList_size(filter->children);
-                int i = 0;
-                for (i = 0; i < size; i++) {
-                    char *operand = celix_arrayList_get(filter->children, i);
-                    free(operand);
-                }
-                celix_arrayList_destroy(filter->children);
-                filter->children = NULL;
-            } else if (filter->operand == CELIX_FILTER_OPERAND_OR || 
filter->operand == CELIX_FILTER_OPERAND_AND || filter->operand == 
CELIX_FILTER_OPERAND_NOT) {
-                int size = celix_arrayList_size(filter->children);
-                int i = 0;
-                for (i = 0; i < size; i++) {
-                    celix_filter_t *f = celix_arrayList_get(filter->children, 
i);
-                    celix_filter_destroy(f);
-                }
-                celix_arrayList_destroy(filter->children);
-                filter->children = NULL;
-            } else {
-                fprintf(stderr, "Filter Error: Corrupt filter. children has a 
value, but not an expected operand\n");
-            }
-        }
-        free((char*)filter->value);
-        filter->value = NULL;
-        free((char*)filter->attribute);
-        filter->attribute = NULL;
-        free((char*)filter->filterStr);
-        filter->filterStr = NULL;
-        if (filter->internal != NULL) {
-            celix_version_destroy(filter->internal->versionValue);
-            free(filter->internal);
-        }
-        free(filter);
+void celix_filter_destroy(celix_filter_t* filter) {
+    if (!filter) {
+        return;
+    }
+
+    if (filter->children != NULL) {
+        celix_arrayList_destroy(filter->children);
+        filter->children = NULL;
     }
+    free((char*)filter->value);
+    filter->value = NULL;
+    free((char*)filter->attribute);
+    filter->attribute = NULL;
+    free((char*)filter->filterStr);
+    filter->filterStr = NULL;
+    if (filter->internal != NULL) {
+        celix_version_destroy(filter->internal->versionValue);
+        free(filter->internal);
+    }
+    free(filter);
 }
 
-bool celix_filter_match(const celix_filter_t *filter, const 
celix_properties_t* properties) {
-    if (filter == NULL) {
-        return true; //matching on null(empty) filter is always true
+bool celix_filter_match(const celix_filter_t* filter, const 
celix_properties_t* properties) {
+    if (!filter) {
+        return true; // if filter is NULL, it matches
     }
-    bool result = false;
-    switch (filter->operand) {
-        case CELIX_FILTER_OPERAND_AND: {
-            celix_array_list_t* children = filter->children;
-            for (int i = 0; i < celix_arrayList_size(children); i++) {
-                celix_filter_t * sfilter = (celix_filter_t *) 
celix_arrayList_get(children, i);
-                bool mresult = celix_filter_match(sfilter, properties);
-                if (!mresult) {
-                    return false;
-                }
+
+    if (filter->operand == CELIX_FILTER_OPERAND_PRESENT) {
+        return celix_properties_get(properties, filter->attribute, NULL) != 
NULL;
+    } else if (filter->operand == CELIX_FILTER_OPERAND_AND) {
+        celix_array_list_t* children = filter->children;
+        for (int i = 0; i < celix_arrayList_size(children); i++) {
+            celix_filter_t* childFilter = 
(celix_filter_t*)celix_arrayList_get(children, i);
+            bool childResult = celix_filter_match(childFilter, properties);
+            if (!childResult) {
+                return false;
             }
+        }
+        return true;
+    } else if (filter->operand == CELIX_FILTER_OPERAND_OR) {
+        celix_array_list_t* children = filter->children;
+        if (celix_arrayList_size(children) == 0) {
             return true;
         }
-        case CELIX_FILTER_OPERAND_OR: {
-            celix_array_list_t* children = filter->children;
-            for (int i = 0; i < celix_arrayList_size(children); i++) {
-                celix_filter_t * sfilter = (celix_filter_t *) 
celix_arrayList_get(children, i);
-                bool mresult = celix_filter_match(sfilter, properties);
-                if (mresult) {
-                    return true;
-                }
+        for (int i = 0; i < celix_arrayList_size(children); i++) {
+            celix_filter_t* childFilter = 
(celix_filter_t*)celix_arrayList_get(children, i);
+            bool childResult = celix_filter_match(childFilter, properties);
+            if (childResult) {
+                return true;
             }
-            return false;
-        }
-        case CELIX_FILTER_OPERAND_NOT: {
-            celix_filter_t * sfilter = celix_arrayList_get(filter->children, 
0);
-            bool mresult = celix_filter_match(sfilter, properties);
-            return !mresult;
-        }
-        case CELIX_FILTER_OPERAND_SUBSTRING :
-        case CELIX_FILTER_OPERAND_EQUAL :
-        case CELIX_FILTER_OPERAND_GREATER :
-        case CELIX_FILTER_OPERAND_GREATEREQUAL :
-        case CELIX_FILTER_OPERAND_LESS :
-        case CELIX_FILTER_OPERAND_LESSEQUAL :
-        case CELIX_FILTER_OPERAND_APPROX : {
-            char * value = (properties == NULL) ? NULL: 
(char*)celix_properties_get(properties, filter->attribute, NULL);
-            filter_compare(filter, value, &result);
-            return result;
-        }
-        case CELIX_FILTER_OPERAND_PRESENT: {
-            char * value = (properties == NULL) ? NULL: 
(char*)celix_properties_get(properties, filter->attribute, NULL);
-            return value != NULL;
         }
+        return false;
+    } else if (filter->operand == CELIX_FILTER_OPERAND_NOT) {
+        celix_filter_t* childFilter = celix_arrayList_get(filter->children, 0);
+        bool childResult = celix_filter_match(childFilter, properties);
+        return !childResult;
     }
-    return result;
+
+    // substring, equal, greater, greaterEqual, less, lessEqual, approx done 
with matchPropertyEntry
+    const celix_properties_entry_t* entry = 
celix_properties_getEntry(properties, filter->attribute);
+    if (!entry) {
+            return false;
+    }
+    return celix_filter_matchPropertyEntry(filter, entry);
 }
 
-bool celix_filter_matchFilter(const celix_filter_t *filter1, const 
celix_filter_t *filter2) {
-    bool result = false;
+bool celix_filter_equals(const celix_filter_t* filter1, const celix_filter_t* 
filter2) {
     if (filter1 == filter2) {
-        result = true; //NOTE. also means NULL filter are equal
-    } else if (filter1 != NULL && filter2 != NULL && filter1->operand == 
filter2->operand) {
-        if (filter1->operand == CELIX_FILTER_OPERAND_AND || filter1->operand 
== CELIX_FILTER_OPERAND_OR || filter1->operand == CELIX_FILTER_OPERAND_NOT) {
-            assert(filter1->children != NULL);
-            assert(filter2->children != NULL);
-            int sizeSrc = celix_arrayList_size(filter1->children);
-            int sizeDest = celix_arrayList_size(filter2->children);
-            if (sizeSrc == sizeDest) {
-                int i;
-                int k;
-                int sameCount = 0;
-                for (i =0; i < sizeSrc; ++i) {
-                    bool same = false;
-                    celix_filter_t *srcPart = 
celix_arrayList_get(filter1->children, i);
-                    for (k = 0; k < sizeDest; ++k) {
-                        celix_filter_t *destPart = 
celix_arrayList_get(filter2->children, k);
-                        filter_match_filter(srcPart, destPart, &same);
-                        if (same) {
-                            sameCount += 1;
-                            break;
-                        }
+        return true;
+    }
+    if (!filter1 || !filter2) {
+        return false;
+    }
+    if (filter1->operand != filter2->operand) {
+        return false;
+    }
+
+    if (filter1->operand == CELIX_FILTER_OPERAND_AND || filter1->operand == 
CELIX_FILTER_OPERAND_OR ||
+        filter1->operand == CELIX_FILTER_OPERAND_NOT) {
+        assert(filter1->children != NULL);
+        assert(filter2->children != NULL);
+        int sizeSrc = celix_arrayList_size(filter1->children);
+        int sizeDest = celix_arrayList_size(filter2->children);
+        if (sizeSrc == sizeDest) {
+            int i;
+            int k;
+            int sameCount = 0;
+            for (i = 0; i < sizeSrc; ++i) {
+                bool same = false;
+                celix_filter_t* srcPart = 
celix_arrayList_get(filter1->children, i);
+                for (k = 0; k < sizeDest; ++k) {
+                    celix_filter_t* destPart = 
celix_arrayList_get(filter2->children, k);
+                    filter_match_filter(srcPart, destPart, &same);
+                    if (same) {
+                        sameCount += 1;
+                        break;
                     }
                 }
-                result = sameCount == sizeSrc;
-            }
-        } else { //compare attr and value
-            bool attrSame = false;
-            bool valSame = false;
-            if (filter1->attribute == NULL && filter2->attribute == NULL) {
-                attrSame = true;
-            } else if (filter1->attribute != NULL && filter2->attribute != 
NULL) {
-                attrSame = celix_utils_stringEquals(filter1->attribute, 
filter2->attribute);
             }
+            return sameCount == sizeSrc;
+        }
+        return false;
+    }
 
-            if (filter1->value == NULL  && filter2->value == NULL) {
-                valSame = true;
-            } else if (filter1->value != NULL && filter2->value != NULL) {
-                valSame = celix_utils_stringEquals(filter1->value, 
filter2->value);
-            }
+    // compare attr and value
+    bool attrSame = false;
+    bool valSame = false;
+    if (filter1->attribute == NULL && filter2->attribute == NULL) {
+        attrSame = true;
+    } else if (filter1->attribute != NULL && filter2->attribute != NULL) {
+        attrSame = celix_utils_stringEquals(filter1->attribute, 
filter2->attribute);
+    }
 
-            result = attrSame && valSame;
-        }
+    if (filter1->value == NULL && filter2->value == NULL) {
+        valSame = true;
+    } else if (filter1->value != NULL && filter2->value != NULL) {
+        valSame = celix_utils_stringEquals(filter1->value, filter2->value);
     }
 
-    return result;
+    return attrSame && valSame;
 }
 
-const char* celix_filter_getFilterString(const celix_filter_t *filter) {
+const char* celix_filter_getFilterString(const celix_filter_t* filter) {
     if (filter != NULL) {
         return filter->filterStr;
     }
     return NULL;
 }
 
-const char* celix_filter_findAttribute(const celix_filter_t *filter, const 
char *attribute) {
-    const char *result = NULL;
+const char* celix_filter_findAttribute(const celix_filter_t* filter, const 
char* attribute) {

Review Comment:
   This interface seems not well-defined: for filter `(|(a=b)(a=c))`, what 
should `celix_filter_findAttribute` return for `a`?
    



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscr...@celix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to