ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
parsing.c
Go to the documentation of this file.
1
7#include "parsing.h"
8#include <string.h>
9#include <errno.h>
10#include <limits.h>
11#include <stdlib.h>
12#include "../asciichat_errno.h"
13
14asciichat_error_t safe_parse_size_message(const char *message, unsigned int *width, unsigned int *height) {
15 if (!message || !width || !height) {
16 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters for size message parsing");
17 }
18
19 // Check if message starts with "SIZE:"
20 if (strncmp(message, "SIZE:", 5) != 0) {
21 return SET_ERRNO(ERROR_INVALID_PARAM, "Message does not start with 'SIZE:'");
22 }
23
24 const char *ptr = message + 5; // Skip "SIZE:"
25 char *endptr;
26
27 // Parse first number (width)
28 errno = 0;
29 unsigned long w = strtoul(ptr, &endptr, 10);
30 if (errno != 0 || endptr == ptr || w > UINT_MAX || w == 0) {
31 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid width value in size message");
32 }
33
34 // Check for comma separator
35 if (*endptr != ',') {
36 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing comma separator in size message");
37 }
38 ptr = endptr + 1;
39
40 // Parse second number (height)
41 errno = 0;
42 unsigned long h = strtoul(ptr, &endptr, 10);
43 if (errno != 0 || endptr == ptr || h > UINT_MAX || h == 0) {
44 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid height value in size message");
45 }
46
47 // Should end with newline or null terminator
48 if (*endptr != '\n' && *endptr != '\0') {
49 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid format: size message should end with newline or null terminator");
50 }
51
52 // Additional bounds checking
53 if (w > 65535 || h > 65535) {
54 return SET_ERRNO(ERROR_INVALID_PARAM, "Size values too large (max 65535)");
55 }
56
57 *width = (unsigned int)w;
58 *height = (unsigned int)h;
59 return ASCIICHAT_OK;
60}
61
62asciichat_error_t safe_parse_audio_message(const char *message, unsigned int *num_samples) {
63 if (!message || !num_samples) {
64 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters for audio message parsing");
65 }
66
67 // Check if message starts with "AUDIO:"
68 if (strncmp(message, "AUDIO:", 6) != 0) {
69 return SET_ERRNO(ERROR_INVALID_PARAM, "Message does not start with 'AUDIO:'");
70 }
71
72 const char *ptr = message + 6; // Skip "AUDIO:"
73 char *endptr;
74
75 // Parse number
76 errno = 0;
77 unsigned long samples = strtoul(ptr, &endptr, 10);
78 if (errno != 0 || endptr == ptr || samples > UINT_MAX || samples == 0) {
79 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid sample count value in audio message");
80 }
81
82 // Should end with newline or null terminator
83 if (*endptr != '\n' && *endptr != '\0') {
84 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid format: audio message should end with newline or null terminator");
85 }
86
87 *num_samples = (unsigned int)samples;
88 return ASCIICHAT_OK;
89}
90
91/* ============================================================================
92 * Integer Parsing Functions
93 * ============================================================================
94 */
95
96asciichat_error_t parse_long(const char *str, long *out_value, long min_value, long max_value) {
97 if (!str) {
98 return SET_ERRNO(ERROR_INVALID_PARAM, "String pointer is NULL");
99 }
100
101 if (!out_value) {
102 return SET_ERRNO(ERROR_INVALID_PARAM, "Output pointer is NULL");
103 }
104
105 if (*str == '\0') {
106 return SET_ERRNO(ERROR_INVALID_PARAM, "Empty string cannot be parsed as integer");
107 }
108
109 // Clear errno before calling strtol to detect errors
110 errno = 0;
111 char *endptr = NULL;
112 long value = strtol(str, &endptr, 10);
113
114 // Check for conversion errors
115 if (errno == ERANGE) {
116 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value out of range: %s", str);
117 }
118
119 // Check that entire string was consumed (no extra characters)
120 if (endptr == str || *endptr != '\0') {
121 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid integer format: %s", str);
122 }
123
124 // Check user-specified range
125 if (value < min_value) {
126 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value %ld is below minimum %ld", value, min_value);
127 }
128
129 if (value > max_value) {
130 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value %ld exceeds maximum %ld", value, max_value);
131 }
132
133 *out_value = value;
134 return ASCIICHAT_OK;
135}
136
137asciichat_error_t parse_ulong(const char *str, unsigned long *out_value, unsigned long min_value,
138 unsigned long max_value) {
139 if (!str) {
140 return SET_ERRNO(ERROR_INVALID_PARAM, "String pointer is NULL");
141 }
142
143 if (!out_value) {
144 return SET_ERRNO(ERROR_INVALID_PARAM, "Output pointer is NULL");
145 }
146
147 if (*str == '\0') {
148 return SET_ERRNO(ERROR_INVALID_PARAM, "Empty string cannot be parsed as integer");
149 }
150
151 // Clear errno before calling strtoul to detect errors
152 errno = 0;
153 char *endptr = NULL;
154 unsigned long value = strtoul(str, &endptr, 10);
155
156 // Check for conversion errors
157 if (errno == ERANGE) {
158 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value out of range: %s", str);
159 }
160
161 // Check that entire string was consumed (no extra characters)
162 if (endptr == str || *endptr != '\0') {
163 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid integer format: %s", str);
164 }
165
166 // Check user-specified range
167 if (value < min_value) {
168 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value %lu is below minimum %lu", value, min_value);
169 }
170
171 if (value > max_value) {
172 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value %lu exceeds maximum %lu", value, max_value);
173 }
174
175 *out_value = value;
176 return ASCIICHAT_OK;
177}
178
179asciichat_error_t parse_ulonglong(const char *str, unsigned long long *out_value, unsigned long long min_value,
180 unsigned long long max_value) {
181 if (!str) {
182 return SET_ERRNO(ERROR_INVALID_PARAM, "String pointer is NULL");
183 }
184
185 if (!out_value) {
186 return SET_ERRNO(ERROR_INVALID_PARAM, "Output pointer is NULL");
187 }
188
189 if (*str == '\0') {
190 return SET_ERRNO(ERROR_INVALID_PARAM, "Empty string cannot be parsed as integer");
191 }
192
193 // Clear errno before calling strtoull to detect errors
194 errno = 0;
195 char *endptr = NULL;
196 unsigned long long value = strtoull(str, &endptr, 10);
197
198 // Check for conversion errors
199 if (errno == ERANGE) {
200 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value out of range: %s", str);
201 }
202
203 // Check that entire string was consumed (no extra characters)
204 if (endptr == str || *endptr != '\0') {
205 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid integer format: %s", str);
206 }
207
208 // Check user-specified range
209 if (value < min_value) {
210 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value too small (below minimum)");
211 }
212
213 if (value > max_value) {
214 return SET_ERRNO(ERROR_INVALID_PARAM, "Integer value too large (exceeds maximum)");
215 }
216
217 *out_value = value;
218 return ASCIICHAT_OK;
219}
220
221asciichat_error_t parse_port(const char *str, uint16_t *out_port) {
222 if (!str) {
223 return SET_ERRNO(ERROR_INVALID_PARAM, "String pointer is NULL");
224 }
225
226 if (!out_port) {
227 return SET_ERRNO(ERROR_INVALID_PARAM, "Output pointer is NULL");
228 }
229
230 unsigned long port_ulong;
231 asciichat_error_t err = parse_ulong(str, &port_ulong, 1, 65535);
232 if (err != ASCIICHAT_OK) {
233 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid port number: %s (must be 1-65535)", str);
234 }
235
236 *out_port = (uint16_t)port_ulong;
237 return ASCIICHAT_OK;
238}
239
240asciichat_error_t parse_int32(const char *str, int32_t *out_value, int32_t min_value, int32_t max_value) {
241 if (!str) {
242 return SET_ERRNO(ERROR_INVALID_PARAM, "String pointer is NULL");
243 }
244
245 if (!out_value) {
246 return SET_ERRNO(ERROR_INVALID_PARAM, "Output pointer is NULL");
247 }
248
249 long value;
250 asciichat_error_t err = parse_long(str, &value, (long)min_value, (long)max_value);
251 if (err != ASCIICHAT_OK) {
252 return err;
253 }
254
255 *out_value = (int32_t)value;
256 return ASCIICHAT_OK;
257}
258
259asciichat_error_t parse_uint32(const char *str, uint32_t *out_value, uint32_t min_value, uint32_t max_value) {
260 if (!str) {
261 return SET_ERRNO(ERROR_INVALID_PARAM, "String pointer is NULL");
262 }
263
264 if (!out_value) {
265 return SET_ERRNO(ERROR_INVALID_PARAM, "Output pointer is NULL");
266 }
267
268 unsigned long value;
269 asciichat_error_t err = parse_ulong(str, &value, (unsigned long)min_value, (unsigned long)max_value);
270 if (err != ASCIICHAT_OK) {
271 return err;
272 }
273
274 *out_value = (uint32_t)value;
275 return ASCIICHAT_OK;
276}
unsigned short uint16_t
Definition common.h:57
unsigned int uint32_t
Definition common.h:58
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_INVALID_PARAM
#define ERANGE
int errno
asciichat_error_t safe_parse_size_message(const char *message, unsigned int *width, unsigned int *height)
Parse SIZE message format.
Definition parsing.c:14
asciichat_error_t safe_parse_audio_message(const char *message, unsigned int *num_samples)
Parse AUDIO message format.
Definition parsing.c:62
Application limits and constraints.
asciichat_error_t parse_ulonglong(const char *str, unsigned long long *out_value, unsigned long long min_value, unsigned long long max_value)
Parse unsigned long long integer with range validation.
Definition parsing.c:179
asciichat_error_t parse_uint32(const char *str, uint32_t *out_value, uint32_t min_value, uint32_t max_value)
Parse unsigned 32-bit integer with range validation.
Definition parsing.c:259
asciichat_error_t parse_ulong(const char *str, unsigned long *out_value, unsigned long min_value, unsigned long max_value)
Parse unsigned long integer with range validation.
Definition parsing.c:137
asciichat_error_t parse_long(const char *str, long *out_value, long min_value, long max_value)
Parse signed long integer with range validation.
Definition parsing.c:96
asciichat_error_t parse_int32(const char *str, int32_t *out_value, int32_t min_value, int32_t max_value)
Parse signed 32-bit integer with range validation.
Definition parsing.c:240
asciichat_error_t parse_port(const char *str, uint16_t *out_port)
Parse port number (1-65535) from string.
Definition parsing.c:221
🔍 Safe Parsing Utilities
🔤 String Manipulation and Shell Escaping Utilities