Przeglądaj źródła

Adding library file.h

Vinicius Teshima 1 rok temu
rodzic
commit
f09d2a3c11
1 zmienionych plików z 167 dodań i 0 usunięć
  1. 167 0
      2024/c/file.h

+ 167 - 0
2024/c/file.h

@@ -0,0 +1,167 @@
+#ifndef FILE_H
+#define FILE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define CONCAT(a, b) CONCAT_INNER(a, b)
+#define CONCAT_INNER(a, b) a ## b
+
+#define UNIQUE_NAME(base) CONCAT(base, __COUNTER__)
+
+enum file_err {
+	FILE_ERR_OK,
+	FILE_ERR_FAIL_OPEN,
+	FILE_ERR_FAIL_SEEK,
+	FILE_ERR_FAIL_READ,
+	FILE_ERR_FAIL_WRITE,
+	FILE_ERR_FAIL_CALLOC,
+	FILE_ERR_FAIL_CLOSE,
+	FILE_ERR_FILE_EMPTY,
+	FILE_ERR_FAIL_WROTE_MORE,
+	FILE_ERR_EMPTY
+};
+
+uint8_t *file_read_all(const char *filepath, size_t *ret_size,
+		       enum file_err *ret_err);
+void file_save(const char *filepath, const char *str, size_t str_size,
+	       enum file_err *ret_err);
+
+void file_err_set(enum file_err *err, enum file_err err_);
+const char *file_err_to_cstr(enum file_err err);
+
+#if defined(BMP_IMP) || defined(IMP)
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+uint8_t *
+file_read_all(const char *filepath, size_t *ret_size, enum file_err *ret_err)
+{
+	int32_t fd = -1;
+	off_t file_size = -1;
+	size_t buf_size = 0;
+	uint8_t *buf = NULL;
+
+	fd = open(filepath, O_RDONLY);
+	if ( fd < 0 ) {
+		file_err_set(ret_err, FILE_ERR_FAIL_OPEN);
+		return NULL;
+	}
+
+	file_size = lseek(fd, 0, SEEK_END);
+	if ( file_size < 0 ) {
+		file_err_set(ret_err, FILE_ERR_FAIL_SEEK);
+		close(fd);
+		return NULL;
+	}
+	lseek(fd, 0, SEEK_SET);
+
+	if ( file_size == 0 ) {
+		file_err_set(ret_err, FILE_ERR_EMPTY);
+		close(fd);
+		return NULL;
+	}
+
+	buf_size = ((size_t)file_size) + 1;
+	buf = calloc(buf_size, sizeof(uint8_t));
+	if ( buf == NULL ) {
+		file_err_set(ret_err, FILE_ERR_FAIL_CALLOC);
+		close(fd);
+		return NULL;
+	}
+
+	{
+		ssize_t rd = read(fd, buf, (size_t)file_size);
+		if ( rd < 0 ) {
+			file_err_set(ret_err, FILE_ERR_FAIL_READ);
+			close(fd);
+			free(buf);
+			return NULL;
+		}
+		if ( rd == 0 ) {
+			file_err_set(ret_err, FILE_ERR_FILE_EMPTY);
+			close(fd);
+			free(buf);
+			return NULL;
+		}
+	}
+
+	if ( close(fd) != 0 ) {
+		/* It should be possible to handle EIO */
+		file_err_set(ret_err, FILE_ERR_FAIL_CLOSE);
+		close(fd);
+		return NULL;
+	}
+
+	if ( ret_size != NULL ) {
+		*ret_size = buf_size;
+	}
+	file_err_set(ret_err, FILE_ERR_OK);
+	return buf;
+}
+
+void
+file_save(const char *filepath, const char *str, size_t str_size,
+	  enum file_err *ret_err)
+{
+	ssize_t wrote = -1;
+	int32_t fd = open(filepath,
+			  O_WRONLY | O_CREAT | O_TRUNC,
+			  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	if ( fd < 0 ) {
+		file_err_set(ret_err, FILE_ERR_FAIL_OPEN);
+		return;
+	}
+
+	wrote = write(fd, str, str_size);
+	if ( wrote == -1 ) {
+		file_err_set(ret_err, FILE_ERR_FAIL_WRITE);
+		return;
+	}
+
+	if ( ((size_t) wrote) != str_size ) {
+		file_err_set(ret_err, FILE_ERR_FAIL_WROTE_MORE);
+		return;
+	}
+
+	if ( close(fd) != 0 ) {
+		/* It should be possible to handle EIO */
+		file_err_set(ret_err, FILE_ERR_FAIL_CLOSE);
+		close(fd);
+		return;
+	}
+
+	file_err_set(ret_err, FILE_ERR_OK);
+}
+
+void
+file_err_set(enum file_err *err, enum file_err err_)
+{
+	if ( err != NULL ) {
+		*err = err_;
+	}
+}
+
+const char *
+file_err_to_cstr(enum file_err err)
+{
+	switch ( err ) {
+	case FILE_ERR_OK: 		return "FILE_ERR_OK"; break;
+	case FILE_ERR_FAIL_OPEN:	return "FILE_ERR_FAIL_OPEN"; break;
+	case FILE_ERR_FAIL_SEEK:	return "FILE_ERR_FAIL_SEEK"; break;
+	case FILE_ERR_FAIL_READ:	return "FILE_ERR_FAIL_READ"; break;
+	case FILE_ERR_FAIL_WRITE:	return "FILE_ERR_FAIL_WRITE"; break;
+	case FILE_ERR_FAIL_CALLOC:	return "FILE_ERR_FAIL_CALLOC"; break;
+	case FILE_ERR_FAIL_CLOSE:	return "FILE_ERR_FAIL_CLOSE"; break;
+	case FILE_ERR_FILE_EMPTY:	return "FILE_ERR_FILE_EMPTY"; break;
+	case FILE_ERR_FAIL_WROTE_MORE:	return "FILE_ERR_FAIL_WROTE_MORE"; break;
+	case FILE_ERR_EMPTY:		return "FILE_ERR_EMPTY"; break;
+	}
+	return "FILE ERR INVALID";
+}
+
+#endif
+#endif