5 #define STRINGIFY(x) #x
6 #define TOSTRING(x) STRINGIFY(x)
8 inline int termux_min3(unsigned int a
, unsigned int b
, unsigned int c
) {
9 return (a
< b ?
(a
< c ? a
: c
) : (b
< c ? b
: c
));
12 int termux_levenshtein_distance(char const* restrict s1
, char const* restrict s2
) {
13 unsigned int s1len
= strlen(s1
);
14 unsigned int s2len
= strlen(s2
);
15 unsigned int matrix
[s2len
+1][s1len
+1];
17 for (unsigned x
= 1; x
<= s2len
; x
++)
18 matrix
[x
][0] = matrix
[x
-1][0] + 1;
19 for (unsigned y
= 1; y
<= s1len
; y
++)
20 matrix
[0][y
] = matrix
[0][y
-1] + 1;
21 for (unsigned x
= 1; x
<= s2len
; x
++)
22 for (unsigned y
= 1; y
<= s1len
; y
++)
23 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));
24 return matrix
[s2len
][s1len
];
27 int main(int argc
, char** argv
) {
29 fprintf(stderr
, "usage: termux-command-not-found <command>\n");
32 char* command_not_found
= argv
[1];
34 FILE* commands_file
= fopen(TOSTRING(TERMUX_COMMANDS_LISTING
), "r");
35 if (commands_file
== NULL
) {
36 perror(TOSTRING(TERMUX_COMMANDS_LISTING
));
40 int best_distance
= -1;
41 int guesses_at_best_distance
= 0;
42 char current_package
[128];
43 char best_package_guess
[128];
44 char best_command_guess
[128];
45 char* current_line
= NULL
;
47 size_t buffer_length
= sizeof(current_line
);
48 ssize_t read_bytes
= getline(¤t_line
, &buffer_length
, commands_file
);
49 if (read_bytes
<= 1) break;
50 size_t line_length
= strlen(current_line
);
51 current_line
[line_length
-1] = 0;
52 if (current_line
[0] == ' ') { // Binary
53 char* binary_name
= current_line
+ 1;
54 int distance
= termux_levenshtein_distance(command_not_found
, binary_name
);
55 if (distance
== 0 && strcmp(command_not_found
, binary_name
) == 0) {
56 printf("The program '%s' is currently not installed. You can install it by executing:\n apt install %s\n", binary_name
, current_package
);
58 } else if (best_distance
== distance
) {
59 guesses_at_best_distance
++;
60 } else if (best_distance
== -1 || best_distance
> distance
) {
61 guesses_at_best_distance
= 0;
62 best_distance
= distance
;
63 strncpy(best_command_guess
, binary_name
, sizeof(best_command_guess
));
64 strncpy(best_package_guess
, current_package
, sizeof(best_package_guess
));
67 strncpy(current_package
, current_line
, sizeof(current_package
));
71 if (best_distance
== -1 || best_distance
> 3) {
72 printf("%s: command not found\n", command_not_found
);
74 printf("No command '%s' found, did you mean:\n", command_not_found
);
75 printf(" Command '%s' from package '%s'\n", best_command_guess
, best_package_guess
);