diff options
Diffstat (limited to 'frame.c')
-rw-r--r-- | frame.c | 789 |
1 files changed, 789 insertions, 0 deletions
@@ -0,0 +1,789 @@ +/* $Id: frame.c,v 1.1 2001/11/08 05:14:54 a-ito Exp $ */ +#include "fm.h" +#include "parsetagx.h" +#include "myctype.h" +#include <signal.h> +#include <setjmp.h> + +#ifdef KANJI_SYMBOLS +#define RULE_WIDTH 2 +#else /* not KANJI_SYMBOLS */ +#define RULE_WIDTH 1 +#endif /* not KANJI_SYMBOLS */ + +static JMP_BUF AbortLoading; +struct frameset *renderFrameSet = NULL; + +static MySignalHandler +KeyAbort(SIGNAL_ARG) +{ + LONGJMP(AbortLoading, 1); +} + +struct frameset * +newFrameSet(struct parsed_tag *tag) +{ + struct frameset *f; + int i; + char *cols = NULL, *rows = NULL, *p, *q; + char *length[100]; + + f = New(struct frameset); + f->attr = F_FRAMESET; + f->name = NULL; + f->currentURL = NULL; + parsedtag_get_value(tag, ATTR_COLS, &cols); + parsedtag_get_value(tag, ATTR_ROWS, &rows); + i = 0; + if (cols) { + length[i] = p = cols; + while (*p != '\0') + if (*p++ == ',') + length[++i] = p; + length[++i] = p + 1; + } + if (i > 1) { + f->col = i; + f->width = New_N(char *, i); + p = length[i]; + do { + i--; + q = p - 2; + p = length[i]; + switch (*q) { + Str tmp; + case '%': + f->width[i] = allocStr(p, q - p + 1); + break; + case '*': + f->width[i] = "*"; + break; + default: + tmp = Sprintf("%d", atoi(p)); + f->width[i] = tmp->ptr; + break; + } + } while (i); + } + else { + f->col = 1; + f->width = New_N(char *, 1); + f->width[0] = "*"; + } + i = 0; + if (rows) { + length[i] = p = rows; + while (*p != '\0') + if (*p++ == ',') + length[++i] = p; + length[++i] = p + 1; + } + if (i > 1) { + f->row = i; + f->height = New_N(char *, i); + p = length[i]; + do { + i--; + q = p - 2; + p = length[i]; + f->height[i] = allocStr(p, q - p + 1); + } while (i); + } + else { + f->row = 1; + f->height = New_N(char *, 1); + f->height[0] = "*"; + } + i = f->row * f->col; + f->i = 0; + f->frame = New_N(union frameset_element, i); + do { + i--; + f->frame[i].element = NULL; + } while (i); + return f; +} + +struct frame_body * +newFrame(struct parsed_tag *tag, ParsedURL * baseURL) +{ + struct frame_body *body; + char *p; + + body = New(struct frame_body); + bzero((void *) body, sizeof(*body)); + body->attr = F_UNLOADED; + body->flags = 0; + body->baseURL = baseURL; + if (tag) { + parsedtag_get_value(tag, ATTR_SRC, &body->url); + if (parsedtag_get_value(tag, ATTR_NAME, &p) && *p != '_') + body->name = p; + } + return body; +} + +static void +unloadFrame(struct frame_body *b) +{ + if (b->source && b->flags & FB_TODELETE) + pushText(fileToDelete, b->source); + b->attr = F_UNLOADED; +} + +void +deleteFrame(struct frame_body *b) +{ + if (b == NULL) + return; + unloadFrame(b); + bzero((void *) b, sizeof(*b)); +} + +void +addFrameSetElement(struct frameset *f, union frameset_element element) +{ + int i; + + if (f == NULL) + return; + i = f->i; + if (i >= f->col * f->row) + return; + f->frame[i] = element; + f->i++; +} + +void +deleteFrameSet(struct frameset *f) +{ + int i; + + if (f == NULL) + return; + for (i = 0; i < f->col * f->row; i++) { + deleteFrameSetElement(f->frame[i]); + } + f->name = NULL; + f->currentURL = NULL; + return; +} + +void +deleteFrameSetElement(union frameset_element e) +{ + if (e.element == NULL) + return; + switch (e.element->attr) { + case F_UNLOADED: + break; + case F_BODY: + deleteFrame(e.body); + break; + case F_FRAMESET: + deleteFrameSet(e.set); + break; + default: + break; + } + return; +} + +static struct frame_body * +copyFrame(struct frame_body *ob) +{ + struct frame_body *rb; + + rb = New(struct frame_body); + bcopy((const void *) ob, (void *) rb, sizeof(struct frame_body)); + rb->flags &= ~FB_TODELETE; + return rb; +} + +struct frameset * +copyFrameSet(struct frameset *of) +{ + struct frameset *rf; + int n; + + rf = New(struct frameset); + n = of->col * of->row; + bcopy((const void *) of, (void *) rf, sizeof(struct frameset)); + rf->width = New_N(char *, rf->col); + bcopy((const void *) of->width, + (void *) rf->width, + sizeof(char *) * rf->col); + rf->height = New_N(char *, rf->row); + bcopy((const void *) of->height, + (void *) rf->height, + sizeof(char *) * rf->row); + rf->frame = New_N(union frameset_element, n); + while (n) { + n--; + if (!of->frame[n].element) + goto attr_default; + switch (of->frame[n].element->attr) { + case F_UNLOADED: + case F_BODY: + rf->frame[n].body = copyFrame(of->frame[n].body); + break; + case F_FRAMESET: + rf->frame[n].set = copyFrameSet(of->frame[n].set); + break; + default: + attr_default: + rf->frame[n].element = NULL; + break; + } + } + return rf; +} + +void +flushFrameSet(struct frameset *fs) +{ + int n = fs->i; + + while (n) { + n--; + if (!fs->frame[n].element) + goto attr_default; + switch (fs->frame[n].element->attr) { + case F_UNLOADED: + case F_BODY: + fs->frame[n].body->nameList = NULL; + break; + case F_FRAMESET: + flushFrameSet(fs->frame[n].set); + break; + default: + attr_default: + /* nothing to do */ + break; + } + } +} + +void +pushFrameTree(struct frameset_queue **fqpp, + struct frameset *fs, + long linenumber, + short pos) +{ + struct frameset_queue *rfq, *cfq = *fqpp; + + if (!fs) + return; + + rfq = New(struct frameset_queue); + rfq->linenumber = linenumber; + rfq->pos = pos; + + rfq->back = cfq; + if (cfq) { + rfq->next = cfq->next; + if (cfq->next) + cfq->next->back = rfq; + cfq->next = rfq; + } + else + rfq->next = cfq; + rfq->frameset = fs; + *fqpp = rfq; + return; +} + +struct frameset * +popFrameTree(struct frameset_queue **fqpp, + long *linenumber, + short *pos) +{ + struct frameset_queue *rfq = NULL, *cfq = *fqpp; + struct frameset *rfs = NULL; + + if (!cfq) + return rfs; + + if (linenumber) + *linenumber = cfq->linenumber; + if (pos) + *pos = cfq->pos; + + rfs = cfq->frameset; + if (cfq->next) { + (rfq = cfq->next)->back = cfq->back; + } + if (cfq->back) { + (rfq = cfq->back)->next = cfq->next; + } + *fqpp = rfq; + bzero((void *) cfq, sizeof(struct frameset_queue)); + return rfs; +} + +void +resetFrameElement(union frameset_element *f_element, + Buffer * buf, + char *referer, + FormList * request) +{ + char *f_name; + struct frame_body *f_body; + + f_name = f_element->element->name; + if (buf->frameset) { + /* frame cascade */ + deleteFrameSetElement(*f_element); + f_element->set = buf->frameset; + f_element->set->currentURL = New(ParsedURL); + copyParsedURL(f_element->set->currentURL, &buf->currentURL); + buf->frameset = popFrameTree(&(buf->frameQ), NULL, NULL); + f_element->set->name = f_name; + } + else { + f_body = newFrame(NULL, baseURL(buf)); + f_body->attr = F_BODY; + f_body->name = f_name; + f_body->url = parsedURL2Str(&buf->currentURL)->ptr; + if (buf->real_scheme == SCM_LOCAL) { + f_body->source = buf->sourcefile; + } + else { + Str tmp = tmpfname(TMPF_FRAME, NULL); + rename(buf->sourcefile, tmp->ptr); + f_body->source = tmp->ptr; + f_body->flags |= FB_TODELETE; + buf->sourcefile = NULL; + } + f_body->referer = referer; + f_body->request = request; + deleteFrameSetElement(*f_element); + f_element->body = f_body; + } +} + +static struct frameset * +frame_download_source(struct frame_body *b, ParsedURL * currentURL, + ParsedURL * baseURL, int flag) +{ + Buffer *buf; + struct frameset *ret_frameset = NULL; + Str tmp; + ParsedURL url; + + if (b == NULL || b->url == NULL || b->url[0] == '\0') + return NULL; + if (b->baseURL) + baseURL = b->baseURL; + parseURL2(b->url, &url, currentURL); + switch (url.scheme) { + case SCM_LOCAL: + b->source = url.file; + b->flags = 0; + default: + is_redisplay = TRUE; + buf = loadGeneralFile(b->url, + baseURL ? baseURL : currentURL, + b->referer, + flag, + b->request); + is_redisplay = FALSE; + break; + } + + if (buf == NULL || buf == NO_BUFFER) { + b->source = NULL; + b->flags = (buf == NO_BUFFER) ? FB_NO_BUFFER : 0; + return NULL; + } + b->url = parsedURL2Str(&buf->currentURL)->ptr; + if (buf->real_scheme != SCM_LOCAL) { + tmp = tmpfname(TMPF_FRAME, NULL); + rename(buf->sourcefile, tmp->ptr); + b->source = tmp->ptr; + b->flags |= FB_TODELETE; + buf->sourcefile = NULL; + } + b->attr = F_BODY; + if (buf->frameset) { + ret_frameset = buf->frameset; + ret_frameset->name = b->name; + ret_frameset->currentURL = New(ParsedURL); + copyParsedURL(ret_frameset->currentURL, &buf->currentURL); + buf->frameset = popFrameTree(&(buf->frameQ), NULL, NULL); + } + discardBuffer(buf); + return ret_frameset; +} + +static int +createFrameFile(struct frameset *f, FILE * f1, Buffer * current, int level, int force_reload) +{ + int r, c, t_stack; + InputStream f2; +#ifdef JP_CHARSET + char code, ic, charset[2]; +#endif /* JP_CHARSET */ + char *d_target, *p_target, *s_target, *t_target; + ParsedURL *currentURL, base; + MySignalHandler(*prevtrap) (SIGNAL_ARG) = NULL; + int flag; + + if (f == NULL) + return -1; + + if (level == 0) { + if (SETJMP(AbortLoading) != 0) { + if (fmInitialized) + term_raw(); + signal(SIGINT, prevtrap); + return -1; + } + prevtrap = signal(SIGINT, KeyAbort); + if (fmInitialized) + term_cbreak(); + + f->name = "_top"; + } + + if (level > 7) { + fputs("Too many frameset tasked.\n", f1); + return -1; + } + + if (level == 0) { + fprintf(f1, "<html><head><title>%s</title></head><body>\n", + htmlquote_str(current->buffername)); + fputs("<table hborder width=\"100%\">\n", f1); + } + else + fputs("<table hborder>\n", f1); + + currentURL = f->currentURL ? f->currentURL : ¤t->currentURL; +#ifdef JP_CHARSET + charset[1] = '\0'; +#endif + for (r = 0; r < f->row; r++) { + fputs("<tr valign=top>\n", f1); + for (c = 0; c < f->col; c++) { + union frameset_element frame; + struct frameset *f_frameset; + int i = c + r * f->col; + char *p = ""; + Str tok = Strnew(); + int status; + + frame = f->frame[i]; + + if (frame.element == NULL) { + fputs("<td>\n</td>\n", f1); + continue; + } + + fputs("<td", f1); + if (frame.element->name) + fprintf(f1, " id=\"_%s\"", htmlquote_str(frame.element->name)); + if (!r) + fprintf(f1, " width=\"%s\"", f->width[c]); + fputs(">\n", f1); + + flag = 0; + if (force_reload) { + flag |= RG_NOCACHE; + if (frame.element->attr == F_BODY) + unloadFrame(frame.body); + } + switch (frame.element->attr) { + default: + fprintf(f1, "Frameset \"%s\" frame %d: type unrecognized", + htmlquote_str(f->name), i + 1); + break; + case F_UNLOADED: + if (!frame.body->name && f->name) { + frame.body->name = Sprintf("%s_%d", f->name, i)->ptr; + } + f_frameset = frame_download_source(frame.body, + currentURL, + current->baseURL, + flag); + if (f_frameset) { + deleteFrame(frame.body); + f->frame[i].set = frame.set = f_frameset; + goto render_frameset; + } + /* fall through */ + case F_BODY: + f2 = NULL; + if (frame.body->source == NULL || + (f2 = openIS(frame.body->source)) == NULL) { + frame.body->attr = F_UNLOADED; + if (frame.body->flags & FB_NO_BUFFER) + fprintf(f1, "Open %s with other method", frame.body->url); + else + fprintf(f1, "Can't open %s", frame.body->url); + break; + } + parseURL2(frame.body->url, &base, currentURL); + p_target = f->name; + s_target = frame.body->name; + t_target = "_blank"; + d_target = TargetSelf ? s_target : t_target; +#ifdef JP_CHARSET + code = '\0'; +#endif /* JP_CHARSET */ + t_stack = 0; + do { + status = R_ST_NORMAL; + do { + if (*p == '\0') { + Str tmp = StrmyISgets(f2); + if (tmp->length == 0 && status != R_ST_NORMAL) + tmp = correct_irrtag(status); + if (tmp->length == 0) + break; +#ifdef JP_CHARSET + if ((ic = checkShiftCode(tmp, code)) != '\0') + tmp = conv_str(tmp, (code = ic), InnerCode); + +#endif /* JP_CHARSET */ + cleanup_line(tmp, HTML_MODE); + p = tmp->ptr; + } + if (status == R_ST_NORMAL || ST_IS_COMMENT(status)) + read_token(tok, &p, &status, 1, 0); + else + read_token(tok, &p, &status, 1, 1); + } while (status != R_ST_NORMAL); + + if (tok->length == 0) + continue; + + if (tok->ptr[0] == '<') { + char *q = tok->ptr; + int j, a_target = 0; + struct parsed_tag *tag; + ParsedURL url; + + if (!(tag = parse_tag(&q, FALSE))) + goto token_end; + + switch (tag->tagid) { + case HTML_TITLE: + fputs("<!-- title:", f1); + goto token_end; + case HTML_N_TITLE: + fputs("-->", f1); + goto token_end; + case HTML_BASE: + if (parsedtag_get_value(tag, ATTR_HREF, &q)) + parseURL(q, &base, NULL); + if (parsedtag_get_value(tag, ATTR_TARGET, &q)) { + if (!strcasecmp(q, "_self")) + d_target = s_target; + else if (!strcasecmp(q, "_parent")) + d_target = p_target; + else + d_target = q; + } + /* fall thru, "BASE" is prohibit tag */ + case HTML_HEAD: + case HTML_N_HEAD: + case HTML_BODY: + case HTML_N_BODY: + case HTML_META: + case HTML_DOCTYPE: + /* prohibit_tags */ + Strshrinkfirst(tok, 1); + Strshrink(tok, 1); + fprintf(f1, "<!-- %s -->", tok->ptr); + goto token_end; + case HTML_TABLE: + t_stack++; + break; + case HTML_N_TABLE: + t_stack--; + if (t_stack < 0) { + t_stack = 0; + Strshrinkfirst(tok, 1); + Strshrink(tok, 1); + fprintf(f1, + "<!-- table stack underflow: %s -->", + tok->ptr); + goto token_end; + } + break; + case HTML_THEAD: + case HTML_N_THEAD: + case HTML_TBODY: + case HTML_N_TBODY: + case HTML_TFOOT: + case HTML_N_TFOOT: + case HTML_TD: + case HTML_N_TD: + case HTML_TR: + case HTML_N_TR: + case HTML_TH: + case HTML_N_TH: + /* table_tags MUST be in table stack */ + if (!t_stack) { + Strshrinkfirst(tok, 1); + Strshrink(tok, 1); + fprintf(f1, "<!-- %s -->", tok->ptr); + goto token_end; + + } + break; + default: + break; + } + for (j = 0; j < TagMAP[tag->tagid].max_attribute; j++) { + switch (tag->attrid[j]) { + case ATTR_SRC: + case ATTR_HREF: + case ATTR_ACTION: + if (!tag->value[j]) + break; + parseURL2(tag->value[j], &url, &base); + if (url.scheme == SCM_MAILTO || + url.scheme == SCM_UNKNOWN || + url.scheme == SCM_MISSING) + break; + a_target |= 1; + tag->value[j] = parsedURL2Str(&url)->ptr; + tag->need_reconstruct = TRUE; + parsedtag_set_value(tag, + ATTR_REFERER, + parsedURL2Str(&base)->ptr); +#ifdef JP_CHARSET + if (code != '\0') { + charset[0] = code; + parsedtag_set_value(tag, + ATTR_CHARSET, + charset); + } +#endif + break; + case ATTR_TARGET: + if (!tag->value[j]) + break; + a_target |= 2; + if (!strcasecmp(tag->value[j], "_self")) { + parsedtag_set_value(tag, + ATTR_TARGET, + s_target); + } + else if (!strcasecmp(tag->value[j], + "_parent")) { + parsedtag_set_value(tag, + ATTR_TARGET, + p_target); + } + break; + case ATTR_NAME: + case ATTR_ID: + if (!tag->value[j]) + break; + parsedtag_set_value(tag, + ATTR_FRAMENAME, + s_target); + break; + } + } + if (a_target == 1) { + /* there is HREF attribute and no TARGET + * attribute */ + parsedtag_set_value(tag, + ATTR_TARGET, + d_target); + } + if (parsedtag_need_reconstruct(tag)) + Strfputs(parsedtag2str(tag), f1); + else + Strfputs(tok, f1); + } + else { + Strfputs(tok, f1); + } + token_end: + Strclear(tok); + } while (*p != '\0' || !iseos(f2)); + while (t_stack--) + fputs("</TABLE>\n", f1); + ISclose(f2); + break; + case F_FRAMESET: + render_frameset: + if (!frame.set->name && f->name) { + frame.set->name = Sprintf("%s_%d", f->name, i)->ptr; + } + createFrameFile(frame.set, f1, current, level + 1, force_reload); + break; + } + fputs("</td>\n", f1); + } + fputs("</tr>\n", f1); + } + + fputs("</table>\n", f1); + if (level == 0) { + fputs("</body></html>\n", f1); + signal(SIGINT, prevtrap); + if (fmInitialized) + term_raw(); + } + return 0; +} + +Buffer * +renderFrame(Buffer * Cbuf, int force_reload) +{ + Str tmp; + FILE *f; + Buffer *buf; + int flag; + struct frameset *fset; + + tmp = tmpfname(TMPF_FRAME, ".html"); + f = fopen(tmp->ptr, "w"); + if (f == NULL) + return NULL; + /* + * if (Cbuf->frameQ != NULL) fset = Cbuf->frameQ->frameset; else */ + fset = Cbuf->frameset; + if (fset == NULL || createFrameFile(fset, f, Cbuf, 0, force_reload) < 0) + return NULL; + fclose(f); + flag = RG_FRAME; + if ((Cbuf->currentURL).is_nocache) + flag |= RG_NOCACHE; + renderFrameSet = Cbuf->frameset; + flushFrameSet(renderFrameSet); + buf = loadGeneralFile(tmp->ptr, NULL, NULL, flag, NULL); + renderFrameSet = NULL; + if (buf == NULL || buf == NO_BUFFER) + return NULL; + buf->sourcefile = tmp->ptr; + copyParsedURL(&buf->currentURL, &Cbuf->currentURL); + return buf; +} + +union frameset_element * +search_frame(struct frameset *fset, char *name) +{ + int i; + union frameset_element *e = NULL; + + for (i = 0; i < fset->col * fset->row; i++) { + e = &(fset->frame[i]); + if (e->element != NULL) { + if (e->element->name && !strcmp(e->element->name, name)) { + return e; + } + else if (e->element->attr == F_FRAMESET && + (e = search_frame(e->set, name))) { + return e; + } + } + } + return NULL; +} |