summaryrefslogtreecommitdiff
path: root/src/bookmarks.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-09-23 22:11:24 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-09-23 22:11:24 +0300
commit27ebfc904b9b3eac3ef5479ed0d0ba166fac1543 (patch)
tree0a7a74bf586701645107c27a04564b41368260db /src/bookmarks.c
parent48c3553660f4c20fc3bb4fb5df95c058adf9dd87 (diff)
Bookmarks: TOML syntax; field for manual order
The bookmarks file is now saved in a TOML subset and named "bookmarks.ini". This makes it more robust and forwards compatible. Added a field for sort order, since that will be used for manual ordering.
Diffstat (limited to 'src/bookmarks.c')
-rw-r--r--src/bookmarks.c141
1 files changed, 128 insertions, 13 deletions
diff --git a/src/bookmarks.c b/src/bookmarks.c
index c27efbfe..94f4be4e 100644
--- a/src/bookmarks.c
+++ b/src/bookmarks.c
@@ -31,13 +31,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
31#include <the_Foundation/path.h> 31#include <the_Foundation/path.h>
32#include <the_Foundation/regexp.h> 32#include <the_Foundation/regexp.h>
33#include <the_Foundation/stringset.h> 33#include <the_Foundation/stringset.h>
34#include <the_Foundation/toml.h>
34 35
35void init_Bookmark(iBookmark *d) { 36void init_Bookmark(iBookmark *d) {
36 init_String(&d->url); 37 init_String(&d->url);
37 init_String(&d->title); 38 init_String(&d->title);
38 init_String(&d->tags); 39 init_String(&d->tags);
39 iZap(d->when); 40 iZap(d->when);
40 d->sourceId = 0; 41 d->parentId = 0;
42 d->order = 0;
41} 43}
42 44
43void deinit_Bookmark(iBookmark *d) { 45void deinit_Bookmark(iBookmark *d) {
@@ -83,7 +85,8 @@ static int cmpTitleAscending_Bookmark_(const iBookmark **a, const iBookmark **b)
83 85
84/*----------------------------------------------------------------------------------------------*/ 86/*----------------------------------------------------------------------------------------------*/
85 87
86static const char *fileName_Bookmarks_ = "bookmarks.txt"; 88static const char *oldFileName_Bookmarks_ = "bookmarks.txt";
89static const char *fileName_Bookmarks_ = "bookmarks.ini"; /* since v1.7 (TOML subset) */
87 90
88struct Impl_Bookmarks { 91struct Impl_Bookmarks {
89 iMutex * mtx; 92 iMutex * mtx;
@@ -123,16 +126,19 @@ void clear_Bookmarks(iBookmarks *d) {
123 unlock_Mutex(d->mtx); 126 unlock_Mutex(d->mtx);
124} 127}
125 128
129static void insertId_Bookmarks_(iBookmarks *d, iBookmark *bookmark, int id) {
130 bookmark->node.key = id;
131 insert_Hash(&d->bookmarks, &bookmark->node);
132}
133
126static void insert_Bookmarks_(iBookmarks *d, iBookmark *bookmark) { 134static void insert_Bookmarks_(iBookmarks *d, iBookmark *bookmark) {
127 lock_Mutex(d->mtx); 135 lock_Mutex(d->mtx);
128 bookmark->node.key = ++d->idEnum; 136 insertId_Bookmarks_(d, bookmark, ++d->idEnum);
129 insert_Hash(&d->bookmarks, &bookmark->node);
130 unlock_Mutex(d->mtx); 137 unlock_Mutex(d->mtx);
131} 138}
132 139
133void load_Bookmarks(iBookmarks *d, const char *dirPath) { 140static void loadOldFormat_Bookmarks(iBookmarks *d, const char *dirPath) {
134 clear_Bookmarks(d); 141 iFile *f = newCStr_File(concatPath_CStr(dirPath, oldFileName_Bookmarks_));
135 iFile *f = newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_));
136 if (open_File(f, readOnly_FileMode | text_FileMode)) { 142 if (open_File(f, readOnly_FileMode | text_FileMode)) {
137 const iRangecc src = range_Block(collect_Block(readAll_File(f))); 143 const iRangecc src = range_Block(collect_Block(readAll_File(f)));
138 iRangecc line = iNullRange; 144 iRangecc line = iNullRange;
@@ -170,6 +176,101 @@ void load_Bookmarks(iBookmarks *d, const char *dirPath) {
170 iRelease(f); 176 iRelease(f);
171} 177}
172 178
179/*----------------------------------------------------------------------------------------------*/
180
181iDeclareType(BookmarkLoader)
182
183struct Impl_BookmarkLoader {
184 iTomlParser *toml;
185 iBookmarks * bookmarks;
186 iBookmark * bm;
187};
188
189static void handleTable_BookmarkLoader_(void *context, const iString *table, iBool isStart) {
190 iBookmarkLoader *d = context;
191 if (isStart) {
192 iAssert(!d->bm);
193 d->bm = new_Bookmark();
194 const int id = toInt_String(table);
195 d->bookmarks->idEnum = iMax(d->bookmarks->idEnum, id);
196 insertId_Bookmarks_(d->bookmarks, d->bm, id);
197 }
198 else {
199 d->bm = NULL;
200 }
201}
202
203static void handleKeyValue_BookmarkLoader_(void *context, const iString *table, const iString *key,
204 const iTomlValue *tv) {
205 iBookmarkLoader *d = context;
206 iBookmark *bm = d->bm;
207 if (bm) {
208 iUnused(table); /* it's the current one */
209 if (!cmp_String(key, "url") && tv->type == string_TomlType) {
210 set_String(&bm->url, tv->value.string);
211 }
212 else if (!cmp_String(key, "title") && tv->type == string_TomlType) {
213 set_String(&bm->title, tv->value.string);
214 }
215 else if (!cmp_String(key, "tags") && tv->type == string_TomlType) {
216 set_String(&bm->tags, tv->value.string);
217 }
218 else if (!cmp_String(key, "icon") && tv->type == int64_TomlType) {
219 bm->icon = (iChar) tv->value.int64;
220 }
221 else if (!cmp_String(key, "created") && tv->type == int64_TomlType) {
222 initSeconds_Time(&bm->when, tv->value.int64);
223 }
224 else if (!cmp_String(key, "parent") && tv->type == int64_TomlType) {
225 bm->parentId = tv->value.int64;
226 }
227 else if (!cmp_String(key, "order") && tv->type == int64_TomlType) {
228 bm->order = tv->value.int64;
229 }
230 }
231}
232
233static void init_BookmarkLoader(iBookmarkLoader *d, iBookmarks *bookmarks) {
234 d->toml = new_TomlParser();
235 setHandlers_TomlParser(d->toml, handleTable_BookmarkLoader_, handleKeyValue_BookmarkLoader_, d);
236 d->bookmarks = bookmarks;
237 d->bm = NULL;
238}
239
240static void deinit_BookmarkLoader(iBookmarkLoader *d) {
241 delete_TomlParser(d->toml);
242}
243
244static void load_BookmarkLoader(iBookmarkLoader *d, iFile *file) {
245 if (!parse_TomlParser(d->toml, collect_String(readString_File(file)))) {
246 fprintf(stderr, "[Bookmarks] syntax error(s) in %s\n", cstr_String(path_File(file)));
247 }
248}
249
250iDefineTypeConstructionArgs(BookmarkLoader, (iBookmarks *b), b)
251
252/*----------------------------------------------------------------------------------------------*/
253
254void load_Bookmarks(iBookmarks *d, const char *dirPath) {
255 clear_Bookmarks(d);
256 /* Load new .ini bookmarks, if present. */
257 iFile *f = iClob(newCStr_File(concatPath_CStr(dirPath, fileName_Bookmarks_)));
258 if (!open_File(f, readOnly_FileMode | text_FileMode)) {
259 /* As a fallback, try loading the v1.6 bookmarks file. */
260 loadOldFormat_Bookmarks(d, dirPath);
261 /* Set ordering based on titles. */
262 iConstForEach(PtrArray, i, list_Bookmarks(d, cmpTitleAscending_Bookmark_, NULL, NULL)) {
263 iBookmark *bm = i.ptr;
264 bm->order = index_PtrArrayConstIterator(&i) + 1;
265 }
266 return;
267 }
268 iBookmarkLoader loader;
269 init_BookmarkLoader(&loader, d);
270 load_BookmarkLoader(&loader, f);
271 deinit_BookmarkLoader(&loader);
272}
273
173void save_Bookmarks(const iBookmarks *d, const char *dirPath) { 274void save_Bookmarks(const iBookmarks *d, const char *dirPath) {
174 lock_Mutex(d->mtx); 275 lock_Mutex(d->mtx);
175 iRegExp *remotePattern = iClob(new_RegExp("\\bremote\\b", caseSensitive_RegExpOption)); 276 iRegExp *remotePattern = iClob(new_RegExp("\\bremote\\b", caseSensitive_RegExpOption));
@@ -185,12 +286,26 @@ void save_Bookmarks(const iBookmarks *d, const char *dirPath) {
185 continue; 286 continue;
186 } 287 }
187 format_String(str, 288 format_String(str,
188 "%08x %.0lf %s\n%s\n%s\n", 289 "[%d]\n"
290 "url = \"%s\"\n"
291 "title = \"%s\"\n"
292 "tags = \"%s\"\n"
293 "icon = 0x%x\n"
294 "created = %.0f # %s\n",
295 id_Bookmark(bm),
296 cstrCollect_String(quote_String(&bm->url, iFalse)),
297 cstrCollect_String(quote_String(&bm->title, iFalse)),
298 cstrCollect_String(quote_String(&bm->tags, iFalse)),
189 bm->icon, 299 bm->icon,
190 seconds_Time(&bm->when), 300 seconds_Time(&bm->when),
191 cstr_String(&bm->url), 301 cstrCollect_String(format_Time(&bm->when, "%Y-%m-%d")));
192 cstr_String(&bm->title), 302 if (bm->parentId) {
193 cstr_String(&bm->tags)); 303 appendFormat_String(str, "parent = %d\n", bm->parentId);
304 }
305 if (bm->order) {
306 appendFormat_String(str, "order = %d\n", bm->order);
307 }
308 appendCStr_String(str, "\n");
194 writeData_File(f, cstr_String(str), size_String(str)); 309 writeData_File(f, cstr_String(str), size_String(str));
195 } 310 }
196 } 311 }
@@ -223,7 +338,7 @@ iBool remove_Bookmarks(iBookmarks *d, uint32_t id) {
223 if (hasTag_Bookmark(bm, remoteSource_BookmarkTag)) { 338 if (hasTag_Bookmark(bm, remoteSource_BookmarkTag)) {
224 iForEach(Hash, i, &d->bookmarks) { 339 iForEach(Hash, i, &d->bookmarks) {
225 iBookmark *j = (iBookmark *) i.value; 340 iBookmark *j = (iBookmark *) i.value;
226 if (j->sourceId == id_Bookmark(bm)) { 341 if (j->parentId == id_Bookmark(bm)) {
227 remove_HashIterator(&i); 342 remove_HashIterator(&i);
228 delete_Bookmark(j); 343 delete_Bookmark(j);
229 } 344 }
@@ -452,7 +567,7 @@ void requestFinished_Bookmarks(iBookmarks *d, iGmRequest *req) {
452 } 567 }
453 const uint32_t bmId = add_Bookmarks(d, absUrl, titleStr, remoteTag, 0x2913); 568 const uint32_t bmId = add_Bookmarks(d, absUrl, titleStr, remoteTag, 0x2913);
454 iBookmark *bm = get_Bookmarks(d, bmId); 569 iBookmark *bm = get_Bookmarks(d, bmId);
455 bm->sourceId = *(uint32_t *) userData_Object(req); 570 bm->parentId = *(uint32_t *) userData_Object(req);
456 delete_String(titleStr); 571 delete_String(titleStr);
457 } 572 }
458 delete_String(urlStr); 573 delete_String(urlStr);