Reorganize global default settings so the comments make sense. No
[xxxterm.git] / history.c
blob53f5ff7716f7a475548032492e0eb80ea2751c5d
1 /*
2 * Copyright (c) 2010, 2011 Marco Peereboom <marco@peereboom.us>
3 * Copyright (c) 2011 Stevan Andjelkovic <stevan@student.chalmers.se>
4 * Copyright (c) 2010, 2011 Edd Barrett <vext01@gmail.com>
5 * Copyright (c) 2011 Todd T. Fries <todd@fries.net>
6 * Copyright (c) 2011 Raphael Graf <r@undefined.ch>
7 * Copyright (c) 2011 Michal Mazurek <akfaew@jasminek.net>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <xxxterm.h>
24 #define XT_HISTORY_FILE ("history")
25 #define XT_MAX_HL_PURGE_COUNT (1000) /* Purge the history for every
26 * MAX_HL_PURGE_COUNT items inserted into
27 * history and delete all items older
28 * than MAX_HISTORY_AGE. */
29 #define XT_MAX_HISTORY_AGE (60.0 * 60.0 * 24 * 14) /* 14 days */
31 int
32 purge_history(void)
34 struct history *h, *next;
35 double age = 0.0;
37 DNPRINTF(XT_D_HISTORY, "%s: hl_purge_count = %d (%d is max)\n",
38 __func__, hl_purge_count, XT_MAX_HL_PURGE_COUNT);
40 if (hl_purge_count == XT_MAX_HL_PURGE_COUNT) {
41 hl_purge_count = 0;
43 for (h = RB_MIN(history_list, &hl); h != NULL; h = next) {
45 next = RB_NEXT(history_list, &hl, h);
47 age = difftime(time(NULL), h->time);
49 if (age > XT_MAX_HISTORY_AGE) {
50 DNPRINTF(XT_D_HISTORY, "%s: removing %s (age %.1f)\n",
51 __func__, h->uri, age);
53 RB_REMOVE(history_list, &hl, h);
54 g_free(h->uri);
55 g_free(h->title);
56 g_free(h);
57 } else {
58 DNPRINTF(XT_D_HISTORY, "%s: keeping %s (age %.1f)\n",
59 __func__, h->uri, age);
64 return (0);
67 int
68 insert_history_item(const gchar *uri, const gchar *title, time_t time)
70 struct history *h;
72 if (!(uri && strlen(uri) && title && strlen(title)))
73 return (1);
75 h = g_malloc(sizeof(struct history));
76 h->uri = g_strdup(uri);
77 h->title = g_strdup(title);
78 h->time = time;
80 DNPRINTF(XT_D_HISTORY, "%s: adding %s\n", __func__, h->uri);
82 RB_INSERT(history_list, &hl, h);
83 completion_add_uri(h->uri);
84 hl_purge_count++;
86 purge_history();
87 update_history_tabs(NULL);
89 return (0);
92 int
93 restore_global_history(void)
95 char file[PATH_MAX];
96 FILE *f;
97 gchar *uri, *title, *stime, *err = NULL;
98 time_t time;
99 struct tm tm;
100 const char delim[3] = {'\\', '\\', '\0'};
102 snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_HISTORY_FILE);
104 if ((f = fopen(file, "r")) == NULL) {
105 warnx("%s: fopen", __func__);
106 return (1);
109 for (;;) {
110 if ((uri = fparseln(f, NULL, NULL, delim, 0)) == NULL)
111 if (feof(f) || ferror(f))
112 break;
114 if ((title = fparseln(f, NULL, NULL, delim, 0)) == NULL)
115 if (feof(f) || ferror(f)) {
116 err = "broken history file (title)";
117 goto done;
120 if ((stime = fparseln(f, NULL, NULL, delim, 0)) == NULL)
121 if (feof(f) || ferror(f)) {
122 err = "broken history file (time)";
123 goto done;
126 if (strptime(stime, "%a %b %d %H:%M:%S %Y", &tm) == NULL) {
127 err = "strptime failed to parse time";
128 goto done;
131 time = mktime(&tm);
133 if (insert_history_item(uri, title, time)) {
134 err = "failed to insert item";
135 goto done;
138 free(uri);
139 free(title);
140 free(stime);
141 uri = NULL;
142 title = NULL;
143 stime = NULL;
146 done:
147 if (err && strlen(err)) {
148 warnx("%s: %s\n", __func__, err);
149 free(uri);
150 free(title);
151 free(stime);
153 return (1);
156 return (0);
160 save_global_history_to_disk(struct tab *t)
162 char file[PATH_MAX];
163 FILE *f;
164 struct history *h;
166 snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_HISTORY_FILE);
168 if ((f = fopen(file, "w")) == NULL) {
169 show_oops(t, "%s: global history file: %s",
170 __func__, strerror(errno));
171 return (1);
174 RB_FOREACH_REVERSE(h, history_list, &hl) {
175 if (h->uri && h->title && h->time)
176 fprintf(f, "%s\n%s\n%s", h->uri, h->title,
177 ctime(&h->time));
180 fclose(f);
182 return (0);
186 * Marshall the internal record of visited URIs into a Javascript hash table in
187 * string form.
189 char *
190 color_visited_helper(void)
192 char *d, *s = NULL, *t;
193 struct history *h;
195 RB_FOREACH_REVERSE(h, history_list, &hl) {
196 if (s == NULL)
197 s = g_strdup_printf("'%s':'dummy'", h->uri);
198 else {
199 d = g_strdup_printf("'%s':'dummy'", h->uri);
200 t = g_strjoin(",", s, d, NULL);
201 g_free(d);
202 g_free(s);
203 s = t;
207 t = g_strdup_printf("{%s}", s);
208 g_free(s);
209 s = t;
211 DNPRINTF(XT_D_VISITED, "%s: s = %s\n", __func__, s);
213 return (s);
217 color_visited(struct tab *t, char *visited)
219 char *s, *v;
221 if (t == NULL || visited == NULL) {
222 show_oops(NULL, "%s: invalid parameters", __func__);
223 return (1);
227 * Create a string representing an annonymous Javascript function, which
228 * takes a hash table of visited URIs as an argument, goes through the
229 * links at the current web page and colors them if they indeed been
230 * visited.
232 v = g_strdup_printf("(%s);", visited),
233 s = g_strconcat(
234 "(function(visitedUris) {",
235 " for (var i = 0; i < document.links.length; i++)",
236 " if (visitedUris[document.links[i].href])",
237 " document.links[i].style.color = 'purple';",
238 "})",
239 v, NULL);
241 run_script(t, s);
242 g_free(s);
243 g_free(v);
244 g_free(visited);
246 return (0);