aboutsummaryrefslogtreecommitdiffstats
path: root/frame.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--frame.c789
1 files changed, 789 insertions, 0 deletions
diff --git a/frame.c b/frame.c
new file mode 100644
index 0000000..79b5981
--- /dev/null
+++ b/frame.c
@@ -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 : &current->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;
+}