274 }; |
274 }; |
275 |
275 |
276 Flag* Flag::flags = flagTable; |
276 Flag* Flag::flags = flagTable; |
277 size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag)); |
277 size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag)); |
278 |
278 |
279 inline bool str_equal(const char* s, char* q, size_t len) { |
279 inline bool str_equal(const char* s, const char* q, size_t len) { |
280 // s is null terminated, q is not! |
280 // s is null terminated, q is not! |
281 if (strlen(s) != (unsigned int) len) return false; |
281 if (strlen(s) != (unsigned int) len) return false; |
282 return strncmp(s, q, len) == 0; |
282 return strncmp(s, q, len) == 0; |
283 } |
283 } |
284 |
284 |
285 // Search the flag table for a named flag |
285 // Search the flag table for a named flag |
286 Flag* Flag::find_flag(char* name, size_t length, bool allow_locked) { |
286 Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked) { |
287 for (Flag* current = &flagTable[0]; current->name != NULL; current++) { |
287 for (Flag* current = &flagTable[0]; current->name != NULL; current++) { |
288 if (str_equal(current->name, name, length)) { |
288 if (str_equal(current->name, name, length)) { |
289 // Found a matching entry. Report locked flags only if allowed. |
289 // Found a matching entry. Report locked flags only if allowed. |
290 if (!(current->is_unlocked() || current->is_unlocker())) { |
290 if (!(current->is_unlocked() || current->is_unlocker())) { |
291 if (!allow_locked) { |
291 if (!allow_locked) { |
299 } |
299 } |
300 // Flag name is not in the flag table |
300 // Flag name is not in the flag table |
301 return NULL; |
301 return NULL; |
302 } |
302 } |
303 |
303 |
|
304 // Compute string similarity based on Dice's coefficient |
|
305 static float str_similar(const char* str1, const char* str2, size_t len2) { |
|
306 int len1 = (int) strlen(str1); |
|
307 int total = len1 + (int) len2; |
|
308 |
|
309 int hit = 0; |
|
310 |
|
311 for (int i = 0; i < len1 -1; ++i) { |
|
312 for (int j = 0; j < (int) len2 -1; ++j) { |
|
313 if ((str1[i] == str2[j]) && (str1[i+1] == str2[j+1])) { |
|
314 ++hit; |
|
315 break; |
|
316 } |
|
317 } |
|
318 } |
|
319 |
|
320 return 2.0f * (float) hit / (float) total; |
|
321 } |
|
322 |
|
323 Flag* Flag::fuzzy_match(const char* name, size_t length, bool allow_locked) { |
|
324 float VMOptionsFuzzyMatchSimilarity = 0.7f; |
|
325 Flag* match = NULL; |
|
326 float score; |
|
327 float max_score = -1; |
|
328 |
|
329 for (Flag* current = &flagTable[0]; current->name != NULL; current++) { |
|
330 score = str_similar(current->name, name, length); |
|
331 if (score > max_score) { |
|
332 max_score = score; |
|
333 match = current; |
|
334 } |
|
335 } |
|
336 |
|
337 if (!(match->is_unlocked() || match->is_unlocker())) { |
|
338 if (!allow_locked) { |
|
339 return NULL; |
|
340 } |
|
341 } |
|
342 |
|
343 if (max_score < VMOptionsFuzzyMatchSimilarity) { |
|
344 return NULL; |
|
345 } |
|
346 |
|
347 return match; |
|
348 } |
|
349 |
304 // Returns the address of the index'th element |
350 // Returns the address of the index'th element |
305 static Flag* address_of_flag(CommandLineFlagWithType flag) { |
351 static Flag* address_of_flag(CommandLineFlagWithType flag) { |
306 assert((size_t)flag < Flag::numFlags, "bad command line flag index"); |
352 assert((size_t)flag < Flag::numFlags, "bad command line flag index"); |
307 return &Flag::flags[flag]; |
353 return &Flag::flags[flag]; |
308 } |
354 } |