#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include "../utils/ast/ast.h" static bool is_var_start_char(char c) { return isalpha(c) || c == '_'; } static bool is_var_char(char c) { return isalnum(c) || c == '_'; } static bool is_special_var_char(char c) { return c == '@' || c == '*' || c == '?' || c == '$' || isdigit(c) || c == '#'; } size_t parse_var_name(char *str, char **res) { char *brace = NULL; size_t i = 1; // skip the '$' if (str[i] == '{' && str[i + 1] != 0 && str[i + 1] != '}') { if (is_special_var_char(str[i + 1]) && str[i + 2] == '}') { // Special variable like ${1}, ${?} *res = strndup(str + i + 1, 1); return 4; // length of ${X} } brace = str + i; i++; // skip the '{' } else if (is_special_var_char(str[i])) { *res = strndup(str + i, 1); return 2; // length of $X } if (!is_var_start_char(str[i])) { // Not a valid variable start *res = NULL; return 0; } while (1) { if (str[i] == '}' && *brace == '{') { *res = strndup(str + 2, i - 2); return i + 1; } else if (!is_var_char(str[i])) { if (brace != NULL) { // Missing closing '}' *res = NULL; return 0; } break; } i++; } *res = strndup(str + 1, i - 1); return i; } struct ast_command *expand(struct ast_command *command) { if (command == NULL) return NULL; bool in_quotes = false; char *str; size_t len; struct list *l = command->command; while (l != NULL) { in_quotes = false; str = (char *)l->data; len = strlen(str); for (size_t i = 0; str[i] != '\0'; i++) { if (in_quotes) { continue; // do nothing } else if (str[i] == '\'') { // remove quote in_quotes = !in_quotes; memmove(&str[i], &str[i + 1], strlen(&str[i + 1]) + 1); i--; } else if (str[i] == '$' && str[i + 1] != 0 && !isspace(str[i + 1])) { // variable expansion } } if (in_quotes) { // error: quote not closed } if (len != strlen(str)) { char *new_str = realloc(str, strlen(str) + 1); if (new_str == NULL) { // error: realloc fail } l->data = new_str; } l = l->next; } return command; }