7 static inline int termux_min3(unsigned int a
, unsigned int b
, unsigned int c
) {
8 return (a
< b ?
(a
< c ? a
: c
) : (b
< c ? b
: c
));
11 static int termux_levenshtein_distance(char const* restrict s1
, char const* restrict s2
) {
12 unsigned int s1len
= strlen(s1
);
13 unsigned int s2len
= strlen(s2
);
14 unsigned int matrix
[s2len
+1][s1len
+1];
16 for (unsigned x
= 1; x
<= s2len
; x
++)
17 matrix
[x
][0] = matrix
[x
-1][0] + 1;
18 for (unsigned y
= 1; y
<= s1len
; y
++)
19 matrix
[0][y
] = matrix
[0][y
-1] + 1;
20 for (unsigned x
= 1; x
<= s2len
; x
++)
21 for (unsigned y
= 1; y
<= s1len
; y
++)
22 matrix
[x
][y
] = termux_min3(matrix
[x
-1][y
] + 1, matrix
[x
][y
-1] + 1, matrix
[x
-1][y
-1] + (s1
[y
-1] == s2
[x
-1] ?
0 : 1));
23 return matrix
[s2len
][s1len
];
26 int main(int argc
, char** argv
) {
28 fprintf(stderr
, "usage: termux-command-not-found <command>\n");
31 char* command_not_found
= argv
[1];
33 int best_distance
= -1;
34 int guesses_at_best_distance
= 0;
35 char current_package
[128];
36 char best_package_guess
[128];
37 char best_command_guess
[128];
38 const int num_commands
= sizeof(commands
) / sizeof(commands
[0]);
39 for (int i
= 0; i
< num_commands
; i
++) {
40 char const* current_line
= commands
[i
];
41 if (current_line
[0] == ' ') { // Binary
42 char const* binary_name
= current_line
+ 1;
43 int distance
= termux_levenshtein_distance(command_not_found
, binary_name
);
44 if (distance
== 0 && strcmp(command_not_found
, binary_name
) == 0) {
45 printf("The program '%s' is not installed. Install it by executing:\n pkg install %s\n", binary_name
, current_package
);
47 } else if (best_distance
== distance
) {
48 guesses_at_best_distance
++;
49 } else if (best_distance
== -1 || best_distance
> distance
) {
50 guesses_at_best_distance
= 0;
51 best_distance
= distance
;
52 strncpy(best_command_guess
, binary_name
, sizeof(best_command_guess
));
53 strncpy(best_package_guess
, current_package
, sizeof(best_package_guess
));
56 strncpy(current_package
, current_line
, sizeof(current_package
));
60 if (best_distance
== -1 || best_distance
> 3) {
61 printf("%s: command not found\n", command_not_found
);
63 printf("No command '%s' found, did you mean:\n", command_not_found
);
64 if (guesses_at_best_distance
== 1) {
65 // Only one suggestion - show it:
66 printf(" Command '%s' from package '%s'\n", best_command_guess
, best_package_guess
);
68 // Multiple suggestions at the same distance - show them all:
69 for (int i
= 0; i
< num_commands
; i
++) {
70 char const* current_line
= commands
[i
];
71 if (current_line
[0] == ' ') { // Binary
72 char const* binary_name
= current_line
+ 1;
73 int distance
= termux_levenshtein_distance(command_not_found
, binary_name
);
74 if (best_distance
== distance
) {
75 printf(" Command '%s' from package '%s'\n", binary_name
, current_package
);
78 strncpy(current_package
, current_line
, sizeof(current_package
));