ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
reader.c File Reference

Read ANSI ASCII frames from file descriptor, chunked by height. More...

Go to the source code of this file.

Data Structures

struct  terminal_fd_reader_s
 

Macros

#define LINE_BUFFER_SIZE   16384
 

Typedefs

typedef struct terminal_fd_reader_s terminal_fd_reader_t
 

Functions

asciichat_error_t terminal_fd_reader_create (int fd, int frame_height, terminal_fd_reader_t **out)
 Create a terminal FD reader from a file descriptor.
 
asciichat_error_t terminal_fd_reader_next (terminal_fd_reader_t *reader, char **out_frame)
 Read next frame from file descriptor.
 
void terminal_fd_reader_destroy (terminal_fd_reader_t *reader)
 Destroy terminal FD reader.
 

Detailed Description

Read ANSI ASCII frames from file descriptor, chunked by height.

Definition in file reader.c.

Macro Definition Documentation

◆ LINE_BUFFER_SIZE

#define LINE_BUFFER_SIZE   16384

Definition at line 26 of file reader.c.

Typedef Documentation

◆ terminal_fd_reader_t

Function Documentation

◆ terminal_fd_reader_create()

asciichat_error_t terminal_fd_reader_create ( int  fd,
int  frame_height,
terminal_fd_reader_t **  out 
)

Create a terminal FD reader from a file descriptor.

Parameters
fdFile descriptor to read from (e.g., STDIN_FILENO, open file)
frame_heightNumber of lines per frame (required - used for frame boundaries)
outPointer to store reader context
Returns
ASCIICHAT_OK on success

Width is auto-detected from the first frame's line length.

Definition at line 28 of file reader.c.

28 {
29 if (fd < 0 || frame_height <= 0) {
30 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid fd or frame height: fd=%d, height=%d", fd, frame_height);
31 }
32
33 FILE *fp = platform_fdopen("terminal_fd_reader", fd, "r");
34 if (!fp) {
35 return SET_ERRNO_SYS(ERROR_INVALID_PARAM, "fdopen failed for FD %d", fd);
36 }
37
38 terminal_fd_reader_t *reader = SAFE_CALLOC(1, sizeof(*reader), terminal_fd_reader_t *);
39 reader->fp = fp;
40 reader->frame_height = frame_height;
41 reader->frame_width = 0; // Will be detected from first frame
42 reader->line_buffer = SAFE_MALLOC(LINE_BUFFER_SIZE, char *);
44 reader->eof_reached = false;
45 reader->first_frame_processed = false;
46
47 log_debug("terminal_fd_reader: created with fd=%d, frame height %d (width auto-detect)", fd, frame_height);
48 *out = reader;
49 return ASCIICHAT_OK;
50}
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define SAFE_CALLOC(count, size, cast)
Definition common.h:274
#define SET_ERRNO_SYS(code, context_msg,...)
Set error code with custom message and system error context, returning the error code.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_INVALID_PARAM
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
FILE * platform_fdopen(const char *name, int fd, const char *mode)
Convert file descriptor to stream (fdopen replacement)
#define LINE_BUFFER_SIZE
Definition reader.c:26
size_t line_buffer_size
Definition reader.c:21
bool first_frame_processed
Definition reader.c:23

References ASCIICHAT_OK, terminal_fd_reader_s::eof_reached, ERROR_INVALID_PARAM, terminal_fd_reader_s::first_frame_processed, terminal_fd_reader_s::fp, terminal_fd_reader_s::frame_height, terminal_fd_reader_s::frame_width, terminal_fd_reader_s::line_buffer, terminal_fd_reader_s::line_buffer_size, LINE_BUFFER_SIZE, log_debug, platform_fdopen(), SAFE_CALLOC, SAFE_MALLOC, SET_ERRNO, and SET_ERRNO_SYS.

◆ terminal_fd_reader_destroy()

void terminal_fd_reader_destroy ( terminal_fd_reader_t *  reader)

Destroy terminal FD reader.

Parameters
readerReader context to destroy

Definition at line 142 of file reader.c.

142 {
143 if (!reader)
144 return;
145 if (reader->fp) {
146 fclose(reader->fp);
147 reader->fp = NULL;
148 }
149 SAFE_FREE(reader->line_buffer);
150 SAFE_FREE(reader);
151}
#define SAFE_FREE(ptr)
Definition common.h:376

References terminal_fd_reader_s::fp, terminal_fd_reader_s::line_buffer, and SAFE_FREE.

◆ terminal_fd_reader_next()

asciichat_error_t terminal_fd_reader_next ( terminal_fd_reader_t *  reader,
char **  out_frame 
)

Read next frame from file descriptor.

