117 lines
4.1 KiB
C
117 lines
4.1 KiB
C
/// @file echo.c
|
|
/// @brief
|
|
/// @copyright (c) 2014-2024 This file is distributed under the MIT License.
|
|
/// See LICENSE.md for details.
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/bitops.h>
|
|
|
|
#define ENV_NORM 1
|
|
#define ENV_BRAK 2
|
|
#define ENV_PROT 3
|
|
|
|
void expand_env(char *str, char *buf, size_t buf_len, int first_word, int last_word)
|
|
{
|
|
// Buffer where we store the name of the variable.
|
|
char buffer[BUFSIZ] = { 0 };
|
|
// Flags used to keep track of the special characters.
|
|
unsigned flags = 0;
|
|
// We keep track of where teh
|
|
char *env_start = NULL;
|
|
// Where we store the retrieved environmental variable value.
|
|
char *ENV = NULL;
|
|
// Get the length of the string.
|
|
size_t str_len = strlen(str);
|
|
// Position where we are writing on the buffer.
|
|
int b_pos = 0;
|
|
// Iterate the string.
|
|
for (int s_pos = 0; s_pos < str_len; ++s_pos) {
|
|
if (first_word && (s_pos == 0) && str[s_pos] == '"')
|
|
continue;
|
|
if (last_word && (s_pos == (str_len - 1)) && str[s_pos] == '"')
|
|
continue;
|
|
// If we find the backslash, we need to protect the next character.
|
|
if (str[s_pos] == '\\') {
|
|
if (bit_check(flags, ENV_PROT))
|
|
buf[b_pos++] = '\\';
|
|
else
|
|
bit_set_assign(flags, ENV_PROT);
|
|
continue;
|
|
}
|
|
// If we find the dollar, we need to catch the meaning.
|
|
if (str[s_pos] == '$') {
|
|
// If the previous character is a backslash, we just need to print the dollar.
|
|
if (bit_check(flags, ENV_PROT)) {
|
|
buf[b_pos++] = '$';
|
|
} else if ((s_pos < (str_len - 2)) && ((str[s_pos + 1] == '{'))) {
|
|
// Toggle the open bracket method of accessing env variables.
|
|
bit_set_assign(flags, ENV_BRAK);
|
|
// We need to skip both the dollar and the open bracket `${`.
|
|
env_start = &str[s_pos + 2];
|
|
} else {
|
|
// Toggle the normal method of accessing env variables.
|
|
bit_set_assign(flags, ENV_NORM);
|
|
// We need to skip the dollar `$`.
|
|
env_start = &str[s_pos + 1];
|
|
}
|
|
continue;
|
|
}
|
|
if (bit_check(flags, ENV_BRAK)) {
|
|
if (str[s_pos] == '}') {
|
|
// Copy the environmental variable name.
|
|
strncpy(buffer, env_start, &str[s_pos] - env_start);
|
|
// Search for the environmental variable, and print it.
|
|
if ((ENV = getenv(buffer)))
|
|
for (int k = 0; k < strlen(ENV); ++k)
|
|
buf[b_pos++] = ENV[k];
|
|
// Remove the flag.
|
|
bit_clear_assign(flags, ENV_BRAK);
|
|
}
|
|
continue;
|
|
}
|
|
if (bit_check(flags, ENV_NORM)) {
|
|
if (str[s_pos] == ':') {
|
|
// Copy the environmental variable name.
|
|
strncpy(buffer, env_start, &str[s_pos] - env_start);
|
|
// Search for the environmental variable, and print it.
|
|
if ((ENV = getenv(buffer)))
|
|
for (int k = 0; k < strlen(ENV); ++k)
|
|
buf[b_pos++] = ENV[k];
|
|
// Copy the `:`.
|
|
buf[b_pos++] = str[s_pos];
|
|
// Remove the flag.
|
|
bit_clear_assign(flags, ENV_NORM);
|
|
}
|
|
continue;
|
|
}
|
|
buf[b_pos++] = str[s_pos];
|
|
}
|
|
if (bit_check(flags, ENV_NORM)) {
|
|
// Copy the environmental variable name.
|
|
strcpy(buffer, env_start);
|
|
// Search for the environmental variable, and print it.
|
|
if ((ENV = getenv(buffer)))
|
|
for (int k = 0; k < strlen(ENV); ++k)
|
|
buf[b_pos++] = ENV[k];
|
|
// Remove the flag.
|
|
bit_clear_assign(flags, ENV_NORM);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char buffer[BUFSIZ];
|
|
// Iterate all the words.
|
|
for (int i = 1; i < argc; ++i) {
|
|
memset(buffer, 0, BUFSIZ);
|
|
expand_env(argv[i], buffer, BUFSIZ, (i == 1), (i == (argc - 1)));
|
|
puts(buffer);
|
|
if (i < (argc - 1))
|
|
putchar(' ');
|
|
}
|
|
printf("\n\n");
|
|
return 0;
|
|
}
|