1 /* $Id: anchor.c,v 1.33 2006/04/08 11:33:16 inu Exp $ */
2 #include "fm.h"
3 #include "myctype.h"
4 #include "regex.h"
5
6 #define FIRST_ANCHOR_SIZE 30
7
8 AnchorList *
putAnchor(AnchorList * al,char * url,char * target,Anchor ** anchor_return,char * referer,char * title,unsigned char key,int line,int pos)9 putAnchor(AnchorList *al, char *url, char *target, Anchor **anchor_return,
10 char *referer, char *title, unsigned char key, int line, int pos)
11 {
12 int n, i, j;
13 Anchor *a;
14 BufferPoint bp = { 0 };
15 if (al == NULL) {
16 al = New(AnchorList);
17 al->anchors = NULL;
18 al->nanchor = al->anchormax = 0;
19 al->acache = -1;
20 }
21 if (al->anchormax == 0) {
22 /* first time; allocate anchor buffer */
23 al->anchors = New_N(Anchor, FIRST_ANCHOR_SIZE);
24 al->anchormax = FIRST_ANCHOR_SIZE;
25 }
26 if (al->nanchor == al->anchormax) { /* need realloc */
27 al->anchormax *= 2;
28 al->anchors = New_Reuse(Anchor, al->anchors, al->anchormax);
29 }
30 bp.line = line;
31 bp.pos = pos;
32 n = al->nanchor;
33 if (!n || bpcmp(al->anchors[n - 1].start, bp) < 0)
34 i = n;
35 else
36 for (i = 0; i < n; i++) {
37 if (bpcmp(al->anchors[i].start, bp) >= 0) {
38 for (j = n; j > i; j--)
39 al->anchors[j] = al->anchors[j - 1];
40 break;
41 }
42 }
43 a = &al->anchors[i];
44 a->url = url;
45 a->target = target;
46 a->referer = referer;
47 a->title = title;
48 a->accesskey = key;
49 a->slave = FALSE;
50 a->start = bp;
51 a->end = bp;
52 al->nanchor++;
53 if (anchor_return)
54 *anchor_return = a;
55 return al;
56 }
57
58
59 Anchor *
registerHref(Buffer * buf,char * url,char * target,char * referer,char * title,unsigned char key,int line,int pos)60 registerHref(Buffer *buf, char *url, char *target, char *referer, char *title,
61 unsigned char key, int line, int pos)
62 {
63 Anchor *a;
64 buf->href = putAnchor(buf->href, url, target, &a, referer, title, key,
65 line, pos);
66 return a;
67 }
68
69 Anchor *
registerName(Buffer * buf,char * url,int line,int pos)70 registerName(Buffer *buf, char *url, int line, int pos)
71 {
72 Anchor *a;
73 buf->name = putAnchor(buf->name, url, NULL, &a, NULL, NULL, '\0', line,
74 pos);
75 return a;
76 }
77
78 Anchor *
registerImg(Buffer * buf,char * url,char * title,int line,int pos)79 registerImg(Buffer *buf, char *url, char *title, int line, int pos)
80 {
81 Anchor *a;
82 buf->img = putAnchor(buf->img, url, NULL, &a, NULL, title, '\0', line,
83 pos);
84 return a;
85 }
86
87 Anchor *
registerForm(Buffer * buf,FormList * flist,struct parsed_tag * tag,int line,int pos)88 registerForm(Buffer *buf, FormList *flist, struct parsed_tag *tag, int line,
89 int pos)
90 {
91 Anchor *a;
92 FormItemList *fi;
93
94 fi = formList_addInput(flist, tag);
95 if (fi == NULL)
96 return NULL;
97 buf->formitem = putAnchor(buf->formitem, (char *)fi, flist->target, &a,
98 NULL, NULL, '\0', line, pos);
99 return a;
100 }
101
102 int
onAnchor(Anchor * a,int line,int pos)103 onAnchor(Anchor *a, int line, int pos)
104 {
105 BufferPoint bp;
106 bp.line = line;
107 bp.pos = pos;
108
109 if (bpcmp(bp, a->start) < 0)
110 return -1;
111 if (bpcmp(a->end, bp) <= 0)
112 return 1;
113 return 0;
114 }
115
116 Anchor *
retrieveAnchor(AnchorList * al,int line,int pos)117 retrieveAnchor(AnchorList *al, int line, int pos)
118 {
119 Anchor *a;
120 size_t b, e;
121 int cmp;
122
123 if (al == NULL || al->nanchor == 0)
124 return NULL;
125
126 if (al->acache < 0 || al->acache >= al->nanchor)
127 al->acache = 0;
128
129 for (b = 0, e = al->nanchor - 1; b <= e; al->acache = (b + e) / 2) {
130 a = &al->anchors[al->acache];
131 cmp = onAnchor(a, line, pos);
132 if (cmp == 0)
133 return a;
134 else if (cmp > 0)
135 b = al->acache + 1;
136 else if (al->acache == 0)
137 return NULL;
138 else
139 e = al->acache - 1;
140 }
141 return NULL;
142 }
143
144 Anchor *
retrieveCurrentAnchor(Buffer * buf)145 retrieveCurrentAnchor(Buffer *buf)
146 {
147 if (buf->currentLine == NULL)
148 return NULL;
149 return retrieveAnchor(buf->href, buf->currentLine->linenumber, buf->pos);
150 }
151
152 Anchor *
retrieveCurrentImg(Buffer * buf)153 retrieveCurrentImg(Buffer *buf)
154 {
155 if (buf->currentLine == NULL)
156 return NULL;
157 return retrieveAnchor(buf->img, buf->currentLine->linenumber, buf->pos);
158 }
159
160 Anchor *
retrieveCurrentForm(Buffer * buf)161 retrieveCurrentForm(Buffer *buf)
162 {
163 if (buf->currentLine == NULL)
164 return NULL;
165 return retrieveAnchor(buf->formitem,
166 buf->currentLine->linenumber, buf->pos);
167 }
168
169 Anchor *
searchAnchor(AnchorList * al,char * str)170 searchAnchor(AnchorList *al, char *str)
171 {
172 int i;
173 Anchor *a;
174 if (al == NULL)
175 return NULL;
176 for (i = 0; i < al->nanchor; i++) {
177 a = &al->anchors[i];
178 if (a->hseq < 0)
179 continue;
180 if (!strcmp(a->url, str))
181 return a;
182 }
183 return NULL;
184 }
185
186 Anchor *
searchURLLabel(Buffer * buf,char * url)187 searchURLLabel(Buffer *buf, char *url)
188 {
189 return searchAnchor(buf->name, url);
190 }
191
192 #ifdef USE_NNTP
193 static Anchor *
_put_anchor_news(Buffer * buf,char * p1,char * p2,int line,int pos)194 _put_anchor_news(Buffer *buf, char *p1, char *p2, int line, int pos)
195 {
196 Str tmp;
197
198 if (*p1 == '<') {
199 p1++;
200 if (*(p2 - 1) == '>')
201 p2--;
202 }
203 tmp = Strnew_charp("news:");
204 Strcat_charp_n(tmp, p1, p2 - p1);
205 return registerHref(buf, url_encode(tmp->ptr, baseURL(buf),
206 buf->document_charset),
207 NULL, NO_REFERER, NULL, '\0', line,
208 pos);
209 }
210 #endif /* USE_NNTP */
211
212 static Anchor *
_put_anchor_all(Buffer * buf,char * p1,char * p2,int line,int pos)213 _put_anchor_all(Buffer *buf, char *p1, char *p2, int line, int pos)
214 {
215 Str tmp;
216
217 tmp = Strnew_charp_n(p1, p2 - p1);
218 return registerHref(buf, url_encode(tmp->ptr, baseURL(buf),
219 buf->document_charset),
220 NULL, NO_REFERER, NULL,
221 '\0', line, pos);
222 }
223
224 static void
reseq_anchor0(AnchorList * al,short * seqmap)225 reseq_anchor0(AnchorList *al, short *seqmap)
226 {
227 int i;
228 Anchor *a;
229
230 if (!al)
231 return;
232
233 for (i = 0; i < al->nanchor; i++) {
234 a = &al->anchors[i];
235 if (a->hseq >= 0) {
236 a->hseq = seqmap[a->hseq];
237 }
238 }
239 }
240
241 /* renumber anchor */
242 static void
reseq_anchor(Buffer * buf)243 reseq_anchor(Buffer *buf)
244 {
245 int i, j, n, nmark = (buf->hmarklist) ? buf->hmarklist->nmark : 0;
246 short *seqmap;
247 Anchor *a, *a1;
248 HmarkerList *ml = NULL;
249
250 if (!buf->href)
251 return;
252
253 n = nmark;
254 for (i = 0; i < buf->href->nanchor; i++) {
255 a = &buf->href->anchors[i];
256 if (a->hseq == -2)
257 n++;
258 }
259
260 if (n == nmark)
261 return;
262
263 seqmap = NewAtom_N(short, n);
264
265 for (i = 0; i < n; i++)
266 seqmap[i] = i;
267
268 n = nmark;
269 for (i = 0; i < buf->href->nanchor; i++) {
270 a = &buf->href->anchors[i];
271 if (a->hseq == -2) {
272 a->hseq = n;
273 a1 = closest_next_anchor(buf->href, NULL, a->start.pos,
274 a->start.line);
275 a1 = closest_next_anchor(buf->formitem, a1, a->start.pos,
276 a->start.line);
277 if (a1 && a1->hseq >= 0) {
278 seqmap[n] = seqmap[a1->hseq];
279 for (j = a1->hseq; j < nmark; j++)
280 seqmap[j]++;
281 }
282 ml = putHmarker(ml, a->start.line, a->start.pos, seqmap[n]);
283 n++;
284 }
285 }
286
287 for (i = 0; i < nmark; i++) {
288 ml = putHmarker(ml, buf->hmarklist->marks[i].line,
289 buf->hmarklist->marks[i].pos, seqmap[i]);
290 }
291 buf->hmarklist = ml;
292
293 reseq_anchor0(buf->href, seqmap);
294 reseq_anchor0(buf->formitem, seqmap);
295 }
296
297 static char *
reAnchorPos(Buffer * buf,Line * l,char * p1,char * p2,Anchor * (* anchorproc)(Buffer *,char *,char *,int,int))298 reAnchorPos(Buffer *buf, Line *l, char *p1, char *p2,
299 Anchor *(*anchorproc) (Buffer *, char *, char *, int, int))
300 {
301 Anchor *a;
302 int spos, epos;
303 int i, hseq = -2;
304
305 spos = p1 - l->lineBuf;
306 epos = p2 - l->lineBuf;
307 for (i = spos; i < epos; i++) {
308 if (l->propBuf[i] & (PE_ANCHOR | PE_FORM))
309 return p2;
310 }
311 for (i = spos; i < epos; i++)
312 l->propBuf[i] |= PE_ANCHOR;
313 while (spos > l->len && l->next && l->next->bpos) {
314 spos -= l->len;
315 epos -= l->len;
316 l = l->next;
317 }
318 while (1) {
319 a = anchorproc(buf, p1, p2, l->linenumber, spos);
320 a->hseq = hseq;
321 if (hseq == -2) {
322 reseq_anchor(buf);
323 hseq = a->hseq;
324 }
325 a->end.line = l->linenumber;
326 if (epos > l->len && l->next && l->next->bpos) {
327 a->end.pos = l->len;
328 spos = 0;
329 epos -= l->len;
330 l = l->next;
331 }
332 else {
333 a->end.pos = epos;
334 break;
335 }
336 }
337 return p2;
338 }
339
340 void
reAnchorWord(Buffer * buf,Line * l,int spos,int epos)341 reAnchorWord(Buffer *buf, Line *l, int spos, int epos)
342 {
343 reAnchorPos(buf, l, &l->lineBuf[spos], &l->lineBuf[epos], _put_anchor_all);
344 }
345
346 /* search regexp and register them as anchors */
347 /* returns error message if any */
348 static char *
reAnchorAny(Buffer * buf,char * re,Anchor * (* anchorproc)(Buffer *,char *,char *,int,int))349 reAnchorAny(Buffer *buf, char *re,
350 Anchor *(*anchorproc) (Buffer *, char *, char *, int, int))
351 {
352 Line *l;
353 char *p = NULL, *p1, *p2;
354
355 if (re == NULL || *re == '\0') {
356 return NULL;
357 }
358 if ((re = regexCompile(re, 1)) != NULL) {
359 return re;
360 }
361 for (l = MarkAllPages ? buf->firstLine : buf->topLine; l != NULL &&
362 (MarkAllPages || l->linenumber < buf->topLine->linenumber + LASTLINE);
363 l = l->next) {
364 if (p && l->bpos)
365 goto next_line;
366 p = l->lineBuf;
367 for (;;) {
368 if (regexMatch(p, &l->lineBuf[l->size] - p, p == l->lineBuf) == 1) {
369 matchedPosition(&p1, &p2);
370 p = reAnchorPos(buf, l, p1, p2, anchorproc);
371 }
372 else
373 break;
374 }
375 next_line:
376 if (MarkAllPages && l->next == NULL && buf->pagerSource &&
377 !(buf->bufferprop & BP_CLOSE))
378 getNextPage(buf, PagerMax);
379 }
380 return NULL;
381 }
382
383 char *
reAnchor(Buffer * buf,char * re)384 reAnchor(Buffer *buf, char *re)
385 {
386 return reAnchorAny(buf, re, _put_anchor_all);
387 }
388
389 #ifdef USE_NNTP
390 char *
reAnchorNews(Buffer * buf,char * re)391 reAnchorNews(Buffer *buf, char *re)
392 {
393 return reAnchorAny(buf, re, _put_anchor_news);
394 }
395
396 char *
reAnchorNewsheader(Buffer * buf)397 reAnchorNewsheader(Buffer *buf)
398 {
399 Line *l;
400 char *p, *p1, *p2;
401 static char *header_mid[] = {
402 "Message-Id:", "References:", "In-Reply-To:", NULL
403 };
404 static char *header_group[] = {
405 "Newsgroups:", NULL
406 };
407 char **header, **q;
408 int i, search = FALSE;
409
410 if (!buf || !buf->firstLine)
411 return NULL;
412 for (i = 0; i <= 1; i++) {
413 if (i == 0) {
414 regexCompile("<[!-;=?-~]+@[a-zA-Z0-9\\.\\-_]+>", 1);
415 header = header_mid;
416 }
417 else {
418 regexCompile("[a-zA-Z0-9\\.\\-_]+", 1);
419 header = header_group;
420 }
421 for (l = buf->firstLine; l != NULL && l->real_linenumber == 0;
422 l = l->next) {
423 if (l->bpos)
424 continue;
425 p = l->lineBuf;
426 if (!IS_SPACE(*p)) {
427 search = FALSE;
428 for (q = header; *q; q++) {
429 if (!strncasecmp(p, *q, strlen(*q))) {
430 search = TRUE;
431 p = strchr(p, ':') + 1;
432 break;
433 }
434 }
435 }
436 if (!search)
437 continue;
438 for (;;) {
439 if (regexMatch(p, &l->lineBuf[l->size] - p, p == l->lineBuf)
440 == 1) {
441 matchedPosition(&p1, &p2);
442 p = reAnchorPos(buf, l, p1, p2, _put_anchor_news);
443 }
444 else
445 break;
446 }
447 }
448 }
449 reseq_anchor(buf);
450 return NULL;
451 }
452 #endif /* USE_NNTP */
453
454 #define FIRST_MARKER_SIZE 30
455 HmarkerList *
putHmarker(HmarkerList * ml,int line,int pos,int seq)456 putHmarker(HmarkerList *ml, int line, int pos, int seq)
457 {
458 if (ml == NULL) {
459 ml = New(HmarkerList);
460 ml->marks = NULL;
461 ml->nmark = 0;
462 ml->markmax = 0;
463 ml->prevhseq = -1;
464 }
465 if (ml->markmax == 0) {
466 ml->markmax = FIRST_MARKER_SIZE;
467 ml->marks = NewAtom_N(BufferPoint, ml->markmax);
468 bzero(ml->marks, sizeof(BufferPoint) * ml->markmax);
469 }
470 if (seq + 1 > ml->nmark)
471 ml->nmark = seq + 1;
472 if (ml->nmark >= ml->markmax) {
473 ml->markmax = ml->nmark * 2;
474 ml->marks = New_Reuse(BufferPoint, ml->marks, ml->markmax);
475 }
476 ml->marks[seq].line = line;
477 ml->marks[seq].pos = pos;
478 ml->marks[seq].invalid = 0;
479 return ml;
480 }
481
482 Anchor *
closest_next_anchor(AnchorList * a,Anchor * an,int x,int y)483 closest_next_anchor(AnchorList *a, Anchor *an, int x, int y)
484 {
485 int i;
486
487 if (a == NULL || a->nanchor == 0)
488 return an;
489 for (i = 0; i < a->nanchor; i++) {
490 if (a->anchors[i].hseq < 0)
491 continue;
492 if (a->anchors[i].start.line > y ||
493 (a->anchors[i].start.line == y && a->anchors[i].start.pos > x)) {
494 if (an == NULL || an->start.line > a->anchors[i].start.line ||
495 (an->start.line == a->anchors[i].start.line &&
496 an->start.pos > a->anchors[i].start.pos))
497 an = &a->anchors[i];
498 }
499 }
500 return an;
501 }
502
503 Anchor *
closest_prev_anchor(AnchorList * a,Anchor * an,int x,int y)504 closest_prev_anchor(AnchorList *a, Anchor *an, int x, int y)
505 {
506 int i;
507
508 if (a == NULL || a->nanchor == 0)
509 return an;
510 for (i = 0; i < a->nanchor; i++) {
511 if (a->anchors[i].hseq < 0)
512 continue;
513 if (a->anchors[i].end.line < y ||
514 (a->anchors[i].end.line == y && a->anchors[i].end.pos <= x)) {
515 if (an == NULL || an->end.line < a->anchors[i].end.line ||
516 (an->end.line == a->anchors[i].end.line &&
517 an->end.pos < a->anchors[i].end.pos))
518 an = &a->anchors[i];
519 }
520 }
521 return an;
522 }
523
524 void
shiftAnchorPosition(AnchorList * al,HmarkerList * hl,int line,int pos,int shift)525 shiftAnchorPosition(AnchorList *al, HmarkerList *hl, int line, int pos,
526 int shift)
527 {
528 Anchor *a;
529 size_t b, e, s = 0;
530 int cmp;
531
532 if (al == NULL || al->nanchor == 0)
533 return;
534
535 s = al->nanchor / 2;
536 for (b = 0, e = al->nanchor - 1; b <= e; s = (b + e + 1) / 2) {
537 a = &al->anchors[s];
538 cmp = onAnchor(a, line, pos);
539 if (cmp == 0)
540 break;
541 else if (cmp > 0)
542 b = s + 1;
543 else if (s == 0)
544 break;
545 else
546 e = s - 1;
547 }
548 for (; s < al->nanchor; s++) {
549 a = &al->anchors[s];
550 if (a->start.line > line)
551 break;
552 if (a->start.pos > pos) {
553 a->start.pos += shift;
554 if (hl && hl->marks &&
555 a->hseq >= 0 && hl->marks[a->hseq].line == line)
556 hl->marks[a->hseq].pos = a->start.pos;
557 }
558 if (a->end.pos >= pos)
559 a->end.pos += shift;
560 }
561 }
562
563 #ifdef USE_IMAGE
564 void
addMultirowsImg(Buffer * buf,AnchorList * al)565 addMultirowsImg(Buffer *buf, AnchorList *al)
566 {
567 int i, j, k, col, ecol, pos;
568 Image *img;
569 Anchor a_img, a_href, a_form, *a;
570 Line *l, *ls;
571
572 if (al == NULL || al->nanchor == 0)
573 return;
574 for (i = 0; i < al->nanchor; i++) {
575 a_img = al->anchors[i];
576 img = a_img.image;
577 if (a_img.hseq < 0 || !img || img->rows <= 1)
578 continue;
579 for (l = buf->firstLine; l != NULL; l = l->next) {
580 if (l->linenumber == img->y)
581 break;
582 }
583 if (!l)
584 continue;
585 if (a_img.y == a_img.start.line)
586 ls = l;
587 else {
588 for (ls = l; ls != NULL;
589 ls = (a_img.y < a_img.start.line) ? ls->next : ls->prev) {
590 if (ls->linenumber == a_img.start.line)
591 break;
592 }
593 if (!ls)
594 continue;
595 }
596 a = retrieveAnchor(buf->href, a_img.start.line, a_img.start.pos);
597 if (a)
598 a_href = *a;
599 else
600 a_href.url = NULL;
601 a = retrieveAnchor(buf->formitem, a_img.start.line, a_img.start.pos);
602 if (a)
603 a_form = *a;
604 else
605 a_form.url = NULL;
606 col = COLPOS(ls, a_img.start.pos);
607 ecol = COLPOS(ls, a_img.end.pos);
608 for (j = 0; l && j < img->rows; l = l->next, j++) {
609 if (a_img.start.line == l->linenumber)
610 continue;
611 pos = columnPos(l, col);
612 a = registerImg(buf, a_img.url, a_img.title, l->linenumber, pos);
613 a->hseq = -a_img.hseq;
614 a->slave = TRUE;
615 a->image = img;
616 a->end.pos = pos + ecol - col;
617 for (k = pos; k < a->end.pos; k++)
618 l->propBuf[k] |= PE_IMAGE;
619 if (a_href.url) {
620 a = registerHref(buf, a_href.url, a_href.target,
621 a_href.referer, a_href.title,
622 a_href.accesskey, l->linenumber, pos);
623 a->hseq = a_href.hseq;
624 a->slave = TRUE;
625 a->end.pos = pos + ecol - col;
626 for (k = pos; k < a->end.pos; k++)
627 l->propBuf[k] |= PE_ANCHOR;
628 }
629 if (a_form.url) {
630 buf->formitem = putAnchor(buf->formitem, a_form.url,
631 a_form.target, &a, NULL, NULL, '\0',
632 l->linenumber, pos);
633 a->hseq = a_form.hseq;
634 a->end.pos = pos + ecol - col;
635 }
636 }
637 img->rows = 0;
638 }
639 }
640 #endif
641
642 void
addMultirowsForm(Buffer * buf,AnchorList * al)643 addMultirowsForm(Buffer *buf, AnchorList *al)
644 {
645 int i, j, k, col, ecol, pos;
646 Anchor a_form, *a;
647 Line *l, *ls;
648
649 if (al == NULL || al->nanchor == 0)
650 return;
651 for (i = 0; i < al->nanchor; i++) {
652 a_form = al->anchors[i];
653 al->anchors[i].rows = 1;
654 if (a_form.hseq < 0 || a_form.rows <= 1)
655 continue;
656 for (l = buf->firstLine; l != NULL; l = l->next) {
657 if (l->linenumber == a_form.y)
658 break;
659 }
660 if (!l)
661 continue;
662 if (a_form.y == a_form.start.line)
663 ls = l;
664 else {
665 for (ls = l; ls != NULL;
666 ls = (a_form.y < a_form.start.line) ? ls->next : ls->prev) {
667 if (ls->linenumber == a_form.start.line)
668 break;
669 }
670 if (!ls)
671 continue;
672 }
673 col = COLPOS(ls, a_form.start.pos);
674 ecol = COLPOS(ls, a_form.end.pos);
675 for (j = 0; l && j < a_form.rows; l = l->next, j++) {
676 pos = columnPos(l, col);
677 if (j == 0) {
678 buf->hmarklist->marks[a_form.hseq].line = l->linenumber;
679 buf->hmarklist->marks[a_form.hseq].pos = pos;
680 }
681 if (a_form.start.line == l->linenumber)
682 continue;
683 buf->formitem = putAnchor(buf->formitem, a_form.url,
684 a_form.target, &a, NULL, NULL, '\0',
685 l->linenumber, pos);
686 a->hseq = a_form.hseq;
687 a->y = a_form.y;
688 a->end.pos = pos + ecol - col;
689 if (pos < 1 || a->end.pos >= l->size)
690 continue;
691 l->lineBuf[pos - 1] = '[';
692 l->lineBuf[a->end.pos] = ']';
693 for (k = pos; k < a->end.pos; k++)
694 l->propBuf[k] |= PE_FORM;
695 }
696 }
697 }
698
699 char *
getAnchorText(Buffer * buf,AnchorList * al,Anchor * a)700 getAnchorText(Buffer *buf, AnchorList *al, Anchor *a)
701 {
702 int hseq, i;
703 Line *l;
704 Str tmp = NULL;
705 char *p, *ep;
706
707 if (!a || a->hseq < 0)
708 return NULL;
709 hseq = a->hseq;
710 l = buf->firstLine;
711 for (i = 0; i < al->nanchor; i++) {
712 a = &al->anchors[i];
713 if (a->hseq != hseq)
714 continue;
715 for (; l; l = l->next) {
716 if (l->linenumber == a->start.line)
717 break;
718 }
719 if (!l)
720 break;
721 p = l->lineBuf + a->start.pos;
722 ep = l->lineBuf + a->end.pos;
723 for (; p < ep && IS_SPACE(*p); p++) ;
724 if (p == ep)
725 continue;
726 if (!tmp)
727 tmp = Strnew_size(ep - p);
728 else
729 Strcat_char(tmp, ' ');
730 Strcat_charp_n(tmp, p, ep - p);
731 }
732 return tmp ? tmp->ptr : NULL;
733 }
734
735 Buffer *
link_list_panel(Buffer * buf)736 link_list_panel(Buffer *buf)
737 {
738 LinkList *l;
739 AnchorList *al;
740 Anchor *a;
741 FormItemList *fi;
742 int i;
743 char *t, *u, *p;
744 ParsedURL pu;
745 /* FIXME: gettextize? */
746 Str tmp = Strnew_charp("<title>Link List</title>\
747 <h1 align=center>Link List</h1>\n");
748
749 if (buf->bufferprop & BP_INTERNAL ||
750 (buf->linklist == NULL && buf->href == NULL && buf->img == NULL)) {
751 return NULL;
752 }
753
754 if (buf->linklist) {
755 Strcat_charp(tmp, "<hr><h2>Links</h2>\n<ol>\n");
756 for (l = buf->linklist; l; l = l->next) {
757 if (l->url) {
758 parseURL2(l->url, &pu, baseURL(buf));
759 p = parsedURL2Str(&pu)->ptr;
760 u = html_quote(p);
761 if (DecodeURL)
762 p = html_quote(url_decode2(p, buf));
763 else
764 p = u;
765 }
766 else
767 u = p = "";
768 if (l->type == LINK_TYPE_REL)
769 t = " [Rel]";
770 else if (l->type == LINK_TYPE_REV)
771 t = " [Rev]";
772 else
773 t = "";
774 t = Sprintf("%s%s\n", l->title ? l->title : "", t)->ptr;
775 t = html_quote(t);
776 Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t, "</a><br>", p,
777 "\n", NULL);
778 }
779 Strcat_charp(tmp, "</ol>\n");
780 }
781
782 if (buf->href) {
783 Strcat_charp(tmp, "<hr><h2>Anchors</h2>\n<ol>\n");
784 al = buf->href;
785 for (i = 0; i < al->nanchor; i++) {
786 a = &al->anchors[i];
787 if (a->hseq < 0 || a->slave)
788 continue;
789 parseURL2(a->url, &pu, baseURL(buf));
790 p = parsedURL2Str(&pu)->ptr;
791 u = html_quote(p);
792 if (DecodeURL)
793 p = html_quote(url_decode2(p, buf));
794 else
795 p = u;
796 t = getAnchorText(buf, al, a);
797 t = t ? html_quote(t) : "";
798 Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t, "</a><br>", p,
799 "\n", NULL);
800 }
801 Strcat_charp(tmp, "</ol>\n");
802 }
803
804 if (buf->img) {
805 Strcat_charp(tmp, "<hr><h2>Images</h2>\n<ol>\n");
806 al = buf->img;
807 for (i = 0; i < al->nanchor; i++) {
808 a = &al->anchors[i];
809 if (a->slave)
810 continue;
811 parseURL2(a->url, &pu, baseURL(buf));
812 p = parsedURL2Str(&pu)->ptr;
813 u = html_quote(p);
814 if (DecodeURL)
815 p = html_quote(url_decode2(p, buf));
816 else
817 p = u;
818 if (a->title && *a->title)
819 t = html_quote(a->title);
820 else
821 t = html_quote(url_decode2(a->url, buf));
822 Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t, "</a><br>", p,
823 "\n", NULL);
824 a = retrieveAnchor(buf->formitem, a->start.line, a->start.pos);
825 if (!a)
826 continue;
827 fi = (FormItemList *)a->url;
828 fi = fi->parent->item;
829 if (fi->parent->method == FORM_METHOD_INTERNAL &&
830 !Strcmp_charp(fi->parent->action, "map") && fi->value) {
831 MapList *ml = searchMapList(buf, fi->value->ptr);
832 ListItem *mi;
833 MapArea *m;
834 if (!ml)
835 continue;
836 Strcat_charp(tmp, "<br>\n<b>Image map</b>\n<ol>\n");
837 for (mi = ml->area->first; mi != NULL; mi = mi->next) {
838 m = (MapArea *) mi->ptr;
839 if (!m)
840 continue;
841 parseURL2(m->url, &pu, baseURL(buf));
842 p = parsedURL2Str(&pu)->ptr;
843 u = html_quote(p);
844 if (DecodeURL)
845 p = html_quote(url_decode2(p, buf));
846 else
847 p = u;
848 if (m->alt && *m->alt)
849 t = html_quote(m->alt);
850 else
851 t = html_quote(url_decode2(m->url, buf));
852 Strcat_m_charp(tmp, "<li><a href=\"", u, "\">", t,
853 "</a><br>", p, "\n", NULL);
854 }
855 Strcat_charp(tmp, "</ol>\n");
856 }
857 }
858 Strcat_charp(tmp, "</ol>\n");
859 }
860
861 return loadHTMLString(tmp);
862 }
863