1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#include <string.h>
#include <stdio.h>
#include "nav.h"
#include "net.h"
#include "err.h"
#include "parse.h"
/* history */
void nav_init(struct nav_state *ns) {
memset(ns, 0, sizeof *ns);
ns->histc = 1;
doc_init(ns->histv);
doc_add_text(ns->histv, "Type ? for command help.");
ns->prot_default = PROT_FILE; /* change to PROT_GOPHER later */
}
void nav_fini(struct nav_state *ns) {
for (size_t i = 0; i < ns->histc; i++) {
doc_fini(&ns->histv[i]);
}
}
void nav_push(struct nav_state *ns, struct doc d) {
while (ns->histc > ns->cur_doc + 1) {
doc_fini(&ns->histv[--ns->histc]);
}
if (ns->histc == HIST_MAX) {
doc_fini(ns->histv);
memmove(ns->histv, &ns->histv[1], sizeof(struct doc) * (HIST_MAX - 1));
memmove(ns->cur_ofs, &ns->cur_ofs[1], sizeof(size_t) * (HIST_MAX - 1));
ns->histc--;
}
ns->cur_ofs[ns->histc] = 0;
ns->histv[ns->histc++] = d;
ns->cur_doc = ns->histc - 1;
}
void nav_prev(struct nav_state *ns) {
if (ns->cur_doc > 0) ns->cur_doc--;
nav_redraw(ns);
}
void nav_next(struct nav_state *ns) {
if (ns->cur_doc + 1 < ns->histc) ns->cur_doc++;
nav_redraw(ns);
}
/* paging */
size_t pg_lines(void) {
return 24;
}
struct doc_line *nav_cur_line(struct nav_state *ns) {
return doc_line_at(&ns->histv[ns->cur_doc], ns->cur_ofs[ns->cur_doc]);
}
int nav_line_up(struct nav_state *ns) {
return !doc_line_prev(&ns->histv[ns->cur_doc], &ns->cur_ofs[ns->cur_doc]);
}
int nav_line_down(struct nav_state *ns) {
return !doc_line_next(&ns->histv[ns->cur_doc], &ns->cur_ofs[ns->cur_doc]);
}
void nav_pg_up(struct nav_state *ns) {
size_t lines = pg_lines() << 1;
while (lines-- && nav_line_up(ns));
nav_pg_down(ns);
}
#define MARGIN 8
void nav_pg_down(struct nav_state *ns) {
size_t lines = pg_lines();
while (lines--) {
struct doc_line *l = nav_cur_line(ns);
int n = 0;
if (l->link != DOC_LINK_NONE) {
n = printf("[%hu]", l->link + 1);
}
while (n++ < MARGIN) putchar(' ');
fwrite(l->txt, 1, l->len, stdout);
putchar('\n');
if (!nav_line_down(ns)) break;
}
}
void nav_redraw(struct nav_state *ns) {
size_t lines = pg_lines();
while (lines-- && nav_line_up(ns));
nav_pg_down(ns);
}
/* network */
int nav_to(struct nav_state *ns, const char *url) {
enum doc_type doct;
struct addr adr;
buf_t buf;
if (net_addr(url, &adr, ns->prot_default)) {
return -1;
}
ns->prot_default = adr.prot;
if (net_fetch(&adr, &buf, &doct)) {
return -1;
}
struct doc d;
if (parse_doc(doct, &d, &buf)) {
buf_free(&buf);
return -1;
}
nav_push(ns, d);
buf_free(&buf);
nav_redraw(ns);
return 0;
}
int nav_link_nr(struct nav_state *ns, unsigned long link_nr) {
struct doc *d = &ns->histv[ns->cur_doc];
const char *url = doc_get_link(d, link_nr);
if (url) {
puts(url);
return nav_to(ns, url);
} else {
perr("invalid link number");
}
return 0;
}
|