From 990cbf302eb04f80174c50040492fa7db6fbad6d Mon Sep 17 00:00:00 2001 From: Michael Giacomelli Date: Tue, 14 Dec 2010 21:33:45 +0000 Subject: [PATCH] Commit FS#11799 by Alexander Meshcheryakov. Improves the text viewer plugin to write to the disk less often, and correct several minor bugs. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28833 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/text_viewer/tv_action.c | 27 ++++- apps/plugins/text_viewer/tv_bookmark.c | 16 +-- apps/plugins/text_viewer/tv_bookmark.h | 3 +- apps/plugins/text_viewer/tv_menu.c | 2 + apps/plugins/text_viewer/tv_preferences.c | 7 ++ apps/plugins/text_viewer/tv_preferences.h | 10 ++ apps/plugins/text_viewer/tv_settings.c | 127 ++++++++++++++-------- apps/plugins/text_viewer/tv_settings.h | 1 + docs/CREDITS | 2 +- 9 files changed, 131 insertions(+), 64 deletions(-) diff --git a/apps/plugins/text_viewer/tv_action.c b/apps/plugins/text_viewer/tv_action.c index 54cec38f72..3a0d895331 100644 --- a/apps/plugins/text_viewer/tv_action.c +++ b/apps/plugins/text_viewer/tv_action.c @@ -28,6 +28,9 @@ #include "tv_settings.h" #include "tv_window.h" +bool bookmarks_changed = false; +bool scrolled = false; + bool tv_init_action(unsigned char **buf, size_t *size) { /* initialize bookmarks and window modules */ @@ -36,10 +39,6 @@ bool tv_init_action(unsigned char **buf, size_t *size) static void tv_finalize_action(void) { - /* save preference and bookmarks */ - if (!tv_save_settings()) - rb->splash(HZ, "Can't save preferences and bookmarks"); - /* finalize bookmark modules */ tv_finalize_bookmark(); @@ -50,8 +49,19 @@ static void tv_finalize_action(void) void tv_exit(void) { /* save preference and bookmarks */ - if (!tv_save_settings()) - rb->splash(HZ, "Can't save preferences and bookmarks"); + DEBUGF("preferences_changed=%d\tbookmarks_changed=%d\tscrolled=%d\n",preferences_changed,bookmarks_changed,scrolled); + if ( preferences_changed || bookmarks_changed +#ifndef HAVE_DISK_STORAGE + || scrolled +#endif + ) + { + DEBUGF("Saving settings\n"); + if (!tv_save_settings()) + rb->splash(HZ, "Can't save preferences and bookmarks"); + } + else + DEBUGF("Skip saving settings\n"); /* finalize modules */ tv_finalize_action(); @@ -95,6 +105,7 @@ void tv_scroll_up(unsigned mode) #endif } tv_move_screen(offset_page, offset_line, SEEK_CUR); + scrolled = true; } void tv_scroll_down(unsigned mode) @@ -111,6 +122,7 @@ void tv_scroll_down(unsigned mode) #endif } tv_move_screen(offset_page, offset_line, SEEK_CUR); + scrolled = true; } void tv_scroll_left(unsigned mode) @@ -130,6 +142,7 @@ void tv_scroll_left(unsigned mode) offset_window--; } tv_move_window(offset_window, offset_column); + scrolled = true; } void tv_scroll_right(unsigned mode) @@ -149,6 +162,7 @@ void tv_scroll_right(unsigned mode) offset_window++; } tv_move_window(offset_window, offset_column); + scrolled = true; } void tv_top(void) @@ -186,4 +200,5 @@ unsigned tv_menu(void) void tv_add_or_remove_bookmark(void) { tv_toggle_bookmark(); + bookmarks_changed = true; } diff --git a/apps/plugins/text_viewer/tv_bookmark.c b/apps/plugins/text_viewer/tv_bookmark.c index 815e7a1f91..5f77d2a92c 100644 --- a/apps/plugins/text_viewer/tv_bookmark.c +++ b/apps/plugins/text_viewer/tv_bookmark.c @@ -32,7 +32,6 @@ enum { TV_BOOKMARK_USER = 2, }; -#define SERIALIZE_BOOKMARK_SIZE 8 struct tv_bookmark_info { struct tv_screen_pos pos; @@ -287,11 +286,8 @@ bool tv_deserialize_bookmarks(int fd) return res; } -static bool tv_write_bookmark_info(int fd, const struct tv_bookmark_info *b) +static void tv_write_bookmark_info(unsigned char *p, const struct tv_bookmark_info *b) { - unsigned char buf[SERIALIZE_BOOKMARK_SIZE]; - unsigned char *p = buf; - *p++ = b->pos.file_pos >> 24; *p++ = b->pos.file_pos >> 16; *p++ = b->pos.file_pos >> 8; @@ -302,21 +298,17 @@ static bool tv_write_bookmark_info(int fd, const struct tv_bookmark_info *b) *p++ = b->pos.line; *p = b->flag; - - return (rb->write(fd, buf, SERIALIZE_BOOKMARK_SIZE) >= 0); } -int tv_serialize_bookmarks(int fd) +int tv_serialize_bookmarks(unsigned char *buf) { int i; - if (rb->write(fd, &bookmark_count, 1) < 0) - return 0; + buf[0] = bookmark_count; for (i = 0; i < bookmark_count; i++) { - if (!tv_write_bookmark_info(fd, &bookmarks[i])) - break; + tv_write_bookmark_info(buf + i * SERIALIZE_BOOKMARK_SIZE + 1, &bookmarks[i]); } return i * SERIALIZE_BOOKMARK_SIZE + 1; } diff --git a/apps/plugins/text_viewer/tv_bookmark.h b/apps/plugins/text_viewer/tv_bookmark.h index b0b91077d4..85b52b2c4f 100644 --- a/apps/plugins/text_viewer/tv_bookmark.h +++ b/apps/plugins/text_viewer/tv_bookmark.h @@ -29,6 +29,7 @@ /* Maximum amount of register possible bookmarks */ #define TV_MAX_BOOKMARKS 16 +#define SERIALIZE_BOOKMARK_SIZE 8 /* * initialize the bookmark module @@ -83,7 +84,7 @@ void tv_create_system_bookmark(void); * Return * the size of the result */ -int tv_serialize_bookmarks(int fd); +int tv_serialize_bookmarks(unsigned char *buf); /* * deserialize the bookmark array diff --git a/apps/plugins/text_viewer/tv_menu.c b/apps/plugins/text_viewer/tv_menu.c index 5e79fd469a..9be8312732 100644 --- a/apps/plugins/text_viewer/tv_menu.c +++ b/apps/plugins/text_viewer/tv_menu.c @@ -329,6 +329,8 @@ unsigned tv_display_menu(void) case 1: /* change settings */ tv_copy_preferences(&new_prefs); result = tv_options_menu(); + if (tv_compare_preferences(&new_prefs)) + preferences_changed = true; if (!tv_set_preferences(&new_prefs)) result = TV_MENU_RESULT_ERROR; break; diff --git a/apps/plugins/text_viewer/tv_preferences.c b/apps/plugins/text_viewer/tv_preferences.c index 5e6677ea58..6d5c1127fc 100644 --- a/apps/plugins/text_viewer/tv_preferences.c +++ b/apps/plugins/text_viewer/tv_preferences.c @@ -28,6 +28,8 @@ static struct tv_preferences prefs; /* read-only preferences pointer, for access by other files */ const struct tv_preferences * const preferences = &prefs; +bool preferences_changed = false; + static int listner_count = 0; #define TV_MAX_LISTNERS 5 @@ -91,6 +93,11 @@ void tv_copy_preferences(struct tv_preferences *copy_prefs) rb->memcpy(copy_prefs, preferences, sizeof(struct tv_preferences)); } +bool tv_compare_preferences(struct tv_preferences *copy_prefs) +{ + return rb->memcmp(copy_prefs, preferences, sizeof(struct tv_preferences)) != 0; +} + void tv_set_default_preferences(struct tv_preferences *p) { p->word_mode = WM_WRAP; diff --git a/apps/plugins/text_viewer/tv_preferences.h b/apps/plugins/text_viewer/tv_preferences.h index bc871a7255..bb448b0f4b 100644 --- a/apps/plugins/text_viewer/tv_preferences.h +++ b/apps/plugins/text_viewer/tv_preferences.h @@ -104,6 +104,7 @@ struct tv_preferences { * global pointer to the preferences (read-only) */ extern const struct tv_preferences * const preferences; +extern bool preferences_changed; /* * change the preferences @@ -125,6 +126,15 @@ bool tv_set_preferences(const struct tv_preferences *new_prefs); */ void tv_copy_preferences(struct tv_preferences *copy_prefs); +/* + * compare the preferences structs (binary) + * + * return + * true differs + * false identical + */ +bool tv_compare_preferences(struct tv_preferences *copy_prefs); + /* * set the default settings * diff --git a/apps/plugins/text_viewer/tv_settings.c b/apps/plugins/text_viewer/tv_settings.c index 3004ac3d60..20e8212147 100644 --- a/apps/plugins/text_viewer/tv_settings.c +++ b/apps/plugins/text_viewer/tv_settings.c @@ -120,6 +120,10 @@ #define TV_SETTINGS_FIRST_VERSION 0x32 #define TV_PREFERENCES_SIZE (28 + MAX_PATH) +#define TV_MAX_FILE_RECORD_SIZE (MAX_PATH+2 + TV_PREFERENCES_SIZE + TV_MAX_BOOKMARKS*SERIALIZE_BOOKMARK_SIZE+1) + +static off_t stored_preferences_offset = 0; +static int stored_preferences_size = 0; /* ---------------------------------------------------------------------------- * read/write the preferences @@ -220,9 +224,8 @@ static bool tv_read_preferences(int pfd, int version, struct tv_preferences *pre return true; } -static bool tv_write_preferences(int pfd, const struct tv_preferences *prefs) +static void tv_serialize_preferences(unsigned char *buf, const struct tv_preferences *prefs) { - unsigned char buf[TV_PREFERENCES_SIZE]; unsigned char *p = buf; rb->memset(buf, 0, TV_PREFERENCES_SIZE); @@ -248,6 +251,13 @@ static bool tv_write_preferences(int pfd, const struct tv_preferences *prefs) #ifdef HAVE_LCD_BITMAP rb->strlcpy(buf + 28, prefs->font_name, MAX_PATH); #endif +} + +static bool tv_write_preferences(int pfd, const struct tv_preferences *prefs) +{ + unsigned char buf[TV_PREFERENCES_SIZE]; + + tv_serialize_preferences(buf, prefs); return (rb->write(pfd, buf, TV_PREFERENCES_SIZE) >= 0); } @@ -427,6 +437,7 @@ bool tv_load_settings(const unsigned char *file_name) int version; unsigned int size; struct tv_preferences prefs; + off_t current_pref_offset; if (!rb->file_exists(TV_SETTINGS_FILE)) tv_convert_settings_file(); @@ -438,6 +449,8 @@ bool tv_load_settings(const unsigned char *file_name) { version = buf[TV_SETTINGS_HEADER_SIZE - 1] - TV_SETTINGS_FIRST_VERSION; fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE+1]; + + current_pref_offset = rb->lseek(fd, 0, SEEK_CUR); for (i = 0; i < fcount; i++) { @@ -448,10 +461,15 @@ bool tv_load_settings(const unsigned char *file_name) { if (tv_read_preferences(fd, version, &prefs)) res = tv_deserialize_bookmarks(fd); + + if (res) { + stored_preferences_offset = current_pref_offset; + stored_preferences_size = size; + } break; } - rb->lseek(fd, size, SEEK_CUR); + current_pref_offset = rb->lseek(fd, size, SEEK_CUR); } } rb->close(fd); @@ -473,38 +491,74 @@ bool tv_load_settings(const unsigned char *file_name) return tv_set_preferences(&prefs); } -static bool tv_copy_settings(int sfd, int dfd, int size) -{ - unsigned char buf[MAX_PATH]; - int i = size / MAX_PATH; - - size %= MAX_PATH; - - while (i--) - { - if ((rb->read(sfd, buf, MAX_PATH) < 0) || (rb->write(dfd, buf, MAX_PATH) < 0)) - return false; - } - - return ((rb->read(sfd, buf, size) >= 0) && (rb->write(dfd, buf, size) >= 0)); -} - bool tv_save_settings(void) { - unsigned char buf[MAX_PATH+2]; + unsigned char buf[TV_MAX_FILE_RECORD_SIZE]; + unsigned char preferences_buf[TV_MAX_FILE_RECORD_SIZE]; unsigned int fcount = 0; + unsigned int new_fcount = 0; unsigned int i; int ofd = -1; int tfd; off_t size; + off_t preferences_buf_size; bool res = true; /* add reading page to bookmarks */ tv_create_system_bookmark(); + /* storing preferences record in memory */ + rb->memset(preferences_buf, 0, MAX_PATH); + rb->strlcpy(preferences_buf, preferences->file_name, MAX_PATH); + preferences_buf_size = MAX_PATH + 2; + + tv_serialize_preferences(preferences_buf + preferences_buf_size, preferences); + preferences_buf_size += TV_PREFERENCES_SIZE; + preferences_buf_size += tv_serialize_bookmarks(preferences_buf + preferences_buf_size); + size = preferences_buf_size - (MAX_PATH + 2); + preferences_buf[MAX_PATH + 0] = size >> 8; + preferences_buf[MAX_PATH + 1] = size; + + + /* Just overwrite preferences if possible*/ + if ( (stored_preferences_offset > 0) && (stored_preferences_size == size) ) + { + DEBUGF("Saving preferences: overwriting\n"); + if ((tfd = rb->open(TV_SETTINGS_FILE, O_WRONLY)) < 0) + return false; + rb->lseek(tfd, stored_preferences_offset, SEEK_SET); + res = (rb->write(tfd, preferences_buf, preferences_buf_size) >= 0); + rb->close(tfd); + return res; + } + + if (!rb->file_exists(TV_SETTINGS_FILE)) tv_convert_settings_file(); + + /* Try appending preferences */ + if ( (stored_preferences_offset == 0) && + ( (tfd = rb->open(TV_SETTINGS_FILE, O_RDWR)) >= 0) ) + { + DEBUGF("Saving preferences: appending\n"); + rb->lseek(tfd, 0, SEEK_END); + if (rb->write(tfd, preferences_buf, preferences_buf_size) < 0) + return false; + + rb->lseek(tfd, TV_SETTINGS_HEADER_SIZE, SEEK_SET); + rb->read(tfd, buf, 2); + fcount = (buf[0] << 8) | buf[1]; + fcount ++; + buf[0] = fcount >> 8; + buf[1] = fcount; + rb->lseek(tfd, TV_SETTINGS_HEADER_SIZE, SEEK_SET); + res = rb->write(tfd, buf, 2) >= 0; + + rb->close(tfd); + return res; + } + /* create header for the temporary file */ rb->memcpy(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1); buf[TV_SETTINGS_HEADER_SIZE - 1] = TV_SETTINGS_VERSION; @@ -539,12 +593,13 @@ bool tv_save_settings(void) rb->lseek(ofd, size, SEEK_CUR); else { - if ((rb->write(tfd, buf, MAX_PATH + 2) < 0) || - (!tv_copy_settings(ofd, tfd, size))) + if ((rb->read(ofd, buf + (MAX_PATH + 2), size) < 0) || + (rb->write(tfd, buf, size + MAX_PATH + 2) < 0)) { res = false; break; } + new_fcount++; } } } @@ -555,31 +610,15 @@ bool tv_save_settings(void) { /* save to current read file's preferences and bookmarks */ res = false; - rb->memset(buf, 0, MAX_PATH); - rb->strlcpy(buf, preferences->file_name, MAX_PATH); - if (rb->write(tfd, buf, MAX_PATH + 2) >= 0) + if (rb->write(tfd, preferences_buf, preferences_buf_size) >= 0) { - if (tv_write_preferences(tfd, preferences)) - { - size = tv_serialize_bookmarks(tfd); - if (size > 0) - { - size += TV_PREFERENCES_SIZE; - rb->lseek(tfd, -size - 2, SEEK_CUR); - buf[0] = size >> 8; - buf[1] = size; - if (rb->write(tfd, buf, 2) >= 0) - { - rb->lseek(tfd, TV_SETTINGS_HEADER_SIZE, SEEK_SET); + rb->lseek(tfd, TV_SETTINGS_HEADER_SIZE, SEEK_SET); - fcount++; - buf[0] = fcount >> 8; - buf[1] = fcount; - res = (rb->write(tfd, buf, 2) >= 0); - } - } - } + new_fcount++; + buf[0] = new_fcount >> 8; + buf[1] = new_fcount; + res = (rb->write(tfd, buf, 2) >= 0); } } rb->close(tfd); diff --git a/apps/plugins/text_viewer/tv_settings.h b/apps/plugins/text_viewer/tv_settings.h index 65b31ecd69..afcf532cd0 100644 --- a/apps/plugins/text_viewer/tv_settings.h +++ b/apps/plugins/text_viewer/tv_settings.h @@ -63,6 +63,7 @@ bool tv_load_settings(const unsigned char *file_name); /* * save the settings at each file + * supposed to be called only once at plugin exit * * return * true success diff --git a/docs/CREDITS b/docs/CREDITS index 422a228a6a..54f21cacbc 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -573,7 +573,7 @@ William Peters Li Jie Cristina Talpiga Ştefan Moisei - +Alexander Meshcheryakov The libmad team The wavpack team