More headers.
[elinks.git] / src / document / document.c
blob074e128d6edda47383251bb76ccef277de9c3df1
1 /** The document base functionality
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
13 #include <sys/types.h>
14 #ifdef HAVE_NETINET_IN_H
15 #include <netinet/in.h> /* OS/2 needs this after sys/types.h */
16 #endif
17 #ifdef HAVE_SYS_SOCKET_H
18 #include <sys/socket.h> /* OS/2 needs this after sys/types.h */
19 #endif
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
22 #endif
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_WS2TCPIP_H
27 #include <ws2tcpip.h> /* socklen_t for MinGW */
28 #endif
30 #ifdef HAVE_GETIFADDRS
31 #ifdef HAVE_NETDB_H
32 #include <netdb.h>
33 #endif
34 #ifdef HAVE_NET_IF_H
35 #include <net/if.h>
36 #endif
37 #ifdef HAVE_IFADDRS_H
38 #include <ifaddrs.h> /* getifaddrs() */
39 #endif
40 #endif /* HAVE_GETIFADDRS */
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
46 #include "elinks.h"
48 #include "cache/cache.h"
49 #include "config/options.h"
50 #include "document/document.h"
51 #include "document/forms.h"
52 #include "document/html/frames.h"
53 #include "document/html/parser.h"
54 #include "document/html/parser/parse.h"
55 #include "document/html/renderer.h"
56 #include "document/options.h"
57 #include "document/refresh.h"
58 #include "main/module.h"
59 #include "main/object.h"
60 #include "network/dns.h"
61 #include "protocol/uri.h"
62 #include "terminal/draw.h"
63 #include "util/color.h"
64 #include "util/error.h"
65 #include "util/lists.h"
66 #include "util/memory.h"
67 #include "util/string.h"
68 #include "viewer/text/link.h"
70 static INIT_LIST_OF(struct document, format_cache);
72 /* DNS callback. */
73 static void
74 found_dns(void *data, struct sockaddr_storage *addr, int addrlen)
76 #ifdef HAVE_INET_NTOP
77 unsigned char buf[64];
78 const unsigned char *res;
79 struct sockaddr *s;
80 unsigned char **ip = (unsigned char **)data;
81 void *src;
83 if (!ip || !addr) return;
84 s = (struct sockaddr *)addr;
85 if (s->sa_family == AF_INET6) {
86 src = &(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr);
87 } else {
88 src = &(((struct sockaddr_in *)s)->sin_addr.s_addr);
90 res = inet_ntop(s->sa_family, src, buf, 64);
91 if (res) {
92 *ip = stracpy(res);
94 #endif
97 static void
98 get_ip(struct document *document)
100 #ifdef HAVE_INET_NTOP
101 struct uri *uri = document->uri;
102 char tmp;
104 if (!uri || !uri->host || !uri->hostlen) return;
105 tmp = uri->host[uri->hostlen];
106 uri->host[uri->hostlen] = 0;
107 find_host(uri->host, &document->querydns, found_dns, &document->ip, 0);
108 uri->host[uri->hostlen] = tmp;
109 #endif
112 struct document *
113 init_document(struct cache_entry *cached, struct document_options *options)
115 struct document *document = mem_calloc(1, sizeof(*document));
117 if (!document) return NULL;
119 document->uri = get_uri_reference(cached->uri);
121 get_ip(document);
123 object_lock(cached);
124 document->cache_id = cached->cache_id;
125 document->cached = cached;
127 init_list(document->forms);
128 init_list(document->tags);
129 init_list(document->nodes);
131 #ifdef CONFIG_ECMASCRIPT
132 init_list(document->onload_snippets);
133 #endif
135 #ifdef CONFIG_COMBINE
136 document->comb_x = -1;
137 document->comb_y = -1;
138 #endif
139 object_nolock(document, "document");
140 object_lock(document);
142 copy_opt(&document->options, options);
144 add_to_list(format_cache, document);
146 return document;
149 static void
150 free_frameset_desc(struct frameset_desc *frameset_desc)
152 int i;
154 for (i = 0; i < frameset_desc->n; i++) {
155 struct frame_desc *frame_desc = &frameset_desc->frame_desc[i];
157 if (frame_desc->subframe)
158 free_frameset_desc(frame_desc->subframe);
159 mem_free_if(frame_desc->name);
160 if (frame_desc->uri)
161 done_uri(frame_desc->uri);
164 mem_free(frameset_desc);
167 void
168 done_link_members(struct link *link)
170 if (link->event_hooks) {
171 struct script_event_hook *evhook, *safety;
173 foreachsafe (evhook, safety, *link->event_hooks) {
174 mem_free_if(evhook->src);
175 mem_free(evhook);
177 mem_free(link->event_hooks);
179 mem_free_if(get_link_name(link));
180 mem_free_if(link->where);
181 mem_free_if(link->target);
182 mem_free_if(link->title);
183 mem_free_if(link->where_img);
184 mem_free_if(link->points);
187 void
188 done_document(struct document *document)
190 assert(document);
191 if_assert_failed return;
193 assertm(!is_object_used(document), "Attempt to free locked formatted data.");
194 if_assert_failed return;
196 assert(document->cached);
197 object_unlock(document->cached);
199 if (document->uri) done_uri(document->uri);
200 if (document->querydns) kill_dns_request(&document->querydns);
201 mem_free_if(document->ip);
202 mem_free_if(document->title);
203 if (document->frame_desc) free_frameset_desc(document->frame_desc);
204 if (document->refresh) done_document_refresh(document->refresh);
206 if (document->links) {
207 int pos;
209 for (pos = 0; pos < document->nlinks; pos++)
210 done_link_members(&document->links[pos]);
212 mem_free(document->links);
215 if (document->data) {
216 int pos;
218 for (pos = 0; pos < document->height; pos++)
219 mem_free_if(document->data[pos].chars);
221 mem_free(document->data);
224 mem_free_if(document->lines1);
225 mem_free_if(document->lines2);
226 done_document_options(&document->options);
228 while (!list_empty(document->forms)) {
229 done_form(document->forms.next);
232 #ifdef CONFIG_CSS
233 free_uri_list(&document->css_imports);
234 #endif
235 #ifdef CONFIG_ECMASCRIPT
236 free_string_list(&document->onload_snippets);
237 free_uri_list(&document->ecmascript_imports);
238 kill_timer(&document->timeout);
239 #endif
241 free_list(document->tags);
242 free_list(document->nodes);
244 mem_free_if(document->search);
245 mem_free_if(document->slines1);
246 mem_free_if(document->slines2);
248 del_from_list(document);
249 mem_free(document);
252 void
253 release_document(struct document *document)
255 assert(document);
256 if_assert_failed return;
258 if (document->refresh) kill_document_refresh(document->refresh);
259 #ifdef CONFIG_ECMASCRIPT
260 kill_timer(&document->timeout);
261 #endif
262 object_unlock(document);
263 move_to_top_of_list(format_cache, document);
267 find_tag(struct document *document, unsigned char *name, int namelen)
269 struct tag *tag;
271 foreach (tag, document->tags)
272 if (!c_strlcasecmp(tag->name, -1, name, namelen))
273 return tag->y;
275 return -1;
278 /* Formatted document cache management */
280 /* ECMAScript doesn't like anything like CSS since it doesn't modify the
281 * formatted document (yet). */
283 #if CONFIG_CSS
284 unsigned long
285 get_document_css_magic(struct document *document)
287 unsigned long css_magic = 0;
288 struct uri *uri;
289 int index;
291 foreach_uri (uri, index, &document->css_imports) {
292 struct cache_entry *cached = find_in_cache(uri);
294 if (cached) css_magic += cached->cache_id + cached->data_size;
297 return css_magic;
300 #define check_document_css_magic(document) \
301 ((document)->css_magic == get_document_css_magic(document))
302 #else
303 #define check_document_css_magic(document) 1
304 #endif
306 void
307 update_cached_document_options(struct session *ses)
309 struct document *document;
310 struct active_link_options active_link;
312 memset(&active_link, 0, sizeof(active_link)); /* Safer. */
313 active_link.color.foreground = get_opt_color("document.browse.links.active_link.colors.text", ses);
314 active_link.color.background = get_opt_color("document.browse.links.active_link.colors.background", ses);
315 active_link.enable_color = get_opt_bool("document.browse.links.active_link.enable_color", ses);
316 active_link.invert = get_opt_bool("document.browse.links.active_link.invert", ses);
317 active_link.underline = get_opt_bool("document.browse.links.active_link.underline", ses);
318 active_link.bold = get_opt_bool("document.browse.links.active_link.bold", ses);
320 foreach (document, format_cache) {
321 copy_struct(&document->options.active_link, &active_link);
325 struct document *
326 get_cached_document(struct cache_entry *cached, struct document_options *options)
328 struct document *document, *next;
330 foreachsafe (document, next, format_cache) {
331 if (!compare_uri(document->uri, cached->uri, 0)
332 || compare_opt(&document->options, options))
333 continue;
335 if (options->no_cache
336 || cached->cache_id != document->cache_id
337 || !check_document_css_magic(document)) {
338 if (!is_object_used(document)) {
339 done_document(document);
341 continue;
344 /* Reactivate */
345 move_to_top_of_list(format_cache, document);
347 object_lock(document);
349 return document;
352 return NULL;
355 void
356 shrink_format_cache(int whole)
358 struct document *document, *next;
359 int format_cache_size = get_opt_int("document.cache.format.size", NULL);
360 int format_cache_entries = 0;
362 foreachsafe (document, next, format_cache) {
363 if (is_object_used(document)) continue;
365 format_cache_entries++;
367 /* Destroy obsolete renderer documents which are already
368 * out-of-sync. */
369 if (document->cached->cache_id == document->cache_id)
370 continue;
372 done_document(document);
373 format_cache_entries--;
376 assertm(format_cache_entries >= 0, "format_cache_entries underflow on entry");
377 if_assert_failed format_cache_entries = 0;
379 foreachbacksafe (document, next, format_cache) {
380 if (is_object_used(document)) continue;
382 /* If we are not purging the whole format cache, stop
383 * once we are below the maximum number of entries. */
384 if (!whole && format_cache_entries <= format_cache_size)
385 break;
387 done_document(document);
388 format_cache_entries--;
391 assertm(format_cache_entries >= 0, "format_cache_entries underflow");
392 if_assert_failed format_cache_entries = 0;
396 get_format_cache_size(void)
398 return list_size(&format_cache);
402 get_format_cache_used_count(void)
404 struct document *document;
405 int i = 0;
407 foreach (document, format_cache)
408 i += is_object_used(document);
409 return i;
413 get_format_cache_refresh_count(void)
415 struct document *document;
416 int i = 0;
418 foreach (document, format_cache)
419 if (document->refresh
420 && document->refresh->timer != TIMER_ID_UNDEF)
421 i++;
422 return i;
425 static void
426 init_documents(struct module *module)
428 init_tags_lookup();
431 static void
432 done_documents(struct module *module)
434 free_tags_lookup();
435 free_table_cache();
438 struct module document_module = struct_module(
439 /* Because this module is listed in main_modules rather than
440 * in builtin_modules, its name does not appear in the user
441 * interface and so need not be translatable. */
442 /* name: */ "Document",
443 /* options: */ NULL,
444 /* hooks: */ NULL,
445 /* submodules: */ NULL,
446 /* data: */ NULL,
447 /* init: */ init_documents,
448 /* done: */ done_documents