ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
string.c
Go to the documentation of this file.
1
7#include "util/string.h"
8#include "common.h"
9#include <string.h>
10#include <ctype.h>
11
12void escape_ascii(const char *str, const char *escape_char, char *out_buffer, size_t out_buffer_size) {
13 if (escape_char == NULL || str == NULL || !out_buffer || out_buffer_size == 0) {
14 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid string or escape character or output buffer");
15 return;
16 }
17
18 // Count how many characters need escaping
19 size_t escape_count = 0;
20 for (size_t i = 0; i < strlen(str); i++) {
21 for (size_t j = 0; j < strlen(escape_char); j++) {
22 if (str[i] == escape_char[j]) {
23 escape_count++;
24 break;
25 }
26 }
27 }
28
29 size_t total_len = strlen(str) + escape_count;
30 if (out_buffer_size < total_len) {
31 SET_ERRNO(ERROR_INVALID_PARAM, "Output buffer is too small");
32 return;
33 }
34
35 size_t out_pos = 0;
36 for (size_t i = 0; i < strlen(str); i++) {
37 bool needs_escape = false;
38 for (size_t j = 0; j < strlen(escape_char); j++) {
39 if (str[i] == escape_char[j]) {
40 needs_escape = true;
41 break;
42 }
43 }
44
45 if (needs_escape) {
46 out_buffer[out_pos++] = '\\';
47 }
48 out_buffer[out_pos++] = str[i];
49 }
50
51 out_buffer[out_pos] = '\0';
52}
53
54bool validate_shell_safe(const char *str, const char *allowed_chars) {
55 if (!str) {
56 return false;
57 }
58
59 // Shell metacharacters that are dangerous
60 // ; & | $ ` \ " ' < > ( ) [ ] { } * ? ! ~ # @ space tab newline
61 const char *dangerous = ";|$`\\\"'<>()[]{}*?!~#@ \t\n\r";
62
63 for (size_t i = 0; str[i] != '\0'; i++) {
64 unsigned char c = (unsigned char)str[i];
65
66 // Allow alphanumeric characters
67 if (isalnum(c)) {
68 continue;
69 }
70
71 // Check if character is in allowed_chars list
72 if (allowed_chars) {
73 bool is_allowed = false;
74 for (size_t j = 0; allowed_chars[j] != '\0'; j++) {
75 if (c == (unsigned char)allowed_chars[j]) {
76 is_allowed = true;
77 break;
78 }
79 }
80 if (is_allowed) {
81 continue;
82 }
83 }
84
85 // Check if character is dangerous
86 bool is_dangerous = false;
87 for (size_t j = 0; dangerous[j] != '\0'; j++) {
88 if (c == (unsigned char)dangerous[j]) {
89 is_dangerous = true;
90 break;
91 }
92 }
93 if (is_dangerous) {
94 return false;
95 }
96 }
97
98 return true;
99}
100
101bool escape_shell_single_quotes(const char *str, char *out_buffer, size_t out_buffer_size) {
102 if (!str || !out_buffer || out_buffer_size == 0) {
103 return false;
104 }
105
106 // Calculate required size: each ' becomes '\'' (4 chars) instead of 1
107 // Worst case: all chars are quotes, so we need strlen(str) * 4 + 2 (for surrounding quotes)
108 size_t required_size = 2; // Start and end quotes
109 for (size_t i = 0; str[i] != '\0'; i++) {
110 if (str[i] == '\'') {
111 required_size += 4; // '\''
112 } else {
113 required_size += 1;
114 }
115 }
116
117 if (out_buffer_size < required_size) {
118 SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Output buffer too small for shell escaping");
119 return false;
120 }
121
122 size_t out_pos = 0;
123 out_buffer[out_pos++] = '\''; // Opening quote
124
125 for (size_t i = 0; str[i] != '\0'; i++) {
126 if (str[i] == '\'') {
127 // Replace ' with '\'' (close quote, escaped quote, open quote)
128 out_buffer[out_pos++] = '\'';
129 out_buffer[out_pos++] = '\\';
130 out_buffer[out_pos++] = '\'';
131 out_buffer[out_pos++] = '\'';
132 } else {
133 out_buffer[out_pos++] = str[i];
134 }
135 }
136
137 out_buffer[out_pos++] = '\''; // Closing quote
138 out_buffer[out_pos] = '\0';
139
140 return true;
141}
142
143bool escape_shell_double_quotes(const char *str, char *out_buffer, size_t out_buffer_size) {
144 if (!str || !out_buffer || out_buffer_size == 0) {
145 return false;
146 }
147
148 // Calculate required size: each " becomes \" (2 chars) instead of 1
149 // Each \ also needs escaping, so \\ becomes \\\\
150 // Worst case: all chars are quotes/backslashes, so we need strlen(str) * 2 + 2 (for surrounding quotes)
151 size_t required_size = 2; // Start and end quotes
152 for (size_t i = 0; str[i] != '\0'; i++) {
153 if (str[i] == '"' || str[i] == '\\') {
154 required_size += 2; // \" or '\\'
155 } else {
156 required_size += 1;
157 }
158 }
159
160 if (out_buffer_size < required_size) {
161 SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Output buffer too small for shell escaping");
162 return false;
163 }
164
165 size_t out_pos = 0;
166 out_buffer[out_pos++] = '"'; // Opening quote
167
168 for (size_t i = 0; str[i] != '\0'; i++) {
169 if (str[i] == '"') {
170 // Escape double quote: " becomes \"
171 out_buffer[out_pos++] = '\\';
172 out_buffer[out_pos++] = '"';
173 } else if (str[i] == '\\') {
174 // Escape backslash: \ becomes '\\'
175 out_buffer[out_pos++] = '\\';
176 out_buffer[out_pos++] = '\\';
177 } else {
178 out_buffer[out_pos++] = str[i];
179 }
180 }
181
182 out_buffer[out_pos++] = '"'; // Closing quote
183 out_buffer[out_pos] = '\0';
184
185 return true;
186}
187
188bool string_needs_shell_quoting(const char *str) {
189 if (!str || str[0] == '\0') {
190 return false; // Empty strings don't need quoting
191 }
192
193 // Check for characters that need shell quoting
194 for (size_t i = 0; str[i] != '\0'; i++) {
195 char c = str[i];
196
197 // Whitespace characters always need quoting
198 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
199 return true;
200 }
201
202 // Shell special characters
203 if (c == '"' || c == '\'' || c == '$' || c == '`' || c == '\\' || c == '<' || c == '>' || c == '&' || c == ';' ||
204 c == '|' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '*' || c == '?' ||
205 c == '!' || c == '~' || c == '#' || c == '@') {
206 return true;
207 }
208 }
209
210 return false;
211}
212
213bool escape_path_for_shell(const char *path, char *out_buffer, size_t out_buffer_size) {
214 if (!path || !out_buffer || out_buffer_size == 0) {
215 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid path or output buffer");
216 return false;
217 }
218
219 // Check if quoting is needed
220 if (!string_needs_shell_quoting(path)) {
221 // No quoting needed, just copy the path
222 size_t path_len = strlen(path);
223 if (out_buffer_size <= path_len) {
224 SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Output buffer too small for path");
225 return false;
226 }
227 SAFE_STRNCPY(out_buffer, path, out_buffer_size);
228 return true;
229 }
230
231 // Quoting is needed, use platform-specific escaping
232#ifdef _WIN32
233 return escape_shell_double_quotes(path, out_buffer, out_buffer_size);
234#else
235 return escape_shell_single_quotes(path, out_buffer, out_buffer_size);
236#endif
237}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:358
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_INVALID_PARAM
@ ERROR_BUFFER_OVERFLOW
Definition error_codes.h:98
bool escape_shell_double_quotes(const char *str, char *out_buffer, size_t out_buffer_size)
Escape a string for safe use in shell commands (double quotes, Windows-compatible)
Definition string.c:143
bool escape_shell_single_quotes(const char *str, char *out_buffer, size_t out_buffer_size)
Escape a string for safe use in shell commands (single quotes)
Definition string.c:101
bool string_needs_shell_quoting(const char *str)
Check if a string needs shell quoting (contains spaces or special chars)
Definition string.c:188
bool validate_shell_safe(const char *str, const char *allowed_chars)
Validate that a string contains only safe characters for shell commands.
Definition string.c:54
void escape_ascii(const char *str, const char *escape_char, char *out_buffer, size_t out_buffer_size)
Escape ASCII characters in a string.
Definition string.c:12
bool escape_path_for_shell(const char *path, char *out_buffer, size_t out_buffer_size)
Escape a path for safe use in shell commands (auto-platform)
Definition string.c:213
🔤 String Manipulation and Shell Escaping Utilities