bookmarks.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // SPDX-FileCopyrightText: 2019-2022 Badwolf Authors <https://hacktivis.me/projects/badwolf>
  2. // SPDX-License-Identifier: MPL-2.0
  3. #include "bookmarks.h"
  4. #include "badwolf.h"
  5. #include "config.h"
  6. #include <glib/gi18n.h> /* _() and other internationalization/localization helpers */
  7. #include <glib/gprintf.h> /* g_fprintf() */
  8. #include <gtk/gtk.h>
  9. #include <libxml/xinclude.h>
  10. #include <libxml/xpath.h>
  11. #include <unistd.h> /* access() */
  12. static gboolean
  13. location_completion_matches(GtkEntryCompletion *completion,
  14. const gchar *key,
  15. GtkTreeIter *iter,
  16. gpointer UNUSED(user_data))
  17. {
  18. gchar *buffer;
  19. gchar *pattern;
  20. gboolean result;
  21. pattern = g_strdup_printf("*%s*", key);
  22. gtk_tree_model_get(gtk_entry_completion_get_model(completion), iter, 0, &buffer, -1);
  23. result = g_pattern_match_simple(pattern, buffer);
  24. g_free(buffer);
  25. g_free(pattern);
  26. return result;
  27. }
  28. void
  29. bookmarks_completion_setup(GtkEntryCompletion *location_completion, GtkTreeModel *tree_model)
  30. {
  31. gtk_entry_completion_set_model(location_completion, tree_model);
  32. gtk_entry_completion_set_text_column(location_completion, 0);
  33. gtk_entry_completion_set_match_func(location_completion, location_completion_matches, NULL, NULL);
  34. gtk_entry_completion_set_inline_selection(location_completion, BADWOLF_LOCATION_INLINE_SELECTION);
  35. }
  36. static void
  37. location_completion_cleanup(xmlXPathObjectPtr xpathObj, xmlXPathContextPtr xpathCtx, xmlDocPtr doc)
  38. {
  39. if(xpathObj != NULL) xmlXPathFreeObject(xpathObj);
  40. if(xpathCtx != NULL) xmlXPathFreeContext(xpathCtx);
  41. if(doc != NULL) xmlFreeDoc(doc);
  42. }
  43. static void
  44. load_xpath_results(GtkListStore *list_store, xmlNodeSetPtr nodes)
  45. {
  46. GtkTreeIter iter;
  47. int size;
  48. size = (nodes) ? nodes->nodeNr : 0;
  49. g_fprintf(stderr, _("Bookmarks: Found %d bookmarks.\n"), size);
  50. for(int i = 0; i < size; i++)
  51. if(nodes->nodeTab[i])
  52. {
  53. gtk_list_store_append(list_store, &iter);
  54. gtk_list_store_set(
  55. list_store, &iter, 0, (char *)xmlXPathCastNodeToString(nodes->nodeTab[i]), -1);
  56. }
  57. }
  58. GtkTreeModel *
  59. bookmarks_completion_init()
  60. {
  61. xmlDocPtr doc = NULL;
  62. xmlXPathContextPtr xpathCtx = NULL;
  63. xmlXPathObjectPtr xpathObj = NULL;
  64. const xmlChar *xpathExpr = (const xmlChar *)"//bookmark/@href";
  65. char *filename = g_build_filename(g_get_user_data_dir(), "badwolf", "bookmarks.xbel", NULL);
  66. GtkListStore *list_store = gtk_list_store_new(1, G_TYPE_STRING);
  67. /* flawfinder: ignore, just a presence check */
  68. if(access(filename, R_OK) != 0)
  69. {
  70. g_fprintf(stderr, _("Bookmarks: No loadable file found at %s\n"), filename);
  71. goto failure;
  72. }
  73. g_fprintf(stderr, _("Bookmarks: loading at %s\n"), filename);
  74. doc = xmlParseFile(filename);
  75. if(doc == NULL)
  76. {
  77. g_fprintf(stderr, _("Bookmarks: unable to parse file \"%s\"\n"), filename);
  78. goto failure;
  79. }
  80. xmlXIncludeProcess(doc);
  81. xpathCtx = xmlXPathNewContext(doc);
  82. if(xpathCtx == NULL)
  83. {
  84. g_fprintf(stderr, _("Bookmarks: unable to create new XPath context\n"));
  85. goto failure;
  86. }
  87. xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
  88. if(xpathObj == NULL)
  89. {
  90. g_fprintf(stderr, _("Bookmarks: unable to evaluate XPath expression \"%s\"\n"), xpathExpr);
  91. goto failure;
  92. }
  93. load_xpath_results(list_store, xpathObj->nodesetval);
  94. location_completion_cleanup(xpathObj, xpathCtx, doc);
  95. g_fprintf(stderr, _("Bookmarks: Done.\n"));
  96. return GTK_TREE_MODEL(list_store);
  97. failure:
  98. location_completion_cleanup(xpathObj, xpathCtx, doc);
  99. g_free(filename);
  100. return NULL;
  101. }