static void glob_like_ucs_nfd_common(sqlite3_context *context, int argc, sqlite3_value **argv, svn_boolean_t sql_like) { svn_sqlite__db_t *const db = sqlite3_user_data(context); const char *const pattern = (void*)sqlite3_value_text(argv[0]); const apr_size_t pattern_len = sqlite3_value_bytes(argv[0]); const char *const string = (void*)sqlite3_value_text(argv[1]); const apr_size_t string_len = sqlite3_value_bytes(argv[1]); const char *escape = NULL; apr_size_t escape_len = 0; svn_boolean_t match; svn_error_t *err; if (pattern_len > SQLITE_MAX_LIKE_PATTERN_LENGTH) { sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } if (argc == 3 && sql_like) { escape = (void*)sqlite3_value_text(argv[2]); escape_len = sqlite3_value_bytes(argv[2]); } if (pattern && string) { err = svn_utf__glob(pattern, pattern_len, string, string_len, escape, escape_len, sql_like, &db->sqlext_buf1, &db->sqlext_buf2, &db->sqlext_buf3, &match); if (err) { const char *errmsg; svn_membuf__ensure(&db->sqlext_buf1, 512); errmsg = svn_err_best_message(err, db->sqlext_buf1.data, db->sqlext_buf1.size - 1); svn_error_clear(err); sqlite3_result_error(context, errmsg, -1); return; } sqlite3_result_int(context, match); } }
unsigned int svn_string__similarity(const svn_string_t *stringa, const svn_string_t *stringb, svn_membuf_t *buffer, apr_size_t *rlcs) { const char *stra = stringa->data; const char *strb = stringb->data; const apr_size_t lena = stringa->len; const apr_size_t lenb = stringb->len; const apr_size_t total = lena + lenb; const char *enda = stra + lena; const char *endb = strb + lenb; apr_size_t lcs = 0; /* Skip the common prefix ... */ while (stra < enda && strb < endb && *stra == *strb) { ++stra; ++strb; ++lcs; } /* ... and the common suffix */ while (stra < enda && strb < endb) { --enda; --endb; if (*enda != *endb) { ++enda; ++endb; break; } ++lcs; } if (stra < enda && strb < endb) { const apr_size_t resta = enda - stra; const apr_size_t restb = endb - strb; const apr_size_t slots = (resta > restb ? restb : resta); apr_size_t *curr, *prev; const char *pstr; /* The outer loop must iterate on the longer string. */ if (resta < restb) { pstr = stra; stra = strb; strb = pstr; pstr = enda; enda = endb; endb = pstr; } /* Allocate two columns in the LCS matrix ### Optimize this to (slots + 2) instesd of 2 * (slots + 1) */ svn_membuf__ensure(buffer, 2 * (slots + 1) * sizeof(apr_size_t)); svn_membuf__nzero(buffer, (slots + 2) * sizeof(apr_size_t)); prev = buffer->data; curr = prev + slots + 1; /* Calculate LCS length of the remainder */ for (pstr = stra; pstr < enda; ++pstr) { int i; for (i = 1; i <= slots; ++i) { if (*pstr == strb[i-1]) curr[i] = prev[i-1] + 1; else curr[i] = (curr[i-1] > prev[i] ? curr[i-1] : prev[i]); } /* Swap the buffers, making the previous one current */ { apr_size_t *const temp = prev; prev = curr; curr = temp; } } lcs += prev[slots]; } if (rlcs) *rlcs = lcs; /* Return similarity ratio rounded to 4 significant digits */ if (total) return(unsigned int)((2000 * lcs + total/2) / total); else return 1000; }