Browse Source

faux: file: Works

Serj Kalichev 3 years ago
parent
commit
cf5cf8f2d9
7 changed files with 167 additions and 79 deletions
  1. 6 0
      faux/file.h
  2. 105 16
      faux/file/file.c
  3. 1 0
      faux/file/private.h
  4. 1 1
      faux/ini.h
  5. 19 39
      faux/ini/ini.c
  6. 1 0
      faux/str.h
  7. 34 23
      faux/str/str.c

+ 6 - 0
faux/file.h

@@ -5,6 +5,11 @@
 #ifndef _faux_file_h
 #define _faux_file_h
 
+// For macros definition
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
 #include "faux/faux.h"
 
 typedef struct faux_file_s faux_file_t;
@@ -15,6 +20,7 @@ faux_file_t *faux_file_fdopen(int fd);
 faux_file_t *faux_file_open(const char *pathname, int flags, mode_t mode);
 int faux_file_close(faux_file_t *file);
 int faux_file_fileno(faux_file_t *file);
+bool_t faux_file_eof(const faux_file_t *file);
 char *faux_file_getline(faux_file_t *file);
 
 C_DECL_END

+ 105 - 16
faux/file/file.c

@@ -22,6 +22,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
 
 #include "private.h"
 #include "faux/faux.h"
@@ -60,6 +61,7 @@ faux_file_t *faux_file_fdopen(int fd) {
 		return NULL;
 	}
 	f->len = 0;
+	f->eof = BOOL_FALSE;
 
 	return f;
 }
@@ -107,46 +109,133 @@ int faux_file_fileno(faux_file_t *f) {
 }
 
 
+bool_t faux_file_eof(const faux_file_t *f) {
+
+	assert(f);
+	if (!f)
+		return BOOL_FALSE;
+
+	return f->eof;
+}
+
+
+static char *faux_file_takeaway(faux_file_t *f,
+	size_t bytes_get, size_t bytes_drop) {
+
+	size_t remove_len = 0;
+	char *line = NULL;
+
+	assert(f);
+	if (!f)
+		return NULL;
+
+	remove_len = bytes_get + bytes_drop;
+	// Try to take away more bytes than buffer contain
+	if ((remove_len > f->len) || (0 == remove_len))
+		return NULL;
+
+	line = faux_zmalloc(bytes_get + 1); // One extra byte for '\0'
+	assert(line);
+	if (!line)
+		return NULL; // Memory problems
+	memcpy(line, f->buf, bytes_get);
+
+	// Remove block from the internal buffer
+	f->len = f->len - remove_len;
+	memmove(f->buf, f->buf + remove_len, f->len);
+
+	return line;
+}
+
+
+static char *faux_file_takeaway_rest(faux_file_t *f) {
+
+	assert(f);
+	if (!f)
+		return NULL;
+
+	return faux_file_takeaway(f, f->len, 0);
+}
+
+
 static char *faux_file_takeaway_line(faux_file_t *f) {
 
 	char *find = NULL;
 	const char *eol = "\n\r";
 	size_t line_len = 0;
-	char *line = NULL;
 
 	assert(f);
 	if (!f)
 		return NULL;
 
+	// Search buffer for EOL
 	find = faux_str_charsn(f->buf, eol, f->len);
 	if (!find)
 		return NULL; // End of line is not found
 	line_len = find - f->buf;
-	line = faux_str_dupn(f->buf, line_len);
-	assert(line);
-	if (!line)
-		return NULL; // Memory problems
 
-	// Remove line from the internal buffer
-	// Remove EOL char also. So additional '1' is used
-	f->len = f->len - line_len - 1;
-	memmove(f->buf, find + 1, f->len);
+	// Takeaway line without trailing EOL. So drop one last byte
+	return faux_file_takeaway(f, line_len, 1);
+}
 
-	return line;
+
+static int faux_file_enlarge_buffer(faux_file_t *f) {
+
+	size_t new_size = 0;
+	char *new_buf = NULL;
+
+	assert(f);
+	if (!f)
+		return -1;
+
+	new_size = f->buf_size + FAUX_FILE_CHUNK_SIZE;
+	new_buf = realloc(f->buf, new_size);
+	assert(new_buf);
+	if (!new_buf)
+		return -1;
+	// NULLify newly allocated memory
+	faux_bzero(new_buf + f->buf_size, new_size - f->buf_size);
+	f->buf = new_buf;
+	f->buf_size = new_size;
+
+	return 0;
 }
 
