1 /* Support for dumping to the file on startup (w/o bfu) */
10 #include <sys/types.h> /* NetBSD flavour */
11 #ifdef HAVE_SYS_SIGNAL_H
12 #include <sys/signal.h>
15 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
23 #include "cache/cache.h"
24 #include "config/options.h"
25 #include "document/document.h"
26 #include "document/options.h"
27 #include "document/renderer.h"
28 #include "document/view.h"
29 #include "intl/gettext/libintl.h"
30 #include "main/select.h"
31 #include "main/main.h"
32 #include "network/connection.h"
33 #include "network/state.h"
34 #include "osdep/ascii.h"
35 #include "osdep/osdep.h"
36 #include "protocol/protocol.h"
37 #include "protocol/uri.h"
38 #include "session/download.h"
39 #include "terminal/color.h"
40 #include "terminal/hardio.h"
41 #include "terminal/terminal.h"
42 #include "util/memory.h"
43 #include "util/string.h"
44 #include "viewer/dump/dump.h"
45 #include "viewer/text/view.h"
46 #include "viewer/text/vs.h"
50 static struct download dump_download
;
51 static int dump_redir_count
= 0;
53 static int dump_to_file_16(struct document
*document
, int fd
);
54 static int dump_to_file_256(struct document
*document
, int fd
);
56 /* This dumps the given @cached's source onto @fd nothing more. It returns 0 if it
57 * all went fine and 1 if something isn't quite right and we should terminate
60 dump_source(int fd
, struct download
*download
, struct cache_entry
*cached
)
62 struct fragment
*frag
;
64 if (!cached
) return 0;
67 foreach (frag
, cached
->frag
) {
68 int d
= dump_pos
- frag
->offset
;
71 if (d
< 0 || frag
->length
<= d
)
75 w
= hard_write(fd
, frag
->data
+ d
, l
);
78 detach_connection(download
, dump_pos
);
81 ERROR(gettext("Can't write to stdout: %s"),
82 (unsigned char *) strerror(errno
));
84 ERROR(gettext("Can't write to stdout."));
86 program
.retval
= RET_ERROR
;
91 detach_connection(download
, dump_pos
);
98 /* This dumps the given @cached's formatted output onto @fd. */
100 dump_formatted(int fd
, struct download
*download
, struct cache_entry
*cached
)
102 struct document_options o
;
103 struct document_view formatted
;
104 struct view_state vs
;
109 memset(&formatted
, 0, sizeof(formatted
));
111 init_document_options(&o
);
112 width
= get_opt_int("document.dump.width");
113 set_box(&o
.box
, 0, 1, width
, DEFAULT_TERMINAL_HEIGHT
);
115 o
.cp
= get_opt_codepage("document.dump.codepage");
116 o
.color_mode
= get_opt_int("document.dump.color_mode");
119 o
.links_numbering
= get_opt_bool("document.dump.numbering");
121 init_vs(&vs
, cached
->uri
, -1);
123 render_document(&vs
, &formatted
, &o
);
124 switch(o
.color_mode
) {
125 case COLOR_MODE_DUMP
:
126 case COLOR_MODE_MONO
: /* FIXME: inversion */
127 dump_to_file(formatted
.document
, fd
);
130 dump_to_file_16(formatted
.document
, fd
);
132 #ifdef CONFIG_88_COLORS
134 dump_to_file_256(formatted
.document
, fd
);
137 #ifdef CONFIG_256_COLORS
139 dump_to_file_256(formatted
.document
, fd
);
146 detach_formatted(&formatted
);
150 static unsigned char *
151 subst_url(unsigned char *str
, struct string
*url
)
153 struct string string
;
155 if (!init_string(&string
)) return NULL
;
160 for (p
= 0; str
[p
] && str
[p
] != '%' && str
[p
] != '\\'; p
++);
162 add_bytes_to_string(&string
, str
, p
);
183 add_char_to_string(&string
, ch
);
188 } else if (*str
!= '%') {
195 if (url
) add_string_to_string(&string
, url
);
202 return string
.source
;
206 dump_print(unsigned char *option
, struct string
*url
)
208 unsigned char *str
= get_opt_str(option
);
211 unsigned char *realstr
= subst_url(str
, url
);
214 printf("%s", realstr
);
222 dump_loading_callback(struct download
*download
, void *p
)
224 struct cache_entry
*cached
= download
->cached
;
225 int fd
= get_output_handle();
227 if (fd
== -1) return;
228 if (cached
&& cached
->redirect
&& dump_redir_count
++ < MAX_REDIRECTS
) {
229 struct uri
*uri
= cached
->redirect
;
231 cancel_download(download
, 0);
233 load_uri(uri
, cached
->uri
, download
, PRI_MAIN
, 0, -1);
237 if (is_in_queued_state(download
->state
)) return;
239 if (get_cmd_opt_bool("dump")) {
240 if (is_in_transfering_state(download
->state
))
243 dump_formatted(fd
, download
, cached
);
246 if (dump_source(fd
, download
, cached
) > 0)
249 if (is_in_progress_state(download
->state
))
254 if (download
->state
!= S_OK
) {
255 usrerror(get_state_message(download
->state
, NULL
));
256 program
.retval
= RET_ERROR
;
261 program
.terminate
= 1;
266 dump_start(unsigned char *url
)
268 unsigned char *wd
= get_cwd();
269 struct uri
*uri
= get_translated_uri(url
, wd
);
273 if (!uri
|| get_protocol_external_handler(NULL
, uri
)) {
274 usrerror(gettext("URL protocol not supported (%s)."), url
);
278 dump_download
.callback
= (download_callback_T
*) dump_loading_callback
;
281 if (load_uri(uri
, NULL
, &dump_download
, PRI_MAIN
, 0, -1)) {
284 program
.terminate
= 1;
285 program
.retval
= RET_SYNTAX
;
288 if (uri
) done_uri(uri
);
292 dump_next(struct list_head
*url_list
)
294 static INIT_LIST_HEAD(todo_list
);
295 static INIT_LIST_HEAD(done_list
);
296 struct string_list_item
*item
;
299 /* Steal all them nice list items but keep the same order */
300 while (!list_empty(*url_list
)) {
301 item
= url_list
->next
;
303 add_to_list_end(todo_list
, item
);
307 /* Dump each url list item one at a time */
308 if (!list_empty(todo_list
)) {
309 static int first
= 1;
311 program
.terminate
= 0;
313 item
= todo_list
.next
;
315 add_to_list(done_list
, item
);
318 dump_print("document.dump.separator", NULL
);
323 dump_print("document.dump.header", &item
->string
);
324 dump_start(item
->string
.source
);
325 /* XXX: I think it ought to print footer at the end of
326 * the whole dump (not only this file). Testing required.
328 dump_print("document.dump.footer", &item
->string
);
331 free_string_list(&done_list
);
332 program
.terminate
= 1;
336 /* Using this function in dump_to_file() is unfortunately slightly slower than
337 * the current code. However having this here instead of in the scripting
338 * backends is better. */
340 add_document_to_string(struct string
*string
, struct document
*document
)
344 assert(string
&& document
);
345 if_assert_failed
return NULL
;
347 for (y
= 0; y
< document
->height
; y
++) {
351 for (x
= 0; x
< document
->data
[y
].length
; x
++) {
352 struct screen_char
*pos
= &document
->data
[y
].chars
[x
];
353 unsigned char data
= pos
->data
;
354 unsigned int frame
= (pos
->attr
& SCREEN_ATTR_FRAME
);
356 if (!isscreensafe(data
)) {
360 if (frame
&& data
>= 176 && data
< 224)
361 data
= frame_dumb
[data
- 176];
367 /* Print spaces if any. */
369 add_xchar_to_string(string
, ' ', white
);
372 add_char_to_string(string
, data
);
377 add_char_to_string(string
, '\n');
386 write_char(unsigned char c
, int fd
, unsigned char *buf
, int *bptr
)
389 if ((*bptr
) >= D_BUF
) {
390 if (hard_write(fd
, buf
, (*bptr
)) != (*bptr
))
399 write_color_16(unsigned char color
, int fd
, unsigned char *buf
, int *bptr
)
401 unsigned char bufor
[] = "\033[0;30;40m";
402 unsigned char *data
= bufor
;
403 int background
= (color
>> 4) & 7;
404 int foreground
= color
& 7;
406 bufor
[5] += foreground
;
407 if (background
) bufor
[8] += background
;
413 if (write_char(*data
++, fd
, buf
, bptr
)) return -1;
420 dump_to_file_16(struct document
*document
, int fd
)
424 unsigned char *buf
= mem_alloc(D_BUF
);
425 unsigned char color
= 0;
426 int width
= get_opt_int("document.dump.width");
430 for (y
= 0; y
< document
->height
; y
++) {
434 write_color_16(color
, fd
, buf
, &bptr
);
435 for (x
= 0; x
< document
->data
[y
].length
; x
++) {
437 unsigned char attr
= document
->data
[y
].chars
[x
].attr
;
438 unsigned char color1
= document
->data
[y
].chars
[x
].color
[0];
440 if (color
!= color1
) {
442 if (write_color_16(color
, fd
, buf
, &bptr
))
446 c
= document
->data
[y
].chars
[x
].data
;
448 if ((attr
& SCREEN_ATTR_FRAME
)
449 && c
>= 176 && c
< 224)
450 c
= frame_dumb
[c
- 176];
458 /* Print spaces if any. */
460 if (write_char(' ', fd
, buf
, &bptr
))
465 /* Print normal char. */
466 if (write_char(c
, fd
, buf
, &bptr
))
469 for (;x
< width
; x
++) {
470 if (write_char(' ', fd
, buf
, &bptr
))
474 /* Print end of line. */
475 if (write_char('\n', fd
, buf
, &bptr
))
479 if (hard_write(fd
, buf
, bptr
) != bptr
) {
485 if (document
->nlinks
&& get_opt_bool("document.dump.references")) {
487 unsigned char *header
= "\nReferences\n\n Visible links\n";
488 int headlen
= strlen(header
);
490 if (hard_write(fd
, header
, headlen
) != headlen
)
493 for (x
= 0; x
< document
->nlinks
; x
++) {
494 struct link
*link
= &document
->links
[x
];
495 unsigned char *where
= link
->where
;
497 if (!where
) continue;
499 if (document
->options
.links_numbering
) {
500 if (link
->title
&& *link
->title
)
501 snprintf(buf
, D_BUF
, "%4d. %s\n\t%s\n",
502 x
+ 1, link
->title
, where
);
504 snprintf(buf
, D_BUF
, "%4d. %s\n",
507 if (link
->title
&& *link
->title
)
508 snprintf(buf
, D_BUF
, " . %s\n\t%s\n",
511 snprintf(buf
, D_BUF
, " . %s\n", where
);
515 if (hard_write(fd
, buf
, bptr
) != bptr
)
525 write_color_256(unsigned char *str
, unsigned char color
, int fd
, unsigned char *buf
, int *bptr
)
527 unsigned char bufor
[16];
528 unsigned char *data
= bufor
;
530 snprintf(bufor
, 16, "\033[%s;5;%dm", str
, color
);
532 if (write_char(*data
++, fd
, buf
, bptr
)) return -1;
538 dump_to_file_256(struct document
*document
, int fd
)
542 unsigned char *buf
= mem_alloc(D_BUF
);
543 unsigned char foreground
= 0;
544 unsigned char background
= 0;
545 int width
= get_opt_int("document.dump.width");
549 for (y
= 0; y
< document
->height
; y
++) {
552 write_color_256("38", foreground
, fd
, buf
, &bptr
);
553 write_color_256("48", background
, fd
, buf
, &bptr
);
555 for (x
= 0; x
< document
->data
[y
].length
; x
++) {
557 unsigned char attr
= document
->data
[y
].chars
[x
].attr
;
558 unsigned char color1
= document
->data
[y
].chars
[x
].color
[0];
559 unsigned char color2
= document
->data
[y
].chars
[x
].color
[1];
561 if (foreground
!= color1
) {
563 if (write_color_256("38", foreground
, fd
, buf
, &bptr
))
567 if (background
!= color2
) {
569 if (write_color_256("48", background
, fd
, buf
, &bptr
))
573 c
= document
->data
[y
].chars
[x
].data
;
575 if ((attr
& SCREEN_ATTR_FRAME
)
576 && c
>= 176 && c
< 224)
577 c
= frame_dumb
[c
- 176];
585 /* Print spaces if any. */
587 if (write_char(' ', fd
, buf
, &bptr
))
592 /* Print normal char. */
593 if (write_char(c
, fd
, buf
, &bptr
))
596 for (;x
< width
; x
++) {
597 if (write_char(' ', fd
, buf
, &bptr
))
601 /* Print end of line. */
602 if (write_char('\n', fd
, buf
, &bptr
))
606 if (hard_write(fd
, buf
, bptr
) != bptr
) {
612 if (document
->nlinks
&& get_opt_bool("document.dump.references")) {
614 unsigned char *header
= "\nReferences\n\n Visible links\n";
615 int headlen
= strlen(header
);
617 if (hard_write(fd
, header
, headlen
) != headlen
)
620 for (x
= 0; x
< document
->nlinks
; x
++) {
621 struct link
*link
= &document
->links
[x
];
622 unsigned char *where
= link
->where
;
624 if (!where
) continue;
626 if (document
->options
.links_numbering
) {
627 if (link
->title
&& *link
->title
)
628 snprintf(buf
, D_BUF
, "%4d. %s\n\t%s\n",
629 x
+ 1, link
->title
, where
);
631 snprintf(buf
, D_BUF
, "%4d. %s\n",
634 if (link
->title
&& *link
->title
)
635 snprintf(buf
, D_BUF
, " . %s\n\t%s\n",
638 snprintf(buf
, D_BUF
, " . %s\n", where
);
642 if (hard_write(fd
, buf
, bptr
) != bptr
)
653 dump_to_file(struct document
*document
, int fd
)
657 unsigned char *buf
= mem_alloc(D_BUF
);
661 for (y
= 0; y
< document
->height
; y
++) {
665 for (x
= 0; x
< document
->data
[y
].length
; x
++) {
667 unsigned char attr
= document
->data
[y
].chars
[x
].attr
;
669 c
= document
->data
[y
].chars
[x
].data
;
671 if ((attr
& SCREEN_ATTR_FRAME
)
672 && c
>= 176 && c
< 224)
673 c
= frame_dumb
[c
- 176];
681 /* Print spaces if any. */
683 if (write_char(' ', fd
, buf
, &bptr
))
688 /* Print normal char. */
689 if (write_char(c
, fd
, buf
, &bptr
))
693 /* Print end of line. */
694 if (write_char('\n', fd
, buf
, &bptr
))
698 if (hard_write(fd
, buf
, bptr
) != bptr
) {
704 if (document
->nlinks
&& get_opt_bool("document.dump.references")) {
706 unsigned char *header
= "\nReferences\n\n Visible links\n";
707 int headlen
= strlen(header
);
709 if (hard_write(fd
, header
, headlen
) != headlen
)
712 for (x
= 0; x
< document
->nlinks
; x
++) {
713 struct link
*link
= &document
->links
[x
];
714 unsigned char *where
= link
->where
;
716 if (!where
) continue;
718 if (document
->options
.links_numbering
) {
719 if (link
->title
&& *link
->title
)
720 snprintf(buf
, D_BUF
, "%4d. %s\n\t%s\n",
721 x
+ 1, link
->title
, where
);
723 snprintf(buf
, D_BUF
, "%4d. %s\n",
726 if (link
->title
&& *link
->title
)
727 snprintf(buf
, D_BUF
, " . %s\n\t%s\n",
730 snprintf(buf
, D_BUF
, " . %s\n", where
);
734 if (hard_write(fd
, buf
, bptr
) != bptr
)