ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
env.c 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.c.

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 214 of file env.c.

214 {
215 const char *env_value = SAFE_GETENV("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
216 if (!env_value || env_value[0] == '\0' || env_value[0] == ';') {
217 return false;
218 }
219
220 // Check if it's all semicolons
221 for (const char *p = env_value; *p; p++) {
222 if (*p != ';') {
223 return true;
224 }
225 }
226
227 return false;
228}

◆ 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;" 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 93 of file env.c.

93 {
94 if (!response_out || response_size < 2) {
95 return false;
96 }
97
98 const char *env_value = SAFE_GETENV("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
99 if (!env_value || env_value[0] == '\0') {
100 return false;
101 }
102
103 // Validate: no leading semicolon (unless escaped)
104 if (env_value[0] == ';') {
105 log_warn("Invalid ASCII_CHAT_QUESTION_PROMPT_RESPONSE format: leading semicolon");
106 return false;
107 }
108
109 // Find the first unescaped semicolon
110 const char *semicolon = find_unescaped_semicolon(env_value);
111
112 if (semicolon == NULL) {
113 // No semicolon - this is the last (or only) response
114 size_t len = strlen(env_value);
115 if (len == 0) {
116 return false;
117 }
118
119 // Validate: ensure it's not empty
120 if (len >= response_size) {
121 log_warn("Response too long: %zu bytes (max: %zu)", len, response_size - 1);
122 return false;
123 }
124
125 // Copy the response
126 SAFE_STRNCPY(response_out, env_value, response_size);
127
128 // Unescape the response (\; → ; and \\ → \‍)
129 unescape_response(response_out);
130
131 // Clear the environment variable
132#ifdef _WIN32
133 _putenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE=");
134#else
135 unsetenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
136#endif
137
138 log_dev("Popped last response from stack: '%s' (cleared env)", response_out);
139 return true;
140 }
141
142 // Calculate response length
143 size_t response_len = (size_t)(semicolon - env_value);
144
145 // Validate: no empty segment
146 if (response_len == 0) {
147 log_warn("Invalid ASCII_CHAT_QUESTION_PROMPT_RESPONSE format: empty segment");
148 return false;
149 }
150
151 if (response_len >= response_size) {
152 log_warn("Response too long: %zu bytes (max: %zu)", response_len, response_size - 1);
153 return false;
154 }
155
156 // Copy the first response
157 memcpy(response_out, env_value, response_len);
158 response_out[response_len] = '\0';
159
160 // Unescape the response (\; → ; and \\ → \‍)
161 unescape_response(response_out);
162
163 // Calculate remaining stack (skip the semicolon)
164 const char *remaining = semicolon + 1;
165
166 // Validate: if remaining is empty or only semicolons, clear the env
167 bool remaining_valid = false;
168 for (const char *p = remaining; *p; p++) {
169 if (*p != ';') {
170 remaining_valid = true;
171 break;
172 }
173 }
174
175 // Update environment variable with remaining responses
176 if (remaining_valid && remaining[0] != '\0') {
177 char new_env[1024];
178 int written = snprintf(new_env, sizeof(new_env), "ASCII_CHAT_QUESTION_PROMPT_RESPONSE=%s", remaining);
179 if (written < 0 || (size_t)written >= sizeof(new_env)) {
180 log_warn("Failed to format new environment variable");
181 return false;
182 }
183
184#ifdef _WIN32
185 _putenv(new_env);
186#else
187 // For POSIX, we need to use setenv
188 if (setenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE", remaining, 1) != 0) {
189 log_warn("Failed to update ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
190 return false;
191 }
192#endif
193
194 log_debug("Popped response from stack: '%s' (remaining: '%s')", response_out, remaining);
195 } else {
196 // No valid remaining responses - clear the env
197#ifdef _WIN32
198 _putenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE=");
199#else
200 unsetenv("ASCII_CHAT_QUESTION_PROMPT_RESPONSE");
201#endif
202
203 log_debug("Popped response from stack: '%s' (cleared env)", response_out);
204 }
205
206 return true;
207}

◆ 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;"
  • "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 250 of file env.c.

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