#include #include #include #include #include #include static enum ivy_status get_name( struct ivy_line_source *src, char *buf, size_t count, size_t *nr_read) { struct ivy_file *f = (struct ivy_file *)src; *nr_read = snprintf(buf, count, "%s", f->f_path); return IVY_OK; } static enum ivy_status get_row( struct ivy_line_source *src, size_t row, char *buf, size_t count, size_t *nr_read) { struct ivy_file *f = (struct ivy_file *)src; size_t nr_rows = b_array_size(f->f_lines); if (row > nr_rows) { return IVY_ERR_EOF; } b_string *line = B_STRING(b_array_at(f->f_lines, row - 1)); const char *line_str = b_string_ptr(line); size_t line_len = b_string_get_size(line, B_STRLEN_NORMAL); size_t copy_len = b_min(ulong, count, line_len); memcpy(buf, line_str, copy_len); buf[copy_len] = 0; buf[strcspn(buf, "\n")] = 0; *nr_read = copy_len; return IVY_OK; } static enum ivy_status readline( struct ivy_line_source *src, char *buf, size_t count, size_t *nr_read, const char *prompt) { if (!count) { *nr_read = 0; return IVY_OK; } struct ivy_file *f = (struct ivy_file *)src; if (!fgets(buf, (int)count, f->f_fp)) { return feof(f->f_fp) ? IVY_ERR_EOF : IVY_ERR_IO_FAILURE; } b_string *line_str = b_string_create_from_cstr(buf); b_array_append(f->f_lines, B_OBJECT(line_str)); b_string_release(line_str); *nr_read = strlen(buf); return IVY_OK; } enum ivy_status ivy_file_open(const char *path, struct ivy_file **out) { FILE *fp = fopen(path, "r"); if (!fp) { return ivy_status_from_errno(errno); } struct ivy_file *file = malloc(sizeof *file); if (!file) { fclose(fp); return IVY_ERR_NO_MEMORY; } memset(file, 0x0, sizeof *file); file->f_base.s_get_name = get_name; file->f_base.s_get_row = get_row; file->f_base.s_readline = readline; file->f_fp = fp; file->f_path = b_strdup(path); file->f_lines = b_array_create(); *out = file; return IVY_OK; } void ivy_file_close(struct ivy_file *file) { b_array_release(file->f_lines); free(file->f_path); fclose(file->f_fp); free(file); }