+
 char *faux_file_getline(faux_file_t *f) {
 
-	char *find = NULL;
+	ssize_t bytes_readed = 0;
 
 	assert(f);
 	if (!f)
 		return NULL;
 
-	// May be buffer already contain line
-	find = faux_file_takeaway_line(f);
-	if (find)
-		return find;
+	do {
+		char *find = NULL;
+
+		// May be buffer already contain line
+		find = faux_file_takeaway_line(f);
+		if (find)
+			return find;
+
+		if (f->buf_size == f->len) { // Buffer is full but doesn't contain line
+			if (faux_file_enlarge_buffer(f) < 0) // Make buffer larger
+				return NULL; // Memory problem
+		}
+
+		// Read new data from file
+		do {
+			bytes_readed = read(f->fd, f->buf + f->len, f->buf_size - f->len);
+			if ((bytes_readed < 0) && (errno != EINTR))
+				return NULL; // Some file error
+		} while (bytes_readed < 0); // i.e. EINTR
+		f->len += bytes_readed;
+
+	} while (bytes_readed > 0);
+
+	// EOF (here bytes_readed == 0)
+	f->eof = BOOL_TRUE;
 
-	return NULL;
+	// The last line can be without eol. Consider it as a line too
+	return faux_file_takeaway_rest(f);
 }

+ 1 - 0
faux/file/private.h

@@ -9,4 +9,5 @@ struct faux_file_s {
 	char *buf; // Data buffer
 	size_t buf_size; // Current buffer size
 	size_t len; // Current data length
+	bool_t eof; // EOF flag
 };

+ 1 - 1
faux/ini.h

@@ -27,7 +27,7 @@ void faux_ini_unset(faux_ini_t *ini, const char *name);
 
 const faux_pair_t *faux_ini_find_pair(const faux_ini_t *ini, const char *name);
 const char *faux_ini_find(const faux_ini_t *ini, const char *name);
-faux_ini_node_t *faux_ini_init_iter(const faux_ini_t *ini);
+faux_ini_node_t *faux_ini_iter(const faux_ini_t *ini);
 const faux_pair_t *faux_ini_each(faux_ini_node_t **iter);
 
 int faux_ini_parse_str(faux_ini_t *ini, const char *str);

+ 19 - 39
faux/ini/ini.c

@@ -11,6 +11,7 @@
 #include "private.h"
 #include "faux/faux.h"
 #include "faux/str.h"
+#include "faux/file.h"
 #include "faux/ini.h"
 
 
