1#include "../include/dotenv.h"
3#include "../include/str_utils.h"
15static char* remove_quotes(
char* str) {
20 size_t len = strlen(str);
26 if ((str[0] ==
'"' && str[len - 1] ==
'"') || (str[0] ==
'\'' && str[len - 1] ==
'\'')) {
41static bool interpolate(
const char* value,
char* result,
size_t result_size) {
42 if (value == NULL || result == NULL || result_size == 0) {
46 size_t result_len = 0;
47 const char* ptr = value;
48 memset(result, 0, result_size);
50 while (*ptr && result_len < result_size - 1) {
52 if (*ptr ==
'$' && *(ptr + 1) ==
'{') {
53 const char* start = ptr + 2;
54 const char* end = strchr(start,
'}');
58 fprintf(stderr,
"Warning: Unclosed variable reference starting at position %td\n", ptr - value);
59 result[result_len++] = *ptr++;
64 size_t var_name_len = (size_t)(end - start);
65 if (var_name_len == 0) {
67 fprintf(stderr,
"Warning: Empty variable name\n");
73 fprintf(stderr,
"Error: Variable name too long (max %d)\n",
MAX_VAR_NAME_LEN - 1);
78 snprintf(var_name,
sizeof(var_name),
"%.*s", (
int)var_name_len, start);
81 const char* var_value =
GETENV(var_name);
82 if (var_value != NULL) {
83 size_t var_value_len = strlen(var_value);
85 if (result_len + var_value_len >= result_size) {
86 fprintf(stderr,
"Error: Result buffer too small for interpolation\n");
90 memcpy(result + result_len, var_value, var_value_len);
91 result_len += var_value_len;
93 fprintf(stderr,
"Warning: Environment variable '%s' not found, skipping\n", var_name);
99 result[result_len++] = *ptr++;
105 fprintf(stderr,
"Error: Result buffer too small\n");
109 result[result_len] =
'\0';
119static bool process_env_pair(
char* key,
char* value) {
120 if (key == NULL || value == NULL) {
125 key = trim_string(key);
127 fprintf(stderr,
"Error: Empty key\n");
132 value = trim_string(value);
133 value = remove_quotes(value);
136 if (strchr(value,
'$') != NULL && strchr(value,
'{') != NULL && strchr(value,
'}') != NULL) {
137 char interpolated_value[MAX_LINE_LENGTH] = {0};
138 if (!interpolate(value, interpolated_value,
sizeof(interpolated_value))) {
139 fprintf(stderr,
"Error: Failed to interpolate value for key '%s'\n", key);
143 if (
SETENV(key, interpolated_value, 1) != 0) {
144 fprintf(stderr,
"Error: Failed to set environment variable '%s': %s\n", key, strerror(errno));
148 if (
SETENV(key, value, 1) != 0) {
149 fprintf(stderr,
"Error: Failed to set environment variable '%s': %s\n", key, strerror(errno));
162 FILE* file = fopen(path,
"r");
164 fprintf(stderr,
"Error: Cannot open file '%s': %s\n", path, strerror(errno));
168 char line[MAX_LINE_LENGTH] = {0};
169 size_t line_number = 0;
170 bool had_errors =
false;
172 while (fgets(line,
sizeof(line), file) != NULL) {
176 size_t len = strlen(line);
177 if (len > 0 && line[len - 1] ==
'\n') {
178 line[len - 1] =
'\0';
181 char* trimmed = trim_string(line);
184 if (*trimmed ==
'\0' || *trimmed ==
'#') {
189 char* equals = strchr(trimmed,
'=');
190 if (equals == NULL) {
191 fprintf(stderr,
"Warning: Invalid line %zu (no '=' found): %s\n", line_number, trimmed);
199 char* value = equals + 1;
201 if (!process_env_pair(key, value)) {
202 fprintf(stderr,
"Warning: Failed to process line %zu\n", line_number);
208 fprintf(stderr,
"Error: Failed to read from file '%s'\n", path);
bool load_dotenv(const char *path)
#define SETENV(name, value, overwrite)