Reads frame_height lines from the FD and returns them as a single frame string. Returns NULL in out_frame when EOF is reached.

Parameters
readerReader context
out_framePointer to store frame data (NULL when EOF, must free with SAFE_FREE)
Returns
ASCIICHAT_OK on success (including EOF)

Definition at line 52 of file reader.c.

52 {
53 if (!reader || !out_frame) {
54 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters to terminal_fd_reader_next");
55 }
56
57 if (reader->eof_reached) {
58 *out_frame = NULL;
59 return ASCIICHAT_OK; // EOF, but no error
60 }
61
62 // Allocate buffer for complete frame (frame_height lines)
63 // Estimate: 16KB per line should be enough for ANSI + ASCII
64 size_t frame_capacity = reader->frame_height * LINE_BUFFER_SIZE;
65 char *frame_data = SAFE_MALLOC(frame_capacity, char *);
66 size_t frame_pos = 0;
67
68 // Read exactly frame_height lines from FD
69 for (int line_num = 0; line_num < reader->frame_height; line_num++) {
70 // Read one line from FD
71 char *line = fgets(reader->line_buffer, (int)reader->line_buffer_size, reader->fp);
72
73 if (!line) {
74 // EOF reached
75 reader->eof_reached = true;
76
77 // If we read some lines but not a complete frame, that's ok - return partial
78 if (frame_pos > 0) {
79 log_debug("terminal_fd_reader: EOF reached after %d/%d lines, returning partial frame", line_num,
80 reader->frame_height);
81 // Remove trailing newline from last line if present
82 if (frame_pos > 0 && frame_data[frame_pos - 1] == '\n') {
83 frame_pos--;
84 }
85 *out_frame = frame_data;
86 return ASCIICHAT_OK;
87 }
88
89 SAFE_FREE(frame_data);
90 *out_frame = NULL;
91 return ASCIICHAT_OK; // EOF
92 }
93
94 // Append line to frame
95 size_t line_len = strlen(line);
96 if (frame_pos + line_len >= frame_capacity) {
97 log_warn("terminal_fd_reader: frame buffer overflow, line %d too large", line_num);
98 // Realloc and continue
99 frame_capacity *= 2;
100 char *new_frame = SAFE_MALLOC(frame_capacity, char *);
101 memcpy(new_frame, frame_data, frame_pos);
102 SAFE_FREE(frame_data);
103 frame_data = new_frame;
104 }
105
106 memcpy(frame_data + frame_pos, line, line_len);
107 frame_pos += line_len;
108 }
109
110 // Remove trailing newline from last line (we'll add it back in display)
111 if (frame_pos > 0 && frame_data[frame_pos - 1] == '\n') {
112 frame_data[frame_pos - 1] = '\0';
113 frame_pos--;
114 }
115
116 // Detect frame width from first frame (count visible chars in first line)
117 if (!reader->first_frame_processed && frame_pos > 0) {
118 reader->first_frame_processed = true;
119
120 // Find first line by looking for newline
121 char *first_newline = strchr(frame_data, '\n');
122 if (first_newline) {
123 // Null-terminate first line temporarily for width calculation
124 char saved_char = *first_newline;
125 *first_newline = '\0';
126 reader->frame_width = display_width(frame_data);
127 *first_newline = saved_char; // Restore
128 } else {
129 // Only one line in frame, use it for width
130 reader->frame_width = display_width(frame_data);
131 }
132
133 log_info("terminal_fd_reader: detected frame width %d from first frame", reader->frame_width);
134 }
135
136 *out_frame = frame_data;
137 log_debug_every(NS_PER_SEC_INT, "terminal_fd_reader: read frame (%zu bytes, %dx%d)", frame_pos, reader->frame_width,
138 reader->frame_height);
139 return ASCIICHAT_OK;
140}
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define NS_PER_SEC_INT
Definition time.h:157
int display_width(const char *text)
Calculate the visible display width of text with ANSI escape codes.
#define log_debug_every(interval_us, fmt,...)
Rate-limited DEBUG logging.
Definition log/log.h:702

References ASCIICHAT_OK, display_width(), terminal_fd_reader_s::eof_reached, ERROR_INVALID_PARAM, terminal_fd_reader_s::first_frame_processed, terminal_fd_reader_s::fp, terminal_fd_reader_s::frame_height, terminal_fd_reader_s::frame_width, terminal_fd_reader_s::line_buffer, terminal_fd_reader_s::line_buffer_size, LINE_BUFFER_SIZE, log_debug, log_debug_every, log_info, log_warn, NS_PER_SEC_INT, SAFE_FREE, SAFE_MALLOC, and SET_ERRNO.