#include #include #include "../include/libstream.h" int get_flags(const char *mode) { int flags; if (strcmp(mode, "r") == 0) { flags = O_RDONLY; } else if (strcmp(mode, "r+") == 0) { flags = O_RDWR; } else if (strcmp(mode, "w") == 0) { flags = O_WRONLY | O_TRUNC | O_CREAT; } else { flags = O_RDWR | O_TRUNC | O_CREAT; } return flags; } struct stream *lbs_fopen(const char *path, const char *mode) { int fd = open(path, get_flags(mode)); return lbs_fdopen(fd, mode); } struct stream *lbs_fdopen(int fd, const char *mode) { if (fd == -1) { return NULL; } struct stream *s = malloc(sizeof(struct stream)); if (s == NULL) { return NULL; } s->flags = get_flags(mode); s->error = 0; s->fd = fd; if (isatty(fd)) { s->buffering_mode = STREAM_LINE_BUFFERED; } else { s->buffering_mode = STREAM_BUFFERED; } s->buffered_size = 0; s->already_read = 0; return s; } int lbs_fflush(struct stream *stream) { if (stream == NULL || stream->buffered_size == 0) { return 0; } if (stream->io_operation == STREAM_READING) { if (!stream_readable(stream)) { stream->error = 1; return LBS_EOF; } if (stream_remaining_buffered(stream) != 0 && lseek(stream->fd, -stream_remaining_buffered(stream), SEEK_CUR) == -1) { stream->error = 1; return LBS_EOF; } stream->buffered_size = 0; stream->already_read = 0; } else { if (!stream_writable(stream)) { stream->error = 1; return LBS_EOF; } ssize_t w; if ((w = write(stream->fd, stream->buffer, stream->buffered_size)) == -1) { stream->error = 1; return LBS_EOF; } stream->buffered_size = 0; stream->already_read = 0; } return 0; } int lbs_fclose(struct stream *stream) { if (stream == NULL) { return 1; } lbs_fflush(stream); if (close(stream->fd) == -1) { return 1; } free(stream); return 0; } int lbs_fputc(int c, struct stream *stream) { if (!stream_writable(stream)) { stream->error = 1; return -1; } if (stream->io_operation == STREAM_READING) { if (lbs_fflush(stream) != 0) { return -1; } stream->buffered_size = 0; stream->already_read = 0; } stream->io_operation = STREAM_WRITING; if (stream_unused_buffer_space(stream) == 0 || stream->buffering_mode == STREAM_UNBUFFERED) { if (lbs_fflush(stream) != 0) { return -1; } } stream->buffer[stream->buffered_size] = c; stream->buffered_size++; if (stream_unused_buffer_space(stream) == 0 || stream->buffering_mode == STREAM_UNBUFFERED || (stream->buffering_mode == STREAM_LINE_BUFFERED && c == '\n')) { if (lbs_fflush(stream) != 0) { return -1; } } return c; } int refill_buffer(struct stream *stream) { stream->already_read = 0; ssize_t r; if ((r = read(stream->fd, stream->buffer, LBS_BUFFER_SIZE)) == -1) { stream->error = 1; return -1; } if (r == 0) { return -1; } stream->buffered_size = r; return r; } int lbs_fgetc(struct stream *stream) { if (!stream_readable(stream)) { stream->error = 1; return -1; } if (stream->io_operation == STREAM_WRITING) { if (lbs_fflush(stream) != 0) { stream->error = 1; return -1; } stream->already_read = 0; } stream->io_operation = STREAM_READING; if (stream_remaining_buffered(stream) == 0) { int r; if ((r = refill_buffer(stream)) == -1) { stream->error = 1; return -1; } } int res = stream->buffer[stream->already_read++]; unsigned char c = res; return c; }