42sh/src/expansion/expansion.c

134 lines
2.8 KiB
C
Raw Normal View History

#define _POSIX_C_SOURCE 200809L
2026-01-09 13:46:37 +00:00
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2026-01-09 23:12:03 +00:00
#include "../utils/ast/ast.h"
2026-01-09 13:46:37 +00:00
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;
}
2026-01-09 16:17:38 +00:00
2026-01-15 18:49:42 +01:00
struct ast_command *expand(struct ast_command *command)
2026-01-09 13:46:37 +00:00
{
2026-01-15 18:49:42 +01:00
if (command == NULL)
2026-01-09 13:46:37 +00:00
return NULL;
bool in_quotes = false;
char *str;
size_t len;
2026-01-15 18:49:42 +01:00
struct list *l = command->command;
2026-01-09 13:46:37 +00:00
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
2026-01-09 13:46:37 +00:00
}
else if (str[i] == '\'')
{
// remove quote
2026-01-09 13:46:37 +00:00
in_quotes = !in_quotes;
memmove(&str[i], &str[i + 1], strlen(&str[i + 1]) + 1);
i--;
2026-01-09 13:46:37 +00:00
}
2026-01-09 16:17:38 +00:00
else if (str[i] == '$' && str[i + 1] != 0 && !isspace(str[i + 1]))
2026-01-09 13:46:37 +00:00
{
// variable expansion
2026-01-09 13:46:37 +00:00
}
}
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;
}
2026-01-15 18:49:42 +01:00
return command;
2026-01-09 13:46:37 +00:00
}