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 if (best_distance
== 0) {
46 fprintf(stderr
, "or\n");
48 fprintf(stderr
, "The program '%s' is not installed. Install it by executing:\n", binary_name
);
50 fprintf(stderr
, " pkg install %s\n", current_package
);
52 } else if (best_distance
== distance
) {
53 guesses_at_best_distance
++;
54 } else if (best_distance
== -1 || best_distance
> distance
) {
55 guesses_at_best_distance
= 0;
56 best_distance
= distance
;
57 strncpy(best_command_guess
, binary_name
, sizeof(best_command_guess
));
58 strncpy(best_package_guess
, current_package
, sizeof(best_package_guess
));
61 strncpy(current_package
, current_line
, sizeof(current_package
));
65 if (best_distance
== 0) return 127;
67 if (best_distance
== -1 || best_distance
> 3) {
68 fprintf(stderr
, "%s: command not found\n", command_not_found
);
70 fprintf(stderr
, "No command '%s' found, did you mean:\n", command_not_found
);
71 if (guesses_at_best_distance
== 1) {
72 // Only one suggestion - show it:
73 fprintf(stderr
, " Command '%s' from package '%s'\n", best_command_guess
, best_package_guess
);
75 // Multiple suggestions at the same distance - show them all:
76 for (int i
= 0; i
< num_commands
; i
++) {
77 char const* current_line
= commands
[i
];
78 if (current_line
[0] == ' ') { // Binary
79 char const* binary_name
= current_line
+ 1;
80 int distance
= termux_levenshtein_distance(command_not_found
, binary_name
);
81 if (best_distance
== distance
) {
82 fprintf(stderr
, " Command '%s' from package '%s'\n", binary_name
, current_package
);
85 strncpy(current_package
, current_line
, sizeof(current_package
));