#include #include #include #include #include #include #include // Config path (absolute) #define ALIAS_CFG_PATH "/config/aliases.cfg" #define ALIAS_MAX_COUNT 32 #define ALIAS_MAX_NAME 64 #define ALIAS_MAX_TMPL 200 #define ALIAS_FILE_MAX 4096 typedef struct { char name[ALIAS_MAX_NAME]; char tmpl[ALIAS_MAX_TMPL]; } alias_entry_t; static alias_entry_t g_aliases[ALIAS_MAX_COUNT]; static int g_alias_count = 0; static int g_alias_loaded = 0; // System config is expected on primary drive. extern uint8 g_current_drive; static int alias_ctx_allow(uint32 caps, uint32 cost) { command_context_t* ctx = current_command_context; if (ctx && !cap_check(ctx->caps, caps)) return 0; if (ctx) { scheduler_account(ctx->wo, cost); scheduler_yield_if_needed(ctx->wo); if (sched_det_is_enabled()) ctx->det_seq++; } return 1; } static uint8 alias_cfg_drive(void) { // Keep this simple: store aliases on the current drive. // (If you want global-only, change to 0.) return g_current_drive; } static int is_alias_ws(char c) { return (c == ' ' || c == '\t' || c == '\r' || c == '\n'); } static int is_name_char(char c) { if (c >= 'a' && c <= 'z') return 1; if (c >= 'A' && c <= 'Z') return 1; if (c >= '0' && c <= '9') return 1; if (c == '_') return 1; return 0; } static int alias_normalize_key(const char *in, char *out, int out_cap) { if (!in || !out || out_cap <= 1) return -1; int pos = 0; int saw_word = 0; int pending_space = 0; int i = 0; // Skip leading whitespace. while (in[i] && is_alias_ws(in[i])) i++; while (in[i]) { char c = in[i++]; if (is_alias_ws(c)) { pending_space = 1; continue; } if (!is_name_char(c)) return -1; if (pending_space && saw_word) { if (pos + 1 >= out_cap) return -1; out[pos++] = ' '; } if (pos + 1 >= out_cap) return -1; out[pos++] = c; saw_word = 1; pending_space = 0; } out[pos] = '\0'; return saw_word ? 0 : -1; } static alias_entry_t *alias_find_mut(const char *name) { for (int i = 0; i < g_alias_count; i++) { if (strcmp(g_aliases[i].name, name) == 0) return &g_aliases[i]; } return NULL; } int shell_alias_exists(const char *name) { if (!g_alias_loaded) { // lazy load (void)shell_alias_define("__lazy_load_guard__", ""); // define() above will return error; but triggers load via helper. } char norm[ALIAS_MAX_NAME]; if (alias_normalize_key(name, norm, sizeof(norm)) != 0) return 0; return alias_find_mut(norm) != NULL; } static void alias_clear_all(void) { memset(g_aliases, 0, sizeof(g_aliases)); g_alias_count = 0; } static void trim_right(char *s) { int n = (int)strlen(s); while (n > 0) { char c = s[n - 1]; if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { s[n - 1] = '\0'; n--; continue; } break; } } static char *trim_left(char *s) { while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') s++; return s; } static int alias_match_prefix_len(const char *input, const char *key) { if (!input || !key || !key[0]) return 0; int ii = 0; int ki = 0; while (key[ki]) { if (is_alias_ws(key[ki])) { if (!is_alias_ws(input[ii])) return 0; while (key[ki] && is_alias_ws(key[ki])) ki++; while (input[ii] && is_alias_ws(input[ii])) ii++; continue; } if (input[ii] != key[ki]) return 0; ii++; ki++; } if (input[ii] && !is_alias_ws(input[ii])) return 0; return ii; } static int contains_meta_chars(const char *s) { // Keep aliases simple and safe: no pipeline/redirection/control operators. for (int i = 0; s[i]; i++) { if (s[i] == '|' || s[i] == '<' || s[i] == '>' || s[i] == '&') return 1; } return 0; } static int alias_parse_config_line(char *line, char *name_out, int name_out_cap, char *tmpl_out, int tmpl_out_cap) { if (!line || !name_out || !tmpl_out || name_out_cap <= 1 || tmpl_out_cap <= 1) return -1; line = trim_left(line); trim_right(line); if (!line[0] || line[0] == '#') return -1; char *name_src = NULL; char *tmpl_src = NULL; if (line[0] == '"') { // New format: "multi word key"