Files
FERRUM/autocorrect.c
2025-06-08 23:08:56 +02:00

173 lines
4.3 KiB
C

/**
* testing
* autocorrect.c
* Implementation of command auto-correction functionality
*/
#include "autocorrect.h"
#include "builtins.h"
/**
* Calculate Levenshtein distance between two strings
* Used to determine similarity between mistyped command and potential
* corrections
*/
int levenshtein_distance(const char *s1, const char *s2) {
int len1 = strlen(s1);
int len2 = strlen(s2);
// Create a matrix to store distances
int **matrix = (int **)malloc((len1 + 1) * sizeof(int *));
if (!matrix)
return -1;
for (int i = 0; i <= len1; i++) {
matrix[i] = (int *)malloc((len2 + 1) * sizeof(int));
if (!matrix[i]) {
for (int j = 0; j < i; j++) {
free(matrix[j]);
}
free(matrix);
return -1;
}
}
// Initialize the matrix
for (int i = 0; i <= len1; i++) {
matrix[i][0] = i;
}
for (int j = 0; j <= len2; j++) {
matrix[0][j] = j;
}
// Fill the matrix
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1;
matrix[i][j] = min3(matrix[i - 1][j] + 1, // deletion
matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j - 1] + cost // substitution
);
}
}
// Get the result and free the matrix
int result = matrix[len1][len2];
for (int i = 0; i <= len1; i++) {
free(matrix[i]);
}
free(matrix);
return result;
}
/**
* Helper function to find minimum of three integers
*/
int min3(int a, int b, int c) {
int min = a;
if (b < min)
min = b;
if (c < min)
min = c;
return min;
}
/**
* Initialize the autocorrect system
*/
void init_autocorrect(void) {
// No initialization required currently
}
/**
* Shutdown the autocorrect system
*/
void shutdown_autocorrect(void) {
// No cleanup required currently
}
/**
* Check a command for possible corrections and suggest alternative
*/
/**
* Check a command for possible corrections and suggest alternative
*/
/**
* Check a command for possible corrections and suggest alternative
*/
char **check_for_corrections(char **args) {
if (!args || !args[0]) {
return NULL;
}
const char *command = args[0];
// Skip very short commands or commands that start with ./ or /
if (strlen(command) < 3 || command[0] == '.' || command[0] == '/') {
return NULL;
}
// Don't try to correct arguments, only the command itself
// Check if the command is valid, if it is, no correction needed
if (is_valid_command(command)) {
return NULL;
}
// List of common commands to check against
const char *common_commands[] = {
"ls", "cd", "grep", "find", "cat", "mv",
"cp", "rm", "mkdir", "rmdir", "chmod", "chown",
"ps", "top", "df", "du", "free", "mount",
"umount", "tar", "zip", "unzip", "ssh", "scp",
"ping", "netstat", "ifconfig", "route", "traceroute", "wget",
"curl", "apt", "apt-get", "yum", "dnf", "pacman",
"git", "make", "gcc", "g++", "python", "python3",
"node", "npm", "vim", "nano", "history", "clear",
"exit", "alias", "man", "help", "touch", "echo",
"pwd", "sudo", "shutdown", "reboot", NULL};
// Check built-in commands too
int best_distance = 3; // Maximum edit distance to consider a correction
const char *best_match = NULL;
// First check among built-in commands
for (int i = 0; i < lsh_num_builtins(); i++) {
int distance = levenshtein_distance(command, builtin_str[i]);
if (distance < best_distance) {
best_distance = distance;
best_match = builtin_str[i];
}
}
// Then check common commands
for (int i = 0; common_commands[i] != NULL; i++) {
int distance = levenshtein_distance(command, common_commands[i]);
if (distance < best_distance) {
best_distance = distance;
best_match = common_commands[i];
}
}
// If we found a good match, suggest it
if (best_match) {
printf("Command '%s' not found. Did you mean '%s'?\n", command, best_match);
// No longer waiting for input - just return NULL
}
return NULL;
}
/**
* Count the number of arguments in a NULL-terminated array
*/
int count_args(char **args) {
int count = 0;
while (args[count] != NULL) {
count++;
}
return count;
}