Intial commit
[profile/ivi/w3m.git] / frame.c
1 /* $Id: frame.c,v 1.34 2003/09/26 17:59:51 ukai Exp $ */
2 #include "fm.h"
3 #include "parsetagx.h"
4 #include "myctype.h"
5 #include <signal.h>
6 #include <setjmp.h>
7
8 static JMP_BUF AbortLoading;
9 struct frameset *renderFrameSet = NULL;
10
11 static MySignalHandler
12 KeyAbort(SIGNAL_ARG)
13 {
14     LONGJMP(AbortLoading, 1);
15 }
16
17 static int
18 parseFrameSetLength(char *s, char ***ret)
19 {
20     int i, len;
21     char *p, *q, **lv;
22
23     i = 1;
24
25     if (s)
26         for (p = s; (p = strchr(p, ',')); ++p)
27             ++i;
28     else
29         s = "*";
30
31     lv = New_N(char *, i);
32
33     for (i = 0, p = s;; ++p) {
34         SKIP_BLANKS(p);
35         len = strtol(p, &q, 10);
36
37         switch (*q) {
38         case '%':
39             lv[i++] = Sprintf("%d%%", len)->ptr;
40             break;
41         case '*':
42             lv[i++] = "*";
43             break;
44         default:
45             lv[i++] = Sprintf("%d", len)->ptr;
46             break;
47         }
48
49         if (!(p = strchr(q, ',')))
50             break;
51     }
52
53     *ret = lv;
54     return i;
55 }
56
57 struct frameset *
58 newFrameSet(struct parsed_tag *tag)
59 {
60     struct frameset *f;
61     int i;
62     char *cols = NULL, *rows = NULL;
63
64     f = New(struct frameset);
65     f->attr = F_FRAMESET;
66     f->name = NULL;
67     f->currentURL = NULL;
68     parsedtag_get_value(tag, ATTR_COLS, &cols);
69     parsedtag_get_value(tag, ATTR_ROWS, &rows);
70     f->col = parseFrameSetLength(cols, &f->width);
71     f->row = parseFrameSetLength(rows, &f->height);
72     f->i = 0;
73     i = f->row * f->col;
74     f->frame = New_N(union frameset_element, i);
75     do {
76         f->frame[--i].element = NULL;
77     } while (i);
78     return f;
79 }
80
81 struct frame_body *
82 newFrame(struct parsed_tag *tag, Buffer *buf)
83 {
84     struct frame_body *body;
85     char *p;
86
87     body = New(struct frame_body);
88     bzero((void *)body, sizeof(*body));
89     body->attr = F_UNLOADED;
90     body->flags = 0;
91     body->baseURL = baseURL(buf);
92     if (tag) {
93         if (parsedtag_get_value(tag, ATTR_SRC, &p))
94             body->url = url_quote_conv(remove_space(p), buf->document_charset);
95         if (parsedtag_get_value(tag, ATTR_NAME, &p) && *p != '_')
96             body->name = url_quote_conv(p, buf->document_charset);
97     }
98     return body;
99 }
100
101 static void
102 unloadFrame(struct frame_body *b)
103 {
104     b->attr = F_UNLOADED;
105 }
106
107 void
108 deleteFrame(struct frame_body *b)
109 {
110     if (b == NULL)
111         return;
112     unloadFrame(b);
113     bzero((void *)b, sizeof(*b));
114 }
115
116 void
117 addFrameSetElement(struct frameset *f, union frameset_element element)
118 {
119     int i;
120
121     if (f == NULL)
122         return;
123     i = f->i;
124     if (i >= f->col * f->row)
125         return;
126     f->frame[i] = element;
127     f->i++;
128 }
129
130 void
131 deleteFrameSet(struct frameset *f)
132 {
133     int i;
134
135     if (f == NULL)
136         return;
137     for (i = 0; i < f->col * f->row; i++) {
138         deleteFrameSetElement(f->frame[i]);
139     }
140     f->name = NULL;
141     f->currentURL = NULL;
142     return;
143 }
144
145 void
146 deleteFrameSetElement(union frameset_element e)
147 {
148     if (e.element == NULL)
149         return;
150     switch (e.element->attr) {
151     case F_UNLOADED:
152         break;
153     case F_BODY:
154         deleteFrame(e.body);
155         break;
156     case F_FRAMESET:
157         deleteFrameSet(e.set);
158         break;
159     default:
160         break;
161     }
162     return;
163 }
164
165 static struct frame_body *
166 copyFrame(struct frame_body *ob)
167 {
168     struct frame_body *rb;
169
170     rb = New(struct frame_body);
171     bcopy((const void *)ob, (void *)rb, sizeof(struct frame_body));
172     return rb;
173 }
174
175 struct frameset *
176 copyFrameSet(struct frameset *of)
177 {
178     struct frameset *rf;
179     int n;
180
181     rf = New(struct frameset);
182     n = of->col * of->row;
183     bcopy((const void *)of, (void *)rf, sizeof(struct frameset));
184     rf->width = New_N(char *, rf->col);
185     bcopy((const void *)of->width,
186           (void *)rf->width, sizeof(char *) * rf->col);
187     rf->height = New_N(char *, rf->row);
188     bcopy((const void *)of->height,
189           (void *)rf->height, sizeof(char *) * rf->row);
190     rf->frame = New_N(union frameset_element, n);
191     while (n) {
192         n--;
193         if (!of->frame[n].element)
194             goto attr_default;
195         switch (of->frame[n].element->attr) {
196         case F_UNLOADED:
197         case F_BODY:
198             rf->frame[n].body = copyFrame(of->frame[n].body);
199             break;
200         case F_FRAMESET:
201             rf->frame[n].set = copyFrameSet(of->frame[n].set);
202             break;
203         default:
204           attr_default:
205             rf->frame[n].element = NULL;
206             break;
207         }
208     }
209     return rf;
210 }
211
212 void
213 flushFrameSet(struct frameset *fs)
214 {
215     int n = fs->i;
216
217     while (n) {
218         n--;
219         if (!fs->frame[n].element)
220             goto attr_default;
221         switch (fs->frame[n].element->attr) {
222         case F_UNLOADED:
223         case F_BODY:
224             fs->frame[n].body->nameList = NULL;
225             break;
226         case F_FRAMESET:
227             flushFrameSet(fs->frame[n].set);
228             break;
229         default:
230           attr_default:
231             /* nothing to do */
232             break;
233         }
234     }
235 }
236
237 void
238 pushFrameTree(struct frameset_queue **fqpp, struct frameset *fs, Buffer *buf)
239 {
240     struct frameset_queue *rfq, *cfq = *fqpp;
241
242     if (!fs)
243         return;
244
245     rfq = New(struct frameset_queue);
246     rfq->linenumber = (buf
247                        && buf->currentLine) ? buf->currentLine->linenumber : 1;
248     rfq->top_linenumber = (buf && buf->topLine) ? buf->topLine->linenumber : 1;
249     rfq->pos = buf ? buf->pos : 0;
250     rfq->currentColumn = buf ? buf->currentColumn : 0;
251     rfq->formitem = buf ? buf->formitem : NULL;
252
253     rfq->back = cfq;
254     if (cfq) {
255         rfq->next = cfq->next;
256         if (cfq->next)
257             cfq->next->back = rfq;
258         cfq->next = rfq;
259     }
260     else
261         rfq->next = cfq;
262     rfq->frameset = fs;
263     *fqpp = rfq;
264     return;
265 }
266
267 struct frameset *
268 popFrameTree(struct frameset_queue **fqpp)
269 {
270     struct frameset_queue *rfq = NULL, *cfq = *fqpp;
271     struct frameset *rfs = NULL;
272
273     if (!cfq)
274         return rfs;
275
276     rfs = cfq->frameset;
277     if (cfq->next) {
278         (rfq = cfq->next)->back = cfq->back;
279     }
280     if (cfq->back) {
281         (rfq = cfq->back)->next = cfq->next;
282     }
283     *fqpp = rfq;
284     bzero((void *)cfq, sizeof(struct frameset_queue));
285     return rfs;
286 }
287
288 void
289 resetFrameElement(union frameset_element *f_element,
290                   Buffer *buf, char *referer, FormList *request)
291 {
292     char *f_name;
293     struct frame_body *f_body;
294
295     f_name = f_element->element->name;
296     if (buf->frameset) {
297         /* frame cascade */
298         deleteFrameSetElement(*f_element);
299         f_element->set = buf->frameset;
300         f_element->set->currentURL = New(ParsedURL);
301         copyParsedURL(f_element->set->currentURL, &buf->currentURL);
302         buf->frameset = popFrameTree(&(buf->frameQ));
303         f_element->set->name = f_name;
304     }
305     else {
306         f_body = newFrame(NULL, buf);
307         f_body->attr = F_BODY;
308         f_body->name = f_name;
309         f_body->url = parsedURL2Str(&buf->currentURL)->ptr;
310         f_body->source = buf->sourcefile;
311         buf->sourcefile = NULL;
312         if (buf->mailcap_source) {
313             f_body->source = buf->mailcap_source;
314             buf->mailcap_source = NULL;
315         }
316         f_body->type = buf->type;
317         f_body->referer = referer;
318         f_body->request = request;
319         deleteFrameSetElement(*f_element);
320         f_element->body = f_body;
321     }
322 }
323
324 static struct frameset *
325 frame_download_source(struct frame_body *b, ParsedURL *currentURL,
326                       ParsedURL *baseURL, int flag)
327 {
328     Buffer *buf;
329     struct frameset *ret_frameset = NULL;
330     ParsedURL url;
331
332     if (b == NULL || b->url == NULL || b->url[0] == '\0')
333         return NULL;
334     if (b->baseURL)
335         baseURL = b->baseURL;
336     parseURL2(b->url, &url, currentURL);
337     switch (url.scheme) {
338     case SCM_LOCAL:
339 #if 0
340         b->source = url.real_file;
341 #endif
342         b->flags = 0;
343     default:
344         is_redisplay = TRUE;
345         w3m_dump |= DUMP_FRAME;
346         buf = loadGeneralFile(b->url,
347                               baseURL ? baseURL : currentURL,
348                               b->referer, flag | RG_FRAME_SRC, b->request);
349 #ifdef USE_SSL
350         /* XXX certificate? */
351         if (buf && buf != NO_BUFFER)
352             b->ssl_certificate = buf->ssl_certificate;
353 #endif
354         w3m_dump &= ~DUMP_FRAME;
355         is_redisplay = FALSE;
356         break;
357     }
358
359     if (buf == NULL || buf == NO_BUFFER) {
360         b->source = NULL;
361         b->flags = (buf == NO_BUFFER) ? FB_NO_BUFFER : 0;
362         return NULL;
363     }
364     b->url = parsedURL2Str(&buf->currentURL)->ptr;
365     b->type = buf->type;
366     b->source = buf->sourcefile;
367     buf->sourcefile = NULL;
368     if (buf->mailcap_source) {
369         b->source = buf->mailcap_source;
370         buf->mailcap_source = NULL;
371     }
372     b->attr = F_BODY;
373     if (buf->frameset) {
374         ret_frameset = buf->frameset;
375         ret_frameset->name = b->name;
376         ret_frameset->currentURL = New(ParsedURL);
377         copyParsedURL(ret_frameset->currentURL, &buf->currentURL);
378         buf->frameset = popFrameTree(&(buf->frameQ));
379     }
380     discardBuffer(buf);
381     return ret_frameset;
382 }
383
384 #define CASE_TABLE_TAG \
385         case HTML_TR:\
386         case HTML_N_TR:\
387         case HTML_TD:\
388         case HTML_N_TD:\
389         case HTML_TH:\
390         case HTML_N_TH:\
391         case HTML_THEAD:\
392         case HTML_N_THEAD:\
393         case HTML_TBODY:\
394         case HTML_N_TBODY:\
395         case HTML_TFOOT:\
396         case HTML_N_TFOOT:\
397         case HTML_COLGROUP:\
398         case HTML_N_COLGROUP:\
399         case HTML_COL
400
401 static int
402 createFrameFile(struct frameset *f, FILE * f1, Buffer *current, int level,
403                 int force_reload)
404 {
405     int r, c, t_stack;
406     URLFile f2;
407 #ifdef USE_M17N
408     wc_ces charset, doc_charset;
409 #endif
410     char *d_target, *p_target, *s_target, *t_target;
411     ParsedURL *currentURL, base;
412     MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
413     int flag;
414
415     if (f == NULL)
416         return -1;
417
418     if (level == 0) {
419         if (SETJMP(AbortLoading) != 0) {
420             TRAP_OFF;
421             return -1;
422         }
423         TRAP_ON;
424         f->name = "_top";
425     }
426
427     if (level > 7) {
428         fputs("Too many frameset tasked.\n", f1);
429         return -1;
430     }
431
432     if (level == 0) {
433         fprintf(f1, "<html><head><title>%s</title></head><body>\n",
434                 html_quote(current->buffername));
435         fputs("<table hborder width=\"100%\">\n", f1);
436     }
437     else
438         fputs("<table hborder>\n", f1);
439
440     currentURL = f->currentURL ? f->currentURL : &current->currentURL;
441     for (r = 0; r < f->row; r++) {
442         fputs("<tr valign=top>\n", f1);
443         for (c = 0; c < f->col; c++) {
444             union frameset_element frame;
445             struct frameset *f_frameset;
446             int i = c + r * f->col;
447             char *p = "";
448             int status = R_ST_NORMAL;
449             Str tok = Strnew();
450             int pre_mode = 0;
451             int end_tag = 0;
452
453             frame = f->frame[i];
454
455             if (frame.element == NULL) {
456                 fputs("<td>\n</td>\n", f1);
457                 continue;
458             }
459
460             fputs("<td", f1);
461             if (frame.element->name)
462                 fprintf(f1, " id=\"_%s\"", html_quote(frame.element->name));
463             if (!r)
464                 fprintf(f1, " width=\"%s\"", f->width[c]);
465             fputs(">\n", f1);
466
467             flag = 0;
468             if (force_reload) {
469                 flag |= RG_NOCACHE;
470                 if (frame.element->attr == F_BODY)
471                     unloadFrame(frame.body);
472             }
473             switch (frame.element->attr) {
474             default:
475                 /* FIXME: gettextize? */
476                 fprintf(f1, "Frameset \"%s\" frame %d: type unrecognized",
477                         html_quote(f->name), i + 1);
478                 break;
479             case F_UNLOADED:
480                 if (!frame.body->name && f->name) {
481                     frame.body->name = Sprintf("%s_%d", f->name, i)->ptr;
482                 }
483                 fflush(f1);
484                 f_frameset = frame_download_source(frame.body,
485                                                    currentURL,
486                                                    current->baseURL, flag);
487                 if (f_frameset) {
488                     deleteFrame(frame.body);
489                     f->frame[i].set = frame.set = f_frameset;
490                     goto render_frameset;
491                 }
492                 /* fall through */
493             case F_BODY:
494                 init_stream(&f2, SCM_LOCAL, NULL);
495                 if (frame.body->source) {
496                     fflush(f1);
497                     examineFile(frame.body->source, &f2);
498                 }
499                 if (f2.stream == NULL) {
500                     frame.body->attr = F_UNLOADED;
501                     if (frame.body->flags & FB_NO_BUFFER)
502                         /* FIXME: gettextize? */
503                         fprintf(f1, "Open %s with other method",
504                                 html_quote(frame.body->url));
505                     else if (frame.body->url)
506                         /* FIXME: gettextize? */
507                         fprintf(f1, "Can't open %s",
508                                 html_quote(frame.body->url));
509                     else
510                         /* FIXME: gettextize? */
511                         fprintf(f1,
512                                 "This frame (%s) contains no src attribute",
513                                 frame.body->name ? html_quote(frame.body->name)
514                                 : "(no name)");
515                     break;
516                 }
517                 parseURL2(frame.body->url, &base, currentURL);
518                 p_target = f->name;
519                 s_target = frame.body->name;
520                 t_target = "_blank";
521                 d_target = TargetSelf ? s_target : t_target;
522 #ifdef USE_M17N
523                 charset = WC_CES_US_ASCII;
524                 if (current->document_charset != WC_CES_US_ASCII)
525                     doc_charset = current->document_charset;
526                 else
527                     doc_charset = DocumentCharset;
528 #endif
529                 t_stack = 0;
530                 if (frame.body->type &&
531                     !strcasecmp(frame.body->type, "text/plain")) {
532                     Str tmp;
533                     fprintf(f1, "<pre>\n");
534                     while ((tmp = StrmyUFgets(&f2))->length) {
535                         tmp = convertLine(NULL, tmp, HTML_MODE, &charset,
536                                           doc_charset);
537                         fprintf(f1, "%s", html_quote(tmp->ptr));
538                     }
539                     fprintf(f1, "</pre>\n");
540                     UFclose(&f2);
541                     break;
542                 }
543                 do {
544                     int is_tag = FALSE;
545                     char *q;
546                     struct parsed_tag *tag;
547
548                     do {
549                         if (*p == '\0') {
550                             Str tmp = StrmyUFgets(&f2);
551                             if (tmp->length == 0)
552                                 break;
553                             tmp = convertLine(NULL, tmp, HTML_MODE, &charset,
554                                               doc_charset);
555                             p = tmp->ptr;
556                         }
557                         read_token(tok, &p, &status, 1, status != R_ST_NORMAL);
558                     } while (status != R_ST_NORMAL);
559
560                     if (tok->length == 0)
561                         continue;
562
563                     if (tok->ptr[0] == '<') {
564                         if (tok->ptr[1] &&
565                             REALLY_THE_BEGINNING_OF_A_TAG(tok->ptr))
566                             is_tag = TRUE;
567                         else if (!(pre_mode & (RB_PLAIN | RB_INTXTA |
568                                                RB_SCRIPT | RB_STYLE))) {
569                             p = Strnew_m_charp(tok->ptr + 1, p, NULL)->ptr;
570                             tok = Strnew_charp("&lt;");
571                         }
572                     }
573                     if (is_tag) {
574                         if (pre_mode & (RB_PLAIN | RB_INTXTA | RB_SCRIPT |
575                                         RB_STYLE)) {
576                             q = tok->ptr;
577                             if ((tag = parse_tag(&q, FALSE)) &&
578                                 tag->tagid == end_tag) {
579                                 if (pre_mode & RB_PLAIN) {
580                                     fputs("</PRE_PLAIN>", f1);
581                                     pre_mode = 0;
582                                     end_tag = 0;
583                                     goto token_end;
584                                 }
585                                 pre_mode = 0;
586                                 end_tag = 0;
587                                 goto proc_normal;
588                             }
589                             if (strncmp(tok->ptr, "<!--", 4) &&
590                                 (q = strchr(tok->ptr + 1, '<'))) {
591                                 tok = Strnew_charp_n(tok->ptr, q - tok->ptr);
592                                 p = Strnew_m_charp(q, p, NULL)->ptr;
593                                 status = R_ST_NORMAL;
594                             }
595                             is_tag = FALSE;
596                         }
597                         else if (pre_mode & RB_INSELECT) {
598                             q = tok->ptr;
599                             if ((tag = parse_tag(&q, FALSE))) {
600                                 if ((tag->tagid == end_tag) ||
601                                     (tag->tagid == HTML_N_FORM)) {
602                                     if (tag->tagid == HTML_N_FORM)
603                                         fputs("</SELECT>", f1);
604                                     pre_mode = 0;
605                                     end_tag = 0;
606                                     goto proc_normal;
607                                 }
608                                 if (t_stack) {
609                                     switch (tag->tagid) {
610                                     case HTML_TABLE:
611                                     case HTML_N_TABLE:
612                                       CASE_TABLE_TAG:
613                                         fputs("</SELECT>", f1);
614                                         pre_mode = 0;
615                                         end_tag = 0;
616                                         goto proc_normal;
617                                     }
618                                 }
619                             }
620                         }
621                     }
622
623                   proc_normal:
624                     if (is_tag) {
625                         char *q = tok->ptr;
626                         int j, a_target = 0;
627                         ParsedURL url;
628
629                         if (!(tag = parse_tag(&q, FALSE)))
630                             goto token_end;
631
632                         switch (tag->tagid) {
633                         case HTML_TITLE:
634                             fputs("<!-- title:", f1);
635                             goto token_end;
636                         case HTML_N_TITLE:
637                             fputs("-->", f1);
638                             goto token_end;
639                         case HTML_BASE:
640                             /* "BASE" is prohibit tag */
641                             if (parsedtag_get_value(tag, ATTR_HREF, &q)) {
642                                 q = url_quote_conv(remove_space(q), charset);
643                                 parseURL(q, &base, NULL);
644                             }
645                             if (parsedtag_get_value(tag, ATTR_TARGET, &q)) {
646                                 if (!strcasecmp(q, "_self"))
647                                     d_target = s_target;
648                                 else if (!strcasecmp(q, "_parent"))
649                                     d_target = p_target;
650                                 else
651                                     d_target = url_quote_conv(q, charset);
652                             }
653                             Strshrinkfirst(tok, 1);
654                             Strshrink(tok, 1);
655                             fprintf(f1, "<!-- %s -->", html_quote(tok->ptr));
656                             goto token_end;
657                         case HTML_META:
658                             if (parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &q)
659                                 && !strcasecmp(q, "refresh")) {
660                                 if (parsedtag_get_value(tag, ATTR_CONTENT, &q)
661                                     ) {
662                                     Str s_tmp = NULL;
663                                     int refresh_interval =
664                                         getMetaRefreshParam(q, &s_tmp);
665                                     if (s_tmp) {
666                                         q = html_quote(s_tmp->ptr);
667                                         fprintf(f1,
668                                                 "Refresh (%d sec) <a href=\"%s\">%s</a>\n",
669                                                 refresh_interval, q, q);
670                                     }
671                                 }
672                             }
673 #ifdef USE_M17N
674                             if (UseContentCharset &&
675                                 parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &q)
676                                 && !strcasecmp(q, "Content-Type")
677                                 && parsedtag_get_value(tag, ATTR_CONTENT, &q)
678                                 && (q = strcasestr(q, "charset")) != NULL) {
679                                 q += 7;
680                                 SKIP_BLANKS(q);
681                                 if (*q == '=') {
682                                     wc_ces c;
683                                     q++;
684                                     SKIP_BLANKS(q);
685                                     if ((c = wc_guess_charset(q, 0)) != 0) {
686                                         doc_charset = c;
687                                         charset = WC_CES_US_ASCII;
688                                     }
689                                 }
690                             }
691 #endif
692                             /* fall thru, "META" is prohibit tag */
693                         case HTML_HEAD:
694                         case HTML_N_HEAD:
695                         case HTML_BODY:
696                         case HTML_N_BODY:
697                         case HTML_DOCTYPE:
698                             /* prohibit_tags */
699                             Strshrinkfirst(tok, 1);
700                             Strshrink(tok, 1);
701                             fprintf(f1, "<!-- %s -->", html_quote(tok->ptr));
702                             goto token_end;
703                         case HTML_TABLE:
704                             t_stack++;
705                             break;
706                         case HTML_N_TABLE:
707                             t_stack--;
708                             if (t_stack < 0) {
709                                 t_stack = 0;
710                                 Strshrinkfirst(tok, 1);
711                                 Strshrink(tok, 1);
712                                 fprintf(f1,
713                                         "<!-- table stack underflow: %s -->",
714                                         html_quote(tok->ptr));
715                                 goto token_end;
716                             }
717                             break;
718                           CASE_TABLE_TAG:
719                             /* table_tags MUST be in table stack */
720                             if (!t_stack) {
721                                 Strshrinkfirst(tok, 1);
722                                 Strshrink(tok, 1);
723                                 fprintf(f1, "<!-- %s -->",
724                                         html_quote(tok->ptr));
725                                 goto token_end;
726
727                             }
728                             break;
729                         case HTML_SELECT:
730                             pre_mode = RB_INSELECT;
731                             end_tag = HTML_N_SELECT;
732                             break;
733                         case HTML_TEXTAREA:
734                             pre_mode = RB_INTXTA;
735                             end_tag = HTML_N_TEXTAREA;
736                             break;
737                         case HTML_SCRIPT:
738                             pre_mode = RB_SCRIPT;
739                             end_tag = HTML_N_SCRIPT;
740                             break;
741                         case HTML_STYLE:
742                             pre_mode = RB_STYLE;
743                             end_tag = HTML_N_STYLE;
744                             break;
745                         case HTML_LISTING:
746                             pre_mode = RB_PLAIN;
747                             end_tag = HTML_N_LISTING;
748                             fputs("<PRE_PLAIN>", f1);
749                             goto token_end;
750                         case HTML_XMP:
751                             pre_mode = RB_PLAIN;
752                             end_tag = HTML_N_XMP;
753                             fputs("<PRE_PLAIN>", f1);
754                             goto token_end;
755                         case HTML_PLAINTEXT:
756                             pre_mode = RB_PLAIN;
757                             end_tag = MAX_HTMLTAG;
758                             fputs("<PRE_PLAIN>", f1);
759                             goto token_end;
760                         default:
761                             break;
762                         }
763                         for (j = 0; j < TagMAP[tag->tagid].max_attribute; j++) {
764                             switch (tag->attrid[j]) {
765                             case ATTR_SRC:
766                             case ATTR_HREF:
767                             case ATTR_ACTION:
768                                 if (!tag->value[j])
769                                     break;
770                                 tag->value[j] =
771                                     url_quote_conv(remove_space(tag->value[j]),
772                                                    charset);
773                                 tag->need_reconstruct = TRUE;
774                                 parseURL2(tag->value[j], &url, &base);
775                                 if (url.scheme == SCM_UNKNOWN ||
776 #ifndef USE_W3MMAILER
777                                     url.scheme == SCM_MAILTO ||
778 #endif
779                                     url.scheme == SCM_MISSING)
780                                     break;
781                                 a_target |= 1;
782                                 tag->value[j] = parsedURL2Str(&url)->ptr;
783                                 parsedtag_set_value(tag,
784                                                     ATTR_REFERER,
785                                                     parsedURL2Str(&base)->ptr);
786 #ifdef USE_M17N
787                                 if (tag->attrid[j] == ATTR_ACTION &&
788                                     charset != WC_CES_US_ASCII)
789                                     parsedtag_set_value(tag,
790                                                         ATTR_CHARSET,
791                                                         wc_ces_to_charset
792                                                         (charset));
793 #endif
794                                 break;
795                             case ATTR_TARGET:
796                                 if (!tag->value[j])
797                                     break;
798                                 a_target |= 2;
799                                 if (!strcasecmp(tag->value[j], "_self")) {
800                                     parsedtag_set_value(tag,
801                                                         ATTR_TARGET, s_target);
802                                 }
803                                 else if (!strcasecmp(tag->value[j], "_parent")) {
804                                     parsedtag_set_value(tag,
805                                                         ATTR_TARGET, p_target);
806                                 }
807                                 break;
808                             case ATTR_NAME:
809                             case ATTR_ID:
810                                 if (!tag->value[j])
811                                     break;
812                                 parsedtag_set_value(tag,
813                                                     ATTR_FRAMENAME, s_target);
814                                 break;
815                             }
816                         }
817                         if (a_target == 1) {
818                             /* there is HREF attribute and no TARGET
819                              * attribute */
820                             parsedtag_set_value(tag, ATTR_TARGET, d_target);
821                         }
822                         if (parsedtag_need_reconstruct(tag))
823                             tok = parsedtag2str(tag);
824                         Strfputs(tok, f1);
825                     }
826                     else {
827                         if (pre_mode & RB_PLAIN)
828                             fprintf(f1, "%s", html_quote(tok->ptr));
829                         else if (pre_mode & RB_INTXTA)
830                             fprintf(f1, "%s",
831                                     html_quote(html_unquote(tok->ptr)));
832                         else
833                             Strfputs(tok, f1);
834                     }
835                   token_end:
836                     Strclear(tok);
837                 } while (*p != '\0' || !iseos(f2.stream));
838                 if (pre_mode & RB_PLAIN)
839                     fputs("</PRE_PLAIN>\n", f1);
840                 else if (pre_mode & RB_INTXTA)
841                     fputs("</TEXTAREA></FORM>\n", f1);
842                 else if (pre_mode & RB_INSELECT)
843                     fputs("</SELECT></FORM>\n", f1);
844                 else if (pre_mode & (RB_SCRIPT | RB_STYLE)) {
845                     if (status != R_ST_NORMAL)
846                         fputs(correct_irrtag(status)->ptr, f1);
847                     if (pre_mode & RB_SCRIPT)
848                         fputs("</SCRIPT>\n", f1);
849                     else if (pre_mode & RB_STYLE)
850                         fputs("</STYLE>\n", f1);
851                 }
852                 while (t_stack--)
853                     fputs("</TABLE>\n", f1);
854                 UFclose(&f2);
855                 break;
856             case F_FRAMESET:
857               render_frameset:
858                 if (!frame.set->name && f->name) {
859                     frame.set->name = Sprintf("%s_%d", f->name, i)->ptr;
860                 }
861                 createFrameFile(frame.set, f1, current, level + 1,
862                                 force_reload);
863                 break;
864             }
865             fputs("</td>\n", f1);
866         }
867         fputs("</tr>\n", f1);
868     }
869
870     fputs("</table>\n", f1);
871     if (level == 0) {
872         fputs("</body></html>\n", f1);
873         TRAP_OFF;
874     }
875     return 0;
876 }
877
878 Buffer *
879 renderFrame(Buffer *Cbuf, int force_reload)
880 {
881     Str tmp;
882     FILE *f;
883     Buffer *buf;
884     int flag;
885     struct frameset *fset;
886 #ifdef USE_M17N
887     wc_ces doc_charset = DocumentCharset;
888 #endif
889
890     tmp = tmpfname(TMPF_FRAME, ".html");
891     f = fopen(tmp->ptr, "w");
892     if (f == NULL)
893         return NULL;
894     /* 
895      * if (Cbuf->frameQ != NULL) fset = Cbuf->frameQ->frameset; else */
896     fset = Cbuf->frameset;
897     if (fset == NULL || createFrameFile(fset, f, Cbuf, 0, force_reload) < 0)
898         return NULL;
899     fclose(f);
900     flag = RG_FRAME;
901     if ((Cbuf->currentURL).is_nocache)
902         flag |= RG_NOCACHE;
903     renderFrameSet = Cbuf->frameset;
904     flushFrameSet(renderFrameSet);
905 #ifdef USE_M17N
906     DocumentCharset = InnerCharset;
907 #endif
908     buf = loadGeneralFile(tmp->ptr, NULL, NULL, flag, NULL);
909 #ifdef USE_M17N
910     DocumentCharset = doc_charset;
911 #endif
912     renderFrameSet = NULL;
913     if (buf == NULL || buf == NO_BUFFER)
914         return NULL;
915     buf->sourcefile = tmp->ptr;
916 #ifdef USE_M17N
917     buf->document_charset = Cbuf->document_charset;
918 #endif
919     copyParsedURL(&buf->currentURL, &Cbuf->currentURL);
920     preFormUpdateBuffer(buf);
921     return buf;
922 }
923
924 union frameset_element *
925 search_frame(struct frameset *fset, char *name)
926 {
927     int i;
928     union frameset_element *e = NULL;
929
930     for (i = 0; i < fset->col * fset->row; i++) {
931         e = &(fset->frame[i]);
932         if (e->element != NULL) {
933             if (e->element->name && !strcmp(e->element->name, name)) {
934                 return e;
935             }
936             else if (e->element->attr == F_FRAMESET &&
937                      (e = search_frame(e->set, name))) {
938                 return e;
939             }
940         }
941     }
942     return NULL;
943 }