Skip to content

Commit

Permalink
Add comment repository load & save
Browse files Browse the repository at this point in the history
  • Loading branch information
BlockoS committed Sep 8, 2024
1 parent efec9a3 commit 37b7ba1
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 66 deletions.
58 changes: 0 additions & 58 deletions comment.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,61 +194,3 @@ void comment_repository_delete(CommentRepository* repository, uint16_t first, ui
}
}
}

#if 0
// [todo] move to comment/load
// Load comments from file.
bool comment_repository_load(CommentRepository* repository, const char* filename) {
assert(filename != NULL);
assert(repository != NULL);

bool ret = false;

json_t* root;
json_error_t err;
json_t* value;
int index = 0;
root = json_load_file(filename, 0, &err);
if(!root) {
ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text);
} else {
if(!json_is_array(root)) {
ERROR_MSG("Array expected.");
} else for (index = 0, ret = true; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) {
ret = false;
if(!json_is_object(value)) {
ERROR_MSG("Expected object.");
} else {
int num;
// logical
json_t *tmp = json_object_get(value, "logical");
if(!json_validate_int(tmp, &num)) {
ERROR_MSG("Invalid or missing logical address.");
} else if((num < 0) || (num > 0xffff)) {
ERROR_MSG("Logical address out of range.");
} else {
uint16_t logical = (uint16_t)num;
// page
tmp = json_object_get(value, "page");
if(!json_validate_int(tmp, &num)) {
ERROR_MSG("Invalid or missing page.");
} else {
// text (same format as section/label description)
char* text = json_load_description(value, "text");
if(text == NULL) {
ERROR_MSG("Invalid or missing text.");
} else if((num < 0) || (num > 0xff)) {
ERROR_MSG("Page value out of range.");
} else if(comment_repository_add(repository, logical, (uint8_t)num, text)) {
ret = true;
}
free(text);
}
}
}
}
json_decref(root);
}
return ret;
}
#endif
9 changes: 8 additions & 1 deletion comment.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,17 @@ bool comment_repository_get(CommentRepository* repository, int index, Comment *o
void comment_repository_delete(CommentRepository* repository, uint16_t first, uint16_t end, uint8_t page);

/// Load comments from file.
/// \param [in, out] repository Comment repository.
/// \param [in] filename Input filename.
/// \param [out] repository Comment repository.
/// \return true if the comments contained in the file was succesfully added to the repository.
/// \return false if an error occured.
bool comment_repository_load(CommentRepository* repository, const char* filename);

/// Save comments to file.
/// \param [in] repository Comment repository.
/// \param [in] filename Output filename.
/// \return true if the comments were succesfully saved.
/// \return false if an error occured.
bool comment_repository_save(CommentRepository* repository, const char* filename);

#endif // ETRIPATOR_COMMENT_H
94 changes: 94 additions & 0 deletions comment/load.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸
¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯
__/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__
\_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_
_> ___/ ¯>__> <<__// __ _/ |> ></ _/> </ ¯ \\__> <<__// /\ // __ _/
_> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ </:. \> \_
|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::|
|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯|
|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _|
\|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/
¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸
¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯
This file is part of Etripator,
copyright (c) 2009--2023 Vincent Cruz.
Etripator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Etripator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Etripator. If not, see <http://www.gnu.org/licenses/>.
¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸
¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯
*/
#include <jansson.h>
#include "../message.h"
#include "../jsonhelpers.h"
#include "../comment.h"

// Load comments from file.
bool comment_repository_load(CommentRepository* repository, const char* filename) {
assert(filename != NULL);
assert(repository != NULL);

bool ret = false;

json_t* root;
json_error_t err;
json_t* value;
int index = 0;
root = json_load_file(filename, 0, &err);
if(!root) {
ERROR_MSG("Failed to parse %s:%d:%d: %s", filename, err.line, err.column, err.text);
} else {
if(!json_is_array(root)) {
ERROR_MSG("Array expected.");
} else for (index = 0, ret = true; ret && (index < json_array_size(root)) && (value = json_array_get(root, index)); index++) {
ret = false;
if(!json_is_object(value)) {
ERROR_MSG("Expected object.");
} else {
int num;
// logical
json_t *tmp = json_object_get(value, "logical");
if(!json_validate_int(tmp, &num)) {
ERROR_MSG("Invalid or missing logical address.");
} else if((num < 0) || (num > 0xffff)) {
ERROR_MSG("Logical address out of range.");
} else {
uint16_t logical = (uint16_t)num;
// page
tmp = json_object_get(value, "page");
if(!json_validate_int(tmp, &num)) {
ERROR_MSG("Invalid or missing page.");
} else {
// text (same format as section/label description)
char* text = json_load_description (value, "text");
if(text == NULL) {
ERROR_MSG("Invalid or missing text.");
} else if((num < 0) || (num > 0xFF)) {
ERROR_MSG("Page value out of range.");
} else if(comment_repository_add(repository, logical, (uint8_t)num, text)) {
ret = true;
}
free(text);
}
}
}
}
json_decref(root);
}
return ret;
}
91 changes: 91 additions & 0 deletions comment/save.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸
¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯
__/¯\____ ___/\__ _/\__ _/\_ _/\__ _/\___ ___/\__ __/\_ _/\__
\_ ____/_> ____ \_/ _ \_ \ < /_ \_/ _>> ____ \_ > \_/ _ \_
_> ___/ ¯>__> <<__// __ _/ |> ></ _/> </ ¯ \\__> <<__// /\ // __ _/
_> \7 <__/:. \__/:. \> \_/ L/ _____/. 7> .\_/:. \__/ <_/ </:. \> \_
|:::::::::::::::::::::::/:::::::::::::>::::::::/::::::::::::::::::::::::/:::::|
|¯¯\::::/\:/¯\::::/¯¯¯¯<::::/\::/¯¯\:/¯¯¯¯¯¯\::\::/¯¯\::::/¯¯\::::/¯¯¯¯<::::/¯|
|__ |¯¯| T _ |¯¯¯| ___ |¯¯| |¯| _ T ______ |¯¯¯¯| _ |¯¯¯| _ |¯¯¯| ___ |¯¯| _|
\|__|/\|/ \|___|/ \|__|/\|_|/ \|/ \| |/ \|___|/ \|___|/dNo\|__|/
¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸
¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯
This file is part of Etripator,
copyright (c) 2009--2023 Vincent Cruz.
Etripator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Etripator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Etripator. If not, see <http://www.gnu.org/licenses/>.
¬°¤*,¸¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸
¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯¬°¤*,¸_¸,*¤°¬°¤*,¸,*¤°¬¯
*/
#include <errno.h>
#include <string.h>

#include "../message.h"
#include "../jsonhelpers.h"
#include "../comment.h"

// Save comments to file.
bool comment_repository_save(CommentRepository* repository, const char* filename) {
assert(filename != NULL);
assert(repository != NULL);

bool ret = false;

int i, count = comment_repository_size(repository);
FILE *stream = fopen(filename, "wb");
if(stream == NULL) {
ERROR_MSG("Failed to open %s: %s", filename, strerror(errno));
} else {
fprintf(stream, "[\n");
for(i=0; i<count; i++) {
Comment entry;
if(comment_repository_get(repository, i, &entry)) {
fprintf(stream, "\t{ \"logical\":\"%04x\", \"page\":\"%02x\", \"text\": ", entry.logical, entry.page);

bool multiline = false;
if(strchr(entry.text, '\n') != NULL) {
multiline = true;
}

if(multiline) {
fprintf(stream, "[\n");
for(char *ptr=entry.text, *next=NULL; ptr!=NULL; ptr=next) {
next = strchr(ptr, '\n');
if(next != NULL) {
fprintf(stream, "\t\"");
fwrite(ptr, 1, next-ptr, stream);
fprintf(stream, "\",\n");
} else {
fprintf(stream, "\"%s\"\n", ptr);
}
}
fprintf(stream, "]\n");
} else {
fprintf(stream, "\"%s\"", entry.text);
}

fprintf(stream,"}%c\n", (i<(count-1)) ? ',' : ' ');
}
}
fprintf(stream, "]\n");
fclose(stream);
ret = true;
}
return ret;
}
5 changes: 4 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,11 @@ add_unit_test(
SOURCES
comment.c
${PROJECT_SOURCE_DIR}/comment.c
${PROJECT_SOURCE_DIR}/comment/load.c
${PROJECT_SOURCE_DIR}/comment/save.c
${PROJECT_SOURCE_DIR}/message.c
${PROJECT_SOURCE_DIR}/jsonhelpers.c
${PROJECT_SOURCE_DIR}/message/console.c
LIBRARIES cwalk
LIBRARIES cwalk jansson
INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}
)
41 changes: 35 additions & 6 deletions test/comment.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,18 @@ MunitResult comment_add_test(const MunitParameter params[] __attribute__((unused
munit_assert_true(comment_repository_add(repository, 0x0001, 0x01, "comment #2"));

munit_assert_true(comment_repository_find(repository, 0x0001, 0x01, &comment));
munit_assert_int(comment.logical, ==, 0x0001);
munit_assert_int(comment.page, ==, 0x01);
munit_assert_uint16(comment.logical, ==, 0x0001);
munit_assert_uint8(comment.page, ==, 0x01);
munit_assert_string_equal(comment.text, "comment #2");

munit_assert_true(comment_repository_find(repository, 0x0001, 0x00, &comment));
munit_assert_int(comment.logical, ==, 0x0001);
munit_assert_int(comment.page, ==, 0x00);
munit_assert_uint16(comment.logical, ==, 0x0001);
munit_assert_uint8(comment.page, ==, 0x00);
munit_assert_string_equal(comment.text, "comment #1");

munit_assert_true(comment_repository_find(repository, 0x0003, 0x00, &comment));
munit_assert_int(comment.logical, ==, 0x0003);
munit_assert_int(comment.page, ==, 0x00);
munit_assert_uint16(comment.logical, ==, 0x0003);
munit_assert_uint8(comment.page, ==, 0x00);
munit_assert_string_equal(comment.text, "comment #3");

munit_assert_int(comment_repository_size(repository), ==, 4);
Expand Down Expand Up @@ -104,9 +104,38 @@ MunitResult comment_delete_test(const MunitParameter params[] __attribute__((unu
return MUNIT_OK;
}

MunitResult comment_load_test(const MunitParameter params[] __attribute__((unused)), void* fixture __attribute__((unused))) {
Comment comment = {0};
CommentRepository *repository = comment_repository_create();

munit_assert_false(comment_repository_load(repository, "/not_here/comment.json"));
munit_assert_int(comment_repository_size(repository), ==, 0);

munit_assert_false(comment_repository_load(repository, "data/comment_1.json"));
munit_assert_int(comment_repository_size(repository), ==, 0);

munit_assert_true(comment_repository_load(repository, "data/comment_0.json"));
munit_assert_int(comment_repository_size(repository), ==, 2);

munit_assert_true(comment_repository_find(repository, 0xC105U, 3, &comment));
munit_assert_uint16(comment.logical, ==, 0xC105U);
munit_assert_uint8(comment.page, ==, 3);
munit_assert_string_equal(comment.text, "line 0\nline 1\nline 2");

munit_assert_true(comment_repository_find(repository, 0xEABCU, 0, &comment));
munit_assert_uint16(comment.logical, ==, 0xEABCU);
munit_assert_uint8(comment.page, ==, 0);
munit_assert_string_equal(comment.text, "single line comment");

comment_repository_destroy(repository);

return MUNIT_OK;
}

static MunitTest comment_tests[] = {
{ "/add", comment_add_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ "/delete", comment_delete_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ "/load", comment_load_test, setup, tear_down, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};

Expand Down
9 changes: 9 additions & 0 deletions test/data/comment_0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
{ "logical": "EABC", "page": "0", "text": "single line comment" },
{ "logical": "C105", "page": "3", "text": [
"line 0",
"line 1",
"line 2"
]
}
]
4 changes: 4 additions & 0 deletions test/data/comment_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
{ "logical": "CAFE", "page": "0a", "text": "hello!" },
{ "logical": "F00D", "page": "40", "text": { "foo": "bar" } }
]

0 comments on commit 37b7ba1

Please sign in to comment.