/* $Id: file.c,v 1.239 2006/04/05 14:18:54 inu Exp $ */ #include "fm.h" #include #include "myctype.h" #include #include #if defined(HAVE_WAITPID) || defined(HAVE_WAIT3) #include #endif #include #include #include #include #include /* foo */ #include "html.h" #include "parsetagx.h" #include "local.h" #include "regex.h" #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif /* not max */ #ifndef min #define min(a,b) ((a) > (b) ? (b) : (a)) #endif /* not min */ static int frame_source = 0; static char *guess_filename(char *file); static int _MoveFile(char *path1, char *path2); static void uncompress_stream(URLFile *uf, char **src); static FILE *lessopen_stream(char *path); static Buffer *loadcmdout(char *cmd, Buffer *(*loadproc) (URLFile *, Buffer *), Buffer *defaultbuf); #ifndef USE_ANSI_COLOR #define addnewline(a,b,c,d,e,f,g) _addnewline(a,b,c,e,f,g) #endif static void addnewline(Buffer *buf, char *line, Lineprop *prop, Linecolor *color, int pos, int width, int nlines); static void addLink(Buffer *buf, struct parsed_tag *tag); static JMP_BUF AbortLoading; static struct table *tables[MAX_TABLE]; static struct table_mode table_mode[MAX_TABLE]; #ifdef USE_IMAGE static ParsedURL *cur_baseURL = NULL; #ifdef USE_M17N static wc_ces cur_document_charset; #endif #endif static Str cur_title; static Str cur_select; static Str select_str; static int select_is_multiple; static int n_selectitem; static Str cur_option; static Str cur_option_value; static Str cur_option_label; static int cur_option_selected; static int cur_status; #ifdef MENU_SELECT /* menu based tag. */ if (v == FORM_INPUT_FILE) q = NULL; if (q) { qq = html_quote(q); qlen = get_strwidth(q); } Strcat_charp(tmp, ""); switch (v) { case FORM_INPUT_PASSWORD: case FORM_INPUT_TEXT: case FORM_INPUT_FILE: case FORM_INPUT_CHECKBOX: Strcat_char(tmp, '['); break; case FORM_INPUT_RADIO: Strcat_char(tmp, '('); } Strcat(tmp, Sprintf("'); if (v == FORM_INPUT_HIDDEN) Strcat_charp(tmp, ""); else { switch (v) { case FORM_INPUT_PASSWORD: case FORM_INPUT_TEXT: case FORM_INPUT_FILE: Strcat_charp(tmp, ""); break; case FORM_INPUT_IMAGE: s = NULL; parsedtag_get_value(tag, ATTR_SRC, &s); if (s) { Strcat(tmp, Sprintf("\"%s\"","); Strcat_charp(tmp, ""); return tmp; } case FORM_INPUT_SUBMIT: case FORM_INPUT_BUTTON: case FORM_INPUT_RESET: Strcat_charp(tmp, "["); break; } switch (v) { case FORM_INPUT_PASSWORD: i = 0; if (q) { for (; i < qlen && i < w; i++) Strcat_char(tmp, '*'); } for (; i < w; i++) Strcat_char(tmp, ' '); break; case FORM_INPUT_TEXT: case FORM_INPUT_FILE: if (q) Strcat(tmp, textfieldrep(Strnew_charp(q), w)); else { for (i = 0; i < w; i++) Strcat_char(tmp, ' '); } break; case FORM_INPUT_SUBMIT: case FORM_INPUT_BUTTON: if (p2) Strcat_charp(tmp, html_quote(p2)); else Strcat_charp(tmp, qq); break; case FORM_INPUT_RESET: Strcat_charp(tmp, qq); break; case FORM_INPUT_RADIO: case FORM_INPUT_CHECKBOX: if (x) Strcat_char(tmp, '*'); else Strcat_char(tmp, ' '); break; } switch (v) { case FORM_INPUT_PASSWORD: case FORM_INPUT_TEXT: case FORM_INPUT_FILE: Strcat_charp(tmp, ""); break; case FORM_INPUT_IMAGE: case FORM_INPUT_SUBMIT: case FORM_INPUT_BUTTON: case FORM_INPUT_RESET: Strcat_charp(tmp, "]"); } Strcat_charp(tmp, ""); switch (v) { case FORM_INPUT_PASSWORD: case FORM_INPUT_TEXT: case FORM_INPUT_FILE: case FORM_INPUT_CHECKBOX: Strcat_char(tmp, ']'); break; case FORM_INPUT_RADIO: Strcat_char(tmp, ')'); } Strcat_charp(tmp, ""); } return tmp; } Str process_select(struct parsed_tag *tag) { Str tmp = NULL; char *p; if (cur_form_id < 0) { char *s = ""; tmp = process_form(parse_tag(&s, TRUE)); } p = ""; parsedtag_get_value(tag, ATTR_NAME, &p); cur_select = Strnew_charp(p); select_is_multiple = parsedtag_exists(tag, ATTR_MULTIPLE); #ifdef MENU_SELECT if (!select_is_multiple) { select_str = Sprintf("["); if (n_select == max_select) { max_select *= 2; select_option = New_Reuse(FormSelectOption, select_option, max_select); } select_option[n_select].first = NULL; select_option[n_select].last = NULL; cur_option_maxwidth = 0; } else #endif /* MENU_SELECT */ select_str = Strnew(); cur_option = NULL; cur_status = R_ST_NORMAL; n_selectitem = 0; return tmp; } Str process_n_select(void) { if (cur_select == NULL) return NULL; process_option(); #ifdef MENU_SELECT if (!select_is_multiple) { if (select_option[n_select].first) { FormItemList sitem; chooseSelectOption(&sitem, select_option[n_select].first); Strcat(select_str, textfieldrep(sitem.label, cur_option_maxwidth)); } Strcat_charp(select_str, "]"); n_select++; } else #endif /* MENU_SELECT */ Strcat_charp(select_str, "
"); cur_select = NULL; n_selectitem = 0; return select_str; } void feed_select(char *str) { Str tmp = Strnew(); int prev_status = cur_status; static int prev_spaces = -1; char *p; if (cur_select == NULL) return; while (read_token(tmp, &str, &cur_status, 0, 0)) { if (cur_status != R_ST_NORMAL || prev_status != R_ST_NORMAL) continue; p = tmp->ptr; if (tmp->ptr[0] == '<' && Strlastchar(tmp) == '>') { struct parsed_tag *tag; char *q; if (!(tag = parse_tag(&p, FALSE))) continue; switch (tag->tagid) { case HTML_OPTION: process_option(); cur_option = Strnew(); if (parsedtag_get_value(tag, ATTR_VALUE, &q)) cur_option_value = Strnew_charp(q); else cur_option_value = NULL; if (parsedtag_get_value(tag, ATTR_LABEL, &q)) cur_option_label = Strnew_charp(q); else cur_option_label = NULL; cur_option_selected = parsedtag_exists(tag, ATTR_SELECTED); prev_spaces = -1; break; case HTML_N_OPTION: /* do nothing */ break; default: /* never happen */ break; } } else if (cur_option) { while (*p) { if (IS_SPACE(*p) && prev_spaces != 0) { p++; if (prev_spaces > 0) prev_spaces++; } else { if (IS_SPACE(*p)) prev_spaces = 1; else prev_spaces = 0; if (*p == '&') Strcat_charp(cur_option, getescapecmd(&p)); else Strcat_char(cur_option, *(p++)); } } } } } void process_option(void) { char begin_char = '[', end_char = ']'; int len; if (cur_select == NULL || cur_option == NULL) return; while (cur_option->length > 0 && IS_SPACE(Strlastchar(cur_option))) Strshrink(cur_option, 1); if (cur_option_value == NULL) cur_option_value = cur_option; if (cur_option_label == NULL) cur_option_label = cur_option; #ifdef MENU_SELECT if (!select_is_multiple) { len = get_Str_strwidth(cur_option_label); if (len > cur_option_maxwidth) cur_option_maxwidth = len; addSelectOption(&select_option[n_select], cur_option_value, cur_option_label, cur_option_selected); return; } #endif /* MENU_SELECT */ if (!select_is_multiple) { begin_char = '('; end_char = ')'; } Strcat(select_str, Sprintf("
%cptr), html_quote(cur_option_value->ptr))); if (cur_option_selected) Strcat_charp(select_str, " checked>*"); else Strcat_charp(select_str, "> "); Strcat_char(select_str, end_char); Strcat_charp(select_str, html_quote(cur_option_label->ptr)); Strcat_charp(select_str, ""); n_selectitem++; } Str process_textarea(struct parsed_tag *tag, int width) { Str tmp = NULL; char *p; if (cur_form_id < 0) { char *s = ""; tmp = process_form(parse_tag(&s, TRUE)); } p = ""; parsedtag_get_value(tag, ATTR_NAME, &p); cur_textarea = Strnew_charp(p); cur_textarea_size = 20; if (parsedtag_get_value(tag, ATTR_COLS, &p)) { cur_textarea_size = atoi(p); if (p[strlen(p) - 1] == '%') cur_textarea_size = width * cur_textarea_size / 100 - 2; if (cur_textarea_size <= 0) cur_textarea_size = 20; } cur_textarea_rows = 1; if (parsedtag_get_value(tag, ATTR_ROWS, &p)) { cur_textarea_rows = atoi(p); if (cur_textarea_rows <= 0) cur_textarea_rows = 1; } cur_textarea_readonly = parsedtag_exists(tag, ATTR_READONLY); if (n_textarea >= max_textarea) { max_textarea *= 2; textarea_str = New_Reuse(Str, textarea_str, max_textarea); } textarea_str[n_textarea] = Strnew(); ignore_nl_textarea = TRUE; return tmp; } Str process_n_textarea(void) { Str tmp; int i; if (cur_textarea == NULL) return NULL; tmp = Strnew(); Strcat(tmp, Sprintf("[ptr), cur_textarea_size, cur_textarea_rows, cur_textarea_rows - 1, n_textarea)); if (cur_textarea_readonly) Strcat_charp(tmp, " readonly"); Strcat_charp(tmp, ">"); for (i = 0; i < cur_textarea_size; i++) Strcat_char(tmp, ' '); Strcat_charp(tmp, "]\n"); cur_hseq++; n_textarea++; cur_textarea = NULL; return tmp; } void feed_textarea(char *str) { if (cur_textarea == NULL) return; if (ignore_nl_textarea) { if (*str == '\r') str++; if (*str == '\n') str++; } ignore_nl_textarea = FALSE; while (*str) { if (*str == '&') Strcat_charp(textarea_str[n_textarea], getescapecmd(&str)); else if (*str == '\n') { Strcat_charp(textarea_str[n_textarea], "\r\n"); str++; } else if (*str != '\r') Strcat_char(textarea_str[n_textarea], *(str++)); } } Str process_hr(struct parsed_tag *tag, int width, int indent_width) { Str tmp = Strnew_charp(""); int w = 0; int x = ALIGN_CENTER; if (width > indent_width) width -= indent_width; if (parsedtag_get_value(tag, ATTR_WIDTH, &w)) w = REAL_WIDTH(w, width); else w = width; parsedtag_get_value(tag, ATTR_ALIGN, &x); switch (x) { case ALIGN_CENTER: Strcat_charp(tmp, ""); break; case ALIGN_RIGHT: Strcat_charp(tmp, ""); break; case ALIGN_LEFT: Strcat_charp(tmp, ""); break; } w /= symbol_width; if (w <= 0) w = 1; push_symbol(tmp, HR_SYMBOL, symbol_width, w); Strcat_charp(tmp, ""); return tmp; } #ifdef USE_M17N static char * check_charset(char *p) { return wc_guess_charset(p, 0) ? p : NULL; } static char * check_accept_charset(char *ac) { char *s = ac, *e; while (*s) { while (*s && (IS_SPACE(*s) || *s == ',')) s++; if (!*s) break; e = s; while (*e && !(IS_SPACE(*e) || *e == ',')) e++; if (wc_guess_charset(Strnew_charp_n(s, e - s)->ptr, 0)) return ac; s = e; } return NULL; } #endif static Str process_form_int(struct parsed_tag *tag, int fid) { char *p, *q, *r, *s, *tg, *n; p = "get"; parsedtag_get_value(tag, ATTR_METHOD, &p); q = "!CURRENT_URL!"; parsedtag_get_value(tag, ATTR_ACTION, &q); r = NULL; #ifdef USE_M17N if (parsedtag_get_value(tag, ATTR_ACCEPT_CHARSET, &r)) r = check_accept_charset(r); if (!r && parsedtag_get_value(tag, ATTR_CHARSET, &r)) r = check_charset(r); #endif s = NULL; parsedtag_get_value(tag, ATTR_ENCTYPE, &s); tg = NULL; parsedtag_get_value(tag, ATTR_TARGET, &tg); n = NULL; parsedtag_get_value(tag, ATTR_NAME, &n); if (fid < 0) { form_max++; form_sp++; fid = form_max; } else { /* */ if (form_max < fid) form_max = fid; form_sp = fid; } if (forms_size == 0) { forms_size = INITIAL_FORM_SIZE; forms = New_N(FormList *, forms_size); form_stack = NewAtom_N(int, forms_size); } else if (forms_size <= form_max) { forms_size += form_max; forms = New_Reuse(FormList *, forms, forms_size); form_stack = New_Reuse(int, form_stack, forms_size); } form_stack[form_sp] = fid; if (w3m_halfdump) { Str tmp = Sprintf(""); return tmp; } forms[fid] = newFormList(q, p, r, s, tg, n, NULL); return NULL; } Str process_form(struct parsed_tag *tag) { return process_form_int(tag, -1); } Str process_n_form(void) { if (form_sp >= 0) form_sp--; return NULL; } static void clear_ignore_p_flag(int cmd, struct readbuffer *obuf) { static int clear_flag_cmd[] = { HTML_HR, HTML_UNKNOWN }; int i; for (i = 0; clear_flag_cmd[i] != HTML_UNKNOWN; i++) { if (cmd == clear_flag_cmd[i]) { obuf->flag &= ~RB_IGNORE_P; return; } } } static void set_alignment(struct readbuffer *obuf, struct parsed_tag *tag) { long flag = -1; int align; if (parsedtag_get_value(tag, ATTR_ALIGN, &align)) { switch (align) { case ALIGN_CENTER: flag = RB_CENTER; break; case ALIGN_RIGHT: flag = RB_RIGHT; break; case ALIGN_LEFT: flag = RB_LEFT; } } RB_SAVE_FLAG(obuf); if (flag != -1) { RB_SET_ALIGN(obuf, flag); } } #ifdef ID_EXT static void process_idattr(struct readbuffer *obuf, int cmd, struct parsed_tag *tag) { char *id = NULL, *framename = NULL; Str idtag = NULL; /* * HTML_TABLE is handled by the other process. */ if (cmd == HTML_TABLE) return; parsedtag_get_value(tag, ATTR_ID, &id); parsedtag_get_value(tag, ATTR_FRAMENAME, &framename); if (id == NULL) return; if (framename) idtag = Sprintf("<_id id=\"%s\" framename=\"%s\">", html_quote(id), html_quote(framename)); else idtag = Sprintf("<_id id=\"%s\">", html_quote(id)); push_tag(obuf, idtag->ptr, HTML_NOP); } #endif /* ID_EXT */ #define CLOSE_P if (obuf->flag & RB_P) { \ flushline(h_env, obuf, envs[h_env->envc].indent,0,h_env->limit);\ RB_RESTORE_FLAG(obuf);\ obuf->flag &= ~RB_P;\ } #define CLOSE_A \ CLOSE_P; \ close_anchor(h_env, obuf); #define CLOSE_DT \ if (obuf->flag & RB_IN_DT) { \ obuf->flag &= ~RB_IN_DT; \ HTMLlineproc1("", h_env); \ } #define PUSH_ENV(cmd) \ if (++h_env->envc_real < h_env->nenv) { \ ++h_env->envc; \ envs[h_env->envc].env = cmd; \ envs[h_env->envc].count = 0; \ if (h_env->envc <= MAX_INDENT_LEVEL) \ envs[h_env->envc].indent = envs[h_env->envc - 1].indent + INDENT_INCR; \ else \ envs[h_env->envc].indent = envs[h_env->envc - 1].indent; \ } #define POP_ENV \ if (h_env->envc_real-- < h_env->nenv) \ h_env->envc--; static int ul_type(struct parsed_tag *tag, int default_type) { char *p; if (parsedtag_get_value(tag, ATTR_TYPE, &p)) { if (!strcasecmp(p, "disc")) return (int)'d'; else if (!strcasecmp(p, "circle")) return (int)'c'; else if (!strcasecmp(p, "square")) return (int)'s'; } return default_type; } int getMetaRefreshParam(char *q, Str *refresh_uri) { int refresh_interval; char *r; Str s_tmp = NULL; if (q == NULL || refresh_uri == NULL) return 0; refresh_interval = atoi(q); if (refresh_interval < 0) return 0; while (*q) { if (!strncasecmp(q, "url=", 4)) { q += 4; if (*q == '\"') /* " */ q++; r = q; while (*r && !IS_SPACE(*r) && *r != ';') r++; s_tmp = Strnew_charp_n(q, r - q); if (s_tmp->ptr[s_tmp->length - 1] == '\"') { /* " */ s_tmp->length--; s_tmp->ptr[s_tmp->length] = '\0'; } q = r; } while (*q && *q != ';') q++; if (*q == ';') q++; while (*q && *q == ' ') q++; } *refresh_uri = s_tmp; return refresh_interval; } int HTMLtagproc1(struct parsed_tag *tag, struct html_feed_environ *h_env) { char *p, *q, *r; int i, w, x, y, z, count, width; struct readbuffer *obuf = h_env->obuf; struct environment *envs = h_env->envs; Str tmp; int hseq; int cmd; #ifdef ID_EXT char *id = NULL; #endif /* ID_EXT */ cmd = tag->tagid; if (obuf->flag & RB_PRE) { switch (cmd) { case HTML_NOBR: case HTML_N_NOBR: case HTML_PRE_INT: case HTML_N_PRE_INT: return 1; } } switch (cmd) { case HTML_B: obuf->in_bold++; if (obuf->in_bold > 1) return 1; return 0; case HTML_N_B: if (obuf->in_bold == 1 && close_effect0(obuf, HTML_B)) obuf->in_bold = 0; if (obuf->in_bold > 0) { obuf->in_bold--; if (obuf->in_bold == 0) return 0; } return 1; case HTML_U: obuf->in_under++; if (obuf->in_under > 1) return 1; return 0; case HTML_N_U: if (obuf->in_under == 1 && close_effect0(obuf, HTML_U)) obuf->in_under = 0; if (obuf->in_under > 0) { obuf->in_under--; if (obuf->in_under == 0) return 0; } return 1; case HTML_EM: HTMLlineproc1("", h_env); return 1; case HTML_N_EM: HTMLlineproc1("", h_env); return 1; case HTML_Q: HTMLlineproc1("`", h_env); return 1; case HTML_N_Q: HTMLlineproc1("'", h_env); return 1; case HTML_P: case HTML_N_P: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 1, h_env->limit); do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } obuf->flag |= RB_IGNORE_P; if (cmd == HTML_P) { set_alignment(obuf, tag); obuf->flag |= RB_P; } return 1; case HTML_BR: flushline(h_env, obuf, envs[h_env->envc].indent, 1, h_env->limit); h_env->blank_lines = 0; return 1; case HTML_H: if (!(obuf->flag & (RB_PREMODE | RB_IGNORE_P))) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } HTMLlineproc1("", h_env); set_alignment(obuf, tag); return 1; case HTML_N_H: HTMLlineproc1("", h_env); if (!(obuf->flag & RB_PREMODE)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); RB_RESTORE_FLAG(obuf); close_anchor(h_env, obuf); obuf->flag |= RB_IGNORE_P; return 1; case HTML_UL: case HTML_OL: case HTML_BLQ: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); if (!(obuf->flag & RB_PREMODE) && (h_env->envc == 0 || cmd == HTML_BLQ)) do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } PUSH_ENV(cmd); if (cmd == HTML_UL || cmd == HTML_OL) { if (parsedtag_get_value(tag, ATTR_START, &count)) { envs[h_env->envc].count = count - 1; } } if (cmd == HTML_OL) { envs[h_env->envc].type = '1'; if (parsedtag_get_value(tag, ATTR_TYPE, &p)) { envs[h_env->envc].type = (int)*p; } } if (cmd == HTML_UL) envs[h_env->envc].type = ul_type(tag, 0); flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); return 1; case HTML_N_UL: case HTML_N_OL: case HTML_N_DL: case HTML_N_BLQ: CLOSE_DT; CLOSE_A; if (h_env->envc > 0) { flushline(h_env, obuf, envs[h_env->envc - 1].indent, 0, h_env->limit); POP_ENV; if (!(obuf->flag & RB_PREMODE) && (h_env->envc == 0 || cmd == HTML_N_DL || cmd == HTML_N_BLQ)) { do_blankline(h_env, obuf, envs[h_env->envc].indent, INDENT_INCR, h_env->limit); obuf->flag |= RB_IGNORE_P; } } close_anchor(h_env, obuf); return 1; case HTML_DL: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); if (!(obuf->flag & RB_PREMODE)) do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } PUSH_ENV(cmd); if (parsedtag_exists(tag, ATTR_COMPACT)) envs[h_env->envc].env = HTML_DL_COMPACT; obuf->flag |= RB_IGNORE_P; return 1; case HTML_LI: CLOSE_A; CLOSE_DT; if (h_env->envc > 0) { Str num; flushline(h_env, obuf, envs[h_env->envc - 1].indent, 0, h_env->limit); envs[h_env->envc].count++; if (parsedtag_get_value(tag, ATTR_VALUE, &p)) { count = atoi(p); if (count > 0) envs[h_env->envc].count = count; else envs[h_env->envc].count = 0; } switch (envs[h_env->envc].env) { case HTML_UL: envs[h_env->envc].type = ul_type(tag, envs[h_env->envc].type); for (i = 0; i < INDENT_INCR - 3; i++) push_charp(obuf, 1, NBSP, PC_ASCII); tmp = Strnew(); switch (envs[h_env->envc].type) { case 'd': push_symbol(tmp, UL_SYMBOL_DISC, symbol_width, 1); break; case 'c': push_symbol(tmp, UL_SYMBOL_CIRCLE, symbol_width, 1); break; case 's': push_symbol(tmp, UL_SYMBOL_SQUARE, symbol_width, 1); break; default: push_symbol(tmp, UL_SYMBOL((h_env->envc_real - 1) % MAX_UL_LEVEL), symbol_width, 1); break; } if (symbol_width == 1) push_charp(obuf, 1, NBSP, PC_ASCII); push_str(obuf, symbol_width, tmp, PC_ASCII); push_charp(obuf, 1, NBSP, PC_ASCII); set_space_to_prevchar(obuf->prevchar); break; case HTML_OL: if (parsedtag_get_value(tag, ATTR_TYPE, &p)) envs[h_env->envc].type = (int)*p; switch ((envs[h_env->envc].count > 0)? envs[h_env->envc].type: '1') { case 'i': num = romanNumeral(envs[h_env->envc].count); break; case 'I': num = romanNumeral(envs[h_env->envc].count); Strupper(num); break; case 'a': num = romanAlphabet(envs[h_env->envc].count); break; case 'A': num = romanAlphabet(envs[h_env->envc].count); Strupper(num); break; default: num = Sprintf("%d", envs[h_env->envc].count); break; } if (INDENT_INCR >= 4) Strcat_charp(num, ". "); else Strcat_char(num, '.'); push_spaces(obuf, 1, INDENT_INCR - num->length); push_str(obuf, num->length, num, PC_ASCII); if (INDENT_INCR >= 4) set_space_to_prevchar(obuf->prevchar); break; default: push_spaces(obuf, 1, INDENT_INCR); break; } } else { flushline(h_env, obuf, 0, 0, h_env->limit); } obuf->flag |= RB_IGNORE_P; return 1; case HTML_DT: CLOSE_A; if (h_env->envc == 0 || (h_env->envc_real < h_env->nenv && envs[h_env->envc].env != HTML_DL && envs[h_env->envc].env != HTML_DL_COMPACT)) { PUSH_ENV(HTML_DL); } if (h_env->envc > 0) { flushline(h_env, obuf, envs[h_env->envc - 1].indent, 0, h_env->limit); } if (!(obuf->flag & RB_IN_DT)) { HTMLlineproc1("", h_env); obuf->flag |= RB_IN_DT; } obuf->flag |= RB_IGNORE_P; return 1; case HTML_DD: CLOSE_A; CLOSE_DT; if (envs[h_env->envc].env == HTML_DL_COMPACT) { if (obuf->pos > envs[h_env->envc].indent) flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); else push_spaces(obuf, 1, envs[h_env->envc].indent - obuf->pos); } else flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); /* obuf->flag |= RB_IGNORE_P; */ return 1; case HTML_TITLE: close_anchor(h_env, obuf); process_title(tag); obuf->flag |= RB_TITLE; obuf->end_tag = HTML_N_TITLE; return 1; case HTML_N_TITLE: if (!(obuf->flag & RB_TITLE)) return 1; obuf->flag &= ~RB_TITLE; obuf->end_tag = 0; tmp = process_n_title(tag); if (tmp) HTMLlineproc1(tmp->ptr, h_env); return 1; case HTML_TITLE_ALT: if (parsedtag_get_value(tag, ATTR_TITLE, &p)) h_env->title = html_unquote(p); return 0; case HTML_FRAMESET: PUSH_ENV(cmd); push_charp(obuf, 9, "--FRAME--", PC_ASCII); flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); return 0; case HTML_N_FRAMESET: if (h_env->envc > 0) { POP_ENV; flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } return 0; case HTML_NOFRAMES: CLOSE_A; flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); obuf->flag |= (RB_NOFRAMES | RB_IGNORE_P); /* istr = str; */ return 1; case HTML_N_NOFRAMES: CLOSE_A; flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); obuf->flag &= ~RB_NOFRAMES; return 1; case HTML_FRAME: q = r = NULL; parsedtag_get_value(tag, ATTR_SRC, &q); parsedtag_get_value(tag, ATTR_NAME, &r); if (q) { q = html_quote(q); push_tag(obuf, Sprintf("", cur_hseq++, q)->ptr, HTML_A); if (r) q = html_quote(r); push_charp(obuf, get_strwidth(q), q, PC_ASCII); push_tag(obuf, "", HTML_N_A); } flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); return 0; case HTML_HR: close_anchor(h_env, obuf); tmp = process_hr(tag, h_env->limit, envs[h_env->envc].indent); HTMLlineproc1(tmp->ptr, h_env); set_space_to_prevchar(obuf->prevchar); return 1; case HTML_PRE: x = parsedtag_exists(tag, ATTR_FOR_TABLE); CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); if (!x) do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } else fillline(obuf, envs[h_env->envc].indent); obuf->flag |= (RB_PRE | RB_IGNORE_P); /* istr = str; */ return 1; case HTML_N_PRE: flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); if (!(obuf->flag & RB_IGNORE_P)) { do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); obuf->flag |= RB_IGNORE_P; } obuf->flag &= ~RB_PRE; close_anchor(h_env, obuf); return 1; case HTML_PRE_INT: i = obuf->line->length; append_tags(obuf); if (!(obuf->flag & RB_SPECIAL)) { set_breakpoint(obuf, obuf->line->length - i); } obuf->flag |= RB_PRE_INT; return 0; case HTML_N_PRE_INT: push_tag(obuf, "", HTML_N_PRE_INT); obuf->flag &= ~RB_PRE_INT; if (!(obuf->flag & RB_SPECIAL) && obuf->pos > obuf->bp.pos) { set_prevchar(obuf->prevchar, "", 0); obuf->prev_ctype = PC_CTRL; } return 1; case HTML_NOBR: obuf->flag |= RB_NOBR; obuf->nobr_level++; return 0; case HTML_N_NOBR: if (obuf->nobr_level > 0) obuf->nobr_level--; if (obuf->nobr_level == 0) obuf->flag &= ~RB_NOBR; return 0; case HTML_PRE_PLAIN: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } obuf->flag |= (RB_PRE | RB_IGNORE_P); return 1; case HTML_N_PRE_PLAIN: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); obuf->flag |= RB_IGNORE_P; } obuf->flag &= ~RB_PRE; return 1; case HTML_LISTING: case HTML_XMP: case HTML_PLAINTEXT: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); } obuf->flag |= (RB_PLAIN | RB_IGNORE_P); switch (cmd) { case HTML_LISTING: obuf->end_tag = HTML_N_LISTING; break; case HTML_XMP: obuf->end_tag = HTML_N_XMP; break; case HTML_PLAINTEXT: obuf->end_tag = MAX_HTMLTAG; break; } return 1; case HTML_N_LISTING: case HTML_N_XMP: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) { flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); obuf->flag |= RB_IGNORE_P; } obuf->flag &= ~RB_PLAIN; obuf->end_tag = 0; return 1; case HTML_SCRIPT: obuf->flag |= RB_SCRIPT; obuf->end_tag = HTML_N_SCRIPT; return 1; case HTML_STYLE: obuf->flag |= RB_STYLE; obuf->end_tag = HTML_N_STYLE; return 1; case HTML_N_SCRIPT: obuf->flag &= ~RB_SCRIPT; obuf->end_tag = 0; return 1; case HTML_N_STYLE: obuf->flag &= ~RB_STYLE; obuf->end_tag = 0; return 1; case HTML_A: if (obuf->anchor.url) close_anchor(h_env, obuf); hseq = 0; if (parsedtag_get_value(tag, ATTR_HREF, &p)) obuf->anchor.url = Strnew_charp(p)->ptr; if (parsedtag_get_value(tag, ATTR_TARGET, &p)) obuf->anchor.target = Strnew_charp(p)->ptr; if (parsedtag_get_value(tag, ATTR_REFERER, &p)) obuf->anchor.referer = Strnew_charp(p)->ptr; if (parsedtag_get_value(tag, ATTR_TITLE, &p)) obuf->anchor.title = Strnew_charp(p)->ptr; if (parsedtag_get_value(tag, ATTR_ACCESSKEY, &p)) obuf->anchor.accesskey = (unsigned char)*p; if (parsedtag_get_value(tag, ATTR_HSEQ, &hseq)) obuf->anchor.hseq = hseq; if (hseq == 0 && obuf->anchor.url) { obuf->anchor.hseq = cur_hseq; tmp = process_anchor(tag, h_env->tagbuf->ptr); push_tag(obuf, tmp->ptr, HTML_A); return 1; } return 0; case HTML_N_A: close_anchor(h_env, obuf); return 1; case HTML_IMG: tmp = process_img(tag, h_env->limit); HTMLlineproc1(tmp->ptr, h_env); return 1; case HTML_IMG_ALT: if (parsedtag_get_value(tag, ATTR_SRC, &p)) obuf->img_alt = Strnew_charp(p); #ifdef USE_IMAGE i = 0; if (parsedtag_get_value(tag, ATTR_TOP_MARGIN, &i)) { if (i > obuf->top_margin) obuf->top_margin = i; } i = 0; if (parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &i)) { if (i > obuf->bottom_margin) obuf->bottom_margin = i; } #endif return 0; case HTML_N_IMG_ALT: if (obuf->img_alt) { if (!close_effect0(obuf, HTML_IMG_ALT)) push_tag(obuf, "", HTML_N_IMG_ALT); obuf->img_alt = NULL; } return 1; case HTML_INPUT_ALT: i = 0; if (parsedtag_get_value(tag, ATTR_TOP_MARGIN, &i)) { if (i > obuf->top_margin) obuf->top_margin = i; } i = 0; if (parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &i)) { if (i > obuf->bottom_margin) obuf->bottom_margin = i; } return 0; case HTML_TABLE: close_anchor(h_env, obuf); obuf->table_level++; if (obuf->table_level >= MAX_TABLE) break; w = BORDER_NONE; /* x: cellspacing, y: cellpadding */ x = 2; y = 1; z = 0; width = 0; if (parsedtag_exists(tag, ATTR_BORDER)) { if (parsedtag_get_value(tag, ATTR_BORDER, &w)) { if (w > 2) w = BORDER_THICK; else if (w < 0) { /* weird */ w = BORDER_THIN; } } else w = BORDER_THIN; } if (parsedtag_get_value(tag, ATTR_WIDTH, &i)) { if (obuf->table_level == 0) width = REAL_WIDTH(i, h_env->limit - envs[h_env->envc].indent); else width = RELATIVE_WIDTH(i); } if (parsedtag_exists(tag, ATTR_HBORDER)) w = BORDER_NOWIN; parsedtag_get_value(tag, ATTR_CELLSPACING, &x); parsedtag_get_value(tag, ATTR_CELLPADDING, &y); parsedtag_get_value(tag, ATTR_VSPACE, &z); #ifdef ID_EXT parsedtag_get_value(tag, ATTR_ID, &id); #endif /* ID_EXT */ tables[obuf->table_level] = begin_table(w, x, y, z); #ifdef ID_EXT if (id != NULL) tables[obuf->table_level]->id = Strnew_charp(id); #endif /* ID_EXT */ table_mode[obuf->table_level].pre_mode = 0; table_mode[obuf->table_level].indent_level = 0; table_mode[obuf->table_level].nobr_level = 0; table_mode[obuf->table_level].caption = 0; table_mode[obuf->table_level].end_tag = 0; /* HTML_UNKNOWN */ #ifndef TABLE_EXPAND tables[obuf->table_level]->total_width = width; #else tables[obuf->table_level]->real_width = width; tables[obuf->table_level]->total_width = 0; #endif return 1; case HTML_N_TABLE: /* should be processed in HTMLlineproc() */ return 1; case HTML_CENTER: CLOSE_A; if (!(obuf->flag & (RB_PREMODE | RB_IGNORE_P))) flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); RB_SAVE_FLAG(obuf); RB_SET_ALIGN(obuf, RB_CENTER); return 1; case HTML_N_CENTER: CLOSE_A; if (!(obuf->flag & RB_PREMODE)) flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); RB_RESTORE_FLAG(obuf); return 1; case HTML_DIV: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); set_alignment(obuf, tag); return 1; case HTML_N_DIV: CLOSE_A; flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); RB_RESTORE_FLAG(obuf); return 1; case HTML_DIV_INT: CLOSE_P; if (!(obuf->flag & RB_IGNORE_P)) flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); set_alignment(obuf, tag); return 1; case HTML_N_DIV_INT: CLOSE_P; flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); RB_RESTORE_FLAG(obuf); return 1; case HTML_FORM: CLOSE_A; if (!(obuf->flag & RB_IGNORE_P)) flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); tmp = process_form(tag); if (tmp) HTMLlineproc1(tmp->ptr, h_env); return 1; case HTML_N_FORM: CLOSE_A; flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); obuf->flag |= RB_IGNORE_P; process_n_form(); return 1; case HTML_INPUT: close_anchor(h_env, obuf); tmp = process_input(tag); if (tmp) HTMLlineproc1(tmp->ptr, h_env); return 1; case HTML_SELECT: close_anchor(h_env, obuf); tmp = process_select(tag); if (tmp) HTMLlineproc1(tmp->ptr, h_env); obuf->flag |= RB_INSELECT; obuf->end_tag = HTML_N_SELECT; return 1; case HTML_N_SELECT: obuf->flag &= ~RB_INSELECT; obuf->end_tag = 0; tmp = process_n_select(); if (tmp) HTMLlineproc1(tmp->ptr, h_env); return 1; case HTML_OPTION: /* nothing */ return 1; case HTML_TEXTAREA: close_anchor(h_env, obuf); tmp = process_textarea(tag, h_env->limit); if (tmp) HTMLlineproc1(tmp->ptr, h_env); obuf->flag |= RB_INTXTA; obuf->end_tag = HTML_N_TEXTAREA; return 1; case HTML_N_TEXTAREA: obuf->flag &= ~RB_INTXTA; obuf->end_tag = 0; tmp = process_n_textarea(); if (tmp) HTMLlineproc1(tmp->ptr, h_env); return 1; case HTML_ISINDEX: p = ""; q = "!CURRENT_URL!"; parsedtag_get_value(tag, ATTR_PROMPT, &p); parsedtag_get_value(tag, ATTR_ACTION, &q); tmp = Strnew_m_charp("
", html_quote(p), "
", NULL); HTMLlineproc1(tmp->ptr, h_env); return 1; case HTML_META: p = q = NULL; parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &p); parsedtag_get_value(tag, ATTR_CONTENT, &q); #ifdef USE_M17N if (p && q && !strcasecmp(p, "Content-Type") && (q = strcasestr(q, "charset")) != NULL) { q += 7; SKIP_BLANKS(q); if (*q == '=') { q++; SKIP_BLANKS(q); meta_charset = wc_guess_charset(q, 0); } } else #endif if (p && q && !strcasecmp(p, "refresh")) { int refresh_interval; tmp = NULL; refresh_interval = getMetaRefreshParam(q, &tmp); if (tmp) { q = html_quote(tmp->ptr); tmp = Sprintf("Refresh (%d sec) %s", refresh_interval, q, q); } else if (refresh_interval > 0) tmp = Sprintf("Refresh (%d sec)", refresh_interval); if (tmp) { HTMLlineproc1(tmp->ptr, h_env); do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); if (!is_redisplay && !((obuf->flag & RB_NOFRAMES) && RenderFrame)) { tag->need_reconstruct = TRUE; return 0; } } } return 1; case HTML_BASE: #ifdef USE_IMAGE p = NULL; if (parsedtag_get_value(tag, ATTR_HREF, &p)) { if (!cur_baseURL) cur_baseURL = New(ParsedURL); parseURL(p, cur_baseURL, NULL); } #endif case HTML_MAP: case HTML_N_MAP: case HTML_AREA: return 0; case HTML_DEL: if (displayInsDel) HTMLlineproc1("[DEL:", h_env); else obuf->flag |= RB_DEL; return 1; case HTML_N_DEL: if (displayInsDel) HTMLlineproc1(":DEL]", h_env); else obuf->flag &= ~RB_DEL; return 1; case HTML_S: if (displayInsDel) HTMLlineproc1("[S:", h_env); else obuf->flag |= RB_S; return 1; case HTML_N_S: if (displayInsDel) HTMLlineproc1(":S]", h_env); else obuf->flag &= ~RB_S; return 1; case HTML_INS: if (displayInsDel) HTMLlineproc1("[INS:", h_env); return 1; case HTML_N_INS: if (displayInsDel) HTMLlineproc1(":INS]", h_env); return 1; case HTML_SUP: if (!(obuf->flag & (RB_DEL | RB_S))) HTMLlineproc1("^", h_env); return 1; case HTML_N_SUP: return 1; case HTML_SUB: if (!(obuf->flag & (RB_DEL | RB_S))) HTMLlineproc1("[", h_env); return 1; case HTML_N_SUB: if (!(obuf->flag & (RB_DEL | RB_S))) HTMLlineproc1("]", h_env); return 1; case HTML_FONT: case HTML_N_FONT: case HTML_NOP: return 1; case HTML_BGSOUND: if (view_unseenobject) { if (parsedtag_get_value(tag, ATTR_SRC, &p)) { Str s; q = html_quote(p); s = Sprintf("bgsound(%s)", q, q); HTMLlineproc1(s->ptr, h_env); } } return 1; case HTML_EMBED: if (view_unseenobject) { if (parsedtag_get_value(tag, ATTR_SRC, &p)) { Str s; q = html_quote(p); s = Sprintf("embed(%s)", q, q); HTMLlineproc1(s->ptr, h_env); } } return 1; case HTML_APPLET: if (view_unseenobject) { if (parsedtag_get_value(tag, ATTR_ARCHIVE, &p)) { Str s; q = html_quote(p); s = Sprintf("applet archive(%s)", q, q); HTMLlineproc1(s->ptr, h_env); } } return 1; case HTML_BODY: if (view_unseenobject) { if (parsedtag_get_value(tag, ATTR_BACKGROUND, &p)) { Str s; q = html_quote(p); s = Sprintf("\"bg
", q, q); HTMLlineproc1(s->ptr, h_env); } } case HTML_N_HEAD: if (obuf->flag & RB_TITLE) HTMLlineproc1("", h_env); case HTML_HEAD: case HTML_N_BODY: return 1; default: /* obuf->prevchar = '\0'; */ return 0; } /* not reached */ return 0; } #define PPUSH(p,c) {outp[pos]=(p);outc[pos]=(c);pos++;} #define PSIZE \ if (out_size <= pos + 1) { \ out_size = pos * 3 / 2; \ outc = New_Reuse(char, outc, out_size); \ outp = New_Reuse(Lineprop, outp, out_size); \ } static TextLineListItem *_tl_lp2; static Str textlist_feed() { TextLine *p; if (_tl_lp2 != NULL) { p = _tl_lp2->ptr; _tl_lp2 = _tl_lp2->next; return p->line; } return NULL; } static void HTMLlineproc2body(Buffer *buf, Str (*feed) (), int llimit) { static char *outc = NULL; static Lineprop *outp = NULL; static int out_size = 0; Anchor *a_href = NULL, *a_img = NULL, *a_form = NULL; char *p, *q, *r, *s, *t, *str; Lineprop mode, effect; int pos; int nlines; #ifdef DEBUG FILE *debug = NULL; #endif struct frameset *frameset_s[FRAMESTACK_SIZE]; int frameset_sp = -1; union frameset_element *idFrame = NULL; char *id = NULL; int hseq, form_id; Str line; char *endp; char symbol = '\0'; int internal = 0; Anchor **a_textarea = NULL; #ifdef MENU_SELECT Anchor **a_select = NULL; #endif if (out_size == 0) { out_size = LINELEN; outc = NewAtom_N(char, out_size); outp = NewAtom_N(Lineprop, out_size); } n_textarea = -1; if (!max_textarea) { /* halfload */ max_textarea = MAX_TEXTAREA; textarea_str = New_N(Str, max_textarea); a_textarea = New_N(Anchor *, max_textarea); } #ifdef MENU_SELECT n_select = -1; if (!max_select) { /* halfload */ max_select = MAX_SELECT; select_option = New_N(FormSelectOption, max_select); a_select = New_N(Anchor *, max_select); } #endif #ifdef DEBUG if (w3m_debug) debug = fopen("zzzerr", "a"); #endif effect = 0; nlines = 0; while ((line = feed()) != NULL) { #ifdef DEBUG if (w3m_debug) { Strfputs(line, debug); fputc('\n', debug); } #endif if (n_textarea >= 0 && *(line->ptr) != '<') { /* halfload */ Strcat(textarea_str[n_textarea], line); continue; } proc_again: if (++nlines == llimit) break; pos = 0; #ifdef ENABLE_REMOVE_TRAILINGSPACES Strremovetrailingspaces(line); #endif str = line->ptr; endp = str + line->length; while (str < endp) { PSIZE; mode = get_mctype(str); if (effect & PC_SYMBOL && *str != '<') { #ifdef USE_M17N char **buf = set_symbol(symbol_width0); int len; p = buf[(int)symbol]; len = get_mclen(p); mode = get_mctype(p); PPUSH(mode | effect, *(p++)); if (--len) { mode = (mode & ~PC_WCHAR1) | PC_WCHAR2; while (len--) { PSIZE; PPUSH(mode | effect, *(p++)); } } #else PPUSH(PC_ASCII | effect, SYMBOL_BASE + symbol); #endif str += symbol_width; } #ifdef USE_M17N else if (mode == PC_CTRL || mode == PC_UNDEF) { #else else if (mode == PC_CTRL || IS_INTSPACE(*str)) { #endif PPUSH(PC_ASCII | effect, ' '); str++; } #ifdef USE_M17N else if (mode & PC_UNKNOWN) { PPUSH(PC_ASCII | effect, ' '); str += get_mclen(str); } #endif else if (*str != '<' && *str != '&') { #ifdef USE_M17N int len = get_mclen(str); #endif PPUSH(mode | effect, *(str++)); #ifdef USE_M17N if (--len) { mode = (mode & ~PC_WCHAR1) | PC_WCHAR2; while (len--) { PSIZE; PPUSH(mode | effect, *(str++)); } } #endif } else if (*str == '&') { /* * & escape processing */ p = getescapecmd(&str); while (*p) { PSIZE; mode = get_mctype((unsigned char *)p); #ifdef USE_M17N if (mode == PC_CTRL || mode == PC_UNDEF) { #else if (mode == PC_CTRL || IS_INTSPACE(*str)) { #endif PPUSH(PC_ASCII | effect, ' '); p++; } #ifdef USE_M17N else if (mode & PC_UNKNOWN) { PPUSH(PC_ASCII | effect, ' '); p += get_mclen(p); } #endif else { #ifdef USE_M17N int len = get_mclen(p); #endif PPUSH(mode | effect, *(p++)); #ifdef USE_M17N if (--len) { mode = (mode & ~PC_WCHAR1) | PC_WCHAR2; while (len--) { PSIZE; PPUSH(mode | effect, *(p++)); } } #endif } } } else { /* tag processing */ struct parsed_tag *tag; if (!(tag = parse_tag(&str, TRUE))) continue; switch (tag->tagid) { case HTML_B: effect |= PE_BOLD; break; case HTML_N_B: effect &= ~PE_BOLD; break; case HTML_U: effect |= PE_UNDER; break; case HTML_N_U: effect &= ~PE_UNDER; break; case HTML_A: if (renderFrameSet && parsedtag_get_value(tag, ATTR_FRAMENAME, &p)) { p = url_quote_conv(p, buf->document_charset); if (!idFrame || strcmp(idFrame->body->name, p)) { idFrame = search_frame(renderFrameSet, p); if (idFrame && idFrame->body->attr != F_BODY) idFrame = NULL; } } p = r = s = NULL; q = buf->baseTarget; t = ""; hseq = 0; id = NULL; if (parsedtag_get_value(tag, ATTR_NAME, &id)) { id = url_quote_conv(id, buf->document_charset); registerName(buf, id, currentLn(buf), pos); } if (parsedtag_get_value(tag, ATTR_HREF, &p)) p = url_quote_conv(remove_space(p), buf->document_charset); if (parsedtag_get_value(tag, ATTR_TARGET, &q)) q = url_quote_conv(q, buf->document_charset); if (parsedtag_get_value(tag, ATTR_REFERER, &r)) r = url_quote_conv(r, buf->document_charset); parsedtag_get_value(tag, ATTR_TITLE, &s); parsedtag_get_value(tag, ATTR_ACCESSKEY, &t); parsedtag_get_value(tag, ATTR_HSEQ, &hseq); if (hseq > 0) buf->hmarklist = putHmarker(buf->hmarklist, currentLn(buf), pos, hseq - 1); else if (hseq < 0) { int h = -hseq - 1; if (buf->hmarklist && h < buf->hmarklist->nmark && buf->hmarklist->marks[h].invalid) { buf->hmarklist->marks[h].pos = pos; buf->hmarklist->marks[h].line = currentLn(buf); buf->hmarklist->marks[h].invalid = 0; hseq = -hseq; } } if (id && idFrame) idFrame->body->nameList = putAnchor(idFrame->body->nameList, id, NULL, (Anchor **)NULL, NULL, NULL, '\0', currentLn(buf), pos); if (p) { effect |= PE_ANCHOR; a_href = registerHref(buf, p, q, r, s, *t, currentLn(buf), pos); a_href->hseq = ((hseq > 0) ? hseq : -hseq) - 1; a_href->slave = (hseq > 0) ? FALSE : TRUE; } break; case HTML_N_A: effect &= ~PE_ANCHOR; if (a_href) { a_href->end.line = currentLn(buf); a_href->end.pos = pos; if (a_href->start.line == a_href->end.line && a_href->start.pos == a_href->end.pos) { if (buf->hmarklist && a_href->hseq < buf->hmarklist->nmark) buf->hmarklist->marks[a_href->hseq].invalid = 1; a_href->hseq = -1; } a_href = NULL; } break; case HTML_LINK: addLink(buf, tag); break; case HTML_IMG_ALT: if (parsedtag_get_value(tag, ATTR_SRC, &p)) { #ifdef USE_IMAGE int w = -1, h = -1, iseq = 0, ismap = 0; int xoffset = 0, yoffset = 0, top = 0, bottom = 0; parsedtag_get_value(tag, ATTR_HSEQ, &iseq); parsedtag_get_value(tag, ATTR_WIDTH, &w); parsedtag_get_value(tag, ATTR_HEIGHT, &h); parsedtag_get_value(tag, ATTR_XOFFSET, &xoffset); parsedtag_get_value(tag, ATTR_YOFFSET, &yoffset); parsedtag_get_value(tag, ATTR_TOP_MARGIN, &top); parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &bottom); if (parsedtag_exists(tag, ATTR_ISMAP)) ismap = 1; q = NULL; parsedtag_get_value(tag, ATTR_USEMAP, &q); if (iseq > 0) { buf->imarklist = putHmarker(buf->imarklist, currentLn(buf), pos, iseq - 1); } #endif s = NULL; parsedtag_get_value(tag, ATTR_TITLE, &s); p = url_quote_conv(remove_space(p), buf->document_charset); a_img = registerImg(buf, p, s, currentLn(buf), pos); #ifdef USE_IMAGE a_img->hseq = iseq; a_img->image = NULL; if (iseq > 0) { ParsedURL u; Image *image; parseURL2(a_img->url, &u, cur_baseURL); a_img->image = image = New(Image); image->url = parsedURL2Str(&u)->ptr; if (!uncompressed_file_type(u.file, &image->ext)) image->ext = filename_extension(u.file, TRUE); image->cache = NULL; image->width = (w > MAX_IMAGE_SIZE) ? MAX_IMAGE_SIZE : w; image->height = (h > MAX_IMAGE_SIZE) ? MAX_IMAGE_SIZE : h; image->xoffset = xoffset; image->yoffset = yoffset; image->y = currentLn(buf) - top; if (image->xoffset < 0 && pos == 0) image->xoffset = 0; if (image->yoffset < 0 && image->y == 1) image->yoffset = 0; image->rows = 1 + top + bottom; image->map = q; image->ismap = ismap; image->touch = 0; image->cache = getImage(image, cur_baseURL, IMG_FLAG_SKIP); } else if (iseq < 0) { BufferPoint *po = buf->imarklist->marks - iseq - 1; Anchor *a = retrieveAnchor(buf->img, po->line, po->pos); if (a) { a_img->url = a->url; a_img->image = a->image; } } #endif } effect |= PE_IMAGE; break; case HTML_N_IMG_ALT: effect &= ~PE_IMAGE; if (a_img) { a_img->end.line = currentLn(buf); a_img->end.pos = pos; } a_img = NULL; break; case HTML_INPUT_ALT: { FormList *form; int top = 0, bottom = 0; int textareanumber = -1; #ifdef MENU_SELECT int selectnumber = -1; #endif hseq = 0; form_id = -1; parsedtag_get_value(tag, ATTR_HSEQ, &hseq); parsedtag_get_value(tag, ATTR_FID, &form_id); parsedtag_get_value(tag, ATTR_TOP_MARGIN, &top); parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &bottom); if (form_id < 0 || form_id > form_max || forms == NULL) break; /* outside of
..
*/ form = forms[form_id]; if (hseq > 0) { int hpos = pos; if (*str == '[') hpos++; buf->hmarklist = putHmarker(buf->hmarklist, currentLn(buf), hpos, hseq - 1); } if (!form->target) form->target = buf->baseTarget; if (a_textarea && parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, &textareanumber)) { if (textareanumber >= max_textarea) { max_textarea = 2 * textareanumber; textarea_str = New_Reuse(Str, textarea_str, max_textarea); a_textarea = New_Reuse(Anchor *, a_textarea, max_textarea); } } #ifdef MENU_SELECT if (a_select && parsedtag_get_value(tag, ATTR_SELECTNUMBER, &selectnumber)) { if (selectnumber >= max_select) { max_select = 2 * selectnumber; select_option = New_Reuse(FormSelectOption, select_option, max_select); a_select = New_Reuse(Anchor *, a_select, max_select); } } #endif a_form = registerForm(buf, form, tag, currentLn(buf), pos); if (a_textarea && textareanumber >= 0) a_textarea[textareanumber] = a_form; #ifdef MENU_SELECT if (a_select && selectnumber >= 0) a_select[selectnumber] = a_form; #endif if (a_form) { a_form->hseq = hseq - 1; a_form->y = currentLn(buf) - top; a_form->rows = 1 + top + bottom; if (!parsedtag_exists(tag, ATTR_NO_EFFECT)) effect |= PE_FORM; break; } } case HTML_N_INPUT_ALT: effect &= ~PE_FORM; if (a_form) { a_form->end.line = currentLn(buf); a_form->end.pos = pos; if (a_form->start.line == a_form->end.line && a_form->start.pos == a_form->end.pos) a_form->hseq = -1; } a_form = NULL; break; case HTML_MAP: if (parsedtag_get_value(tag, ATTR_NAME, &p)) { MapList *m = New(MapList); m->name = Strnew_charp(p); m->area = newGeneralList(); m->next = buf->maplist; buf->maplist = m; } break; case HTML_N_MAP: /* nothing to do */ break; case HTML_AREA: if (buf->maplist == NULL) /* outside of .. */ break; if (parsedtag_get_value(tag, ATTR_HREF, &p)) { MapArea *a; p = url_quote_conv(remove_space(p), buf->document_charset); t = NULL; parsedtag_get_value(tag, ATTR_TARGET, &t); q = ""; parsedtag_get_value(tag, ATTR_ALT, &q); r = NULL; s = NULL; #ifdef USE_IMAGE parsedtag_get_value(tag, ATTR_SHAPE, &r); parsedtag_get_value(tag, ATTR_COORDS, &s); #endif a = newMapArea(p, t, q, r, s); pushValue(buf->maplist->area, (void *)a); } break; case HTML_FRAMESET: frameset_sp++; if (frameset_sp >= FRAMESTACK_SIZE) break; frameset_s[frameset_sp] = newFrameSet(tag); if (frameset_s[frameset_sp] == NULL) break; if (frameset_sp == 0) { if (buf->frameset == NULL) { buf->frameset = frameset_s[frameset_sp]; } else pushFrameTree(&(buf->frameQ), frameset_s[frameset_sp], NULL); } else addFrameSetElement(frameset_s[frameset_sp - 1], *(union frameset_element *) &frameset_s[frameset_sp]); break; case HTML_N_FRAMESET: if (frameset_sp >= 0) frameset_sp--; break; case HTML_FRAME: if (frameset_sp >= 0 && frameset_sp < FRAMESTACK_SIZE) { union frameset_element element; element.body = newFrame(tag, buf); addFrameSetElement(frameset_s[frameset_sp], element); } break; case HTML_BASE: if (parsedtag_get_value(tag, ATTR_HREF, &p)) { p = url_quote_conv(remove_space(p), buf->document_charset); if (!buf->baseURL) buf->baseURL = New(ParsedURL); parseURL(p, buf->baseURL, NULL); } if (parsedtag_get_value(tag, ATTR_TARGET, &p)) buf->baseTarget = url_quote_conv(p, buf->document_charset); break; case HTML_META: p = q = NULL; parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &p); parsedtag_get_value(tag, ATTR_CONTENT, &q); if (p && q && !strcasecmp(p, "refresh") && MetaRefresh) { Str tmp = NULL; int refresh_interval = getMetaRefreshParam(q, &tmp); #ifdef USE_ALARM if (tmp) { p = url_quote_conv(remove_space(tmp->ptr), buf->document_charset); buf->event = setAlarmEvent(buf->event, refresh_interval, AL_IMPLICIT_ONCE, FUNCNAME_gorURL, p); } else if (refresh_interval > 0) buf->event = setAlarmEvent(buf->event, refresh_interval, AL_IMPLICIT, FUNCNAME_reload, NULL); #else if (tmp && refresh_interval == 0) { p = url_quote_conv(remove_space(tmp->ptr), buf->document_charset); pushEvent(FUNCNAME_gorURL, p); } #endif } break; case HTML_INTERNAL: internal = HTML_INTERNAL; break; case HTML_N_INTERNAL: internal = HTML_N_INTERNAL; break; case HTML_FORM_INT: if (parsedtag_get_value(tag, ATTR_FID, &form_id)) process_form_int(tag, form_id); break; case HTML_TEXTAREA_INT: if (parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, &n_textarea) && n_textarea < max_textarea) { textarea_str[n_textarea] = Strnew(); } else n_textarea = -1; break; case HTML_N_TEXTAREA_INT: if (n_textarea >= 0) { FormItemList *item = (FormItemList *)a_textarea[n_textarea]->url; item->init_value = item->value = textarea_str[n_textarea]; } break; #ifdef MENU_SELECT case HTML_SELECT_INT: if (parsedtag_get_value(tag, ATTR_SELECTNUMBER, &n_select) && n_select < max_select) { select_option[n_select].first = NULL; select_option[n_select].last = NULL; } else n_select = -1; break; case HTML_N_SELECT_INT: if (n_select >= 0) { FormItemList *item = (FormItemList *)a_select[n_select]->url; item->select_option = select_option[n_select].first; chooseSelectOption(item, item->select_option); item->init_selected = item->selected; item->init_value = item->value; item->init_label = item->label; } break; case HTML_OPTION_INT: if (n_select >= 0) { int selected; q = ""; parsedtag_get_value(tag, ATTR_LABEL, &q); p = q; parsedtag_get_value(tag, ATTR_VALUE, &p); selected = parsedtag_exists(tag, ATTR_SELECTED); addSelectOption(&select_option[n_select], Strnew_charp(p), Strnew_charp(q), selected); } break; #endif case HTML_TITLE_ALT: if (parsedtag_get_value(tag, ATTR_TITLE, &p)) buf->buffername = html_unquote(p); break; case HTML_SYMBOL: effect |= PC_SYMBOL; if (parsedtag_get_value(tag, ATTR_TYPE, &p)) symbol = (char)atoi(p); break; case HTML_N_SYMBOL: effect &= ~PC_SYMBOL; break; } #ifdef ID_EXT id = NULL; if (parsedtag_get_value(tag, ATTR_ID, &id)) { id = url_quote_conv(id, buf->document_charset); registerName(buf, id, currentLn(buf), pos); } if (renderFrameSet && parsedtag_get_value(tag, ATTR_FRAMENAME, &p)) { p = url_quote_conv(p, buf->document_charset); if (!idFrame || strcmp(idFrame->body->name, p)) { idFrame = search_frame(renderFrameSet, p); if (idFrame && idFrame->body->attr != F_BODY) idFrame = NULL; } } if (id && idFrame) idFrame->body->nameList = putAnchor(idFrame->body->nameList, id, NULL, (Anchor **)NULL, NULL, NULL, '\0', currentLn(buf), pos); #endif /* ID_EXT */ } } /* end of processing for one line */ if (!internal) addnewline(buf, outc, outp, NULL, pos, -1, nlines); if (internal == HTML_N_INTERNAL) internal = 0; if (str != endp) { line = Strsubstr(line, str - line->ptr, endp - str); goto proc_again; } } #ifdef DEBUG if (w3m_debug) fclose(debug); #endif for (form_id = 1; form_id <= form_max; form_id++) forms[form_id]->next = forms[form_id - 1]; buf->formlist = (form_max >= 0) ? forms[form_max] : NULL; if (n_textarea) addMultirowsForm(buf, buf->formitem); #ifdef USE_IMAGE addMultirowsImg(buf, buf->img); #endif } static void addLink(Buffer *buf, struct parsed_tag *tag) { char *href = NULL, *title = NULL, *ctype = NULL, *rel = NULL, *rev = NULL; char type = LINK_TYPE_NONE; LinkList *l; parsedtag_get_value(tag, ATTR_HREF, &href); if (href) href = url_quote_conv(remove_space(href), buf->document_charset); parsedtag_get_value(tag, ATTR_TITLE, &title); parsedtag_get_value(tag, ATTR_TYPE, &ctype); parsedtag_get_value(tag, ATTR_REL, &rel); if (rel != NULL) { /* forward link type */ type = LINK_TYPE_REL; if (title == NULL) title = rel; } parsedtag_get_value(tag, ATTR_REV, &rev); if (rev != NULL) { /* reverse link type */ type = LINK_TYPE_REV; if (title == NULL) title = rev; } l = New(LinkList); l->url = href; l->title = title; l->ctype = ctype; l->type = type; l->next = NULL; if (buf->linklist) { LinkList *i; for (i = buf->linklist; i->next; i = i->next) ; i->next = l; } else buf->linklist = l; } void HTMLlineproc2(Buffer *buf, TextLineList *tl) { _tl_lp2 = tl->first; HTMLlineproc2body(buf, textlist_feed, -1); } static InputStream _file_lp2; static Str file_feed() { Str s; s = StrISgets(_file_lp2); if (s->length == 0) { ISclose(_file_lp2); return NULL; } return s; } void HTMLlineproc3(Buffer *buf, InputStream stream) { _file_lp2 = stream; HTMLlineproc2body(buf, file_feed, -1); } static void proc_escape(struct readbuffer *obuf, char **str_return) { char *str = *str_return, *estr; int ech = getescapechar(str_return); int width, n_add = *str_return - str; Lineprop mode = PC_ASCII; if (ech < 0) { *str_return = str; proc_mchar(obuf, obuf->flag & RB_SPECIAL, 1, str_return, PC_ASCII); return; } mode = IS_CNTRL(ech) ? PC_CTRL : PC_ASCII; estr = conv_entity(ech); check_breakpoint(obuf, obuf->flag & RB_SPECIAL, estr); width = get_strwidth(estr); if (width == 1 && ech == (unsigned char)*estr && ech != '&' && ech != '<' && ech != '>') { if (IS_CNTRL(ech)) mode = PC_CTRL; push_charp(obuf, width, estr, mode); } else push_nchars(obuf, width, str, n_add, mode); set_prevchar(obuf->prevchar, estr, strlen(estr)); obuf->prev_ctype = mode; } static int need_flushline(struct html_feed_environ *h_env, struct readbuffer *obuf, Lineprop mode) { char ch; if (obuf->flag & RB_PRE_INT) { if (obuf->pos > h_env->limit) return 1; else return 0; } ch = Strlastchar(obuf->line); /* if (ch == ' ' && obuf->tag_sp > 0) */ if (ch == ' ') return 0; if (obuf->pos > h_env->limit) return 1; return 0; } static int table_width(struct html_feed_environ *h_env, int table_level) { int width; if (table_level < 0) return 0; width = tables[table_level]->total_width; if (table_level > 0 || width > 0) return width; return h_env->limit - h_env->envs[h_env->envc].indent; } /* HTML processing first pass */ void HTMLlineproc0(char *line, struct html_feed_environ *h_env, int internal) { Lineprop mode; int cmd; struct readbuffer *obuf = h_env->obuf; int indent, delta; struct parsed_tag *tag; Str tokbuf; struct table *tbl = NULL; struct table_mode *tbl_mode = NULL; int tbl_width = 0; #ifdef USE_M17N int is_hangul, prev_is_hangul = 0; #endif #ifdef DEBUG if (w3m_debug) { FILE *f = fopen("zzzproc1", "a"); fprintf(f, "%c%c%c%c", (obuf->flag & RB_PREMODE) ? 'P' : ' ', (obuf->table_level >= 0) ? 'T' : ' ', (obuf->flag & RB_INTXTA) ? 'X' : ' ', (obuf->flag & (RB_SCRIPT | RB_STYLE)) ? 'S' : ' '); fprintf(f, "HTMLlineproc1(\"%s\",%d,%lx)\n", line, h_env->limit, (unsigned long)h_env); fclose(f); } #endif tokbuf = Strnew(); table_start: if (obuf->table_level >= 0) { int level = min(obuf->table_level, MAX_TABLE - 1); tbl = tables[level]; tbl_mode = &table_mode[level]; tbl_width = table_width(h_env, level); } while (*line != '\0') { char *str, *p; int is_tag = FALSE; int pre_mode = (obuf->table_level >= 0) ? tbl_mode->pre_mode : obuf->flag; int end_tag = (obuf->table_level >= 0) ? tbl_mode->end_tag : obuf->end_tag; if (*line == '<' || obuf->status != R_ST_NORMAL) { /* * Tag processing */ if (obuf->status == R_ST_EOL) obuf->status = R_ST_NORMAL; else { read_token(h_env->tagbuf, &line, &obuf->status, pre_mode & RB_PREMODE, obuf->status != R_ST_NORMAL); if (obuf->status != R_ST_NORMAL) return; } if (h_env->tagbuf->length == 0) continue; str = h_env->tagbuf->ptr; if (*str == '<') { if (str[1] && REALLY_THE_BEGINNING_OF_A_TAG(str)) is_tag = TRUE; else if (!(pre_mode & (RB_PLAIN | RB_INTXTA | RB_INSELECT | RB_SCRIPT | RB_STYLE | RB_TITLE))) { line = Strnew_m_charp(str + 1, line, NULL)->ptr; str = "<"; } } } else { read_token(tokbuf, &line, &obuf->status, pre_mode & RB_PREMODE, 0); if (obuf->status != R_ST_NORMAL) /* R_ST_AMP ? */ obuf->status = R_ST_NORMAL; str = tokbuf->ptr; } if (pre_mode & (RB_PLAIN | RB_INTXTA | RB_INSELECT | RB_SCRIPT | RB_STYLE | RB_TITLE)) { if (is_tag) { p = str; if ((tag = parse_tag(&p, internal))) { if (tag->tagid == end_tag || (pre_mode & RB_INSELECT && tag->tagid == HTML_N_FORM) || (pre_mode & RB_TITLE && (tag->tagid == HTML_N_HEAD || tag->tagid == HTML_BODY))) goto proc_normal; } } /* title */ if (pre_mode & RB_TITLE) { feed_title(str); continue; } /* select */ if (pre_mode & RB_INSELECT) { if (obuf->table_level >= 0) goto proc_normal; feed_select(str); continue; } if (is_tag) { if (strncmp(str, "