/* * Accept INI property value and store known values in handler_first_param * struct. */ static int ini_handler(void* hfp, const char* section, const char* name, const char* value) { handler_first_param* hfparam = (handler_first_param*)hfp; /* prepend ** to pattern */ char* pattern; /* root = true, clear all previous values */ if (*section == '\0' && !strcasecmp(name, "root") && !strcasecmp(value, "true")) { array_editorconfig_name_value_clear(&hfparam->array_name_value); array_editorconfig_name_value_init(&hfparam->array_name_value); return 1; } /* pattern would be: /dir/of/editorconfig/file[double_star]/[section] if * section does not contain '/', or /dir/of/editorconfig/file[section] * if section starts with a '/', or /dir/of/editorconfig/file/[section] if * section contains '/' but does not start with '/' */ pattern = (char*)malloc( strlen(hfparam->editorconfig_file_dir) * sizeof(char) + sizeof("**/") + strlen(section) * sizeof(char)); if (!pattern) return 0; strcpy(pattern, hfparam->editorconfig_file_dir); if (strchr(section, '/') == NULL) /* No / is found, append '[star][star]/' */ strcat(pattern, "**/"); else if (*section != '/') /* The first char is not '/' but section contains '/', append a '/' */ strcat(pattern, "/"); strcat(pattern, section); if (ec_fnmatch(pattern, hfparam->full_filename, EC_FNM_PATHNAME) == 0) { if (array_editorconfig_name_value_add(&hfparam->array_name_value, name, value)) { free(pattern); return 0; } } free(pattern); return 1; }
EDITORCONFIG_LOCAL int ec_fnmatch(const char *pattern, const char *string, int flags) { const char *stringstart; char c, test; /* When multi stars presents, should_fnm_pathname will be set to 0 * regardless of whether EC_FNM_PATHNAME is set into flags. Otherwise, the * value equals to flags & EC_FNM_PATHNAME */ _Bool should_fnm_pathname = 0; for (stringstart = string;;) switch (c = *pattern++) { case EOS: if ((flags & EC_FNM_LEADING_DIR) && *string == '/') return (0); return (*string == EOS ? 0 : EC_FNM_NOMATCH); case '?': if (*string == EOS) return (EC_FNM_NOMATCH); if (*string == '/' && (flags & EC_FNM_PATHNAME)) return (EC_FNM_NOMATCH); if (*string == '.' && (flags & EC_FNM_PERIOD) && (string == stringstart || ((flags & EC_FNM_PATHNAME) && *(string - 1) == '/'))) return (EC_FNM_NOMATCH); ++string; break; case '*': c = *pattern; /* see the comments above the declaration of should_fnm_pathname */ should_fnm_pathname = (_Bool)((c != '*') && (flags & EC_FNM_PATHNAME)); /* Collapse multiple stars. */ while (c == '*') c = *++pattern; if (*string == '.' && (flags & EC_FNM_PERIOD) && (string == stringstart || (should_fnm_pathname && *(string - 1) == '/'))) return (EC_FNM_NOMATCH); /* Optimize for pattern with * at end or before /. */ if (c == EOS) if (should_fnm_pathname) return ((flags & EC_FNM_LEADING_DIR) || strchr(string, '/') == NULL ? 0 : EC_FNM_NOMATCH); else return (0); else if (c == '/' && should_fnm_pathname) { if ((string = strchr(string, '/')) == NULL) return (EC_FNM_NOMATCH); break; } /* General case, use recursion. */ while ((test = *string) != EOS) { if (!ec_fnmatch(pattern, string, flags & ~EC_FNM_PERIOD)) return (0); if (test == '/' && should_fnm_pathname) break; ++string; } return (EC_FNM_NOMATCH); case '[': if (*string == EOS) return (EC_FNM_NOMATCH); if (*string == '/' && flags & EC_FNM_PATHNAME) return (EC_FNM_NOMATCH); if ((pattern = rangematch(pattern, *string, flags)) == NULL) return (EC_FNM_NOMATCH); ++string; break; case '\\': if (!(flags & EC_FNM_NOESCAPE)) { if ((c = *pattern++) == EOS) { c = '\\'; --pattern; } } /* FALLTHROUGH */ default: if (c == *string) ; else if ((flags & EC_FNM_CASEFOLD) && (tolower((unsigned char)c) == tolower((unsigned char)*string))) ; else if ((flags & EC_FNM_PREFIX_DIRS) && *string == EOS && ((c == '/' && string != stringstart) || (string == stringstart+1 && *stringstart == '/'))) return (0); else return (EC_FNM_NOMATCH); string++; break; } /* NOTREACHED */ }