src: Add command-line option guess
This commit is contained in:
parent
a15fc5fbb4
commit
90ea7ba92a
|
@ -1801,6 +1801,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
|
util::show_candidates(argv[optind - 1], long_options);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
case 0:
|
case 0:
|
||||||
switch(flag) {
|
switch(flag) {
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include "app_helper.h"
|
#include "app_helper.h"
|
||||||
#include "HttpServer.h"
|
#include "HttpServer.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace nghttp2 {
|
namespace nghttp2 {
|
||||||
|
|
||||||
|
@ -178,6 +179,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
|
util::show_candidates(argv[optind - 1], long_options);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
case 0:
|
case 0:
|
||||||
switch(flag) {
|
switch(flag) {
|
||||||
|
|
|
@ -52,6 +52,9 @@
|
||||||
#include "shrpx_config.h"
|
#include "shrpx_config.h"
|
||||||
#include "shrpx_listen_handler.h"
|
#include "shrpx_listen_handler.h"
|
||||||
#include "shrpx_ssl.h"
|
#include "shrpx_ssl.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
using namespace nghttp2;
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
|
@ -859,6 +862,7 @@ int main(int argc, char **argv)
|
||||||
print_version(std::cout);
|
print_version(std::cout);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
case '?':
|
case '?':
|
||||||
|
util::show_candidates(argv[optind - 1], long_options);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
case 0:
|
case 0:
|
||||||
switch(flag) {
|
switch(flag) {
|
||||||
|
|
72
src/util.cc
72
src/util.cc
|
@ -29,6 +29,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "timegm.h"
|
#include "timegm.h"
|
||||||
|
|
||||||
|
@ -281,6 +282,77 @@ void inp_strlower(std::string& s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Calculates Damerau–Levenshtein distance between c-string a and b
|
||||||
|
// with given costs. swapcost, subcost, addcost and delcost are cost
|
||||||
|
// to swap 2 adjacent characters, substitute characters, add character
|
||||||
|
// and delete character respectively.
|
||||||
|
int levenshtein
|
||||||
|
(const char* a,
|
||||||
|
const char* b,
|
||||||
|
int swapcost,
|
||||||
|
int subcost,
|
||||||
|
int addcost,
|
||||||
|
int delcost)
|
||||||
|
{
|
||||||
|
int alen = strlen(a);
|
||||||
|
int blen = strlen(b);
|
||||||
|
auto dp = std::vector<std::vector<int>>(3, std::vector<int>(blen+1));
|
||||||
|
for(int i = 0; i <= blen; ++i) {
|
||||||
|
dp[1][i] = i;
|
||||||
|
}
|
||||||
|
for(int i = 1; i <= alen; ++i) {
|
||||||
|
dp[0][0] = i;
|
||||||
|
for(int j = 1; j <= blen; ++j) {
|
||||||
|
dp[0][j] = dp[1][j-1]+(a[i-1] == b[j-1] ? 0 : subcost);
|
||||||
|
if(i >= 2 && j >= 2 && a[i-1] != b[j-1] &&
|
||||||
|
a[i-2] == b[j-1] && a[i-1] == b[j-2]) {
|
||||||
|
dp[0][j] = std::min(dp[0][j], dp[2][j-2]+swapcost);
|
||||||
|
}
|
||||||
|
dp[0][j] = std::min(dp[0][j],
|
||||||
|
std::min(dp[1][j]+delcost, dp[0][j-1]+addcost));
|
||||||
|
}
|
||||||
|
std::rotate(std::begin(dp), std::begin(dp)+2, std::end(dp));
|
||||||
|
}
|
||||||
|
return dp[1][blen];
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void show_candidates(const char *unkopt, option *options)
|
||||||
|
{
|
||||||
|
for(; *unkopt == '-'; ++unkopt);
|
||||||
|
if(*unkopt == '\0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto cands = std::vector<std::pair<int, const char*>>();
|
||||||
|
for(size_t i = 0; options[i].name != nullptr; ++i) {
|
||||||
|
// Use cost 0 for prefix match
|
||||||
|
if(istartsWith(options[i].name, unkopt)) {
|
||||||
|
cands.emplace_back(0, options[i].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// cost values are borrowed from git, help.c.
|
||||||
|
int sim = levenshtein(unkopt, options[i].name, 0, 2, 1, 3);
|
||||||
|
cands.emplace_back(sim, options[i].name);
|
||||||
|
}
|
||||||
|
if(cands.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::sort(std::begin(cands), std::end(cands));
|
||||||
|
int threshold = cands[0].first;
|
||||||
|
// threshold value is a magic value.
|
||||||
|
if(threshold > 6) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::cerr << "\nDid you mean:\n";
|
||||||
|
for(auto& item : cands) {
|
||||||
|
if(item.first > threshold) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::cerr << "\t--" << item.second << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
|
|
||||||
#include "nghttp2_config.h"
|
#include "nghttp2_config.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -403,6 +406,8 @@ make_unique(size_t size)
|
||||||
void to_token68(std::string& base64str);
|
void to_token68(std::string& base64str);
|
||||||
void to_base64(std::string& token68str);
|
void to_base64(std::string& token68str);
|
||||||
|
|
||||||
|
void show_candidates(const char *unkopt, option *options);
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|
Loading…
Reference in New Issue