rclone: Switch tarballs to signed (fixes #2382)
[termux-packages] / packages / command-not-found / command-not-found.c
CommitLineData
284604c7
FF
1#include <stdio.h>
2#include <string.h>
3#include <stdbool.h>
4
d03f7fe6 5#include "commands.h"
284604c7 6
86b760f6 7static inline int termux_min3(unsigned int a, unsigned int b, unsigned int c) {
284604c7
FF
8 return (a < b ? (a < c ? a : c) : (b < c ? b : c));
9}
10
86b760f6 11static int termux_levenshtein_distance(char const* restrict s1, char const* restrict s2) {
284604c7
FF
12 unsigned int s1len = strlen(s1);
13 unsigned int s2len = strlen(s2);
14 unsigned int matrix[s2len+1][s1len+1];
15 matrix[0][0] = 0;
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];
24}
25
26int main(int argc, char** argv) {
27 if (argc != 2) {
28 fprintf(stderr, "usage: termux-command-not-found <command>\n");
29 return 1;
30 }
31 char* command_not_found = argv[1];
32
284604c7
FF
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];
d03f7fe6
FF
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];
284604c7 41 if (current_line[0] == ' ') { // Binary
d03f7fe6 42 char const* binary_name = current_line + 1;
284604c7
FF
43 int distance = termux_levenshtein_distance(command_not_found, binary_name);
44 if (distance == 0 && strcmp(command_not_found, binary_name) == 0) {
4f61067b 45 if (best_distance == 0) {
c3629906 46 fprintf(stderr, "or\n");
4f61067b 47 } else {
c3629906 48 fprintf(stderr, "The program '%s' is not installed. Install it by executing:\n", binary_name);
4f61067b 49 }
c3629906 50 fprintf(stderr, " pkg install %s\n", current_package);
4f61067b 51 best_distance = 0;
284604c7
FF
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));
59 }
60 } else { // Package
61 strncpy(current_package, current_line, sizeof(current_package));
62 }
63 }
64
4f61067b
FF
65 if (best_distance == 0) return 127;
66
284604c7 67 if (best_distance == -1 || best_distance > 3) {
c3629906 68 fprintf(stderr, "%s: command not found\n", command_not_found);
284604c7 69 } else {
c3629906 70 fprintf(stderr, "No command '%s' found, did you mean:\n", command_not_found);
6ee3449e
FF
71 if (guesses_at_best_distance == 1) {
72 // Only one suggestion - show it:
c3629906 73 fprintf(stderr, " Command '%s' from package '%s'\n", best_command_guess, best_package_guess);
6ee3449e
FF
74 } else {
75 // Multiple suggestions at the same distance - show them all:
d03f7fe6
FF
76 for (int i = 0; i < num_commands; i++) {
77 char const* current_line = commands[i];
6ee3449e 78 if (current_line[0] == ' ') { // Binary
d03f7fe6 79 char const* binary_name = current_line + 1;
6ee3449e
FF
80 int distance = termux_levenshtein_distance(command_not_found, binary_name);
81 if (best_distance == distance) {
c3629906 82 fprintf(stderr, " Command '%s' from package '%s'\n", binary_name, current_package);
6ee3449e
FF
83 }
84 } else { // Package
85 strncpy(current_package, current_line, sizeof(current_package));
86 }
87 }
88 }
284604c7 89 }
9f057269 90 return 127;
284604c7
FF
91}
92