@@ -188,7 +189,7 @@ const char *faux_ini_find(const faux_ini_t *ini, const char *name) {
  * @return Initialized iterator.
  * @sa faux_ini_each()
  */
-faux_ini_node_t *faux_ini_init_iter(const faux_ini_t *ini) {
+faux_ini_node_t *faux_ini_iter(const faux_ini_t *ini) {
 
 	assert(ini);
 	if (!ini)
@@ -200,7 +201,7 @@ faux_ini_node_t *faux_ini_init_iter(const faux_ini_t *ini) {
 
 /** @brief Iterate entire INI object for pairs 'name/value'.
  *
- * Before iteration the iterator must be initialized by faux_ini_init_iter()
+ * Before iteration the iterator must be initialized by faux_ini_iter()
  * function. Doesn't use faux_ini_each() with uninitialized iterator.
  *
  * On each call function returns pair 'name/value' and modify iterator.
@@ -208,7 +209,7 @@ faux_ini_node_t *faux_ini_init_iter(const faux_ini_t *ini) {
  *
  * @param [in,out] iter Iterator.
  * @return Pair 'name/value'.
- * @sa faux_ini_init_iter()
+ * @sa faux_ini_iter()
  */
 const faux_pair_t *faux_ini_each(faux_ini_node_t **iter) {
 
@@ -378,12 +379,9 @@ int faux_ini_parse_str(faux_ini_t *ini, const char *string) {
  */
 int faux_ini_parse_file(faux_ini_t *ini, const char *fn) {
 
-	int ret = -1; // Pessimistic retval
-	FILE *fd = NULL;
+	bool_t eof = BOOL_FALSE;
+	faux_file_t *f = NULL;
 	char *buf = NULL;
-	unsigned int bytes_readed = 0;
-	const int chunk_size = 128;
-	int size = chunk_size; // Buffer size
 
 	assert(ini);
 	assert(fn);
@@ -391,42 +389,24 @@ int faux_ini_parse_file(faux_ini_t *ini, const char *fn) {
 		return -1;
 	if (!fn || '\0' == *fn)
 		return -1;
-	fd = fopen(fn, "r");
-	if (!fd)
-		return -1;
 
-	buf = faux_zmalloc(size);
-	assert(buf);
-	if (!buf)
-		goto error;
-	while (fgets(buf + bytes_readed, size - bytes_readed, fd)) {
-
-		// Not enough space in buffer. Make it larger.
-		if (feof(fd) == 0 && !strchr(buf + bytes_readed, '\n') &&
-			!strchr(buf + bytes_readed, '\r')) {
-			char *tmp = NULL;
-			bytes_readed =
-				size - 1; // fgets() put '\0' to last byte
-			size += chunk_size;
-			tmp = realloc(buf, size);
-			if (!tmp) // Memory problems
-				goto error;
-			buf = tmp;
-			continue; // Read the rest of line
-		}
+	f = faux_file_open(fn, O_RDONLY, 0);
+	if (!f)
+		return -1;
 
+	while ((buf = faux_file_getline(f))) {
 		// Don't analyze retval because it's not obvious what
 		// to do on error. May be next string will be ok.
 		faux_ini_parse_str(ini, buf);
-		bytes_readed = 0;
+		faux_str_free(buf);
 	}
 
-	ret = 0;
-error:
-	faux_free(buf);
-	fclose(fd);
+	eof = faux_file_eof(f);
+	faux_file_close(f);
+	if (!eof) // File reading was interrupted before EOF
+		return -1;
 
-	return ret;
+	return 0;
 }
 
 
@@ -456,7 +436,7 @@ int faux_ini_write_file(const faux_ini_t *ini, const char *fn) {
 	if (!fd)
 		return -1;
 
-	iter = faux_ini_init_iter(ini);
+	iter = faux_ini_iter(ini);
 	while ((pair = faux_ini_each(&iter))) {
 		char *quote = NULL;
 		const char *name = faux_pair_name(pair);
@@ -464,12 +444,12 @@ int faux_ini_write_file(const faux_ini_t *ini, const char *fn) {
 
 		// Print name field
 		// Word with spaces needs quotes
-		quote = strchr(name, ' ') ? "" : "\"";
+		quote = strchr(name, ' ') ? "\"" : "";
 		fprintf(fd, "%s%s%s=", quote, name, quote);
 
 		// Print value field
 		// Word with spaces needs quotes
-		quote = strchr(value, ' ') ? "" : "\"";
+		quote = strchr(value, ' ') ? "\"" : "";
 		fprintf(fd, "%s%s%s\n", quote, value, quote);
 	}
 

+ 1 - 0
faux/str.h

@@ -31,6 +31,7 @@ int faux_str_casecmpn(const char *str1, const char *str2, size_t n);
 int faux_str_casecmp(const char *str1, const char *str2);
 char *faux_str_casestr(const char *haystack, const char *needle);
 char *faux_str_charsn(const char *str, const char *chars_to_search, size_t n);
+char *faux_str_chars(const char *str, const char *chars_to_search);
 
 
 //const char *faux_str_suffix(const char *string);

+ 34 - 23
faux/str/str.c

@@ -401,20 +401,20 @@ char *faux_str_c_esc(const char *src) {
 
 /** @brief Search the n-th chars of string for one of the specified chars.
  *
- *	The function search for any of specified characters within string.
- *	The search is limited to first n characters of the string. If
- *	terminating '\0' is before n-th character then search will stop on
- *	it.
- *
- *	@param [in] str String (or memory block) to search in.
- *	@param [in] chars_to_string Chars enumeration to search for.
- *	@return Pointer to the first occurence of one of specified chars.
- *		NULL on error.
+ * The function search for any of specified characters within string.
+ * The search is limited to first n characters of the string. If
+ * terminating '\0' is before n-th character then search will stop on
+ * it. Can be used with raw memory block.
+ *
+ * @param [in] str String (or memory block) to search in.
+ * @param [in] chars_to_string Chars enumeration to search for.
+ * @param [in] n Maximum number of bytes to search within.
+ * @return Pointer to the first occurence of one of specified chars.
+ * NULL on error.
  */
 char *faux_str_charsn(const char *str, const char *chars_to_search, size_t n) {
 
-	const char *current_char = NULL;
-	char *nullp = NULL;
+	const char *current_char = str;
 	size_t len = n;
 
 	assert(str);
@@ -422,24 +422,35 @@ char *faux_str_charsn(const char *str, const char *chars_to_search, size_t n) {
 	if (!str || !chars_to_search)
 		return NULL;
 
-	// May be '\0' is before n-th char
-	nullp = memchr(str, '\0', n);
-	if (nullp)
-		len = nullp - str;
-
-	current_char = chars_to_search;
-	while (*current_char != '\0') {
-		void *find = NULL;
-
-		find = memchr(str, *current_char, len);
-		if (find)
-			return (char *)find;
+	while ((*current_char != '\0') && (len > 0)) {
+		if (strchr(chars_to_search, *current_char))
+			return (char *)current_char;
 		current_char++;
+		len--;
 	}
 
 	return NULL;
 }
 
+
+/** @brief Search string for one of the specified chars.
+ *
+ * The function search for any of specified characters within string.
+ *
+ * @param [in] str String to search in.
+ * @param [in] chars_to_string Chars enumeration to search for.
+ * @return Pointer to the first occurence of one of specified chars.
+ * NULL on error.
+ */
+char *faux_str_chars(const char *str, const char *chars_to_search) {
+
+	assert(str);
+	if (!str)
+		return NULL;
+
+	return faux_str_charsn(str, chars_to_search, strlen(str));
+}
+
 /* TODO: If it nedeed?
 const char *faux_str_nextword(const char *string,
 	size_t *len, size_t *offset, size_t *quoted)