2#define _POSIX_C_SOURCE 1
5#include "../include/stdstreams.h"
20bool readline(
const char* prompt,
char* buffer,
size_t buffer_len) {
26 if (fgets(buffer, (
int)buffer_len, stdin) == NULL) {
30 buffer[strcspn(buffer,
"\n")] =
'\0';
32 if (strlen(buffer) >= buffer_len - 1) {
34 while ((c = getchar()) != EOF) {
46int getpassword(
const char* prompt,
char* buffer,
size_t buffer_len) {
53 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
58 if (hStdin == INVALID_HANDLE_VALUE) {
62 if (!GetConsoleMode(hStdin, &mode)) {
66 if (!SetConsoleMode(hStdin, mode & ~ENABLE_ECHO_INPUT)) {
70 for (i = 0; i < buffer_len - 1; i++) {
71 if (!ReadConsoleA(hStdin, &buffer[i], 1, &count, NULL) || count == 0) {
75 if (buffer[i] ==
'\n' || buffer[i] ==
'\r') {
83 if (!SetConsoleMode(hStdin, mode)) {
90 struct termios old, new;
94 if (tcgetattr(fileno(stdin), &old) != 0) {
99 new.c_lflag &= (tcflag_t)~ECHO;
101 if (tcsetattr(fileno(stdin), TCSAFLUSH, &
new) != 0) {
106 nread = readline(prompt, buffer, buffer_len);
109 if (tcsetattr(fileno(stdin), TCSAFLUSH, &old) != 0) {
130 unsigned long (*read)(
void* handle,
size_t size,
size_t count,
void* ptr);
133 int (*read_char)(
void* handle);
137 size_t (*write)(
const void* ptr,
size_t size,
size_t count,
void* handle);
140 int (*eof)(
void* handle);
143 int (*seek)(
void* handle,
long offset,
int whence);
146 int (*flush)(
void* handle);
152 enum stream_type type;
155static size_t file_write(
const void* ptr,
size_t size,
size_t count,
void* handle) {
156 return fwrite(ptr, size, count, (FILE*)handle);
159static unsigned long file_read(
void* handle,
size_t size,
size_t count,
void* ptr) {
160 return fread(ptr, size, count, (FILE*)handle);
163size_t file_stream_read(stream_t s,
void* restrict ptr,
size_t size,
size_t count) {
164 if (s->type == FILE_STREAM) {
165 s->seek(s->handle, 0, SEEK_SET);
166 return fread(ptr, size, count, (FILE*)s->handle);
169 fprintf(stderr,
"Reading from a non file stream\n");
173stream_t create_file_stream(FILE* fp) {
174 stream_t stream = malloc(
sizeof(
struct stream));
181 stream->flush = (int (*)(
void*))fflush;
182 stream->seek = (int (*)(
void*,
long int, int))fseek;
183 stream->eof = (int (*)(
void*))feof;
184 stream->read_char = (int (*)(
void*))fgetc;
186 stream->type = FILE_STREAM;
190ssize_t read_until(stream_t stream,
int delim,
char* buffer,
size_t buffer_size) {
191 ssize_t bytes_read = 0;
193 while ((ch = stream->read_char(stream->handle)) != EOF && ch != delim && bytes_read < (
int)buffer_size - 1) {
194 buffer[bytes_read++] = (char)ch;
198 if (ch == EOF && stream->eof(stream->handle)) {
203 if (bytes_read < (
int)(buffer_size - 1)) {
204 buffer[bytes_read] =
'\0';
208 puts(
"[read_upto_char]: Buffer overflow");
209 printf(
"read %zd bytes, buffer size %zu\n", bytes_read, buffer_size);
211 buffer[buffer_size - 1] =
'\0';
216unsigned long io_copy(stream_t writer, stream_t reader) {
218 unsigned long nread = 0;
219 unsigned long total_written = 0;
220 reader->seek(reader->handle, 0, SEEK_SET);
222 while ((nread = reader->read(reader->handle, 1,
sizeof(buffer), buffer)) > 0) {
223 total_written += writer->write(buffer, 1, nread, writer->handle);
227 writer->flush(writer->handle);
228 return total_written;
233unsigned long io_copy_n(stream_t writer, stream_t reader,
size_t n) {
235 unsigned long nread = 0;
236 unsigned long total_written = 0;
237 reader->seek(reader->handle, 0, SEEK_SET);
239 while (n > 0 && (nread = reader->read(reader->handle, 1,
sizeof(buffer), buffer)) > 0) {
244 total_written += writer->write(buffer, 1, nread, writer->handle);
249 writer->flush(writer->handle);
250 return total_written;
254static unsigned long inner_string_stream_read(
void* handle,
size_t size,
size_t count,
void* ptr) {
257 string_stream* ss = (string_stream*)handle;
258 size_t string_len =
cstr_len(ss->str);
260 if (count == 0 || ss->pos >= string_len) {
265 if (count > SIZE_MAX) {
271 if (ss->pos + count > string_len) {
272 count = string_len - ss->pos;
277 memcpy(ptr, data + ss->pos, count);
284static int string_stream_read_char(
void* handle) {
285 string_stream* ss = (string_stream*)handle;
293static int string_stream_eof(
void* handle) {
294 string_stream* ss = (string_stream*)handle;
295 return ss->pos >=
cstr_len(ss->str);
299static size_t inner__string_stream_write(
const void* ptr,
size_t size,
size_t count,
void* handle) {
300 string_stream* ss = (string_stream*)handle;
301 size_t bytes_written = 0;
302 size_t total_bytes = size * count;
303 bool resized =
false;
311 for (
size_t i = 0; i < total_bytes; i++) {
312 data[ss->pos++] = ((
char*)ptr)[i];
315 return bytes_written / size;
318static int string_stream_seek(
void* handle,
long offset,
int whence) {
319 string_stream* ss = (string_stream*)handle;
321 size_t new_pos = ss->pos;
325 if (offset < 0 || (
size_t)offset > length)
return EOF;
326 new_pos = (size_t)offset;
329 if ((offset < 0 && (
size_t)(-offset) > ss->pos) || (offset > 0 && ss->pos + (size_t)offset > length))
331 new_pos += (size_t)offset;
334 if ((offset < 0 && (
size_t)(-offset) > length) || (offset > 0))
return EOF;
335 new_pos = length + (size_t)offset;
345static int string_flush(
void* handle) {
351int string_stream_write(stream_t stream,
const char* str) {
354 string_stream* ss = (string_stream*)stream->handle;
358 return (
int)strlen(str);
361const char* string_stream_data(stream_t stream) {
362 if (stream->type == STRING_STREAM) {
363 string_stream* ss = (string_stream*)stream->handle;
370static void inner__free_file_stream(stream_t stream) {
372 FILE* fp = (FILE*)stream->handle;
374 if (!(fp == stdout || fp == stderr || fp == stdin)) {
382static void inner__free_string_stream(stream_t stream) {
385 if (stream->handle) {
386 free(stream->handle);
387 stream->handle = NULL;
394void stream_destroy(stream_t stream) {
395 switch (stream->type) {
397 inner__free_file_stream(stream);
400 inner__free_string_stream(stream);
404 fprintf(stderr,
"Invalid stream");
410stream_t create_string_stream(
size_t initial_capacity) {
411 stream_t stream = malloc(
sizeof(
struct stream));
416 string_stream* ss = (string_stream*)malloc(
sizeof(string_stream));
423 if (ss->str == NULL) {
430 stream->read = inner_string_stream_read;
431 stream->flush = (int (*)(
void*))string_flush;
432 stream->read_char = string_stream_read_char;
433 stream->eof = string_stream_eof;
434 stream->write = inner__string_stream_write;
435 stream->seek = string_stream_seek;
437 stream->type = STRING_STREAM;
CSTR_INLINE bool cstr_resize(cstr *s, size_t capacity) CSTR_NONNULL(1) CSTR_WARN_UNUSED
bool cstr_append(cstr *s, const char *CSTR_RESTRICT append) CSTR_NONNULL(1
Append a NUL-terminated C string.
CSTR_INLINE size_t cstr_len(const cstr *s) CSTR_PURE
Length of the string, excluding NUL.
cstr * cstr_init(size_t initial_capacity) CSTR_WARN_UNUSED
Create a new heap-allocated cstr with a given initial capacity.
CSTR_INLINE char * cstr_data(cstr *s) CSTR_PURE
Mutable pointer to the NUL-terminated string data. Never NULL for a valid cstr.
size_t file_read(const file_t *file, void *buffer, size_t size, size_t count)
size_t file_write(file_t *file, const void *buffer, size_t size, size_t count)