1#include "../include/dotenv.h"
2#include "../include/str.h"
14static char* remove_quotes(
char* str) {
19 size_t len = strlen(str);
25 if ((str[0] ==
'"' && str[len - 1] ==
'"') || (str[0] ==
'\'' && str[len - 1] ==
'\'')) {
40static bool interpolate(
const char* value,
char* result,
size_t result_size) {
41 if (value == NULL || result == NULL || result_size == 0) {
45 size_t result_len = 0;
46 const char* ptr = value;
47 memset(result, 0, result_size);
49 while (*ptr && result_len < result_size - 1) {
51 if (*ptr ==
'$' && *(ptr + 1) ==
'{') {
52 const char* start = ptr + 2;
53 const char* end = strchr(start,
'}');
57 fprintf(stderr,
"Warning: Unclosed variable reference starting at position %td\n", ptr - value);
58 result[result_len++] = *ptr++;
63 size_t var_name_len = (size_t)(end - start);
64 if (var_name_len == 0) {
66 fprintf(stderr,
"Warning: Empty variable name\n");
72 fprintf(stderr,
"Error: Variable name too long (max %d)\n",
MAX_VAR_NAME_LEN - 1);
77 snprintf(var_name,
sizeof(var_name),
"%.*s", (
int)var_name_len, start);
80 const char* var_value =
GETENV(var_name);
81 if (var_value != NULL) {
82 size_t var_value_len = strlen(var_value);
84 if (result_len + var_value_len >= result_size) {
85 fprintf(stderr,
"Error: Result buffer too small for interpolation\n");
89 memcpy(result + result_len, var_value, var_value_len);
90 result_len += var_value_len;
92 fprintf(stderr,
"Warning: Environment variable '%s' not found, skipping\n", var_name);
98 result[result_len++] = *ptr++;
104 fprintf(stderr,
"Error: Result buffer too small\n");
108 result[result_len] =
'\0';
118static bool process_env_pair(
char* key,
char* value) {
119 if (key == NULL || value == NULL) {
131 value = remove_quotes(value);
134 if (strchr(value,
'$') != NULL && strchr(value,
'{') != NULL && strchr(value,
'}') != NULL) {
135 char interpolated_value[MAX_LINE_LENGTH] = {0};
136 if (!interpolate(value, interpolated_value,
sizeof(interpolated_value))) {
137 fprintf(stderr,
"Error: Failed to interpolate value for key '%s'\n", key);
141 if (
SETENV(key, interpolated_value, 1) != 0) {
142 fprintf(stderr,
"Error: Failed to set environment variable '%s': %s\n", key, strerror(errno));
146 if (
SETENV(key, value, 1) != 0) {
147 fprintf(stderr,
"Error: Failed to set environment variable '%s': %s\n", key, strerror(errno));
160 FILE* file = fopen(path,
"r");
162 fprintf(stderr,
"Error: Cannot open file '%s': %s\n", path, strerror(errno));
166 char line[MAX_LINE_LENGTH] = {0};
167 size_t line_number = 0;
168 bool had_errors =
false;
170 while (fgets(line,
sizeof(line), file) != NULL) {
174 size_t len = strlen(line);
175 if (len > 0 && line[len - 1] ==
'\n') {
176 line[len - 1] =
'\0';
181 if (*line ==
'\0' || *line ==
'#') {
186 char* equals = strchr(line,
'=');
187 if (equals == NULL) {
188 fprintf(stderr,
"Warning: Invalid line %zu (no '=' found): %s\n", line_number, line);
196 char* value = equals + 1;
198 if (!process_env_pair(key, value)) {
199 fprintf(stderr,
"Warning: Failed to process line %zu\n", line_number);
205 fprintf(stderr,
"Error: Failed to read from file '%s'\n", path);
bool load_dotenv(const char *path)
#define SETENV(name, value, overwrite)