ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
env.h File Reference

Environment variable utilities with stack-based prompt responses. More...

Go to the source code of this file.

Functions

bool env_pop_prompt_response (char *response_out, size_t response_size)
 Pop the first response from ASCII_CHAT_QUESTION_PROMPT_RESPONSE stack.
bool env_has_prompt_response (void)
 Check if ASCII_CHAT_QUESTION_PROMPT_RESPONSE has any responses available.
bool env_validate_prompt_response_format (void)
 Validate ASCII_CHAT_QUESTION_PROMPT_RESPONSE format.

Detailed Description

Environment variable utilities with stack-based prompt responses.

Definition in file env.h.

Function Documentation

◆ env_has_prompt_response()

bool env_has_prompt_response ( void )

Check if ASCII_CHAT_QUESTION_PROMPT_RESPONSE has any responses available.

Returns
true if at least one response is available, false otherwise

Definition at line 204 of file env.c.

204 {
205 const char *env_value = SAFE_GETENV("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
206 if (!env_value || env_value[0] == '\0' || env_value[0] == ';') {
207 return false;
208 }
209
210 // Check if it's all semicolons
211 for (const char *p = env_value; *p; p++) {
212 if (*p != ';') {
213 return true;
214 }
215 }
216
217 return false;
218}
#define SAFE_GETENV(name)
Definition common.h:449

References SAFE_GETENV.

◆ env_pop_prompt_response()

bool env_pop_prompt_response ( char * response_out,
size_t response_size )

Pop the first response from ASCII_CHAT_QUESTION_PROMPT_RESPONSE stack.

Format: "response1;response2;response3" or "response1;response2;response3;"

Examples:

  • "y;n;123" -> returns "y", sets env to "n;123"
  • "password" -> returns "password", sets env to ""
  • "y;" -> returns "y", sets env to ""
Parameters
response_outBuffer to store the popped response (must be at least 256 bytes)
response_sizeSize of response_out buffer
Returns
true if a response was successfully popped, false otherwise

Format: "response1;response2;response3" or "response1;response2;response3;" This function extracts the first response and updates the environment variable to contain the remaining responses.

Escaping: Use backslash to include literal semicolons or backslashes:

  • \; → ; (literal semicolon)
  • \ → \ (literal backslash)

Examples:

  • "y;n;123" -> returns "y", sets env to "n;123"
  • "password" -> returns "password", sets env to ""
  • "y;" -> returns "y", sets env to ""
  • "pass\;word;y" -> returns "pass;word", sets env to "y"
  • "path\\to\\file;n" -> returns "path\to\file", sets env to "n"
  • "" -> returns NULL
  • ";;y" -> returns NULL (invalid format)
  • ";y" -> returns NULL (invalid format)
Parameters
response_outBuffer to store the popped response (must be at least 256 bytes)
response_sizeSize of response_out buffer
Returns
true if a response was successfully popped, false otherwise

Definition at line 96 of file env.c.

96 {
97 if (!response_out || response_size < 2) {
98 return false;
99 }
100
101 const char *env_value = SAFE_GETENV("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
102 if (!env_value || env_value[0] == '\0') {
103 return false;
104 }
105
106 // Validate: no leading semicolon (unless escaped)
107 if (env_value[0] == ';') {
108 log_warn("Invalid ASCII_CHAT_QUESTION_PROMPT_RESPONSE format: leading semicolon");
109 return false;
110 }
111
112 // Find the first unescaped semicolon
113 const char *semicolon = find_unescaped_semicolon(env_value);
114
115 if (semicolon == NULL) {
116 // No semicolon - this is the last (or only) response
117 size_t len = strlen(env_value);
118 if (len == 0) {
119 return false;
120 }
121
122 // Validate: ensure it's not empty
123 if (len >= response_size) {
124 log_warn("Response too long: %zu bytes (max: %zu)", len, response_size - 1);
125 return false;
126 }
127
128 // Copy the response
129 SAFE_STRNCPY(response_out, env_value, response_size);
130
131 // Unescape the response (\; → ; and \\ → \‍)
132 unescape_response(response_out);
133
134 // Clear the environment variable
135 platform_unsetenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
136
137 log_dev("Popped last response from stack: '%s' (cleared env)", response_out);
138 return true;
139 }
140
141 // Calculate response length
142 size_t response_len = (size_t)(semicolon - env_value);
143
144 // Validate: no empty segment
145 if (response_len == 0) {
146 log_warn("Invalid ASCII_CHAT_QUESTION_PROMPT_RESPONSE format: empty segment");
147 return false;
148 }
149
150 if (response_len >= response_size) {
151 log_warn("Response too long: %zu bytes (max: %zu)", response_len, response_size - 1);
152 return false;
153 }
154
155 // Copy the first response
156 memcpy(response_out, env_value, response_len);
157 response_out[response_len] = '\0';
158
159 // Unescape the response (\; → ; and \\ → \‍)
160 unescape_response(response_out);
161
162 // Calculate remaining stack (skip the semicolon)
163 const char *remaining = semicolon + 1;
164
165 // Validate: if remaining is empty or only semicolons, clear the env
166 bool remaining_valid = false;
167 for (const char *p = remaining; *p; p++) {
168 if (*p != ';') {
169 remaining_valid = true;
170 break;
171 }
172 }
173
174 // Update environment variable with remaining responses
175 if (remaining_valid && remaining[0] != '\0') {
176 char new_env[UTIL_ENV_NEW_ENV_BUFFER_SIZE];
177 int written = snprintf(new_env, sizeof(new_env), "ASCII_CHAT_QUESTION_PROMPT_RESPONSE=%s", remaining);
178 if (written < 0 || (size_t)written >= sizeof(new_env)) {
179 log_warn("Failed to format new environment variable");
180 return false;
181 }
182
183 if (platform_setenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE", remaining) != 0) {
184 log_warn("Failed to update ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
185 return false;
186 }
187
188 log_debug("Popped response from stack: '%s' (remaining: '%s')", response_out, remaining);
189 } else {
190 // No valid remaining responses - clear the env
191 platform_unsetenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
192
193 log_debug("Popped response from stack: '%s' (cleared env)", response_out);
194 }
195
196 return true;
197}
#define UTIL_ENV_NEW_ENV_BUFFER_SIZE
Definition env.c:7
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:423
#define log_warn(...)
Log a WARN message.
Definition log/log.h:621
#define log_dev(...)
Log a DEV message (most verbose, development only).
Definition log/log.h:581
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
int platform_setenv(const char *name, const char *value)
Set an environment variable.
int platform_unsetenv(const char *name)
Remove an environment variable.

References log_debug, log_dev, log_warn, platform_setenv(), platform_unsetenv(), SAFE_GETENV, SAFE_STRNCPY, and UTIL_ENV_NEW_ENV_BUFFER_SIZE.

Referenced by main(), and ui_input_password().

◆ env_validate_prompt_response_format()

bool env_validate_prompt_response_format ( void )

Validate ASCII_CHAT_QUESTION_PROMPT_RESPONSE format.

Valid formats: "y", "y;n", "y;n;123", "y;n;123;" Invalid formats: "", ";", ";y", "y;;n", ";;"

Returns
true if format is valid, false otherwise

Valid formats:

  • "y"
  • "y;n"
  • "y;n;123"
  • "y;n;123;"
  • "pass\;word;y" (escaped semicolon)
  • "path\\to\\file" (escaped backslash)

Invalid formats:

  • ""
  • ";"
  • ";y"
  • "y;;n" (empty segment)
  • ";;"
Returns
true if format is valid, false otherwise

Definition at line 240 of file env.c.

240 {
241 const char *env_value = SAFE_GETENV("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
242 if (!env_value) {
243 return true; // Not set is valid (no automated responses)
244 }
245
246 if (env_value[0] == '\0') {
247 return true; // Empty is valid (no automated responses)
248 }
249
250 // Invalid: leading semicolon (unless escaped)
251 if (env_value[0] == ';') {
252 return false;
253 }
254
255 // Check for consecutive unescaped semicolons or empty segments
256 const char *p = env_value;
257 bool last_was_semicolon = false;
258
259 while (*p) {
260 if (*p == '\\' && *(p + 1)) {
261 // Skip escaped character
262 last_was_semicolon = false;
263 p += 2;
264 continue;
265 }
266 if (*p == ';') {
267 if (last_was_semicolon) {
268 return false; // Consecutive unescaped semicolons (empty segment)
269 }
270 last_was_semicolon = true;
271 } else {
272 last_was_semicolon = false;
273 }
274 p++;
275 }
276
277 // Trailing semicolon is allowed
278 return true;
279}

References SAFE_GETENV.