w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

frame.c (22052B)


      1 /* $Id$ */
      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 }