aboutsummaryrefslogtreecommitdiffstats
path: root/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'file.c')
-rw-r--r--file.c8016
1 files changed, 8016 insertions, 0 deletions
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..18346e9
--- /dev/null
+++ b/file.c
@@ -0,0 +1,8016 @@
+/* $Id: file.c,v 1.235 2004/04/16 18:47:19 ukai Exp $ */
+#include "fm.h"
+#include <sys/types.h>
+#include "myctype.h"
+#include <signal.h>
+#include <setjmp.h>
+#if defined(HAVE_WAITPID) || defined(HAVE_WAIT3)
+#include <sys/wait.h>
+#endif
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utime.h>
+/* 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 char 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 <select> */
+FormSelectOption *select_option;
+static int max_select = MAX_SELECT;
+static int n_select;
+static int cur_option_maxwidth;
+#endif /* MENU_SELECT */
+
+static Str cur_textarea;
+Str *textarea_str;
+static int cur_textarea_size;
+static int cur_textarea_rows;
+static int cur_textarea_readonly;
+static int n_textarea;
+static int ignore_nl_textarea;
+static int max_textarea = MAX_TEXTAREA;
+
+static int http_response_code;
+
+#ifdef USE_M17N
+static wc_ces content_charset = 0;
+static wc_ces meta_charset = 0;
+static char *check_charset(char *p);
+static char *check_accept_charset(char *p);
+#endif
+
+#define set_prevchar(x,y,n) Strcopy_charp_n((x),(y),(n))
+#define set_space_to_prevchar(x) Strcopy_charp_n((x)," ",1)
+
+struct link_stack {
+ int cmd;
+ short offset;
+ short pos;
+ struct link_stack *next;
+};
+
+static struct link_stack *link_stack = NULL;
+
+#define FORMSTACK_SIZE 10
+#define FRAMESTACK_SIZE 10
+
+#ifdef USE_NNTP
+#define Str_news_endline(s) ((s)->ptr[0]=='.'&&((s)->ptr[1]=='\n'||(s)->ptr[1]=='\r'||(s)->ptr[1]=='\0'))
+#endif /* USE_NNTP */
+
+#define INITIAL_FORM_SIZE 10
+static FormList **forms;
+static int *form_stack;
+static int form_max = -1;
+static int forms_size = 0;
+#define cur_form_id ((form_sp >= 0)? form_stack[form_sp] : -1)
+static int form_sp = 0;
+
+static clen_t current_content_length;
+
+static int cur_hseq;
+#ifdef USE_IMAGE
+static int cur_iseq;
+#endif
+
+#define MAX_UL_LEVEL 9
+#define UL_SYMBOL(x) (N_GRAPH_SYMBOL + (x))
+#define UL_SYMBOL_DISC UL_SYMBOL(9)
+#define UL_SYMBOL_CIRCLE UL_SYMBOL(10)
+#define UL_SYMBOL_SQUARE UL_SYMBOL(11)
+#define IMG_SYMBOL UL_SYMBOL(12)
+#define HR_SYMBOL 26
+
+#ifdef USE_COOKIE
+/* This array should be somewhere else */
+/* FIXME: gettextize? */
+char *violations[COO_EMAX] = {
+ "internal error",
+ "tail match failed",
+ "wrong number of dots",
+ "RFC 2109 4.3.2 rule 1",
+ "RFC 2109 4.3.2 rule 2.1",
+ "RFC 2109 4.3.2 rule 2.2",
+ "RFC 2109 4.3.2 rule 3",
+ "RFC 2109 4.3.2 rule 4",
+ "RFC XXXX 4.3.2 rule 5"
+};
+#endif
+
+/* *INDENT-OFF* */
+static struct compression_decoder {
+ int type;
+ char *ext;
+ char *mime_type;
+ int auxbin_p;
+ char *cmd;
+ char *name;
+ char *encoding;
+ char *encodings[4];
+} compression_decoders[] = {
+ { CMP_COMPRESS, ".gz", "application/x-gzip",
+ 0, GUNZIP_CMDNAME, GUNZIP_NAME, "gzip",
+ {"gzip", "x-gzip", NULL} },
+ { CMP_COMPRESS, ".Z", "application/x-compress",
+ 0, GUNZIP_CMDNAME, GUNZIP_NAME, "compress",
+ {"compress", "x-compress", NULL} },
+ { CMP_BZIP2, ".bz2", "application/x-bzip",
+ 0, BUNZIP2_CMDNAME, BUNZIP2_NAME, "bzip, bzip2",
+ {"x-bzip", "bzip", "bzip2", NULL} },
+ { CMP_DEFLATE, ".deflate", "application/x-deflate",
+ 1, INFLATE_CMDNAME, INFLATE_NAME, "deflate",
+ {"deflate", "x-deflate", NULL} },
+ { CMP_NOCOMPRESS, NULL, NULL, 0, NULL, NULL, NULL, {NULL}},
+};
+/* *INDENT-ON* */
+
+#define SAVE_BUF_SIZE 1536
+
+static MySignalHandler
+KeyAbort(SIGNAL_ARG)
+{
+ LONGJMP(AbortLoading, 1);
+ SIGNAL_RETURN;
+}
+
+static void
+UFhalfclose(URLFile *f)
+{
+ switch (f->scheme) {
+ case SCM_FTP:
+ closeFTP();
+ break;
+#ifdef USE_NNTP
+ case SCM_NEWS:
+ case SCM_NNTP:
+ closeNews();
+ break;
+#endif
+ default:
+ UFclose(f);
+ break;
+ }
+}
+
+int
+currentLn(Buffer *buf)
+{
+ if (buf->currentLine)
+ /* return buf->currentLine->real_linenumber + 1; */
+ return buf->currentLine->linenumber + 1;
+ else
+ return 1;
+}
+
+static Buffer *
+loadSomething(URLFile *f,
+ char *path,
+ Buffer *(*loadproc) (URLFile *, Buffer *), Buffer *defaultbuf)
+{
+ Buffer *buf;
+
+ if ((buf = loadproc(f, defaultbuf)) == NULL)
+ return NULL;
+
+ buf->filename = path;
+ if (buf->buffername == NULL || buf->buffername[0] == '\0') {
+ buf->buffername = checkHeader(buf, "Subject:");
+ if (buf->buffername == NULL)
+ buf->buffername = conv_from_system(lastFileName(path));
+ }
+ if (buf->currentURL.scheme == SCM_UNKNOWN)
+ buf->currentURL.scheme = f->scheme;
+ buf->real_scheme = f->scheme;
+ if (f->scheme == SCM_LOCAL && buf->sourcefile == NULL)
+ buf->sourcefile = path;
+ return buf;
+}
+
+int
+dir_exist(char *path)
+{
+ struct stat stbuf;
+
+ if (path == NULL || *path == '\0')
+ return 0;
+ if (stat(path, &stbuf) == -1)
+ return 0;
+ return IS_DIRECTORY(stbuf.st_mode);
+}
+
+static int
+is_dump_text_type(char *type)
+{
+ struct mailcap *mcap;
+ return (type && (mcap = searchExtViewer(type)) &&
+ (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)));
+}
+
+static int
+is_text_type(char *type)
+{
+ return (type == NULL || type[0] == '\0' ||
+ strncasecmp(type, "text/", 5) == 0 ||
+ strncasecmp(type, "message/", sizeof("message/") - 1) == 0);
+}
+
+static int
+is_plain_text_type(char *type)
+{
+ return ((type && strcasecmp(type, "text/plain") == 0) ||
+ (is_text_type(type) && !is_dump_text_type(type)));
+}
+
+static void
+check_compression(char *path, URLFile *uf)
+{
+ int len;
+ struct compression_decoder *d;
+
+ if (path == NULL)
+ return;
+
+ len = strlen(path);
+ uf->compression = CMP_NOCOMPRESS;
+ for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
+ int elen;
+ if (d->ext == NULL)
+ continue;
+ elen = strlen(d->ext);
+ if (len > elen && strcasecmp(&path[len - elen], d->ext) == 0) {
+ uf->compression = d->type;
+ uf->guess_type = d->mime_type;
+ break;
+ }
+ }
+}
+
+static char *
+compress_application_type(int compression)
+{
+ struct compression_decoder *d;
+
+ for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
+ if (d->type == compression)
+ return d->mime_type;
+ }
+ return NULL;
+}
+
+static char *
+uncompressed_file_type(char *path, char **ext)
+{
+ int len, slen;
+ Str fn;
+ char *t0;
+ struct compression_decoder *d;
+
+ if (path == NULL)
+ return NULL;
+
+ slen = 0;
+ len = strlen(path);
+ for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
+ if (d->ext == NULL)
+ continue;
+ slen = strlen(d->ext);
+ if (len > slen && strcasecmp(&path[len - slen], d->ext) == 0)
+ break;
+ }
+ if (d->type == CMP_NOCOMPRESS)
+ return NULL;
+
+ fn = Strnew_charp(path);
+ Strshrink(fn, slen);
+ if (ext)
+ *ext = filename_extension(fn->ptr, 0);
+ t0 = guessContentType(fn->ptr);
+ if (t0 == NULL)
+ t0 = "text/plain";
+ return t0;
+}
+
+static int
+setModtime(char *path, time_t modtime)
+{
+ struct utimbuf t;
+ struct stat st;
+
+ if (stat(path, &st) == 0)
+ t.actime = st.st_atime;
+ else
+ t.actime = time(NULL);
+ t.modtime = modtime;
+ return utime(path, &t);
+}
+
+void
+examineFile(char *path, URLFile *uf)
+{
+ struct stat stbuf;
+
+ uf->guess_type = NULL;
+ if (path == NULL || *path == '\0' ||
+ stat(path, &stbuf) == -1 || NOT_REGULAR(stbuf.st_mode)) {
+ uf->stream = NULL;
+ return;
+ }
+ uf->stream = openIS(path);
+ if (!do_download) {
+ if (use_lessopen && getenv("LESSOPEN") != NULL) {
+ FILE *fp;
+ uf->guess_type = guessContentType(path);
+ if (uf->guess_type == NULL)
+ uf->guess_type = "text/plain";
+ if (strcasecmp(uf->guess_type, "text/html") == 0)
+ return;
+ if ((fp = lessopen_stream(path))) {
+ UFclose(uf);
+ uf->stream = newFileStream(fp, (void (*)())pclose);
+ uf->guess_type = "text/plain";
+ return;
+ }
+ }
+ check_compression(path, uf);
+ if (uf->compression != CMP_NOCOMPRESS) {
+ char *ext = uf->ext;
+ char *t0 = uncompressed_file_type(path, &ext);
+ uf->guess_type = t0;
+ uf->ext = ext;
+ uncompress_stream(uf, NULL);
+ return;
+ }
+ }
+}
+
+#define S_IXANY (S_IXUSR|S_IXGRP|S_IXOTH)
+
+int
+check_command(char *cmd, int auxbin_p)
+{
+ static char *path = NULL;
+ Str dirs;
+ char *p, *np;
+ Str pathname;
+ struct stat st;
+
+ if (path == NULL)
+ path = getenv("PATH");
+ if (auxbin_p)
+ dirs = Strnew_charp(w3m_auxbin_dir());
+ else
+ dirs = Strnew_charp(path);
+ for (p = dirs->ptr; p != NULL; p = np) {
+ np = strchr(p, PATH_SEPARATOR);
+ if (np)
+ *np++ = '\0';
+ pathname = Strnew();
+ Strcat_charp(pathname, p);
+ Strcat_char(pathname, '/');
+ Strcat_charp(pathname, cmd);
+ if (stat(pathname->ptr, &st) == 0 && S_ISREG(st.st_mode)
+ && (st.st_mode & S_IXANY) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+char *
+acceptableEncoding()
+{
+ static Str encodings = NULL;
+ struct compression_decoder *d;
+ TextList *l;
+ char *p;
+
+ if (encodings != NULL)
+ return encodings->ptr;
+ l = newTextList();
+ for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
+ if (check_command(d->cmd, d->auxbin_p)) {
+ pushText(l, d->encoding);
+ }
+ }
+ encodings = Strnew();
+ while ((p = popText(l)) != NULL) {
+ if (encodings->length)
+ Strcat_charp(encodings, ", ");
+ Strcat_charp(encodings, p);
+ }
+ return encodings->ptr;
+}
+
+/*
+ * convert line
+ */
+#ifdef USE_M17N
+Str
+convertLine(URLFile *uf, Str line, int mode, wc_ces * charset,
+ wc_ces doc_charset)
+#else
+Str
+convertLine0(URLFile *uf, Str line, int mode)
+#endif
+{
+#ifdef USE_M17N
+ line = wc_Str_conv_with_detect(line, charset, doc_charset, InnerCharset);
+#endif
+ if (mode != RAW_MODE)
+ cleanup_line(line, mode);
+#ifdef USE_NNTP
+ if (uf && uf->scheme == SCM_NEWS)
+ Strchop(line);
+#endif /* USE_NNTP */
+ return line;
+}
+
+/*
+ * loadFile: load file to buffer
+ */
+Buffer *
+loadFile(char *path)
+{
+ Buffer *buf;
+ URLFile uf;
+ init_stream(&uf, SCM_LOCAL, NULL);
+ examineFile(path, &uf);
+ if (uf.stream == NULL)
+ return NULL;
+ buf = newBuffer(INIT_BUFFER_WIDTH);
+ current_content_length = 0;
+#ifdef USE_M17N
+ content_charset = 0;
+#endif
+ buf = loadSomething(&uf, path, loadBuffer, buf);
+ UFclose(&uf);
+ return buf;
+}
+
+int
+matchattr(char *p, char *attr, int len, Str *value)
+{
+ int quoted;
+ char *q = NULL;
+
+ if (strncasecmp(p, attr, len) == 0) {
+ p += len;
+ SKIP_BLANKS(p);
+ if (value) {
+ *value = Strnew();
+ if (*p == '=') {
+ p++;
+ SKIP_BLANKS(p);
+ quoted = 0;
+ while (!IS_ENDL(*p) && (quoted || *p != ';')) {
+ if (!IS_SPACE(*p))
+ q = p;
+ if (*p == '"')
+ quoted = (quoted) ? 0 : 1;
+ else
+ Strcat_char(*value, *p);
+ p++;
+ }
+ if (q)
+ Strshrink(*value, p - q - 1);
+ }
+ return 1;
+ }
+ else {
+ if (IS_ENDT(*p)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+#ifdef USE_IMAGE
+#ifdef USE_XFACE
+static char *
+xface2xpm(char *xface)
+{
+ Image image;
+ ImageCache *cache;
+ FILE *f;
+ struct stat st;
+
+ SKIP_BLANKS(xface);
+ image.url = xface;
+ image.ext = ".xpm";
+ image.width = 48;
+ image.height = 48;
+ image.cache = NULL;
+ cache = getImage(&image, NULL, IMG_FLAG_AUTO);
+ if (cache->loaded & IMG_FLAG_LOADED && !stat(cache->file, &st))
+ return cache->file;
+ cache->loaded = IMG_FLAG_ERROR;
+
+ f = popen(Sprintf("%s > %s", shell_quote(auxbinFile(XFACE2XPM)),
+ shell_quote(cache->file))->ptr, "w");
+ if (!f)
+ return NULL;
+ fputs(xface, f);
+ pclose(f);
+ if (stat(cache->file, &st) || !st.st_size)
+ return NULL;
+ cache->loaded = IMG_FLAG_LOADED | IMG_FLAG_DONT_REMOVE;
+ cache->index = 0;
+ return cache->file;
+}
+#endif
+#endif
+
+void
+readHeader(URLFile *uf, Buffer *newBuf, int thru, ParsedURL *pu)
+{
+ char *p, *q;
+#ifdef USE_COOKIE
+ char *emsg;
+#endif
+ char c;
+ Str lineBuf2 = NULL;
+ Str tmp;
+ TextList *headerlist;
+#ifdef USE_M17N
+ wc_ces charset = WC_CES_US_ASCII, mime_charset;
+#endif
+ char *tmpf;
+ FILE *src = NULL;
+ Lineprop *propBuffer;
+
+ headerlist = newBuf->document_header = newTextList();
+ if (uf->scheme == SCM_HTTP
+#ifdef USE_SSL
+ || uf->scheme == SCM_HTTPS
+#endif /* USE_SSL */
+ )
+ http_response_code = -1;
+ else
+ http_response_code = 0;
+
+ if (thru && !newBuf->header_source
+#ifdef USE_IMAGE
+ && !image_source
+#endif
+ ) {
+ tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
+ src = fopen(tmpf, "w");
+ if (src)
+ newBuf->header_source = tmpf;
+ }
+ while ((tmp = StrmyUFgets(uf))->length) {
+#ifdef USE_NNTP
+ if (uf->scheme == SCM_NEWS && tmp->ptr[0] == '.')
+ Strshrinkfirst(tmp, 1);
+#endif
+#ifdef HTTP_DEBUG
+ {
+ FILE *ff;
+ ff = fopen("zzrequest", "a");
+ Strfputs(tmp, ff);
+ fclose(ff);
+ }
+#endif /* HTTP_DEBUG */
+ if (src)
+ Strfputs(tmp, src);
+ cleanup_line(tmp, HEADER_MODE);
+ if (tmp->ptr[0] == '\n' || tmp->ptr[0] == '\r' || tmp->ptr[0] == '\0') {
+ if (!lineBuf2)
+ /* there is no header */
+ break;
+ /* last header */
+ }
+ else if (!(w3m_dump & DUMP_HEAD)) {
+ if (lineBuf2) {
+ Strcat(lineBuf2, tmp);
+ }
+ else {
+ lineBuf2 = tmp;
+ }
+ c = UFgetc(uf);
+ UFundogetc(uf);
+ if (c == ' ' || c == '\t')
+ /* header line is continued */
+ continue;
+ lineBuf2 = decodeMIME(lineBuf2, &mime_charset);
+ lineBuf2 = convertLine(NULL, lineBuf2, RAW_MODE,
+ mime_charset ? &mime_charset : &charset,
+ mime_charset ? mime_charset
+ : DocumentCharset);
+ /* separated with line and stored */
+ tmp = Strnew_size(lineBuf2->length);
+ for (p = lineBuf2->ptr; *p; p = q) {
+ for (q = p; *q && *q != '\r' && *q != '\n'; q++) ;
+ lineBuf2 = checkType(Strnew_charp_n(p, q - p), &propBuffer,
+ NULL);
+ Strcat(tmp, lineBuf2);
+ if (thru)
+ addnewline(newBuf, lineBuf2->ptr, propBuffer, NULL,
+ lineBuf2->length, FOLD_BUFFER_WIDTH, -1);
+ for (; *q && (*q == '\r' || *q == '\n'); q++) ;
+ }
+#ifdef USE_IMAGE
+ if (thru && activeImage && displayImage) {
+ Str src = NULL;
+ if (!strncasecmp(tmp->ptr, "X-Image-URL:", 12)) {
+ tmpf = &tmp->ptr[12];
+ SKIP_BLANKS(tmpf);
+ src = Strnew_m_charp("<img src=\"", html_quote(tmpf),
+ "\" alt=\"X-Image-URL\">", NULL);
+ }
+#ifdef USE_XFACE
+ else if (!strncasecmp(tmp->ptr, "X-Face:", 7)) {
+ tmpf = xface2xpm(&tmp->ptr[7]);
+ if (tmpf)
+ src = Strnew_m_charp("<img src=\"file:",
+ html_quote(tmpf),
+ "\" alt=\"X-Face\"",
+ " width=48 height=48>", NULL);
+ }
+#endif
+ if (src) {
+ URLFile f;
+ Line *l;
+#ifdef USE_M17N
+ wc_ces old_charset = newBuf->document_charset;
+#endif
+ init_stream(&f, SCM_LOCAL, newStrStream(src));
+ loadHTMLstream(&f, newBuf, NULL, TRUE);
+ for (l = newBuf->lastLine; l && l->real_linenumber;
+ l = l->prev)
+ l->real_linenumber = 0;
+#ifdef USE_M17N
+ newBuf->document_charset = old_charset;
+#endif
+ }
+ }
+#endif
+ lineBuf2 = tmp;
+ }
+ else {
+ lineBuf2 = tmp;
+ }
+ if ((uf->scheme == SCM_HTTP
+#ifdef USE_SSL
+ || uf->scheme == SCM_HTTPS
+#endif /* USE_SSL */
+ ) && http_response_code == -1) {
+ p = lineBuf2->ptr;
+ while (*p && !IS_SPACE(*p))
+ p++;
+ while (*p && IS_SPACE(*p))
+ p++;
+ http_response_code = atoi(p);
+ if (fmInitialized) {
+ message(lineBuf2->ptr, 0, 0);
+ refresh();
+ }
+ }
+ if (!strncasecmp(lineBuf2->ptr, "content-transfer-encoding:", 26)) {
+ p = lineBuf2->ptr + 26;
+ while (IS_SPACE(*p))
+ p++;
+ if (!strncasecmp(p, "base64", 6))
+ uf->encoding = ENC_BASE64;
+ else if (!strncasecmp(p, "quoted-printable", 16))
+ uf->encoding = ENC_QUOTE;
+ else if (!strncasecmp(p, "uuencode", 8) ||
+ !strncasecmp(p, "x-uuencode", 10))
+ uf->encoding = ENC_UUENCODE;
+ else
+ uf->encoding = ENC_7BIT;
+ }
+ else if (!strncasecmp(lineBuf2->ptr, "content-encoding:", 17)) {
+ struct compression_decoder *d;
+ p = lineBuf2->ptr + 17;
+ while (IS_SPACE(*p))
+ p++;
+ uf->compression = CMP_NOCOMPRESS;
+ for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
+ char **e;
+ for (e = d->encodings; *e != NULL; e++) {
+ if (strncasecmp(p, *e, strlen(*e)) == 0) {
+ uf->compression = d->type;
+ break;
+ }
+ }
+ if (uf->compression != CMP_NOCOMPRESS)
+ break;
+ }
+ }
+#ifdef USE_COOKIE
+ else if (use_cookie && accept_cookie &&
+ pu && check_cookie_accept_domain(pu->host) &&
+ (!strncasecmp(lineBuf2->ptr, "Set-Cookie:", 11) ||
+ !strncasecmp(lineBuf2->ptr, "Set-Cookie2:", 12))) {
+ Str name = Strnew(), value = Strnew(), domain = NULL, path = NULL,
+ comment = NULL, commentURL = NULL, port = NULL, tmp2;
+ int version, quoted, flag = 0;
+ time_t expires = (time_t) - 1;
+
+ q = NULL;
+ if (lineBuf2->ptr[10] == '2') {
+ p = lineBuf2->ptr + 12;
+ version = 1;
+ }
+ else {
+ p = lineBuf2->ptr + 11;
+ version = 0;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Set-Cookie: [%s]\n", p);
+#endif /* DEBUG */
+ SKIP_BLANKS(p);
+ while (*p != '=' && !IS_ENDT(*p))
+ Strcat_char(name, *(p++));
+ Strremovetrailingspaces(name);
+ if (*p == '=') {
+ p++;
+ SKIP_BLANKS(p);
+ quoted = 0;
+ while (!IS_ENDL(*p) && (quoted || *p != ';')) {
+ if (!IS_SPACE(*p))
+ q = p;
+ if (*p == '"')
+ quoted = (quoted) ? 0 : 1;
+ Strcat_char(value, *(p++));
+ }
+ if (q)
+ Strshrink(value, p - q - 1);
+ }
+ while (*p == ';') {
+ p++;
+ SKIP_BLANKS(p);
+ if (matchattr(p, "expires", 7, &tmp2)) {
+ /* version 0 */
+ expires = mymktime(tmp2->ptr);
+ }
+ else if (matchattr(p, "max-age", 7, &tmp2)) {
+ /* XXX Is there any problem with max-age=0? (RFC 2109 ss. 4.2.1, 4.2.2 */
+ expires = time(NULL) + atol(tmp2->ptr);
+ }
+ else if (matchattr(p, "domain", 6, &tmp2)) {
+ domain = tmp2;
+ }
+ else if (matchattr(p, "path", 4, &tmp2)) {
+ path = tmp2;
+ }
+ else if (matchattr(p, "secure", 6, NULL)) {
+ flag |= COO_SECURE;
+ }
+ else if (matchattr(p, "comment", 7, &tmp2)) {
+ comment = tmp2;
+ }
+ else if (matchattr(p, "version", 7, &tmp2)) {
+ version = atoi(tmp2->ptr);
+ }
+ else if (matchattr(p, "port", 4, &tmp2)) {
+ /* version 1, Set-Cookie2 */
+ port = tmp2;
+ }
+ else if (matchattr(p, "commentURL", 10, &tmp2)) {
+ /* version 1, Set-Cookie2 */
+ commentURL = tmp2;
+ }
+ else if (matchattr(p, "discard", 7, NULL)) {
+ /* version 1, Set-Cookie2 */
+ flag |= COO_DISCARD;
+ }
+ quoted = 0;
+ while (!IS_ENDL(*p) && (quoted || *p != ';')) {
+ if (*p == '"')
+ quoted = (quoted) ? 0 : 1;
+ p++;
+ }
+ }
+ if (pu && name->length > 0) {
+ int err;
+ if (flag & COO_SECURE)
+ disp_message_nsec("Received a secured cookie", FALSE, 1,
+ TRUE, FALSE);
+ else
+ disp_message_nsec(Sprintf("Received cookie: %s=%s",
+ name->ptr, value->ptr)->ptr,
+ FALSE, 1, TRUE, FALSE);
+ err =
+ add_cookie(pu, name, value, expires, domain, path, flag,
+ comment, version, port, commentURL);
+ if (err) {
+ char *ans = (accept_bad_cookie == ACCEPT_BAD_COOKIE_ACCEPT)
+ ? "y" : NULL;
+ if (fmInitialized && (err & COO_OVERRIDE_OK) &&
+ accept_bad_cookie == ACCEPT_BAD_COOKIE_ASK) {
+ Str msg = Sprintf("Accept bad cookie from %s for %s?",
+ pu->host,
+ ((domain && domain->ptr)
+ ? domain->ptr : "<localdomain>"));
+ if (msg->length > COLS - 10)
+ Strshrink(msg, msg->length - (COLS - 10));
+ Strcat_charp(msg, " (y/n)");
+ ans = inputAnswer(msg->ptr);
+ }
+ if (ans == NULL || TOLOWER(*ans) != 'y' ||
+ (err =
+ add_cookie(pu, name, value, expires, domain, path,
+ flag | COO_OVERRIDE, comment, version,
+ port, commentURL))) {
+ err = (err & ~COO_OVERRIDE_OK) - 1;
+ if (err >= 0 && err < COO_EMAX)
+ emsg = Sprintf("This cookie was rejected "
+ "to prevent security violation. [%s]",
+ violations[err])->ptr;
+ else
+ emsg =
+ "This cookie was rejected to prevent security violation.";
+ record_err_message(emsg);
+ disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE);
+ }
+ else
+ disp_message_nsec(Sprintf
+ ("Accepting invalid cookie: %s=%s",
+ name->ptr, value->ptr)->ptr, FALSE,
+ 1, TRUE, FALSE);
+ }
+ }
+ }
+#endif /* USE_COOKIE */
+ else if (!strncasecmp(lineBuf2->ptr, "w3m-control:", 12) &&
+ uf->scheme == SCM_LOCAL_CGI) {
+ Str funcname = Strnew();
+ int f;
+
+ p = lineBuf2->ptr + 12;
+ SKIP_BLANKS(p);
+ while (*p && !IS_SPACE(*p))
+ Strcat_char(funcname, *(p++));
+ SKIP_BLANKS(p);
+ f = getFuncList(funcname->ptr);
+ if (f >= 0) {
+ tmp = Strnew_charp(p);
+ Strchop(tmp);
+ pushEvent(f, tmp->ptr);
+ }
+ }
+ if (headerlist)
+ pushText(headerlist, lineBuf2->ptr);
+ Strfree(lineBuf2);
+ lineBuf2 = NULL;
+ }
+ if (thru)
+ addnewline(newBuf, "", propBuffer, NULL, 0, -1, -1);
+ if (src)
+ fclose(src);
+}
+
+char *
+checkHeader(Buffer *buf, char *field)
+{
+ int len;
+ TextListItem *i;
+ char *p;
+
+ if (buf == NULL || field == NULL || buf->document_header == NULL)
+ return NULL;
+ len = strlen(field);
+ for (i = buf->document_header->first; i != NULL; i = i->next) {
+ if (!strncasecmp(i->ptr, field, len)) {
+ p = i->ptr + len;
+ return remove_space(p);
+ }
+ }
+ return NULL;
+}
+
+char *
+checkContentType(Buffer *buf)
+{
+ char *p;
+ Str r;
+ p = checkHeader(buf, "Content-Type:");
+ if (p == NULL)
+ return NULL;
+ r = Strnew();
+ while (*p && *p != ';' && !IS_SPACE(*p))
+ Strcat_char(r, *p++);
+#ifdef USE_M17N
+ if ((p = strcasestr(p, "charset")) != NULL) {
+ p += 7;
+ SKIP_BLANKS(p);
+ if (*p == '=') {
+ p++;
+ SKIP_BLANKS(p);
+ if (*p == '"')
+ p++;
+ content_charset = wc_guess_charset(p, 0);
+ }
+ }
+#endif
+ return r->ptr;
+}
+
+struct auth_param {
+ char *name;
+ Str val;
+};
+
+struct http_auth {
+ int pri;
+ char *scheme;
+ struct auth_param *param;
+ Str (*cred) (struct http_auth * ha, Str uname, Str pw, ParsedURL *pu,
+ HRequest *hr, FormList *request);
+};
+
+#define TOKEN_PAT "[^][()<>@,;:\\\"/?={} \t\001-\037\177]*"
+
+static Str
+extract_auth_val(char **q)
+{
+ unsigned char *qq = *(unsigned char **)q;
+ int quoted = 0;
+ Str val = Strnew();
+
+ SKIP_BLANKS(qq);
+ if (*qq == '"') {
+ quoted = TRUE;
+ Strcat_char(val, *qq++);
+ }
+ while (*qq != '\0') {
+ if (quoted && *qq == '"') {
+ Strcat_char(val, *qq++);
+ break;
+ }
+ if (!quoted) {
+ switch (*qq) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '"':
+ case '/':
+ case '?':
+ case '=':
+ case ' ':
+ case '\t':
+ qq++;
+ goto end_token;
+ default:
+ if (*qq <= 037 || *qq == 0177) {
+ qq++;
+ goto end_token;
+ }
+ }
+ }
+ else if (quoted && *qq == '\\')
+ Strcat_char(val, *qq++);
+ Strcat_char(val, *qq++);
+ }
+ end_token:
+ if (*qq != '\0') {
+ SKIP_BLANKS(qq);
+ if (*qq == ',')
+ qq++;
+ }
+ *q = (char *)qq;
+ return val;
+}
+
+static Str
+qstr_unquote(Str s)
+{
+ char *p;
+
+ if (s == NULL)
+ return NULL;
+ p = s->ptr;
+ if (*p == '"') {
+ Str tmp = Strnew();
+ for (p++; *p != '\0'; p++) {
+ if (*p == '\\')
+ p++;
+ Strcat_char(tmp, *p);
+ }
+ if (Strlastchar(tmp) == '"')
+ Strshrink(tmp, 1);
+ return tmp;
+ }
+ else
+ return s;
+}
+
+static char *
+extract_auth_param(char *q, struct auth_param *auth)
+{
+ struct auth_param *ap;
+ char *q0;
+ Regex re_token;
+
+ newRegex(TOKEN_PAT, FALSE, &re_token, NULL);
+
+ for (ap = auth; ap->name != NULL; ap++) {
+ ap->val = NULL;
+ }
+
+ while (*q != '\0') {
+ SKIP_BLANKS(q);
+ for (ap = auth; ap->name != NULL; ap++) {
+ if (strncasecmp(q, ap->name, strlen(ap->name)) == 0) {
+ q += strlen(ap->name);
+ SKIP_BLANKS(q);
+ if (*q != '=')
+ return q;
+ q++;
+ ap->val = extract_auth_val(&q);
+ break;
+ }
+ }
+ if (ap->name == NULL) {
+ /* skip unknown param */
+ if (RegexMatch(&re_token, q, -1, TRUE) == 0)
+ return q;
+ MatchedPosition(&re_token, &q0, &q);
+ SKIP_BLANKS(q);
+ if (*q != '=')
+ return q;
+ q++;
+ extract_auth_val(&q);
+ }
+ }
+ return q;
+}
+
+static Str
+get_auth_param(struct auth_param *auth, char *name)
+{
+ struct auth_param *ap;
+ for (ap = auth; ap->name != NULL; ap++) {
+ if (strcasecmp(name, ap->name) == 0)
+ return ap->val;
+ }
+ return NULL;
+}
+
+static Str
+AuthBasicCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
+ HRequest *hr, FormList *request)
+{
+ Str s = Strdup(uname);
+ Strcat_char(s, ':');
+ Strcat(s, pw);
+ return Strnew_m_charp("Basic ", encodeB(s->ptr)->ptr, NULL);
+}
+
+#ifdef USE_DIGEST_AUTH
+#include <openssl/md5.h>
+
+/* RFC2617: 3.2.2 The Authorization Request Header
+ *
+ * credentials = "Digest" digest-response
+ * digest-response = 1#( username | realm | nonce | digest-uri
+ * | response | [ algorithm ] | [cnonce] |
+ * [opaque] | [message-qop] |
+ * [nonce-count] | [auth-param] )
+ *
+ * username = "username" "=" username-value
+ * username-value = quoted-string
+ * digest-uri = "uri" "=" digest-uri-value
+ * digest-uri-value = request-uri ; As specified by HTTP/1.1
+ * message-qop = "qop" "=" qop-value
+ * cnonce = "cnonce" "=" cnonce-value
+ * cnonce-value = nonce-value
+ * nonce-count = "nc" "=" nc-value
+ * nc-value = 8LHEX
+ * response = "response" "=" request-digest
+ * request-digest = <"> 32LHEX <">
+ * LHEX = "0" | "1" | "2" | "3" |
+ * "4" | "5" | "6" | "7" |
+ * "8" | "9" | "a" | "b" |
+ * "c" | "d" | "e" | "f"
+ */
+
+static Str
+digest_hex(char *p)
+{
+ char *h = "0123456789abcdef";
+ Str tmp = Strnew_size(MD5_DIGEST_LENGTH * 2 + 1);
+ int i;
+ for (i = 0; i < MD5_DIGEST_LENGTH; i++, p++) {
+ Strcat_char(tmp, h[(*p >> 4) & 0x0f]);
+ Strcat_char(tmp, h[*p & 0x0f]);
+ }
+ return tmp;
+}
+
+static Str
+AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
+ HRequest *hr, FormList *request)
+{
+ Str tmp, a1buf, a2buf, rd, s;
+ char md5[MD5_DIGEST_LENGTH + 1];
+ Str uri = HTTPrequestURI(pu, hr);
+ char nc[] = "00000001";
+
+ Str algorithm = qstr_unquote(get_auth_param(ha->param, "algorithm"));
+ Str nonce = qstr_unquote(get_auth_param(ha->param, "nonce"));
+ Str cnonce = qstr_unquote(get_auth_param(ha->param, "cnonce"));
+ Str qop = qstr_unquote(get_auth_param(ha->param, "qop"));
+
+ if (cnonce == NULL)
+ cnonce = Strnew_charp("cnonce"); /* XXX */
+
+ /* A1 = unq(username-value) ":" unq(realm-value) ":" passwd */
+ tmp = Strnew_m_charp(uname->ptr, ":",
+ qstr_unquote(get_auth_param(ha->param, "realm"))->ptr,
+ ":", pw->ptr, NULL);
+ MD5(tmp->ptr, strlen(tmp->ptr), md5);
+ a1buf = digest_hex(md5);
+
+ if (algorithm) {
+ if (strcasecmp(algorithm->ptr, "MD5-sess") == 0) {
+ /* A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd)
+ * ":" unq(nonce-value) ":" unq(cnonce-value)
+ */
+ if (nonce == NULL)
+ return NULL;
+ tmp = Strnew_m_charp(a1buf->ptr, ":",
+ qstr_unquote(nonce)->ptr,
+ ":", qstr_unquote(cnonce)->ptr, NULL);
+ MD5(tmp->ptr, strlen(tmp->ptr), md5);
+ a1buf = digest_hex(md5);
+ }
+ else if (strcasecmp(algorithm->ptr, "MD5") == 0)
+ /* ok default */
+ ;
+ else
+ /* unknown algorithm */
+ return NULL;
+ }
+
+ /* A2 = Method ":" digest-uri-value */
+ tmp = Strnew_m_charp(HTTPrequestMethod(hr)->ptr, ":", uri->ptr, NULL);
+ if (qop && (strcasecmp(qop->ptr, "auth-int") == 0)) {
+ /* A2 = Method ":" digest-uri-value ":" H(entity-body) */
+ Str ebody = Strnew();
+ if (request && request->body) {
+ FILE *fp = fopen(request->body, "r");
+ if (fp != NULL) {
+ int c;
+ while ((c = fgetc(fp)) != EOF)
+ Strcat_char(ebody, c);
+ fclose(fp);
+ }
+ }
+ MD5(ebody->ptr, strlen(ebody->ptr), md5);
+ ebody = digest_hex(md5);
+ Strcat_m_charp(tmp, ":", ebody->ptr, NULL);
+ }
+ MD5(tmp->ptr, strlen(tmp->ptr), md5);
+ a2buf = digest_hex(md5);
+
+ if (qop &&
+ (strcasecmp(qop->ptr, "auth") == 0
+ || strcasecmp(qop->ptr, "auth-int") == 0)) {
+ /* request-digest = <"> < KD ( H(A1), unq(nonce-value)
+ * ":" nc-value
+ * ":" unq(cnonce-value)
+ * ":" unq(qop-value)
+ * ":" H(A2)
+ * ) <">
+ */
+ if (nonce == NULL)
+ return NULL;
+ tmp = Strnew_m_charp(a1buf->ptr, ":", qstr_unquote(nonce)->ptr,
+ ":", nc,
+ ":", qstr_unquote(cnonce)->ptr,
+ ":", qstr_unquote(qop)->ptr,
+ ":", a2buf->ptr, NULL);
+ MD5(tmp->ptr, strlen(tmp->ptr), md5);
+ rd = digest_hex(md5);
+ }
+ else {
+ /* compatibility with RFC 2069
+ * request_digest = KD(H(A1), unq(nonce), H(A2))
+ */
+ tmp = Strnew_m_charp(a1buf->ptr, ":",
+ qstr_unquote(get_auth_param(ha->param, "nonce"))->
+ ptr, ":", a2buf->ptr, NULL);
+ MD5(tmp->ptr, strlen(tmp->ptr), md5);
+ rd = digest_hex(md5);
+ }
+
+ /*
+ * digest-response = 1#( username | realm | nonce | digest-uri
+ * | response | [ algorithm ] | [cnonce] |
+ * [opaque] | [message-qop] |
+ * [nonce-count] | [auth-param] )
+ */
+
+ tmp = Strnew_m_charp("Digest username=\"", uname->ptr, "\"", NULL);
+ Strcat_m_charp(tmp, ", realm=",
+ get_auth_param(ha->param, "realm")->ptr, NULL);
+ Strcat_m_charp(tmp, ", nonce=",
+ get_auth_param(ha->param, "nonce")->ptr, NULL);
+ Strcat_m_charp(tmp, ", uri=\"", uri->ptr, "\"", NULL);
+ Strcat_m_charp(tmp, ", response=\"", rd->ptr, "\"", NULL);
+
+ if (algorithm)
+ Strcat_m_charp(tmp, ", algorithm=",
+ get_auth_param(ha->param, "algorithm")->ptr, NULL);
+
+ if (cnonce)
+ Strcat_m_charp(tmp, ", cnonce=\"", cnonce->ptr, "\"", NULL);
+
+ if ((s = get_auth_param(ha->param, "opaque")) != NULL)
+ Strcat_m_charp(tmp, ", opaque=", s->ptr, NULL);
+
+ if (qop) {
+ Strcat_m_charp(tmp, ", qop=",
+ get_auth_param(ha->param, "qop")->ptr, NULL);
+ /* XXX how to count? */
+ Strcat_m_charp(tmp, ", nc=", nc, NULL);
+ }
+
+ return tmp;
+}
+#endif
+
+/* *INDENT-OFF* */
+struct auth_param none_auth_param[] = {
+ {NULL, NULL}
+};
+
+struct auth_param basic_auth_param[] = {
+ {"realm", NULL},
+ {NULL, NULL}
+};
+
+#ifdef USE_DIGEST_AUTH
+/* RFC2617: 3.2.1 The WWW-Authenticate Response Header
+ * challenge = "Digest" digest-challenge
+ *
+ * digest-challenge = 1#( realm | [ domain ] | nonce |
+ * [ opaque ] |[ stale ] | [ algorithm ] |
+ * [ qop-options ] | [auth-param] )
+ *
+ * domain = "domain" "=" <"> URI ( 1*SP URI ) <">
+ * URI = absoluteURI | abs_path
+ * nonce = "nonce" "=" nonce-value
+ * nonce-value = quoted-string
+ * opaque = "opaque" "=" quoted-string
+ * stale = "stale" "=" ( "true" | "false" )
+ * algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" |
+ * token )
+ * qop-options = "qop" "=" <"> 1#qop-value <">
+ * qop-value = "auth" | "auth-int" | token
+ */
+struct auth_param digest_auth_param[] = {
+ {"realm", NULL},
+ {"domain", NULL},
+ {"nonce", NULL},
+ {"opaque", NULL},
+ {"stale", NULL},
+ {"algorithm", NULL},
+ {"qop", NULL},
+ {NULL, NULL}
+};
+#endif
+/* for RFC2617: HTTP Authentication */
+struct http_auth www_auth[] = {
+ { 1, "Basic ", basic_auth_param, AuthBasicCred },
+#ifdef USE_DIGEST_AUTH
+ { 10, "Digest ", digest_auth_param, AuthDigestCred },
+#endif
+ { 0, NULL, NULL, NULL,}
+};
+/* *INDENT-ON* */
+
+static struct http_auth *
+findAuthentication(struct http_auth *hauth, Buffer *buf, char *auth_field)
+{
+ struct http_auth *ha;
+ int len = strlen(auth_field);
+ TextListItem *i;
+ char *p0, *p;
+ Regex re_token;
+
+ newRegex(TOKEN_PAT, FALSE, &re_token, NULL);
+
+ bzero(hauth, sizeof(struct http_auth));
+ for (i = buf->document_header->first; i != NULL; i = i->next) {
+ if (strncasecmp(i->ptr, auth_field, len) == 0) {
+ for (p = i->ptr + len; p != NULL && *p != '\0';) {
+ SKIP_BLANKS(p);
+ p0 = p;
+ for (ha = &www_auth[0]; ha->scheme != NULL; ha++) {
+ if (strncasecmp(p, ha->scheme, strlen(ha->scheme)) == 0) {
+ if (hauth->pri < ha->pri) {
+ *hauth = *ha;
+ p += strlen(ha->scheme);
+ SKIP_BLANKS(p);
+ p = extract_auth_param(p, hauth->param);
+ break;
+ }
+ else {
+ /* weak auth */
+ p += strlen(ha->scheme);
+ SKIP_BLANKS(p);
+ p = extract_auth_param(p, none_auth_param);
+ }
+ }
+ }
+ if (p0 == p) {
+ /* all unknown auth failed */
+ if (RegexMatch(&re_token, p0, -1, TRUE) == 0)
+ return NULL;
+ MatchedPosition(&re_token, &p0, &p);
+ SKIP_BLANKS(p);
+ p = extract_auth_param(p, none_auth_param);
+ }
+ }
+ }
+ }
+ return hauth->scheme ? hauth : NULL;
+}
+
+static void
+getAuthCookie(struct http_auth *hauth, char *auth_header,
+ TextList *extra_header, ParsedURL *pu, HRequest *hr,
+ FormList *request,
+ volatile Str *uname, volatile Str *pwd)
+{
+ Str ss = NULL;
+ Str tmp;
+ TextListItem *i;
+ int a_found;
+ int auth_header_len = strlen(auth_header);
+ char *realm = NULL;
+ int proxy;
+
+ if (hauth)
+ realm = qstr_unquote(get_auth_param(hauth->param, "realm"))->ptr;
+
+ if (!realm)
+ return;
+
+ a_found = FALSE;
+ for (i = extra_header->first; i != NULL; i = i->next) {
+ if (!strncasecmp(i->ptr, auth_header, auth_header_len)) {
+ a_found = TRUE;
+ break;
+ }
+ }
+ proxy = !strncasecmp("Proxy-Authorization:", auth_header,
+ auth_header_len);
+ if (a_found) {
+ /* This means that *-Authenticate: header is received after
+ * Authorization: header is sent to the server.
+ */
+ if (fmInitialized) {
+ message("Wrong username or password", 0, 0);
+ refresh();
+ }
+ else
+ fprintf(stderr, "Wrong username or password\n");
+ sleep(1);
+ /* delete Authenticate: header from extra_header */
+ delText(extra_header, i);
+ invalidate_auth_user_passwd(pu, realm, *uname, *pwd, proxy);
+ }
+ *uname = NULL;
+ *pwd = NULL;
+
+ if (!a_found && find_auth_user_passwd(pu, realm, (Str*)uname, (Str*)pwd,
+ proxy)) {
+ /* found username & password in passwd file */ ;
+ }
+ else {
+ if (QuietMessage)
+ return;
+ /* input username and password */
+ sleep(2);
+ if (fmInitialized) {
+ char *pp;
+ term_raw();
+ /* FIXME: gettextize? */
+ if ((pp = inputStr(Sprintf("Username for %s: ", realm)->ptr,
+ NULL)) == NULL)
+ return;
+ *uname = Str_conv_to_system(Strnew_charp(pp));
+ if ((pp = inputLine(Sprintf("Password for %s: ", realm)->ptr, NULL,
+ IN_PASSWORD)) == NULL) {
+ *uname = NULL;
+ return;
+ }
+ *pwd = Str_conv_to_system(Strnew_charp(pp));
+ term_cbreak();
+ }
+ else {
+ /*
+ * If post file is specified as '-', stdin is closed at this
+ * point.
+ * In this case, w3m cannot read username from stdin.
+ * So exit with error message.
+ * (This is same behavior as lwp-request.)
+ */
+ if (feof(stdin) || ferror(stdin)) {
+ /* FIXME: gettextize? */
+ fprintf(stderr, "w3m: Authorization required for %s\n",
+ realm);
+ exit(1);
+ }
+
+ /* FIXME: gettextize? */
+ printf(proxy ? "Proxy Username for %s: " : "Username for %s: ",
+ realm);
+ fflush(stdout);
+ *uname = Strfgets(stdin);
+ Strchop(*uname);
+#ifdef HAVE_GETPASSPHRASE
+ *pwd = Strnew_charp((char *)
+ getpassphrase(proxy ? "Proxy Password: " :
+ "Password: "));
+#else
+ *pwd = Strnew_charp((char *)
+ getpass(proxy ? "Proxy Password: " :
+ "Password: "));
+#endif
+ }
+ }
+ ss = hauth->cred(hauth, *uname, *pwd, pu, hr, request);
+ if (ss) {
+ tmp = Strnew_charp(auth_header);
+ Strcat_m_charp(tmp, " ", ss->ptr, "\r\n", NULL);
+ pushText(extra_header, tmp->ptr);
+ }
+ else {
+ *uname = NULL;
+ *pwd = NULL;
+ }
+ return;
+}
+
+static int
+same_url_p(ParsedURL *pu1, ParsedURL *pu2)
+{
+ return (pu1->scheme == pu2->scheme && pu1->port == pu2->port &&
+ (pu1->host ? pu2->host ? !strcasecmp(pu1->host, pu2->host) : 0 : 1)
+ && (pu1->file ? pu2->
+ file ? !strcmp(pu1->file, pu2->file) : 0 : 1));
+}
+
+static int
+checkRedirection(ParsedURL *pu)
+{
+ static ParsedURL *puv = NULL;
+ static int nredir = 0;
+ static int nredir_size = 0;
+ Str tmp;
+
+ if (pu == NULL) {
+ nredir = 0;
+ nredir_size = 0;
+ puv = NULL;
+ return TRUE;
+ }
+ if (nredir >= FollowRedirection) {
+ /* FIXME: gettextize? */
+ tmp = Sprintf("Number of redirections exceeded %d at %s",
+ FollowRedirection, parsedURL2Str(pu)->ptr);
+ disp_err_message(tmp->ptr, FALSE);
+ return FALSE;
+ }
+ else if (nredir_size > 0 &&
+ (same_url_p(pu, &puv[(nredir - 1) % nredir_size]) ||
+ (!(nredir % 2)
+ && same_url_p(pu, &puv[(nredir / 2) % nredir_size])))) {
+ /* FIXME: gettextize? */
+ tmp = Sprintf("Redirection loop detected (%s)",
+ parsedURL2Str(pu)->ptr);
+ disp_err_message(tmp->ptr, FALSE);
+ return FALSE;
+ }
+ if (!puv) {
+ nredir_size = FollowRedirection / 2 + 1;
+ puv = New_N(ParsedURL, nredir_size);
+ memset(puv, 0, sizeof(ParsedURL) * nredir_size);
+ }
+ copyParsedURL(&puv[nredir % nredir_size], pu);
+ nredir++;
+ return TRUE;
+}
+
+/*
+ * loadGeneralFile: load file to buffer
+ */
+Buffer *
+loadGeneralFile(char *path, ParsedURL *volatile current, char *referer,
+ int flag, FormList *volatile request)
+{
+ URLFile f, *volatile of = NULL;
+ ParsedURL pu;
+ Buffer *b = NULL, *(*volatile proc)() = loadBuffer;
+ char *volatile tpath;
+ char *volatile t = "text/plain", *p, *volatile real_type = NULL;
+ Buffer *volatile t_buf = NULL;
+ int volatile searchHeader = SearchHeader;
+ int volatile searchHeader_through = TRUE;
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+ TextList *extra_header = newTextList();
+ volatile Str uname = NULL;
+ volatile Str pwd = NULL;
+ volatile Str realm = NULL;
+ int volatile add_auth_cookie_flag;
+ unsigned char status = HTST_NORMAL;
+ URLOption url_option;
+ Str tmp;
+ Str volatile page = NULL;
+#ifdef USE_M17N
+ wc_ces charset = WC_CES_US_ASCII;
+#endif
+ HRequest hr;
+ ParsedURL *volatile auth_pu;
+
+ tpath = path;
+ prevtrap = NULL;
+ add_auth_cookie_flag = 0;
+
+ checkRedirection(NULL);
+ load_doc:
+ TRAP_OFF;
+ url_option.referer = referer;
+ url_option.flag = flag;
+ f = openURL(tpath, &pu, current, &url_option, request, extra_header, of,
+ &hr, &status);
+ of = NULL;
+#ifdef USE_M17N
+ content_charset = 0;
+#endif
+ if (f.stream == NULL) {
+ switch (f.scheme) {
+ case SCM_LOCAL:
+ {
+ struct stat st;
+ if (stat(pu.real_file, &st) < 0)
+ return NULL;
+ if (S_ISDIR(st.st_mode)) {
+ if (UseExternalDirBuffer) {
+ Str cmd = Sprintf("%s?dir=%s#current",
+ DirBufferCommand, pu.file);
+ b = loadGeneralFile(cmd->ptr, NULL, NO_REFERER, 0,
+ NULL);
+ if (b != NULL && b != NO_BUFFER) {
+ copyParsedURL(&b->currentURL, &pu);
+ b->filename = b->currentURL.real_file;
+ }
+ return b;
+ }
+ else {
+ page = loadLocalDir(pu.real_file);
+ t = "local:directory";
+#ifdef USE_M17N
+ charset = SystemCharset;
+#endif
+ }
+ }
+ }
+ break;
+ case SCM_FTPDIR:
+ page = loadFTPDir(&pu, &charset);
+ t = "ftp:directory";
+ break;
+#ifdef USE_NNTP
+ case SCM_NEWS_GROUP:
+ page = loadNewsgroup(&pu, &charset);
+ t = "news:group";
+ break;
+#endif
+ case SCM_UNKNOWN:
+#ifdef USE_EXTERNAL_URI_LOADER
+ tmp = searchURIMethods(&pu);
+ if (tmp != NULL) {
+ b = loadGeneralFile(tmp->ptr, current, referer, flag, request);
+ if (b != NULL && b != NO_BUFFER)
+ copyParsedURL(&b->currentURL, &pu);
+ return b;
+ }
+#endif
+ /* FIXME: gettextize? */
+ disp_err_message(Sprintf("Unknown URI: %s",
+ parsedURL2Str(&pu)->ptr)->ptr, FALSE);
+ break;
+ }
+ if (page && page->length > 0)
+ goto page_loaded;
+ return NULL;
+ }
+
+ if (status == HTST_MISSING) {
+ TRAP_OFF;
+ UFclose(&f);
+ return NULL;
+ }
+
+ /* openURL() succeeded */
+ if (SETJMP(AbortLoading) != 0) {
+ /* transfer interrupted */
+ TRAP_OFF;
+ if (b)
+ discardBuffer(b);
+ UFclose(&f);
+ return NULL;
+ }
+
+ b = NULL;
+ if (f.is_cgi) {
+ /* local CGI */
+ searchHeader = TRUE;
+ searchHeader_through = FALSE;
+ }
+ if (header_string)
+ header_string = NULL;
+ TRAP_ON;
+ if (pu.scheme == SCM_HTTP ||
+#ifdef USE_SSL
+ pu.scheme == SCM_HTTPS ||
+#endif /* USE_SSL */
+ ((
+#ifdef USE_GOPHER
+ (pu.scheme == SCM_GOPHER && non_null(GOPHER_proxy)) ||
+#endif /* USE_GOPHER */
+ (pu.scheme == SCM_FTP && non_null(FTP_proxy))
+ ) && !Do_not_use_proxy && !check_no_proxy(pu.host))) {
+
+ if (fmInitialized) {
+ term_cbreak();
+ /* FIXME: gettextize? */
+ message(Sprintf("%s contacted. Waiting for reply...", pu.host)->
+ ptr, 0, 0);
+ refresh();
+ }
+ if (t_buf == NULL)
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+#if 0 /* USE_SSL */
+ if (IStype(f.stream) == IST_SSL) {
+ Str s = ssl_get_certificate(f.stream, pu.host);
+ if (s == NULL)
+ return NULL;
+ else
+ t_buf->ssl_certificate = s->ptr;
+ }
+#endif
+ readHeader(&f, t_buf, FALSE, &pu);
+ if (((http_response_code >= 301 && http_response_code <= 303)
+ || http_response_code == 307)
+ && (p = checkHeader(t_buf, "Location:")) != NULL
+ && checkRedirection(&pu)) {
+ /* document moved */
+ /* 301: Moved Permanently */
+ /* 302: Found */
+ /* 303: See Other */
+ /* 307: Temporary Redirect (HTTP/1.1) */
+ tpath = url_quote_conv(p, DocumentCharset);
+ request = NULL;
+ UFclose(&f);
+ current = New(ParsedURL);
+ copyParsedURL(current, &pu);
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+ t_buf->bufferprop |= BP_REDIRECTED;
+ status = HTST_NORMAL;
+ goto load_doc;
+ }
+ t = checkContentType(t_buf);
+ if (t == NULL && pu.file != NULL) {
+ if (!((http_response_code >= 400 && http_response_code <= 407) ||
+ (http_response_code >= 500 && http_response_code <= 505)))
+ t = guessContentType(pu.file);
+ }
+ if (t == NULL)
+ t = "text/plain";
+ if (add_auth_cookie_flag && realm && uname && pwd) {
+ /* If authorization is required and passed */
+ add_auth_user_passwd(&pu, qstr_unquote(realm)->ptr, uname, pwd,
+ 0);
+ add_auth_cookie_flag = 0;
+ }
+ if ((p = checkHeader(t_buf, "WWW-Authenticate:")) != NULL &&
+ http_response_code == 401) {
+ /* Authentication needed */
+ struct http_auth hauth;
+ if (findAuthentication(&hauth, t_buf, "WWW-Authenticate:") != NULL
+ && (realm = get_auth_param(hauth.param, "realm")) != NULL) {
+ auth_pu = &pu;
+ getAuthCookie(&hauth, "Authorization:", extra_header,
+ auth_pu, &hr, request, &uname, &pwd);
+ if (uname == NULL) {
+ /* abort */
+ TRAP_OFF;
+ goto page_loaded;
+ }
+ UFclose(&f);
+ add_auth_cookie_flag = 1;
+ status = HTST_NORMAL;
+ goto load_doc;
+ }
+ }
+ if ((p = checkHeader(t_buf, "Proxy-Authenticate:")) != NULL &&
+ http_response_code == 407) {
+ /* Authentication needed */
+ struct http_auth hauth;
+ if (findAuthentication(&hauth, t_buf, "Proxy-Authenticate:")
+ != NULL
+ && (realm = get_auth_param(hauth.param, "realm")) != NULL) {
+ auth_pu = schemeToProxy(pu.scheme);
+ getAuthCookie(&hauth, "Proxy-Authorization:",
+ extra_header, auth_pu, &hr, request,
+ &uname, &pwd);
+ if (uname == NULL) {
+ /* abort */
+ TRAP_OFF;
+ goto page_loaded;
+ }
+ UFclose(&f);
+ add_auth_cookie_flag = 1;
+ status = HTST_NORMAL;
+ goto load_doc;
+ }
+ }
+ /* XXX: RFC2617 3.2.3 Authentication-Info: ? */
+
+ if (status == HTST_CONNECT) {
+ of = &f;
+ goto load_doc;
+ }
+
+ f.modtime = mymktime(checkHeader(t_buf, "Last-Modified:"));
+ }
+#ifdef USE_NNTP
+ else if (pu.scheme == SCM_NEWS || pu.scheme == SCM_NNTP) {
+ if (t_buf == NULL)
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+ readHeader(&f, t_buf, TRUE, &pu);
+ t = checkContentType(t_buf);
+ if (t == NULL)
+ t = "text/plain";
+ }
+#endif /* USE_NNTP */
+#ifdef USE_GOPHER
+ else if (pu.scheme == SCM_GOPHER) {
+ switch (*pu.file) {
+ case '0':
+ t = "text/plain";
+ break;
+ case '1':
+ case 'm':
+ page = loadGopherDir(&f, &pu, &charset);
+ t = "gopher:directory";
+ TRAP_OFF;
+ goto page_loaded;
+ case 's':
+ t = "audio/basic";
+ break;
+ case 'g':
+ t = "image/gif";
+ break;
+ case 'h':
+ t = "text/html";
+ break;
+ }
+ }
+#endif /* USE_GOPHER */
+ else if (pu.scheme == SCM_FTP) {
+ check_compression(path, &f);
+ if (f.compression != CMP_NOCOMPRESS) {
+ char *t1 = uncompressed_file_type(pu.file, NULL);
+ real_type = f.guess_type;
+#if 0
+ if (t1 && strncasecmp(t1, "application/", 12) == 0) {
+ f.compression = CMP_NOCOMPRESS;
+ t = real_type;
+ }
+ else
+#endif
+ if (t1)
+ t = t1;
+ else
+ t = real_type;
+ }
+ else {
+ real_type = guessContentType(pu.file);
+ if (real_type == NULL)
+ real_type = "text/plain";
+ t = real_type;
+ }
+#if 0
+ if (!strncasecmp(t, "application/", 12)) {
+ char *tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
+ current_content_length = 0;
+ if (save2tmp(f, tmpf) < 0)
+ UFclose(&f);
+ else {
+ UFclose(&f);
+ TRAP_OFF;
+ doFileMove(tmpf, guess_save_name(t_buf, pu.file));
+ }
+ return NO_BUFFER;
+ }
+#endif
+ }
+ else if (pu.scheme == SCM_DATA) {
+ t = f.guess_type;
+ }
+ else if (searchHeader) {
+ searchHeader = SearchHeader = FALSE;
+ if (t_buf == NULL)
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+ readHeader(&f, t_buf, searchHeader_through, &pu);
+ if (f.is_cgi && (p = checkHeader(t_buf, "Location:")) != NULL &&
+ checkRedirection(&pu)) {
+ /* document moved */
+ tpath = url_quote_conv(remove_space(p), DocumentCharset);
+ request = NULL;
+ UFclose(&f);
+ add_auth_cookie_flag = 0;
+ current = New(ParsedURL);
+ copyParsedURL(current, &pu);
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+ t_buf->bufferprop |= BP_REDIRECTED;
+ status = HTST_NORMAL;
+ goto load_doc;
+ }
+ t = checkContentType(t_buf);
+ if (t == NULL)
+ t = "text/plain";
+ }
+ else if (DefaultType) {
+ t = DefaultType;
+ DefaultType = NULL;
+ }
+ else {
+ t = guessContentType(pu.file);
+ if (t == NULL)
+ t = "text/plain";
+ real_type = t;
+ if (f.guess_type)
+ t = f.guess_type;
+ }
+
+ page_loaded:
+ if (page) {
+ FILE *src;
+#ifdef USE_IMAGE
+ if (image_source)
+ return NULL;
+#endif
+ tmp = tmpfname(TMPF_SRC, ".html");
+ src = fopen(tmp->ptr, "w");
+ if (src) {
+ Str s;
+ s = wc_Str_conv_strict(page, InnerCharset, charset);
+ Strfputs(s, src);
+ fclose(src);
+ }
+ if (do_download) {
+ char *file;
+ if (!src)
+ return NULL;
+ file = guess_filename(pu.file);
+#ifdef USE_GOPHER
+ if (f.scheme == SCM_GOPHER)
+ file = Sprintf("%s.html", file)->ptr;
+#endif
+#ifdef USE_NNTP
+ if (f.scheme == SCM_NEWS_GROUP)
+ file = Sprintf("%s.html", file)->ptr;
+#endif
+ doFileMove(tmp->ptr, file);
+ return NO_BUFFER;
+ }
+ b = loadHTMLString(page);
+ if (b) {
+ copyParsedURL(&b->currentURL, &pu);
+ b->real_scheme = pu.scheme;
+ b->real_type = t;
+ if (src)
+ b->sourcefile = tmp->ptr;
+#ifdef USE_M17N
+ b->document_charset = charset;
+#endif
+ }
+ return b;
+ }
+
+ if (real_type == NULL)
+ real_type = t;
+ proc = loadBuffer;
+#ifdef USE_IMAGE
+ cur_baseURL = New(ParsedURL);
+ copyParsedURL(cur_baseURL, &pu);
+#endif
+
+ current_content_length = 0;
+ if ((p = checkHeader(t_buf, "Content-Length:")) != NULL)
+ current_content_length = strtoclen(p);
+ if (do_download) {
+ /* download only */
+ char *file;
+ TRAP_OFF;
+ if (DecodeCTE && IStype(f.stream) != IST_ENCODED)
+ f.stream = newEncodedStream(f.stream, f.encoding);
+ if (pu.scheme == SCM_LOCAL) {
+ struct stat st;
+ if (PreserveTimestamp && !stat(pu.real_file, &st))
+ f.modtime = st.st_mtime;
+ file = conv_from_system(guess_save_name(NULL, pu.real_file));
+ }
+ else
+ file = guess_save_name(t_buf, pu.file);
+ if (doFileSave(f, file) == 0)
+ UFhalfclose(&f);
+ else
+ UFclose(&f);
+ return NO_BUFFER;
+ }
+
+ if (f.compression != CMP_NOCOMPRESS) {
+ if (!(w3m_dump & DUMP_SOURCE) &&
+ (w3m_dump & ~DUMP_FRAME || is_text_type(t)
+ || searchExtViewer(t))) {
+ if (t_buf == NULL)
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+ uncompress_stream(&f, &t_buf->sourcefile);
+ uncompressed_file_type(pu.file, &f.ext);
+ }
+ else {
+ t = compress_application_type(f.compression);
+ f.compression = CMP_NOCOMPRESS;
+ }
+ }
+#ifdef USE_IMAGE
+ if (image_source) {
+ Buffer *b = NULL;
+ if (IStype(f.stream) != IST_ENCODED)
+ f.stream = newEncodedStream(f.stream, f.encoding);
+ if (save2tmp(f, image_source) == 0) {
+ b = newBuffer(INIT_BUFFER_WIDTH);
+ b->sourcefile = image_source;
+ b->real_type = t;
+ }
+ UFclose(&f);
+ TRAP_OFF;
+ return b;
+ }
+#endif
+
+ if (!strcasecmp(t, "text/html"))
+ proc = loadHTMLBuffer;
+ else if (is_plain_text_type(t))
+ proc = loadBuffer;
+#ifdef USE_IMAGE
+ else if (activeImage && displayImage && !useExtImageViewer &&
+ !(w3m_dump & ~DUMP_FRAME) && !strncasecmp(t, "image/", 6))
+ proc = loadImageBuffer;
+#endif
+ else if (w3m_backend) ;
+ else if (!(w3m_dump & ~DUMP_FRAME) || is_dump_text_type(t)) {
+ if (!do_download && doExternal(f,
+ pu.real_file ? pu.real_file : pu.file,
+ t, &b, t_buf)) {
+ if (b && b != NO_BUFFER) {
+ b->real_scheme = f.scheme;
+ b->real_type = real_type;
+ if (b->currentURL.host == NULL && b->currentURL.file == NULL)
+ copyParsedURL(&b->currentURL, &pu);
+ }
+ UFclose(&f);
+ TRAP_OFF;
+ return b;
+ }
+ else {
+ TRAP_OFF;
+ if (pu.scheme == SCM_LOCAL) {
+ UFclose(&f);
+ _doFileCopy(pu.real_file,
+ conv_from_system(guess_save_name
+ (NULL, pu.real_file)), TRUE);
+ }
+ else {
+ if (DecodeCTE && IStype(f.stream) != IST_ENCODED)
+ f.stream = newEncodedStream(f.stream, f.encoding);
+ if (doFileSave(f, guess_save_name(t_buf, pu.file)) == 0)
+ UFhalfclose(&f);
+ else
+ UFclose(&f);
+ }
+ return NO_BUFFER;
+ }
+ }
+ else if (w3m_dump & DUMP_FRAME)
+ return NULL;
+
+ if (flag & RG_FRAME) {
+ if (t_buf == NULL)
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+ t_buf->bufferprop |= BP_FRAME;
+ }
+#ifdef USE_SSL
+ if (t_buf)
+ t_buf->ssl_certificate = f.ssl_certificate;
+#endif
+ frame_source = flag & RG_FRAME_SRC;
+ b = loadSomething(&f, pu.real_file ? pu.real_file : pu.file, proc, t_buf);
+ UFclose(&f);
+ frame_source = 0;
+ if (b) {
+ b->real_scheme = f.scheme;
+ b->real_type = real_type;
+ if (b->currentURL.host == NULL && b->currentURL.file == NULL)
+ copyParsedURL(&b->currentURL, &pu);
+ if (!strcasecmp(t, "text/html"))
+ b->type = "text/html";
+ else if (w3m_backend) {
+ Str s = Strnew_charp(t);
+ b->type = s->ptr;
+ }
+#ifdef USE_IMAGE
+ else if (proc == loadImageBuffer)
+ b->type = "text/html";
+#endif
+ else
+ b->type = "text/plain";
+ if (pu.label) {
+ if (proc == loadHTMLBuffer) {
+ Anchor *a;
+ a = searchURLLabel(b, pu.label);
+ if (a != NULL) {
+ gotoLine(b, a->start.line);
+ if (label_topline)
+ b->topLine = lineSkip(b, b->topLine,
+ b->currentLine->linenumber
+ - b->topLine->linenumber, FALSE);
+ b->pos = a->start.pos;
+ arrangeCursor(b);
+ }
+ }
+ else { /* plain text */
+ int l = atoi(pu.label);
+ gotoLine(b, l);
+ b->pos = 0;
+ arrangeCursor(b);
+ }
+ }
+ }
+ if (header_string)
+ header_string = NULL;
+#ifdef USE_NNTP
+ if (f.scheme == SCM_NNTP || f.scheme == SCM_NEWS)
+ reAnchorNewsheader(b);
+#endif
+ preFormUpdateBuffer(b);
+ TRAP_OFF;
+ return b;
+}
+
+#define TAG_IS(s,tag,len)\
+ (strncasecmp(s,tag,len)==0&&(s[len] == '>' || IS_SPACE((int)s[len])))
+
+static char *
+has_hidden_link(struct readbuffer *obuf, int cmd)
+{
+ Str line = obuf->line;
+ struct link_stack *p;
+
+ if (Strlastchar(line) != '>')
+ return NULL;
+
+ for (p = link_stack; p; p = p->next)
+ if (p->cmd == cmd)
+ break;
+ if (!p)
+ return NULL;
+
+ if (obuf->pos == p->pos)
+ return line->ptr + p->offset;
+
+ return NULL;
+}
+
+static void
+push_link(int cmd, int offset, int pos)
+{
+ struct link_stack *p;
+ p = New(struct link_stack);
+ p->cmd = cmd;
+ p->offset = offset;
+ p->pos = pos;
+ p->next = link_stack;
+ link_stack = p;
+}
+
+static int
+is_period_char(unsigned char *ch)
+{
+ switch (*ch) {
+ case ',':
+ case '.':
+ case ':':
+ case ';':
+ case '?':
+ case '!':
+ case ')':
+ case ']':
+ case '}':
+ case '>':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+is_beginning_char(unsigned char *ch)
+{
+ switch (*ch) {
+ case '(':
+ case '[':
+ case '{':
+ case '`':
+ case '<':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+is_word_char(unsigned char *ch)
+{
+ Lineprop ctype = get_mctype(ch);
+
+#ifdef USE_M17N
+ if (ctype & (PC_CTRL | PC_KANJI | PC_UNKNOWN))
+ return 0;
+ if (ctype & (PC_WCHAR1 | PC_WCHAR2))
+ return 1;
+#else
+ if (ctype == PC_CTRL)
+ return 0;
+#endif
+
+ if (IS_ALNUM(*ch))
+ return 1;
+
+ switch (*ch) {
+ case ',':
+ case '.':
+ case ':':
+ case '\"': /* " */
+ case '\'':
+ case '$':
+ case '%':
+ case '*':
+ case '+':
+ case '-':
+ case '@':
+ case '~':
+ case '_':
+ return 1;
+ }
+#ifdef USE_M17N
+ if (*ch == NBSP_CODE)
+ return 1;
+#else
+ if (*ch == TIMES_CODE || *ch == DIVIDE_CODE || *ch == ANSP_CODE)
+ return 0;
+ if (*ch >= AGRAVE_CODE || *ch == NBSP_CODE)
+ return 1;
+#endif
+ return 0;
+}
+
+#ifdef USE_M17N
+static int
+is_combining_char(unsigned char *ch)
+{
+ Lineprop ctype = get_mctype(ch);
+
+ if (ctype & PC_WCHAR2)
+ return 1;
+ return 0;
+}
+#endif
+
+int
+is_boundary(unsigned char *ch1, unsigned char *ch2)
+{
+ if (!*ch1 || !*ch2)
+ return 1;
+
+ if (*ch1 == ' ' && *ch2 == ' ')
+ return 0;
+
+ if (*ch1 != ' ' && is_period_char(ch2))
+ return 0;
+
+ if (*ch2 != ' ' && is_beginning_char(ch1))
+ return 0;
+
+#ifdef USE_M17N
+ if (is_combining_char(ch2))
+ return 0;
+#endif
+ if (is_word_char(ch1) && is_word_char(ch2))
+ return 0;
+
+ return 1;
+}
+
+
+static void
+set_breakpoint(struct readbuffer *obuf, int tag_length)
+{
+ obuf->bp.len = obuf->line->length;
+ obuf->bp.pos = obuf->pos;
+ obuf->bp.tlen = tag_length;
+ obuf->bp.flag = obuf->flag;
+#ifdef FORMAT_NICE
+ obuf->bp.flag &= ~RB_FILL;
+#endif /* FORMAT_NICE */
+ obuf->bp.top_margin = obuf->top_margin;
+ obuf->bp.bottom_margin = obuf->bottom_margin;
+
+ if (!obuf->bp.init_flag)
+ return;
+
+ bcopy((void *)&obuf->anchor, (void *)&obuf->bp.anchor,
+ sizeof(obuf->anchor));
+ obuf->bp.img_alt = obuf->img_alt;
+ obuf->bp.in_bold = obuf->in_bold;
+ obuf->bp.in_under = obuf->in_under;
+ obuf->bp.nobr_level = obuf->nobr_level;
+ obuf->bp.prev_ctype = obuf->prev_ctype;
+ obuf->bp.init_flag = 0;
+}
+
+static void
+back_to_breakpoint(struct readbuffer *obuf)
+{
+ obuf->flag = obuf->bp.flag;
+ bcopy((void *)&obuf->bp.anchor, (void *)&obuf->anchor,
+ sizeof(obuf->anchor));
+ obuf->img_alt = obuf->bp.img_alt;
+ obuf->in_bold = obuf->bp.in_bold;
+ obuf->in_under = obuf->bp.in_under;
+ obuf->prev_ctype = obuf->bp.prev_ctype;
+ obuf->pos = obuf->bp.pos;
+ obuf->top_margin = obuf->bp.top_margin;
+ obuf->bottom_margin = obuf->bp.bottom_margin;
+ if (obuf->flag & RB_NOBR)
+ obuf->nobr_level = obuf->bp.nobr_level;
+}
+
+static void
+append_tags(struct readbuffer *obuf)
+{
+ int i;
+ int len = obuf->line->length;
+ int set_bp = 0;
+
+ for (i = 0; i < obuf->tag_sp; i++) {
+ switch (obuf->tag_stack[i]->cmd) {
+ case HTML_A:
+ case HTML_IMG_ALT:
+ case HTML_B:
+ case HTML_U:
+ push_link(obuf->tag_stack[i]->cmd, obuf->line->length, obuf->pos);
+ break;
+ }
+ Strcat_charp(obuf->line, obuf->tag_stack[i]->cmdname);
+ switch (obuf->tag_stack[i]->cmd) {
+ case HTML_NOBR:
+ if (obuf->nobr_level > 1)
+ break;
+ case HTML_WBR:
+ set_bp = 1;
+ break;
+ }
+ }
+ obuf->tag_sp = 0;
+ if (set_bp)
+ set_breakpoint(obuf, obuf->line->length - len);
+}
+
+static void
+push_tag(struct readbuffer *obuf, char *cmdname, int cmd)
+{
+ obuf->tag_stack[obuf->tag_sp] = New(struct cmdtable);
+ obuf->tag_stack[obuf->tag_sp]->cmdname = allocStr(cmdname, -1);
+ obuf->tag_stack[obuf->tag_sp]->cmd = cmd;
+ obuf->tag_sp++;
+ if (obuf->tag_sp >= TAG_STACK_SIZE || obuf->flag & (RB_SPECIAL & ~RB_NOBR))
+ append_tags(obuf);
+}
+
+static void
+push_nchars(struct readbuffer *obuf, int width,
+ char *str, int len, Lineprop mode)
+{
+ append_tags(obuf);
+ Strcat_charp_n(obuf->line, str, len);
+ obuf->pos += width;
+ if (width > 0) {
+ set_prevchar(obuf->prevchar, str, len);
+ obuf->prev_ctype = mode;
+ }
+ obuf->flag |= RB_NFLUSHED;
+}
+
+#define push_charp(obuf, width, str, mode)\
+push_nchars(obuf, width, str, strlen(str), mode)
+
+#define push_str(obuf, width, str, mode)\
+push_nchars(obuf, width, str->ptr, str->length, mode)
+
+static void
+check_breakpoint(struct readbuffer *obuf, int pre_mode, char *ch)
+{
+ int tlen, len = obuf->line->length;
+
+ append_tags(obuf);
+ if (pre_mode)
+ return;
+ tlen = obuf->line->length - len;
+ if (tlen > 0
+ || is_boundary((unsigned char *)obuf->prevchar->ptr,
+ (unsigned char *)ch))
+ set_breakpoint(obuf, tlen);
+}
+
+static void
+push_char(struct readbuffer *obuf, int pre_mode, char ch)
+{
+ check_breakpoint(obuf, pre_mode, &ch);
+ Strcat_char(obuf->line, ch);
+ obuf->pos++;
+ set_prevchar(obuf->prevchar, &ch, 1);
+ if (ch != ' ')
+ obuf->prev_ctype = PC_ASCII;
+ obuf->flag |= RB_NFLUSHED;
+}
+
+#define PUSH(c) push_char(obuf, obuf->flag & RB_SPECIAL, c)
+
+static void
+push_spaces(struct readbuffer *obuf, int pre_mode, int width)
+{
+ int i;
+
+ if (width <= 0)
+ return;
+ check_breakpoint(obuf, pre_mode, " ");
+ for (i = 0; i < width; i++)
+ Strcat_char(obuf->line, ' ');
+ obuf->pos += width;
+ set_space_to_prevchar(obuf->prevchar);
+ obuf->flag |= RB_NFLUSHED;
+}
+
+static void
+proc_mchar(struct readbuffer *obuf, int pre_mode,
+ int width, char **str, Lineprop mode)
+{
+ check_breakpoint(obuf, pre_mode, *str);
+ obuf->pos += width;
+ Strcat_charp_n(obuf->line, *str, get_mclen(*str));
+ if (width > 0) {
+ set_prevchar(obuf->prevchar, *str, 1);
+ if (**str != ' ')
+ obuf->prev_ctype = mode;
+ }
+ (*str) += get_mclen(*str);
+ obuf->flag |= RB_NFLUSHED;
+}
+
+void
+push_render_image(Str str, int width, int limit,
+ struct html_feed_environ *h_env)
+{
+ struct readbuffer *obuf = h_env->obuf;
+ int indent = h_env->envs[h_env->envc].indent;
+
+ push_spaces(obuf, 1, (limit - width) / 2);
+ push_str(obuf, width, str, PC_ASCII);
+ push_spaces(obuf, 1, (limit - width + 1) / 2);
+ if (width > 0)
+ flushline(h_env, obuf, indent, 0, h_env->limit);
+}
+
+static int
+sloppy_parse_line(char **str)
+{
+ if (**str == '<') {
+ while (**str && **str != '>')
+ (*str)++;
+ if (**str == '>')
+ (*str)++;
+ return 1;
+ }
+ else {
+ while (**str && **str != '<')
+ (*str)++;
+ return 0;
+ }
+}
+
+static void
+passthrough(struct readbuffer *obuf, char *str, int back)
+{
+ int cmd;
+ Str tok = Strnew();
+ char *str_bak;
+
+ if (back) {
+ Str str_save = Strnew_charp(str);
+ Strshrink(obuf->line, obuf->line->ptr + obuf->line->length - str);
+ str = str_save->ptr;
+ }
+ while (*str) {
+ str_bak = str;
+ if (sloppy_parse_line(&str)) {
+ char *q = str_bak;
+ cmd = gethtmlcmd(&q);
+ if (back) {
+ struct link_stack *p;
+ for (p = link_stack; p; p = p->next) {
+ if (p->cmd == cmd) {
+ link_stack = p->next;
+ break;
+ }
+ }
+ back = 0;
+ }
+ else {
+ Strcat_charp_n(tok, str_bak, str - str_bak);
+ push_tag(obuf, tok->ptr, cmd);
+ Strclear(tok);
+ }
+ }
+ else {
+ push_nchars(obuf, 0, str_bak, str - str_bak, obuf->prev_ctype);
+ }
+ }
+}
+
+#if 0
+int
+is_blank_line(char *line, int indent)
+{
+ int i, is_blank = 0;
+
+ for (i = 0; i < indent; i++) {
+ if (line[i] == '\0') {
+ is_blank = 1;
+ }
+ else if (line[i] != ' ') {
+ break;
+ }
+ }
+ if (i == indent && line[i] == '\0')
+ is_blank = 1;
+ return is_blank;
+}
+#endif
+
+void
+fillline(struct readbuffer *obuf, int indent)
+{
+ push_spaces(obuf, 1, indent - obuf->pos);
+ obuf->flag &= ~RB_NFLUSHED;
+}
+
+void
+flushline(struct html_feed_environ *h_env, struct readbuffer *obuf, int indent,
+ int force, int width)
+{
+ TextLineList *buf = h_env->buf;
+ FILE *f = h_env->f;
+ Str line = obuf->line, pass = NULL;
+ char *hidden_anchor = NULL, *hidden_img = NULL, *hidden_bold = NULL,
+ *hidden_under = NULL, *hidden = NULL;
+
+#ifdef DEBUG
+ if (w3m_debug) {
+ FILE *df = fopen("zzzproc1", "a");
+ fprintf(df, "flushline(%s,%d,%d,%d)\n", obuf->line->ptr, indent, force,
+ width);
+ if (buf) {
+ TextLineListItem *p;
+ for (p = buf->first; p; p = p->next) {
+ fprintf(df, "buf=\"%s\"\n", p->ptr->line->ptr);
+ }
+ }
+ fclose(df);
+ }
+#endif
+
+ if (!(obuf->flag & (RB_SPECIAL & ~RB_NOBR)) && Strlastchar(line) == ' ') {
+ Strshrink(line, 1);
+ obuf->pos--;
+ }
+
+ append_tags(obuf);
+
+ if (obuf->anchor.url)
+ hidden = hidden_anchor = has_hidden_link(obuf, HTML_A);
+ if (obuf->img_alt) {
+ if ((hidden_img = has_hidden_link(obuf, HTML_IMG_ALT)) != NULL) {
+ if (!hidden || hidden_img < hidden)
+ hidden = hidden_img;
+ }
+ }
+ if (obuf->in_bold) {
+ if ((hidden_bold = has_hidden_link(obuf, HTML_B)) != NULL) {
+ if (!hidden || hidden_bold < hidden)
+ hidden = hidden_bold;
+ }
+ }
+ if (obuf->in_under) {
+ if ((hidden_under = has_hidden_link(obuf, HTML_U)) != NULL) {
+ if (!hidden || hidden_under < hidden)
+ hidden = hidden_under;
+ }
+ }
+ if (hidden) {
+ pass = Strnew_charp(hidden);
+ Strshrink(line, line->ptr + line->length - hidden);
+ }
+
+ if (!(obuf->flag & (RB_SPECIAL & ~RB_NOBR)) && obuf->pos > width) {
+ char *tp = &line->ptr[obuf->bp.len - obuf->bp.tlen];
+ char *ep = &line->ptr[line->length];
+
+ if (obuf->bp.pos == obuf->pos && tp <= ep &&
+ tp > line->ptr && tp[-1] == ' ') {
+ bcopy(tp, tp - 1, ep - tp + 1);
+ line->length--;
+ obuf->pos--;
+ }
+ }
+
+ if (obuf->anchor.url && !hidden_anchor)
+ Strcat_charp(line, "</a>");
+ if (obuf->img_alt && !hidden_img)
+ Strcat_charp(line, "</img_alt>");
+ if (obuf->in_bold && !hidden_bold)
+ Strcat_charp(line, "</b>");
+ if (obuf->in_under && !hidden_under)
+ Strcat_charp(line, "</u>");
+
+ if (obuf->top_margin > 0) {
+ int i;
+ struct html_feed_environ h;
+ struct readbuffer o;
+ struct environment e[1];
+
+ init_henv(&h, &o, e, 1, NULL, width, indent);
+ o.line = Strnew_size(width + 20);
+ o.pos = obuf->pos;
+ o.flag = obuf->flag;
+ o.top_margin = -1;
+ o.bottom_margin = -1;
+ Strcat_charp(o.line, "<pre_int>");
+ for (i = 0; i < o.pos; i++)
+ Strcat_char(o.line, ' ');
+ Strcat_charp(o.line, "</pre_int>");
+ for (i = 0; i < obuf->top_margin; i++)
+ flushline(h_env, &o, indent, force, width);
+ }
+
+ if (force == 1 || obuf->flag & RB_NFLUSHED) {
+ TextLine *lbuf = newTextLine(line, obuf->pos);
+ if (RB_GET_ALIGN(obuf) == RB_CENTER) {
+ align(lbuf, width, ALIGN_CENTER);
+ }
+ else if (RB_GET_ALIGN(obuf) == RB_RIGHT) {
+ align(lbuf, width, ALIGN_RIGHT);
+ }
+ else if (RB_GET_ALIGN(obuf) == RB_LEFT && obuf->flag & RB_INTABLE) {
+ align(lbuf, width, ALIGN_LEFT);
+ }
+#ifdef FORMAT_NICE
+ else if (obuf->flag & RB_FILL) {
+ char *p;
+ int rest, rrest;
+ int nspace, d, i;
+
+ rest = width - get_Str_strwidth(line);
+ if (rest > 1) {
+ nspace = 0;
+ for (p = line->ptr + indent; *p; p++) {
+ if (*p == ' ')
+ nspace++;
+ }
+ if (nspace > 0) {
+ int indent_here = 0;
+ d = rest / nspace;
+ p = line->ptr;
+ while (IS_SPACE(*p)) {
+ p++;
+ indent_here++;
+ }
+ rrest = rest - d * nspace;
+ line = Strnew_size(width + 1);
+ for (i = 0; i < indent_here; i++)
+ Strcat_char(line, ' ');
+ for (; *p; p++) {
+ Strcat_char(line, *p);
+ if (*p == ' ') {
+ for (i = 0; i < d; i++)
+ Strcat_char(line, ' ');
+ if (rrest > 0) {
+ Strcat_char(line, ' ');
+ rrest--;
+ }
+ }
+ }
+ lbuf = newTextLine(line, width);
+ }
+ }
+ }
+#endif /* FORMAT_NICE */
+#ifdef TABLE_DEBUG
+ if (w3m_debug) {
+ FILE *f = fopen("zzzproc1", "a");
+ fprintf(f, "pos=%d,%d, maxlimit=%d\n",
+ visible_length(lbuf->line->ptr), lbuf->pos,
+ h_env->maxlimit);
+ fclose(f);
+ }
+#endif
+ if (lbuf->pos > h_env->maxlimit)
+ h_env->maxlimit = lbuf->pos;
+ if (buf)
+ pushTextLine(buf, lbuf);
+ else if (f) {
+ Strfputs(Str_conv_to_halfdump(lbuf->line), f);
+ fputc('\n', f);
+ }
+ if (obuf->flag & RB_SPECIAL || obuf->flag & RB_NFLUSHED)
+ h_env->blank_lines = 0;
+ else
+ h_env->blank_lines++;
+ }
+ else {
+ char *p = line->ptr, *q;
+ Str tmp = Strnew(), tmp2 = Strnew();
+
+#define APPEND(str) \
+ if (buf) \
+ appendTextLine(buf,(str),0); \
+ else if (f) \
+ Strfputs((str),f)
+
+ while (*p) {
+ q = p;
+ if (sloppy_parse_line(&p)) {
+ Strcat_charp_n(tmp, q, p - q);
+ if (force == 2) {
+ APPEND(tmp);
+ }
+ else
+ Strcat(tmp2, tmp);
+ Strclear(tmp);
+ }
+ }
+ if (force == 2) {
+ if (pass) {
+ APPEND(pass);
+ }
+ pass = NULL;
+ }
+ else {
+ if (pass)
+ Strcat(tmp2, pass);
+ pass = tmp2;
+ }
+ }
+
+ if (obuf->bottom_margin > 0) {
+ int i;
+ struct html_feed_environ h;
+ struct readbuffer o;
+ struct environment e[1];
+
+ init_henv(&h, &o, e, 1, NULL, width, indent);
+ o.line = Strnew_size(width + 20);
+ o.pos = obuf->pos;
+ o.flag = obuf->flag;
+ o.top_margin = -1;
+ o.bottom_margin = -1;
+ Strcat_charp(o.line, "<pre_int>");
+ for (i = 0; i < o.pos; i++)
+ Strcat_char(o.line, ' ');
+ Strcat_charp(o.line, "</pre_int>");
+ for (i = 0; i < obuf->bottom_margin; i++)
+ flushline(h_env, &o, indent, force, width);
+ }
+ if (obuf->top_margin < 0 || obuf->bottom_margin < 0)
+ return;
+
+ obuf->line = Strnew_size(256);
+ obuf->pos = 0;
+ obuf->top_margin = 0;
+ obuf->bottom_margin = 0;
+ set_space_to_prevchar(obuf->prevchar);
+ obuf->bp.init_flag = 1;
+ obuf->flag &= ~RB_NFLUSHED;
+ set_breakpoint(obuf, 0);
+ obuf->prev_ctype = PC_ASCII;
+ link_stack = NULL;
+ fillline(obuf, indent);
+ if (pass)
+ passthrough(obuf, pass->ptr, 0);
+ if (!hidden_anchor && obuf->anchor.url) {
+ Str tmp;
+ if (obuf->anchor.hseq > 0)
+ obuf->anchor.hseq = -obuf->anchor.hseq;
+ tmp = Sprintf("<A HSEQ=\"%d\" HREF=\"", obuf->anchor.hseq);
+ Strcat_charp(tmp, html_quote(obuf->anchor.url));
+ if (obuf->anchor.target) {
+ Strcat_charp(tmp, "\" TARGET=\"");
+ Strcat_charp(tmp, html_quote(obuf->anchor.target));
+ }
+ if (obuf->anchor.referer) {
+ Strcat_charp(tmp, "\" REFERER=\"");
+ Strcat_charp(tmp, html_quote(obuf->anchor.referer));
+ }
+ if (obuf->anchor.title) {
+ Strcat_charp(tmp, "\" TITLE=\"");
+ Strcat_charp(tmp, html_quote(obuf->anchor.title));
+ }
+ if (obuf->anchor.accesskey) {
+ char *c = html_quote_char(obuf->anchor.accesskey);
+ Strcat_charp(tmp, "\" ACCESSKEY=\"");
+ if (c)
+ Strcat_charp(tmp, c);
+ else
+ Strcat_char(tmp, obuf->anchor.accesskey);
+ }
+ Strcat_charp(tmp, "\">");
+ push_tag(obuf, tmp->ptr, HTML_A);
+ }
+ if (!hidden_img && obuf->img_alt) {
+ Str tmp = Strnew_charp("<IMG_ALT SRC=\"");
+ Strcat_charp(tmp, html_quote(obuf->img_alt->ptr));
+ Strcat_charp(tmp, "\">");
+ push_tag(obuf, tmp->ptr, HTML_IMG_ALT);
+ }
+ if (!hidden_bold && obuf->in_bold)
+ push_tag(obuf, "<B>", HTML_B);
+ if (!hidden_under && obuf->in_under)
+ push_tag(obuf, "<U>", HTML_U);
+}
+
+void
+do_blankline(struct html_feed_environ *h_env, struct readbuffer *obuf,
+ int indent, int indent_incr, int width)
+{
+ if (h_env->blank_lines == 0)
+ flushline(h_env, obuf, indent, 1, width);
+}
+
+void
+purgeline(struct html_feed_environ *h_env)
+{
+ char *p, *q;
+ Str tmp;
+
+ if (h_env->buf == NULL || h_env->blank_lines == 0)
+ return;
+
+ p = rpopTextLine(h_env->buf)->line->ptr;
+ tmp = Strnew();
+ while (*p) {
+ q = p;
+ if (sloppy_parse_line(&p)) {
+ Strcat_charp_n(tmp, q, p - q);
+ }
+ }
+ appendTextLine(h_env->buf, tmp, 0);
+ h_env->blank_lines--;
+}
+
+static int
+close_effect0(struct readbuffer *obuf, int cmd)
+{
+ int i;
+ char *p;
+
+ for (i = obuf->tag_sp - 1; i >= 0; i--) {
+ if (obuf->tag_stack[i]->cmd == cmd)
+ break;
+ }
+ if (i >= 0) {
+ obuf->tag_sp--;
+ bcopy(&obuf->tag_stack[i + 1], &obuf->tag_stack[i],
+ (obuf->tag_sp - i) * sizeof(struct cmdtable *));
+ return 1;
+ }
+ else if ((p = has_hidden_link(obuf, cmd)) != NULL) {
+ passthrough(obuf, p, 1);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+close_anchor(struct html_feed_environ *h_env, struct readbuffer *obuf)
+{
+ if (obuf->anchor.url) {
+ int i;
+ char *p = NULL;
+ int is_erased = 0;
+
+ for (i = obuf->tag_sp - 1; i >= 0; i--) {
+ if (obuf->tag_stack[i]->cmd == HTML_A)
+ break;
+ }
+ if (i < 0 && obuf->anchor.hseq > 0 && Strlastchar(obuf->line) == ' ') {
+ Strshrink(obuf->line, 1);
+ obuf->pos--;
+ is_erased = 1;
+ }
+
+ if (i >= 0 || (p = has_hidden_link(obuf, HTML_A))) {
+ if (obuf->anchor.hseq > 0) {
+ HTMLlineproc1(ANSP, h_env);
+ set_space_to_prevchar(obuf->prevchar);
+ }
+ else {
+ if (i >= 0) {
+ obuf->tag_sp--;
+ bcopy(&obuf->tag_stack[i + 1], &obuf->tag_stack[i],
+ (obuf->tag_sp - i) * sizeof(struct cmdtable *));
+ }
+ else {
+ passthrough(obuf, p, 1);
+ }
+ bzero((void *)&obuf->anchor, sizeof(obuf->anchor));
+ return;
+ }
+ is_erased = 0;
+ }
+ if (is_erased) {
+ Strcat_char(obuf->line, ' ');
+ obuf->pos++;
+ }
+
+ push_tag(obuf, "</a>", HTML_N_A);
+ }
+ bzero((void *)&obuf->anchor, sizeof(obuf->anchor));
+}
+
+void
+save_fonteffect(struct html_feed_environ *h_env, struct readbuffer *obuf)
+{
+ if (obuf->fontstat_sp < FONT_STACK_SIZE)
+ bcopy(obuf->fontstat, obuf->fontstat_stack[obuf->fontstat_sp],
+ FONTSTAT_SIZE);
+ obuf->fontstat_sp++;
+ if (obuf->in_bold)
+ push_tag(obuf, "</b>", HTML_N_B);
+ if (obuf->in_under)
+ push_tag(obuf, "</u>", HTML_N_U);
+ bzero(obuf->fontstat, FONTSTAT_SIZE);
+}
+
+void
+restore_fonteffect(struct html_feed_environ *h_env, struct readbuffer *obuf)
+{
+ if (obuf->fontstat_sp > 0)
+ obuf->fontstat_sp--;
+ if (obuf->fontstat_sp < FONT_STACK_SIZE)
+ bcopy(obuf->fontstat_stack[obuf->fontstat_sp], obuf->fontstat,
+ FONTSTAT_SIZE);
+ if (obuf->in_bold)
+ push_tag(obuf, "<b>", HTML_B);
+ if (obuf->in_under)
+ push_tag(obuf, "<u>", HTML_U);
+}
+
+static Str
+process_title(struct parsed_tag *tag)
+{
+ cur_title = Strnew();
+ return NULL;
+}
+
+static Str
+process_n_title(struct parsed_tag *tag)
+{
+ Str tmp;
+
+ if (!cur_title)
+ return NULL;
+ Strremovefirstspaces(cur_title);
+ Strremovetrailingspaces(cur_title);
+ tmp = Strnew_m_charp("<title_alt title=\"",
+ html_quote(cur_title->ptr), "\">", NULL);
+ cur_title = NULL;
+ return tmp;
+}
+
+static void
+feed_title(char *str)
+{
+ if (!cur_title)
+ return;
+ while (*str) {
+ if (*str == '&')
+ Strcat_charp(cur_title, getescapecmd(&str));
+ else if (*str == '\n' || *str == '\r') {
+ Strcat_char(cur_title, ' ');
+ str++;
+ }
+ else
+ Strcat_char(cur_title, *(str++));
+ }
+}
+
+Str
+process_img(struct parsed_tag *tag, int width)
+{
+ char *p, *q, *r, *r2 = NULL, *s, *t;
+#ifdef USE_IMAGE
+ int w, i, nw, ni = 1, n, w0 = -1, i0 = -1;
+ int align, xoffset, yoffset, top, bottom, ismap = 0;
+ int use_image = activeImage && displayImage;
+#else
+ int w, i, nw, n;
+#endif
+ int pre_int = FALSE;
+ Str tmp = Strnew();
+
+ if (!parsedtag_get_value(tag, ATTR_SRC, &p))
+ return tmp;
+ p = remove_space(p);
+ q = NULL;
+ parsedtag_get_value(tag, ATTR_ALT, &q);
+ t = q;
+ parsedtag_get_value(tag, ATTR_TITLE, &t);
+ w = -1;
+ if (parsedtag_get_value(tag, ATTR_WIDTH, &w)) {
+ if (w < 0) {
+ if (width > 0)
+ w = (int)(-width * pixel_per_char * w / 100 + 0.5);
+ else
+ w = -1;
+ }
+#ifdef USE_IMAGE
+ if (use_image) {
+ if (w > 0) {
+ w = (int)(w * image_scale / 100 + 0.5);
+ if (w == 0)
+ w = 1;
+ else if (w > MAX_IMAGE_SIZE)
+ w = MAX_IMAGE_SIZE;
+ }
+ }
+#endif
+ }
+#ifdef USE_IMAGE
+ if (use_image) {
+ i = -1;
+ if (parsedtag_get_value(tag, ATTR_HEIGHT, &i)) {
+ if (i > 0) {
+ i = (int)(i * image_scale / 100 + 0.5);
+ if (i == 0)
+ i = 1;
+ else if (i > MAX_IMAGE_SIZE)
+ i = MAX_IMAGE_SIZE;
+ }
+ else {
+ i = -1;
+ }
+ }
+ align = -1;
+ parsedtag_get_value(tag, ATTR_ALIGN, &align);
+ ismap = 0;
+ if (parsedtag_exists(tag, ATTR_ISMAP))
+ ismap = 1;
+ }
+ else
+#endif
+ parsedtag_get_value(tag, ATTR_HEIGHT, &i);
+ r = NULL;
+ parsedtag_get_value(tag, ATTR_USEMAP, &r);
+
+ tmp = Strnew_size(128);
+#ifdef USE_IMAGE
+ if (use_image) {
+ switch (align) {
+ case ALIGN_LEFT:
+ Strcat_charp(tmp, "<div_int align=left>");
+ break;
+ case ALIGN_CENTER:
+ Strcat_charp(tmp, "<div_int align=center>");
+ break;
+ case ALIGN_RIGHT:
+ Strcat_charp(tmp, "<div_int align=right>");
+ break;
+ }
+ }
+#endif
+ if (r) {
+ Str tmp2;
+ r2 = strchr(r, '#');
+ s = "<form_int method=internal action=map>";
+ tmp2 = process_form(parse_tag(&s, TRUE));
+ if (tmp2)
+ Strcat(tmp, tmp2);
+ Strcat(tmp, Sprintf("<input_alt fid=\"%d\" "
+ "type=hidden name=link value=\"", cur_form_id));
+ Strcat_charp(tmp, html_quote((r2) ? r2 + 1 : r));
+ Strcat(tmp, Sprintf("\"><input_alt hseq=\"%d\" fid=\"%d\" "
+ "type=submit no_effect=true>",
+ cur_hseq++, cur_form_id));
+ }
+#ifdef USE_IMAGE
+ if (use_image) {
+ w0 = w;
+ i0 = i;
+ if (w < 0 || i < 0) {
+ Image image;
+ ParsedURL u;
+
+#ifdef USE_M17N
+ parseURL2(wc_conv(p, InnerCharset, cur_document_charset)->ptr, &u,
+ cur_baseURL);
+#else
+ parseURL2(p, &u, cur_baseURL);
+#endif
+ 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;
+ image.height = i;
+
+ image.cache = getImage(&image, cur_baseURL, IMG_FLAG_SKIP);
+ if (image.cache && image.cache->width > 0 &&
+ image.cache->height > 0) {
+ w = w0 = image.cache->width;
+ i = i0 = image.cache->height;
+ }
+ if (w < 0)
+ w = 8 * pixel_per_char;
+ if (i < 0)
+ i = pixel_per_line;
+ }
+ nw = (w > 3) ? (int)((w - 3) / pixel_per_char + 1) : 1;
+ ni = (i > 3) ? (int)((i - 3) / pixel_per_line + 1) : 1;
+ Strcat(tmp,
+ Sprintf("<pre_int><img_alt hseq=\"%d\" src=\"", cur_iseq++));
+ pre_int = TRUE;
+ }
+ else
+#endif
+ {
+ if (w < 0)
+ w = 12 * pixel_per_char;
+ nw = w ? (int)((w - 1) / pixel_per_char + 1) : 1;
+ if (r) {
+ Strcat_charp(tmp, "<pre_int>");
+ pre_int = TRUE;
+ }
+ Strcat_charp(tmp, "<img_alt src=\"");
+ }
+ Strcat_charp(tmp, html_quote(p));
+ Strcat_charp(tmp, "\"");
+ if (t) {
+ Strcat_charp(tmp, " title=\"");
+ Strcat_charp(tmp, html_quote(t));
+ Strcat_charp(tmp, "\"");
+ }
+#ifdef USE_IMAGE
+ if (use_image) {
+ if (w0 >= 0)
+ Strcat(tmp, Sprintf(" width=%d", w0));
+ if (i0 >= 0)
+ Strcat(tmp, Sprintf(" height=%d", i0));
+ switch (align) {
+ case ALIGN_TOP:
+ top = 0;
+ bottom = ni - 1;
+ yoffset = 0;
+ break;
+ case ALIGN_MIDDLE:
+ top = ni / 2;
+ bottom = top;
+ if (top * 2 == ni)
+ yoffset = (int)(((ni + 1) * pixel_per_line - i) / 2);
+ else
+ yoffset = (int)((ni * pixel_per_line - i) / 2);
+ break;
+ case ALIGN_BOTTOM:
+ top = ni - 1;
+ bottom = 0;
+ yoffset = (int)(ni * pixel_per_line - i);
+ break;
+ default:
+ top = ni - 1;
+ bottom = 0;
+ if (ni == 1 && ni * pixel_per_line > i)
+ yoffset = 0;
+ else {
+ yoffset = (int)(ni * pixel_per_line - i);
+ if (yoffset <= -2)
+ yoffset++;
+ }
+ break;
+ }
+ xoffset = (int)((nw * pixel_per_char - w) / 2);
+ if (xoffset)
+ Strcat(tmp, Sprintf(" xoffset=%d", xoffset));
+ if (yoffset)
+ Strcat(tmp, Sprintf(" yoffset=%d", yoffset));
+ if (top)
+ Strcat(tmp, Sprintf(" top_margin=%d", top));
+ if (bottom)
+ Strcat(tmp, Sprintf(" bottom_margin=%d", bottom));
+ if (r) {
+ Strcat_charp(tmp, " usemap=\"");
+ Strcat_charp(tmp, html_quote((r2) ? r2 + 1 : r));
+ Strcat_charp(tmp, "\"");
+ }
+ if (ismap)
+ Strcat_charp(tmp, " ismap");
+ }
+#endif
+ Strcat_charp(tmp, ">");
+ if (q != NULL && *q == '\0' && ignore_null_img_alt)
+ q = NULL;
+ if (q != NULL) {
+ n = get_strwidth(q);
+#ifdef USE_IMAGE
+ if (use_image) {
+ if (n > nw) {
+ char *r;
+ for (r = q, n = 0; r; r += get_mclen(r), n += get_mcwidth(r)) {
+ if (n + get_mcwidth(r) > nw)
+ break;
+ }
+ Strcat_charp(tmp, html_quote(Strnew_charp_n(q, r - q)->ptr));
+ }
+ else
+ Strcat_charp(tmp, html_quote(q));
+ }
+ else
+#endif
+ Strcat_charp(tmp, html_quote(q));
+ goto img_end;
+ }
+ if (w > 0 && i > 0) {
+ /* guess what the image is! */
+ if (w < 32 && i < 48) {
+ /* must be an icon or space */
+ n = 1;
+ if (strcasestr(p, "space") || strcasestr(p, "blank"))
+ Strcat_charp(tmp, "_");
+ else {
+ if (w * i < 8 * 16)
+ Strcat_charp(tmp, "*");
+ else {
+ if (!pre_int) {
+ Strcat_charp(tmp, "<pre_int>");
+ pre_int = TRUE;
+ }
+ push_symbol(tmp, IMG_SYMBOL, symbol_width, 1);
+ n = symbol_width;
+ }
+ }
+ goto img_end;
+ }
+ if (w > 200 && i < 13) {
+ /* must be a horizontal line */
+ if (!pre_int) {
+ Strcat_charp(tmp, "<pre_int>");
+ pre_int = TRUE;
+ }
+ w = w / pixel_per_char / symbol_width;
+ if (w <= 0)
+ w = 1;
+ push_symbol(tmp, HR_SYMBOL, symbol_width, w);
+ n = w * symbol_width;
+ goto img_end;
+ }
+ }
+ for (q = p; *q; q++) ;
+ while (q > p && *q != '/')
+ q--;
+ if (*q == '/')
+ q++;
+ Strcat_char(tmp, '[');
+ n = 1;
+ p = q;
+ for (; *q; q++) {
+ if (!IS_ALNUM(*q) && *q != '_' && *q != '-') {
+ break;
+ }
+ Strcat_char(tmp, *q);
+ n++;
+ if (n + 1 >= nw)
+ break;
+ }
+ Strcat_char(tmp, ']');
+ n++;
+ img_end:
+#ifdef USE_IMAGE
+ if (use_image) {
+ for (; n < nw; n++)
+ Strcat_char(tmp, ' ');
+ }
+#endif
+ Strcat_charp(tmp, "</img_alt>");
+ if (pre_int)
+ Strcat_charp(tmp, "</pre_int>");
+ if (r) {
+ Strcat_charp(tmp, "</input_alt>");
+ process_n_form();
+ }
+#ifdef USE_IMAGE
+ if (use_image) {
+ switch (align) {
+ case ALIGN_RIGHT:
+ case ALIGN_CENTER:
+ case ALIGN_LEFT:
+ Strcat_charp(tmp, "</div_int>");
+ break;
+ }
+ }
+#endif
+ return tmp;
+}
+
+Str
+process_anchor(struct parsed_tag *tag, char *tagbuf)
+{
+ if (parsedtag_need_reconstruct(tag)) {
+ parsedtag_set_value(tag, ATTR_HSEQ, Sprintf("%d", cur_hseq++)->ptr);
+ return parsedtag2str(tag);
+ }
+ else {
+ Str tmp = Sprintf("<a hseq=\"%d\"", cur_hseq++);
+ Strcat_charp(tmp, tagbuf + 2);
+ return tmp;
+ }
+}
+
+Str
+process_input(struct parsed_tag *tag)
+{
+ int i, w, v, x, y, z, iw, ih;
+ char *q, *p, *r, *p2, *s;
+ Str tmp = NULL;
+ char *qq = "";
+ int qlen = 0;
+
+ if (cur_form_id < 0) {
+ char *s = "<form_int method=internal action=none>";
+ tmp = process_form(parse_tag(&s, TRUE));
+ }
+ if (tmp == NULL)
+ tmp = Strnew();
+
+ p = "text";
+ parsedtag_get_value(tag, ATTR_TYPE, &p);
+ q = NULL;
+ parsedtag_get_value(tag, ATTR_VALUE, &q);
+ r = "";
+ parsedtag_get_value(tag, ATTR_NAME, &r);
+ w = 20;
+ parsedtag_get_value(tag, ATTR_SIZE, &w);
+ i = 20;
+ parsedtag_get_value(tag, ATTR_MAXLENGTH, &i);
+ p2 = NULL;
+ parsedtag_get_value(tag, ATTR_ALT, &p2);
+ x = parsedtag_exists(tag, ATTR_CHECKED);
+ y = parsedtag_exists(tag, ATTR_ACCEPT);
+ z = parsedtag_exists(tag, ATTR_READONLY);
+
+ v = formtype(p);
+ if (v == FORM_UNKNOWN)
+ return NULL;
+
+ if (!q) {
+ switch (v) {
+ case FORM_INPUT_IMAGE:
+ case FORM_INPUT_SUBMIT:
+ case FORM_INPUT_BUTTON:
+ q = "SUBMIT";
+ break;
+ case FORM_INPUT_RESET:
+ q = "RESET";
+ break;
+ /* if no VALUE attribute is specified in
+ * <INPUT TYPE=CHECKBOX> tag, then the value "on" is used
+ * as a default value. It is not a part of HTML4.0
+ * specification, but an imitation of Netscape behaviour.
+ */
+ case FORM_INPUT_CHECKBOX:
+ q = "on";
+ }
+ }
+ /* VALUE attribute is not allowed in <INPUT TYPE=FILE> tag. */
+ if (v == FORM_INPUT_FILE)
+ q = NULL;
+ if (q) {
+ qq = html_quote(q);
+ qlen = get_strwidth(q);
+ }
+
+ Strcat_charp(tmp, "<pre_int>");
+ 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("<input_alt hseq=\"%d\" fid=\"%d\" type=%s "
+ "name=\"%s\" width=%d maxlength=%d value=\"%s\"",
+ cur_hseq++, cur_form_id, p, html_quote(r), w, i, qq));
+ if (x)
+ Strcat_charp(tmp, " checked");
+ if (y)
+ Strcat_charp(tmp, " accept");
+ if (z)
+ Strcat_charp(tmp, " readonly");
+ Strcat_char(tmp, '>');
+
+ if (v == FORM_INPUT_HIDDEN)
+ Strcat_charp(tmp, "</input_alt></pre_int>");
+ else {
+ switch (v) {
+ case FORM_INPUT_PASSWORD:
+ case FORM_INPUT_TEXT:
+ case FORM_INPUT_FILE:
+ Strcat_charp(tmp, "<u>");
+ break;
+ case FORM_INPUT_IMAGE:
+ s = NULL;
+ parsedtag_get_value(tag, ATTR_SRC, &s);
+ if (s) {
+ Strcat(tmp, Sprintf("<img src=\"%s\"", html_quote(s)));
+ if (p2)
+ Strcat(tmp, Sprintf(" alt=\"%s\"", html_quote(p2)));
+ if (parsedtag_get_value(tag, ATTR_WIDTH, &iw))
+ Strcat(tmp, Sprintf(" width=\"%d\"", iw));
+ if (parsedtag_get_value(tag, ATTR_HEIGHT, &ih))
+ Strcat(tmp, Sprintf(" height=\"%d\"", ih));
+ Strcat_charp(tmp, ">");
+ Strcat_charp(tmp, "</input_alt></pre_int>");
+ 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, "</u>");
+ break;
+ case FORM_INPUT_IMAGE:
+ case FORM_INPUT_SUBMIT:
+ case FORM_INPUT_BUTTON:
+ case FORM_INPUT_RESET:
+ Strcat_charp(tmp, "]");
+ }
+ Strcat_charp(tmp, "</input_alt>");
+ 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, "</pre_int>");
+ }
+ return tmp;
+}
+
+Str
+process_select(struct parsed_tag *tag)
+{
+ Str tmp = NULL;
+ char *p;
+
+ if (cur_form_id < 0) {
+ char *s = "<form_int method=internal action=none>";
+ 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("<pre_int>[<input_alt hseq=\"%d\" "
+ "fid=\"%d\" type=select name=\"%s\" selectnumber=%d",
+ cur_hseq++, cur_form_id, html_quote(p), n_select);
+ Strcat_charp(select_str, ">");
+ 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, "</input_alt>]</pre_int>");
+ n_select++;
+ }
+ else
+#endif /* MENU_SELECT */
+ Strcat_charp(select_str, "<br>");
+ 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("<br><pre_int>%c<input_alt hseq=\"%d\" "
+ "fid=\"%d\" type=%s name=\"%s\" value=\"%s\"",
+ begin_char, cur_hseq++, cur_form_id,
+ select_is_multiple ? "checkbox" : "radio",
+ html_quote(cur_select->ptr),
+ html_quote(cur_option_value->ptr)));
+ if (cur_option_selected)
+ Strcat_charp(select_str, " checked>*</input_alt>");
+ else
+ Strcat_charp(select_str, "> </input_alt>");
+ Strcat_char(select_str, end_char);
+ Strcat_charp(select_str, html_quote(cur_option_label->ptr));
+ Strcat_charp(select_str, "</pre_int>");
+ n_selectitem++;
+}
+
+Str
+process_textarea(struct parsed_tag *tag, int width)
+{
+ Str tmp = NULL;
+ char *p;
+
+ if (cur_form_id < 0) {
+ char *s = "<form_int method=internal action=none>";
+ 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("<pre_int>[<input_alt hseq=\"%d\" fid=\"%d\" "
+ "type=textarea name=\"%s\" size=%d rows=%d "
+ "top_margin=%d textareanumber=%d",
+ cur_hseq, cur_form_id,
+ html_quote(cur_textarea->ptr),
+ cur_textarea_size, cur_textarea_rows,
+ cur_textarea_rows - 1, n_textarea));
+ if (cur_textarea_readonly)
+ Strcat_charp(tmp, " readonly");
+ Strcat_charp(tmp, "><u>");
+ for (i = 0; i < cur_textarea_size; i++)
+ Strcat_char(tmp, ' ');
+ Strcat_charp(tmp, "</u></input_alt>]</pre_int>\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("<nobr>");
+ 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, "<div_int align=center>");
+ break;
+ case ALIGN_RIGHT:
+ Strcat_charp(tmp, "<div_int align=right>");
+ break;
+ case ALIGN_LEFT:
+ Strcat_charp(tmp, "<div_int align=left>");
+ break;
+ }
+ w /= symbol_width;
+ if (w <= 0)
+ w = 1;
+ push_symbol(tmp, HR_SYMBOL, symbol_width, w);
+ Strcat_charp(tmp, "</div_int></nobr>");
+ 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 { /* <form_int> */
+ 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("<form_int fid=\"%d\" action=\"%s\" method=\"%s\"",
+ fid, html_quote(q), html_quote(p));
+ if (s)
+ Strcat(tmp, Sprintf(" enctype=\"%s\"", html_quote(s)));
+ if (tg)
+ Strcat(tmp, Sprintf(" target=\"%s\"", html_quote(tg)));
+ if (n)
+ Strcat(tmp, Sprintf(" name=\"%s\"", html_quote(n)));
+#ifdef USE_M17N
+ if (r)
+ Strcat(tmp, Sprintf(" accept-charset=\"%s\"", html_quote(r)));
+#endif
+ Strcat_charp(tmp, ">");
+ 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("</b>", 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("<b>", h_env);
+ return 1;
+ case HTML_N_EM:
+ HTMLlineproc1("</b>", 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("<b>", h_env);
+ set_alignment(obuf, tag);
+ return 1;
+ case HTML_N_H:
+ HTMLlineproc1("</b>", 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) && count > 0) {
+ 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;
+ }
+ 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].type) {
+ 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("<b>", 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("<a hseq=\"%d\" href=\"%s\">",
+ cur_hseq++, q)->ptr, HTML_A);
+ if (r)
+ q = html_quote(r);
+ push_charp(obuf, get_strwidth(q), q, PC_ASCII);
+ push_tag(obuf, "</a>", 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, "</pre_int>", 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, "</img_alt>", 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("<form method=get action=\"",
+ html_quote(q),
+ "\">",
+ html_quote(p),
+ "<input type=text name=\"\" accept></form>",
+ 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) <a href=\"%s\">%s</a>",
+ 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("<U>[DEL:</U>", h_env);
+ else
+ obuf->flag |= RB_DEL;
+ return 1;
+ case HTML_N_DEL:
+ if (displayInsDel)
+ HTMLlineproc1("<U>:DEL]</U>", h_env);
+ else
+ obuf->flag &= ~RB_DEL;
+ return 1;
+ case HTML_S:
+ if (displayInsDel)
+ HTMLlineproc1("<U>[S:</U>", h_env);
+ else
+ obuf->flag |= RB_S;
+ return 1;
+ case HTML_N_S:
+ if (displayInsDel)
+ HTMLlineproc1("<U>:S]</U>", h_env);
+ else
+ obuf->flag &= ~RB_S;
+ return 1;
+ case HTML_INS:
+ if (displayInsDel)
+ HTMLlineproc1("<U>[INS:</U>", h_env);
+ return 1;
+ case HTML_N_INS:
+ if (displayInsDel)
+ HTMLlineproc1("<U>:INS]</U>", 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("<A HREF=\"%s\">bgsound(%s)</A>", 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("<A HREF=\"%s\">embed(%s)</A>", 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("<A HREF=\"%s\">applet archive(%s)</A>", 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("<IMG SRC=\"%s\" ALT=\"bg image(%s)\"><BR>", q, q);
+ HTMLlineproc1(s->ptr, h_env);
+ }
+ }
+ case HTML_N_HEAD:
+ if (obuf->flag & RB_TITLE)
+ HTMLlineproc1("</title>", 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);
+ 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)
+ 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>..</form> */
+ 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 <map>..</map> */
+ 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 = "&lt;";
+ }
+ }
+ }
+ 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, "<!--", 4) && (p = strchr(str + 1, '<'))) {
+ str = Strnew_charp_n(str, p - str)->ptr;
+ line = Strnew_m_charp(p, line, NULL)->ptr;
+ }
+ is_tag = FALSE;
+ }
+ if (obuf->table_level >= 0)
+ goto proc_normal;
+ /* textarea */
+ if (pre_mode & RB_INTXTA) {
+ feed_textarea(str);
+ continue;
+ }
+ /* script */
+ if (pre_mode & RB_SCRIPT)
+ continue;
+ /* style */
+ if (pre_mode & RB_STYLE)
+ continue;
+ }
+
+ proc_normal:
+ if (obuf->table_level >= 0) {
+ /*
+ * within table: in <table>..</table>, all input tokens
+ * are fed to the table renderer, and then the renderer
+ * makes HTML output.
+ */
+ switch (feed_table(tbl, str, tbl_mode, tbl_width, internal)) {
+ case 0:
+ /* </table> tag */
+ obuf->table_level--;
+ if (obuf->table_level >= MAX_TABLE - 1)
+ continue;
+ end_table(tbl);
+ if (obuf->table_level >= 0) {
+ struct table *tbl0 = tables[obuf->table_level];
+ str = Sprintf("<table_alt tid=%d>", tbl0->ntable)->ptr;
+ pushTable(tbl0, tbl);
+ tbl = tbl0;
+ tbl_mode = &table_mode[obuf->table_level];
+ tbl_width = table_width(h_env, obuf->table_level);
+ feed_table(tbl, str, tbl_mode, tbl_width, TRUE);
+ continue;
+ /* continue to the next */
+ }
+ if (obuf->flag & RB_DEL)
+ continue;
+ /* all tables have been read */
+ if (tbl->vspace > 0 && !(obuf->flag & RB_IGNORE_P)) {
+ int indent = h_env->envs[h_env->envc].indent;
+ flushline(h_env, obuf, indent, 0, h_env->limit);
+ do_blankline(h_env, obuf, indent, 0, h_env->limit);
+ }
+ save_fonteffect(h_env, obuf);
+ renderTable(tbl, tbl_width, h_env);
+ restore_fonteffect(h_env, obuf);
+ obuf->flag &= ~RB_IGNORE_P;
+ if (tbl->vspace > 0) {
+ int indent = h_env->envs[h_env->envc].indent;
+ do_blankline(h_env, obuf, indent, 0, h_env->limit);
+ obuf->flag |= RB_IGNORE_P;
+ }
+ set_space_to_prevchar(obuf->prevchar);
+ continue;
+ case 1:
+ /* <table> tag */
+ break;
+ default:
+ continue;
+ }
+ }
+
+ if (is_tag) {
+/*** Beginning of a new tag ***/
+ if ((tag = parse_tag(&str, internal)))
+ cmd = tag->tagid;
+ else
+ continue;
+ /* process tags */
+ if (HTMLtagproc1(tag, h_env) == 0) {
+ /* preserve the tag for second-stage processing */
+ if (parsedtag_need_reconstruct(tag))
+ h_env->tagbuf = parsedtag2str(tag);
+ push_tag(obuf, h_env->tagbuf->ptr, cmd);
+ }
+#ifdef ID_EXT
+ else {
+ process_idattr(obuf, cmd, tag);
+ }
+#endif /* ID_EXT */
+ obuf->bp.init_flag = 1;
+ clear_ignore_p_flag(cmd, obuf);
+ if (cmd == HTML_TABLE)
+ goto table_start;
+ else
+ continue;
+ }
+
+ if (obuf->flag & (RB_DEL | RB_S))
+ continue;
+ while (*str) {
+ mode = get_mctype(str);
+ delta = get_mcwidth(str);
+ if (obuf->flag & (RB_SPECIAL & ~RB_NOBR)) {
+ char ch = *str;
+ if (!(obuf->flag & RB_PLAIN) && (*str == '&')) {
+ char *p = str;
+ int ech = getescapechar(&p);
+ if (ech == '\n' || ech == '\r') {
+ ch = '\n';
+ str = p - 1;
+ }
+ else if (ech == '\t') {
+ ch = '\t';
+ str = p - 1;
+ }
+ }
+ if (ch != '\n')
+ obuf->flag &= ~RB_IGNORE_P;
+ if (ch == '\n') {
+ str++;
+ if (obuf->flag & RB_IGNORE_P) {
+ obuf->flag &= ~RB_IGNORE_P;
+ continue;
+ }
+ if (obuf->flag & RB_PRE_INT)
+ PUSH(' ');
+ else
+ flushline(h_env, obuf, h_env->envs[h_env->envc].indent,
+ 1, h_env->limit);
+ }
+ else if (ch == '\t') {
+ do {
+ PUSH(' ');
+ } while ((h_env->envs[h_env->envc].indent + obuf->pos)
+ % Tabstop != 0);
+ str++;
+ }
+ else if (obuf->flag & RB_PLAIN) {
+ char *p = html_quote_char(*str);
+ if (p) {
+ push_charp(obuf, 1, p, PC_ASCII);
+ str++;
+ }
+ else {
+ proc_mchar(obuf, 1, delta, &str, mode);
+ }
+ }
+ else {
+ if (*str == '&')
+ proc_escape(obuf, &str);
+ else
+ proc_mchar(obuf, 1, delta, &str, mode);
+ }
+ if (obuf->flag & (RB_SPECIAL & ~RB_PRE_INT))
+ continue;
+ }
+ else {
+ if (!IS_SPACE(*str))
+ obuf->flag &= ~RB_IGNORE_P;
+ if ((mode == PC_ASCII || mode == PC_CTRL) && IS_SPACE(*str)) {
+ if (*obuf->prevchar->ptr != ' ') {
+ PUSH(' ');
+ }
+ str++;
+ }
+ else {
+#ifdef USE_M17N
+ if (mode == PC_KANJI1)
+ is_hangul = wtf_is_hangul((wc_uchar *) str);
+ else
+ is_hangul = 0;
+ if (mode == PC_KANJI1 &&
+ !is_hangul && !prev_is_hangul &&
+ obuf->pos > h_env->envs[h_env->envc].indent &&
+ Strlastchar(obuf->line) == ' ') {
+ while (obuf->line->length >= 2 &&
+ !strncmp(obuf->line->ptr + obuf->line->length -
+ 2, " ", 2)
+ && obuf->pos >= h_env->envs[h_env->envc].indent) {
+ Strshrink(obuf->line, 1);
+ obuf->pos--;
+ }
+ if (obuf->line->length >= 3 &&
+ obuf->prev_ctype == PC_KANJI1 &&
+ Strlastchar(obuf->line) == ' ' &&
+ obuf->pos >= h_env->envs[h_env->envc].indent) {
+ Strshrink(obuf->line, 1);
+ obuf->pos--;
+ }
+ }
+ prev_is_hangul = is_hangul;
+#endif
+ if (*str == '&')
+ proc_escape(obuf, &str);
+ else
+ proc_mchar(obuf, obuf->flag & RB_SPECIAL, delta, &str,
+ mode);
+ }
+ }
+ if (need_flushline(h_env, obuf, mode)) {
+ char *bp = obuf->line->ptr + obuf->bp.len;
+ char *tp = bp - obuf->bp.tlen;
+ int i = 0;
+
+ if (tp > obuf->line->ptr && tp[-1] == ' ')
+ i = 1;
+
+ indent = h_env->envs[h_env->envc].indent;
+ if (obuf->bp.pos - i > indent) {
+ Str line;
+ append_tags(obuf);
+ line = Strnew_charp(bp);
+ Strshrink(obuf->line, obuf->line->length - obuf->bp.len);
+#ifdef FORMAT_NICE
+ if (obuf->pos - i > h_env->limit)
+ obuf->flag |= RB_FILL;
+#endif /* FORMAT_NICE */
+ back_to_breakpoint(obuf);
+ flushline(h_env, obuf, indent, 0, h_env->limit);
+#ifdef FORMAT_NICE
+ obuf->flag &= ~RB_FILL;
+#endif /* FORMAT_NICE */
+ HTMLlineproc1(line->ptr, h_env);
+ }
+ }
+ }
+ }
+ if (!(obuf->flag & (RB_SPECIAL | RB_INTXTA | RB_INSELECT))) {
+ char *tp;
+ int i = 0;
+
+ if (obuf->bp.pos == obuf->pos) {
+ tp = &obuf->line->ptr[obuf->bp.len - obuf->bp.tlen];
+ }
+ else {
+ tp = &obuf->line->ptr[obuf->line->length];
+ }
+
+ if (tp > obuf->line->ptr && tp[-1] == ' ')
+ i = 1;
+ indent = h_env->envs[h_env->envc].indent;
+ if (obuf->pos - i > h_env->limit) {
+#ifdef FORMAT_NICE
+ obuf->flag |= RB_FILL;
+#endif /* FORMAT_NICE */
+ flushline(h_env, obuf, indent, 0, h_env->limit);
+#ifdef FORMAT_NICE
+ obuf->flag &= ~RB_FILL;
+#endif /* FORMAT_NICE */
+ }
+ }
+}
+
+extern char *NullLine;
+extern Lineprop NullProp[];
+
+#ifndef USE_ANSI_COLOR
+#define addnewline2(a,b,c,d,e,f) _addnewline2(a,b,c,e,f)
+#endif
+static void
+addnewline2(Buffer *buf, char *line, Lineprop *prop, Linecolor *color, int pos,
+ int nlines)
+{
+ Line *l;
+ l = New(Line);
+ l->next = NULL;
+ l->lineBuf = line;
+ l->propBuf = prop;
+#ifdef USE_ANSI_COLOR
+ l->colorBuf = color;
+#endif
+ l->len = pos;
+ l->width = -1;
+ l->size = pos;
+ l->bpos = 0;
+ l->bwidth = 0;
+ l->prev = buf->currentLine;
+ if (buf->currentLine) {
+ l->next = buf->currentLine->next;
+ buf->currentLine->next = l;
+ }
+ else
+ l->next = NULL;
+ if (buf->lastLine == NULL || buf->lastLine == buf->currentLine)
+ buf->lastLine = l;
+ buf->currentLine = l;
+ if (buf->firstLine == NULL)
+ buf->firstLine = l;
+ l->linenumber = ++buf->allLine;
+ if (nlines < 0) {
+ /* l->real_linenumber = l->linenumber; */
+ l->real_linenumber = 0;
+ }
+ else {
+ l->real_linenumber = nlines;
+ }
+ l = NULL;
+}
+
+static void
+addnewline(Buffer *buf, char *line, Lineprop *prop, Linecolor *color, int pos,
+ int width, int nlines)
+{
+ char *s;
+ Lineprop *p;
+#ifdef USE_ANSI_COLOR
+ Linecolor *c;
+#endif
+ Line *l;
+ int i, bpos, bwidth;
+
+ if (pos > 0) {
+ s = allocStr(line, pos);
+ p = NewAtom_N(Lineprop, pos);
+ bcopy((void *)prop, (void *)p, pos * sizeof(Lineprop));
+ }
+ else {
+ s = NullLine;
+ p = NullProp;
+ }
+#ifdef USE_ANSI_COLOR
+ if (pos > 0 && color) {
+ c = NewAtom_N(Linecolor, pos);
+ bcopy((void *)color, (void *)c, pos * sizeof(Linecolor));
+ }
+ else {
+ c = NULL;
+ }
+#endif
+ addnewline2(buf, s, p, c, pos, nlines);
+ if (pos <= 0 || width <= 0)
+ return;
+ bpos = 0;
+ bwidth = 0;
+ while (1) {
+ l = buf->currentLine;
+ l->bpos = bpos;
+ l->bwidth = bwidth;
+ i = columnLen(l, width);
+ if (i == 0) {
+ i++;
+#ifdef USE_M17N
+ while (i < l->len && p[i] & PC_WCHAR2)
+ i++;
+#endif
+ }
+ l->len = i;
+ l->width = COLPOS(l, l->len);
+ if (pos <= i)
+ return;
+ bpos += l->len;
+ bwidth += l->width;
+ s += i;
+ p += i;
+#ifdef USE_ANSI_COLOR
+ if (c)
+ c += i;
+#endif
+ pos -= i;
+ addnewline2(buf, s, p, c, pos, nlines);
+ }
+}
+
+/*
+ * loadHTMLBuffer: read file and make new buffer
+ */
+Buffer *
+loadHTMLBuffer(URLFile *f, Buffer *newBuf)
+{
+ FILE *src = NULL;
+ Str tmp;
+
+ if (newBuf == NULL)
+ newBuf = newBuffer(INIT_BUFFER_WIDTH);
+ if (newBuf->sourcefile == NULL &&
+ (f->scheme != SCM_LOCAL || newBuf->mailcap)) {
+ tmp = tmpfname(TMPF_SRC, ".html");
+ src = fopen(tmp->ptr, "w");
+ if (src)
+ newBuf->sourcefile = tmp->ptr;
+ }
+
+ loadHTMLstream(f, newBuf, src, newBuf->bufferprop & BP_FRAME);
+
+ newBuf->topLine = newBuf->firstLine;
+ newBuf->lastLine = newBuf->currentLine;
+ newBuf->currentLine = newBuf->firstLine;
+ if (n_textarea)
+ formResetBuffer(newBuf, newBuf->formitem);
+ if (src)
+ fclose(src);
+
+ return newBuf;
+}
+
+static char *_size_unit[] = { "b", "kb", "Mb", "Gb", "Tb",
+ "Pb", "Eb", "Zb", "Bb", "Yb", NULL
+};
+
+char *
+convert_size(clen_t size, int usefloat)
+{
+ float csize;
+ int sizepos = 0;
+ char **sizes = _size_unit;
+
+ csize = (float)size;
+ while (csize >= 999.495 && sizes[sizepos + 1]) {
+ csize = csize / 1024.0;
+ sizepos++;
+ }
+ return Sprintf(usefloat ? "%.3g%s" : "%.0f%s",
+ floor(csize * 100.0 + 0.5) / 100.0, sizes[sizepos])->ptr;
+}
+
+char *
+convert_size2(clen_t size1, clen_t size2, int usefloat)
+{
+ char **sizes = _size_unit;
+ float csize, factor = 1;
+ int sizepos = 0;
+
+ csize = (float)((size1 > size2) ? size1 : size2);
+ while (csize / factor >= 999.495 && sizes[sizepos + 1]) {
+ factor *= 1024.0;
+ sizepos++;
+ }
+ return Sprintf(usefloat ? "%.3g/%.3g%s" : "%.0f/%.0f%s",
+ floor(size1 / factor * 100.0 + 0.5) / 100.0,
+ floor(size2 / factor * 100.0 + 0.5) / 100.0,
+ sizes[sizepos])->ptr;
+}
+
+void
+showProgress(clen_t * linelen, clen_t * trbyte)
+{
+ int i, j, rate, duration, eta, pos;
+ static time_t last_time, start_time;
+ time_t cur_time;
+ Str messages;
+ char *fmtrbyte, *fmrate;
+
+ if (!fmInitialized)
+ return;
+
+ if (*linelen < 1024)
+ return;
+ if (current_content_length > 0) {
+ double ratio;
+ cur_time = time(0);
+ if (*trbyte == 0) {
+ move(LASTLINE, 0);
+ clrtoeolx();
+ start_time = cur_time;
+ }
+ *trbyte += *linelen;
+ *linelen = 0;
+ if (cur_time == last_time)
+ return;
+ last_time = cur_time;
+ move(LASTLINE, 0);
+ ratio = 100.0 * (*trbyte) / current_content_length;
+ fmtrbyte = convert_size2(*trbyte, current_content_length, 1);
+ duration = cur_time - start_time;
+ if (duration) {
+ rate = *trbyte / duration;
+ fmrate = convert_size(rate, 1);
+ eta = rate ? (current_content_length - *trbyte) / rate : -1;
+ messages = Sprintf("%11s %3.0f%% "
+ "%7s/s "
+ "eta %02d:%02d:%02d ",
+ fmtrbyte, ratio,
+ fmrate,
+ eta / (60 * 60), (eta / 60) % 60, eta % 60);
+ }
+ else {
+ messages = Sprintf("%11s %3.0f%% ",
+ fmtrbyte, ratio);
+ }
+ addstr(messages->ptr);
+ pos = 42;
+ i = pos + (COLS - pos - 1) * (*trbyte) / current_content_length;
+ move(LASTLINE, pos);
+ standout();
+ addch(' ');
+ for (j = pos + 1; j <= i; j++)
+ addch('|');
+ standend();
+ /* no_clrtoeol(); */
+ refresh();
+ }
+ else {
+ cur_time = time(0);
+ if (*trbyte == 0) {
+ move(LASTLINE, 0);
+ clrtoeolx();
+ start_time = cur_time;
+ }
+ *trbyte += *linelen;
+ *linelen = 0;
+ if (cur_time == last_time)
+ return;
+ last_time = cur_time;
+ move(LASTLINE, 0);
+ fmtrbyte = convert_size(*trbyte, 1);
+ duration = cur_time - start_time;
+ if (duration) {
+ fmrate = convert_size(*trbyte / duration, 1);
+ messages = Sprintf("%7s loaded %7s/s", fmtrbyte, fmrate);
+ }
+ else {
+ messages = Sprintf("%7s loaded", fmtrbyte);
+ }
+ message(messages->ptr, 0, 0);
+ refresh();
+ }
+}
+
+void
+init_henv(struct html_feed_environ *h_env, struct readbuffer *obuf,
+ struct environment *envs, int nenv, TextLineList *buf,
+ int limit, int indent)
+{
+ envs[0].indent = indent;
+
+ obuf->line = Strnew();
+ obuf->cprop = 0;
+ obuf->pos = 0;
+ obuf->prevchar = Strnew_size(8);
+ set_space_to_prevchar(obuf->prevchar);
+ obuf->flag = RB_IGNORE_P;
+ obuf->flag_sp = 0;
+ obuf->status = R_ST_NORMAL;
+ obuf->table_level = -1;
+ obuf->nobr_level = 0;
+ bzero((void *)&obuf->anchor, sizeof(obuf->anchor));
+ obuf->img_alt = 0;
+ obuf->in_bold = 0;
+ obuf->in_under = 0;
+ obuf->prev_ctype = PC_ASCII;
+ obuf->tag_sp = 0;
+ obuf->fontstat_sp = 0;
+ obuf->top_margin = 0;
+ obuf->bottom_margin = 0;
+ obuf->bp.init_flag = 1;
+ set_breakpoint(obuf, 0);
+
+ h_env->buf = buf;
+ h_env->f = NULL;
+ h_env->obuf = obuf;
+ h_env->tagbuf = Strnew();
+ h_env->limit = limit;
+ h_env->maxlimit = 0;
+ h_env->envs = envs;
+ h_env->nenv = nenv;
+ h_env->envc = 0;
+ h_env->envc_real = 0;
+ h_env->title = NULL;
+ h_env->blank_lines = 0;
+}
+
+void
+completeHTMLstream(struct html_feed_environ *h_env, struct readbuffer *obuf)
+{
+ close_anchor(h_env, obuf);
+ if (obuf->img_alt) {
+ push_tag(obuf, "</img_alt>", HTML_N_IMG_ALT);
+ obuf->img_alt = NULL;
+ }
+ if (obuf->in_bold) {
+ push_tag(obuf, "</b>", HTML_N_B);
+ obuf->in_bold = 0;
+ }
+ if (obuf->in_under) {
+ push_tag(obuf, "</u>", HTML_N_U);
+ obuf->in_under = 0;
+ }
+ if (obuf->flag & RB_INTXTA)
+ HTMLlineproc1("</textarea>", h_env);
+ /* for unbalanced select tag */
+ if (obuf->flag & RB_INSELECT)
+ HTMLlineproc1("</select>", h_env);
+ if (obuf->flag & RB_TITLE)
+ HTMLlineproc1("</title>", h_env);
+
+ /* for unbalanced table tag */
+ if (obuf->table_level >= MAX_TABLE)
+ obuf->table_level = MAX_TABLE - 1;
+
+ while (obuf->table_level >= 0) {
+ table_mode[obuf->table_level].pre_mode
+ &= ~(TBLM_SCRIPT | TBLM_STYLE | TBLM_PLAIN);
+ HTMLlineproc1("</table>", h_env);
+ }
+}
+
+static void
+print_internal_information(struct html_feed_environ *henv)
+{
+ int i;
+ Str s;
+ TextLineList *tl = newTextLineList();
+
+ s = Strnew_charp("<internal>");
+ pushTextLine(tl, newTextLine(s, 0));
+ if (henv->title) {
+ s = Strnew_m_charp("<title_alt title=\"",
+ html_quote(henv->title), "\">", NULL);
+ pushTextLine(tl, newTextLine(s, 0));
+ }
+#if 0
+ if (form_max >= 0) {
+ FormList *fp;
+ for (i = 0; i <= form_max; i++) {
+ fp = forms[i];
+ s = Sprintf("<form_int fid=\"%d\" action=\"%s\" method=\"%s\"",
+ i, html_quote(fp->action->ptr),
+ (fp->method == FORM_METHOD_POST) ? "post"
+ : ((fp->method ==
+ FORM_METHOD_INTERNAL) ? "internal" : "get"));
+ if (fp->target)
+ Strcat(s, Sprintf(" target=\"%s\"", html_quote(fp->target)));
+ if (fp->enctype == FORM_ENCTYPE_MULTIPART)
+ Strcat_charp(s, " enctype=\"multipart/form-data\"");
+#ifdef USE_M17N
+ if (fp->charset)
+ Strcat(s, Sprintf(" accept-charset=\"%s\"",
+ html_quote(fp->charset)));
+#endif
+ Strcat_charp(s, ">");
+ pushTextLine(tl, newTextLine(s, 0));
+ }
+ }
+#endif
+#ifdef MENU_SELECT
+ if (n_select > 0) {
+ FormSelectOptionItem *ip;
+ for (i = 0; i < n_select; i++) {
+ s = Sprintf("<select_int selectnumber=%d>", i);
+ pushTextLine(tl, newTextLine(s, 0));
+ for (ip = select_option[i].first; ip; ip = ip->next) {
+ s = Sprintf("<option_int value=\"%s\" label=\"%s\"%s>",
+ html_quote(ip->value ? ip->value->ptr :
+ ip->label->ptr),
+ html_quote(ip->label->ptr),
+ ip->checked ? " selected" : "");
+ pushTextLine(tl, newTextLine(s, 0));
+ }
+ s = Strnew_charp("</select_int>");
+ pushTextLine(tl, newTextLine(s, 0));
+ }
+ }
+#endif /* MENU_SELECT */
+ if (n_textarea > 0) {
+ for (i = 0; i < n_textarea; i++) {
+ s = Sprintf("<textarea_int textareanumber=%d>", i);
+ pushTextLine(tl, newTextLine(s, 0));
+ s = Strnew_charp(html_quote(textarea_str[i]->ptr));
+ Strcat_charp(s, "</textarea_int>");
+ pushTextLine(tl, newTextLine(s, 0));
+ }
+ }
+ s = Strnew_charp("</internal>");
+ pushTextLine(tl, newTextLine(s, 0));
+
+ if (henv->buf)
+ appendTextLineList(henv->buf, tl);
+ else if (henv->f) {
+ TextLineListItem *p;
+ for (p = tl->first; p; p = p->next)
+ fprintf(henv->f, "%s\n", Str_conv_to_halfdump(p->ptr->line)->ptr);
+ }
+}
+
+void
+loadHTMLstream(URLFile *f, Buffer *newBuf, FILE * src, int internal)
+{
+ struct environment envs[MAX_ENV_LEVEL];
+ clen_t linelen = 0;
+ clen_t trbyte = 0;
+ Str lineBuf2 = Strnew();
+#ifdef USE_M17N
+ wc_ces charset = WC_CES_US_ASCII;
+ wc_ces volatile doc_charset = DocumentCharset;
+#endif
+ struct html_feed_environ htmlenv1;
+ struct readbuffer obuf;
+#ifdef USE_IMAGE
+ int volatile image_flag;
+#endif
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+
+#ifdef USE_M17N
+ if (fmInitialized && graph_ok()) {
+ symbol_width = symbol_width0 = 1;
+ }
+ else {
+ symbol_width0 = 0;
+ get_symbol(DisplayCharset, &symbol_width0);
+ symbol_width = WcOption.use_wide ? symbol_width0 : 1;
+ }
+#else
+ symbol_width = symbol_width0 = 1;
+#endif
+
+ cur_title = NULL;
+ n_textarea = 0;
+ cur_textarea = NULL;
+ max_textarea = MAX_TEXTAREA;
+ textarea_str = New_N(Str, max_textarea);
+#ifdef MENU_SELECT
+ n_select = 0;
+ max_select = MAX_SELECT;
+ select_option = New_N(FormSelectOption, max_select);
+#endif /* MENU_SELECT */
+ cur_select = NULL;
+ form_sp = -1;
+ form_max = -1;
+ forms_size = 0;
+ forms = NULL;
+ cur_hseq = 1;
+#ifdef USE_IMAGE
+ cur_iseq = 1;
+ if (newBuf->image_flag)
+ image_flag = newBuf->image_flag;
+ else if (activeImage && displayImage && autoImage)
+ image_flag = IMG_FLAG_AUTO;
+ else
+ image_flag = IMG_FLAG_SKIP;
+ if (newBuf->currentURL.file)
+ cur_baseURL = baseURL(newBuf);
+#endif
+
+ if (w3m_halfload) {
+ newBuf->buffername = "---";
+#ifdef USE_M17N
+ newBuf->document_charset = InnerCharset;
+#endif
+ max_textarea = 0;
+#ifdef MENU_SELECT
+ max_select = 0;
+#endif
+ HTMLlineproc3(newBuf, f->stream);
+ w3m_halfload = FALSE;
+ return;
+ }
+
+ init_henv(&htmlenv1, &obuf, envs, MAX_ENV_LEVEL, NULL, newBuf->width, 0);
+
+ if (w3m_halfdump)
+ htmlenv1.f = stdout;
+ else
+ htmlenv1.buf = newTextLineList();
+
+ if (SETJMP(AbortLoading) != 0) {
+ HTMLlineproc1("<br>Transfer Interrupted!<br>", &htmlenv1);
+ goto phase2;
+ }
+ TRAP_ON;
+
+#ifdef USE_M17N
+ if (newBuf != NULL) {
+ if (newBuf->bufferprop & BP_FRAME)
+ charset = InnerCharset;
+ else if (newBuf->document_charset)
+ charset = doc_charset = newBuf->document_charset;
+ }
+ if (content_charset && UseContentCharset)
+ doc_charset = content_charset;
+ meta_charset = 0;
+#endif
+#if 0
+ do_blankline(&htmlenv1, &obuf, 0, 0, htmlenv1.limit);
+ obuf.flag = RB_IGNORE_P;
+#endif
+ if (IStype(f->stream) != IST_ENCODED)
+ f->stream = newEncodedStream(f->stream, f->encoding);
+ while ((lineBuf2 = StrmyUFgets(f))->length) {
+#ifdef USE_NNTP
+ if (f->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') {
+ Strshrinkfirst(lineBuf2, 1);
+ if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' ||
+ lineBuf2->ptr[0] == '\0') {
+ /*
+ * iseos(f->stream) = TRUE;
+ */
+ break;
+ }
+ }
+#endif /* USE_NNTP */
+ if (src)
+ Strfputs(lineBuf2, src);
+ linelen += lineBuf2->length;
+ if (w3m_dump & DUMP_SOURCE)
+ continue;
+ showProgress(&linelen, &trbyte);
+ /*
+ * if (frame_source)
+ * continue;
+ */
+#ifdef USE_M17N
+ if (meta_charset) { /* <META> */
+ if (content_charset == 0 && UseContentCharset) {
+ doc_charset = meta_charset;
+ charset = WC_CES_US_ASCII;
+ }
+ meta_charset = 0;
+ }
+#endif
+ lineBuf2 = convertLine(f, lineBuf2, HTML_MODE, &charset, doc_charset);
+#if defined(USE_M17N) && defined(USE_IMAGE)
+ cur_document_charset = charset;
+#endif
+ HTMLlineproc0(lineBuf2->ptr, &htmlenv1, internal);
+ }
+ if (obuf.status != R_ST_NORMAL) {
+ obuf.status = R_ST_EOL;
+ HTMLlineproc0("\n", &htmlenv1, internal);
+ }
+ obuf.status = R_ST_NORMAL;
+ completeHTMLstream(&htmlenv1, &obuf);
+ flushline(&htmlenv1, &obuf, 0, 2, htmlenv1.limit);
+ if (htmlenv1.title)
+ newBuf->buffername = htmlenv1.title;
+ if (w3m_halfdump) {
+ TRAP_OFF;
+ print_internal_information(&htmlenv1);
+ return;
+ }
+ if (w3m_backend) {
+ TRAP_OFF;
+ print_internal_information(&htmlenv1);
+ backend_halfdump_buf = htmlenv1.buf;
+ return;
+ }
+ phase2:
+ newBuf->trbyte = trbyte + linelen;
+ TRAP_OFF;
+#ifdef USE_M17N
+ if (!(newBuf->bufferprop & BP_FRAME))
+ newBuf->document_charset = charset;
+#endif
+#ifdef USE_IMAGE
+ newBuf->image_flag = image_flag;
+#endif
+ HTMLlineproc2(newBuf, htmlenv1.buf);
+}
+
+/*
+ * loadHTMLString: read string and make new buffer
+ */
+Buffer *
+loadHTMLString(Str page)
+{
+ URLFile f;
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+ Buffer *newBuf;
+
+ newBuf = newBuffer(INIT_BUFFER_WIDTH);
+ if (SETJMP(AbortLoading) != 0) {
+ TRAP_OFF;
+ discardBuffer(newBuf);
+ return NULL;
+ }
+ TRAP_ON;
+
+ init_stream(&f, SCM_LOCAL, newStrStream(page));
+
+#ifdef USE_M17N
+ newBuf->document_charset = InnerCharset;
+#endif
+ loadHTMLstream(&f, newBuf, NULL, TRUE);
+#ifdef USE_M17N
+ newBuf->document_charset = WC_CES_US_ASCII;
+#endif
+
+ TRAP_OFF;
+ newBuf->topLine = newBuf->firstLine;
+ newBuf->lastLine = newBuf->currentLine;
+ newBuf->currentLine = newBuf->firstLine;
+ newBuf->type = "text/html";
+ newBuf->real_type = newBuf->type;
+ if (n_textarea)
+ formResetBuffer(newBuf, newBuf->formitem);
+ return newBuf;
+}
+
+#ifdef USE_GOPHER
+
+/*
+ * loadGopherDir: get gopher directory
+ */
+Str
+loadGopherDir(URLFile *uf, ParsedURL *pu, wc_ces * charset)
+{
+ Str volatile tmp;
+ Str lbuf, name, file, host, port;
+ char *volatile p, *volatile q;
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+#ifdef USE_M17N
+ wc_ces doc_charset = DocumentCharset;
+#endif
+
+ tmp = parsedURL2Str(pu);
+ p = html_quote(tmp->ptr);
+ tmp =
+ convertLine(NULL, Strnew_charp(file_unquote(tmp->ptr)), RAW_MODE,
+ charset, doc_charset);
+ q = html_quote(tmp->ptr);
+ tmp = Strnew_m_charp("<html>\n<head>\n<base href=\"", p, "\">\n<title>", q,
+ "</title>\n</head>\n<body>\n<h1>Index of ", q,
+ "</h1>\n<table>\n", NULL);
+
+ if (SETJMP(AbortLoading) != 0)
+ goto gopher_end;
+ TRAP_ON;
+
+ while (1) {
+ if (lbuf = StrUFgets(uf), lbuf->length == 0)
+ break;
+ if (lbuf->ptr[0] == '.' &&
+ (lbuf->ptr[1] == '\n' || lbuf->ptr[1] == '\r'))
+ break;
+ lbuf = convertLine(uf, lbuf, HTML_MODE, charset, doc_charset);
+ p = lbuf->ptr;
+ for (q = p; *q && *q != '\t'; q++) ;
+ name = Strnew_charp_n(p, q - p);
+ if (!*q)
+ continue;
+ p = q + 1;
+ for (q = p; *q && *q != '\t'; q++) ;
+ file = Strnew_charp_n(p, q - p);
+ if (!*q)
+ continue;
+ p = q + 1;
+ for (q = p; *q && *q != '\t'; q++) ;
+ host = Strnew_charp_n(p, q - p);
+ if (!*q)
+ continue;
+ p = q + 1;
+ for (q = p; *q && *q != '\t' && *q != '\r' && *q != '\n'; q++) ;
+ port = Strnew_charp_n(p, q - p);
+
+ switch (name->ptr[0]) {
+ case '0':
+ p = "[text file]";
+ break;
+ case '1':
+ p = "[directory]";
+ break;
+ case 'm':
+ p = "[message]";
+ break;
+ case 's':
+ p = "[sound]";
+ break;
+ case 'g':
+ p = "[gif]";
+ break;
+ case 'h':
+ p = "[HTML]";
+ break;
+ default:
+ p = "[unsupported]";
+ break;
+ }
+ q = Strnew_m_charp("gopher://", host->ptr, ":", port->ptr,
+ "/", file->ptr, NULL)->ptr;
+ Strcat_m_charp(tmp, "<a href=\"",
+ html_quote(url_quote_conv(q, *charset)),
+ "\">", p, html_quote(name->ptr + 1), "</a>\n", NULL);
+ }
+
+ gopher_end:
+ TRAP_OFF;
+
+ Strcat_charp(tmp, "</table>\n</body>\n</html>\n");
+ return tmp;
+}
+#endif /* USE_GOPHER */
+
+/*
+ * loadBuffer: read file and make new buffer
+ */
+Buffer *
+loadBuffer(URLFile *uf, Buffer *volatile newBuf)
+{
+ FILE *volatile src = NULL;
+#ifdef USE_M17N
+ wc_ces charset = WC_CES_US_ASCII;
+ wc_ces volatile doc_charset = DocumentCharset;
+#endif
+ Str lineBuf2;
+ volatile char pre_lbuf = '\0';
+ int nlines;
+ Str tmpf;
+ clen_t linelen = 0, trbyte = 0;
+ Lineprop *propBuffer = NULL;
+#ifdef USE_ANSI_COLOR
+ Linecolor *colorBuffer = NULL;
+#endif
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+
+ if (newBuf == NULL)
+ newBuf = newBuffer(INIT_BUFFER_WIDTH);
+ lineBuf2 = Strnew();
+
+ if (SETJMP(AbortLoading) != 0) {
+ goto _end;
+ }
+ TRAP_ON;
+
+ if (newBuf->sourcefile == NULL &&
+ (uf->scheme != SCM_LOCAL || newBuf->mailcap)) {
+ tmpf = tmpfname(TMPF_SRC, NULL);
+ src = fopen(tmpf->ptr, "w");
+ if (src)
+ newBuf->sourcefile = tmpf->ptr;
+ }
+#ifdef USE_M17N
+ if (newBuf->document_charset)
+ charset = doc_charset = newBuf->document_charset;
+ if (content_charset && UseContentCharset)
+ doc_charset = content_charset;
+#endif
+
+ nlines = 0;
+ if (IStype(uf->stream) != IST_ENCODED)
+ uf->stream = newEncodedStream(uf->stream, uf->encoding);
+ while ((lineBuf2 = StrmyISgets(uf->stream))->length) {
+#ifdef USE_NNTP
+ if (uf->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') {
+ Strshrinkfirst(lineBuf2, 1);
+ if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' ||
+ lineBuf2->ptr[0] == '\0') {
+ /*
+ * iseos(uf->stream) = TRUE;
+ */
+ break;
+ }
+ }
+#endif /* USE_NNTP */
+ if (src)
+ Strfputs(lineBuf2, src);
+ linelen += lineBuf2->length;
+ if (w3m_dump & DUMP_SOURCE)
+ continue;
+ showProgress(&linelen, &trbyte);
+ if (frame_source)
+ continue;
+ lineBuf2 =
+ convertLine(uf, lineBuf2, PAGER_MODE, &charset, doc_charset);
+ if (squeezeBlankLine) {
+ if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') {
+ ++nlines;
+ continue;
+ }
+ pre_lbuf = lineBuf2->ptr[0];
+ }
+ ++nlines;
+ Strchop(lineBuf2);
+ lineBuf2 = checkType(lineBuf2, &propBuffer, NULL);
+ addnewline(newBuf, lineBuf2->ptr, propBuffer, colorBuffer,
+ lineBuf2->length, FOLD_BUFFER_WIDTH, nlines);
+ }
+ _end:
+ TRAP_OFF;
+ newBuf->topLine = newBuf->firstLine;
+ newBuf->lastLine = newBuf->currentLine;
+ newBuf->currentLine = newBuf->firstLine;
+ newBuf->trbyte = trbyte + linelen;
+#ifdef USE_M17N
+ newBuf->document_charset = charset;
+#endif
+ if (src)
+ fclose(src);
+
+ return newBuf;
+}
+
+#ifdef USE_IMAGE
+Buffer *
+loadImageBuffer(URLFile *uf, Buffer *newBuf)
+{
+ Image image;
+ ImageCache *cache;
+ Str tmp, tmpf;
+ FILE *src = NULL;
+ URLFile f;
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+ struct stat st;
+
+ loadImage(newBuf, IMG_FLAG_STOP);
+ image.url = uf->url;
+ image.ext = uf->ext;
+ image.width = -1;
+ image.height = -1;
+ image.cache = NULL;
+ cache = getImage(&image, cur_baseURL, IMG_FLAG_AUTO);
+ if (!cur_baseURL->is_nocache && cache->loaded & IMG_FLAG_LOADED &&
+ !stat(cache->file, &st))
+ goto image_buffer;
+
+ TRAP_ON;
+ if (IStype(uf->stream) != IST_ENCODED)
+ uf->stream = newEncodedStream(uf->stream, uf->encoding);
+ if (save2tmp(*uf, cache->file) < 0) {
+ UFclose(uf);
+ TRAP_OFF;
+ return NULL;
+ }
+ UFclose(uf);
+ TRAP_OFF;
+
+ cache->loaded = IMG_FLAG_LOADED;
+ cache->index = 0;
+
+ image_buffer:
+ if (newBuf == NULL)
+ newBuf = newBuffer(INIT_BUFFER_WIDTH);
+ cache->loaded |= IMG_FLAG_DONT_REMOVE;
+ if (newBuf->sourcefile == NULL && uf->scheme != SCM_LOCAL)
+ newBuf->sourcefile = cache->file;
+
+ tmp = Sprintf("<img src=\"%s\"><br><br>", html_quote(image.url));
+ tmpf = tmpfname(TMPF_SRC, ".html");
+ src = fopen(tmpf->ptr, "w");
+ newBuf->mailcap_source = tmpf->ptr;
+
+ init_stream(&f, SCM_LOCAL, newStrStream(tmp));
+ loadHTMLstream(&f, newBuf, src, TRUE);
+ if (src)
+ fclose(src);
+
+ newBuf->topLine = newBuf->firstLine;
+ newBuf->lastLine = newBuf->currentLine;
+ newBuf->currentLine = newBuf->firstLine;
+ newBuf->image_flag = IMG_FLAG_AUTO;
+ return newBuf;
+}
+#endif
+
+static Str
+conv_symbol(Line *l)
+{
+ Str tmp = NULL;
+ char *p = l->lineBuf, *ep = p + l->len;
+ Lineprop *pr = l->propBuf;
+#ifdef USE_M17N
+ int w;
+ char **symbol = NULL;
+#else
+ char **symbol = get_symbol();
+#endif
+
+ for (; p < ep; p++, pr++) {
+ if (*pr & PC_SYMBOL) {
+#ifdef USE_M17N
+ char c = ((char)wtf_get_code((wc_uchar *) p) & 0x7f) - SYMBOL_BASE;
+ int len = get_mclen(p);
+#else
+ char c = *p - SYMBOL_BASE;
+#endif
+ if (tmp == NULL) {
+ tmp = Strnew_size(l->len);
+ Strcopy_charp_n(tmp, l->lineBuf, p - l->lineBuf);
+#ifdef USE_M17N
+ w = (*pr & PC_KANJI) ? 2 : 1;
+ symbol = get_symbol(DisplayCharset, &w);
+#endif
+ }
+ Strcat_charp(tmp, symbol[(int)c]);
+#ifdef USE_M17N
+ p += len - 1;
+ pr += len - 1;
+#endif
+ }
+ else if (tmp != NULL)
+ Strcat_char(tmp, *p);
+ }
+ if (tmp)
+ return tmp;
+ else
+ return Strnew_charp_n(l->lineBuf, l->len);
+}
+
+/*
+ * saveBuffer: write buffer to file
+ */
+static void
+_saveBuffer(Buffer *buf, Line *l, FILE * f, int cont)
+{
+ Str tmp;
+ int is_html = FALSE;
+#ifdef USE_M17N
+ int set_charset = !DisplayCharset;
+ wc_ces charset = DisplayCharset ? DisplayCharset : WC_CES_US_ASCII;
+#endif
+
+ if (buf->type && !strcasecmp(buf->type, "text/html"))
+ is_html = TRUE;
+
+ pager_next:
+ for (; l != NULL; l = l->next) {
+ if (is_html)
+ tmp = conv_symbol(l);
+ else
+ tmp = Strnew_charp_n(l->lineBuf, l->len);
+ tmp = wc_Str_conv(tmp, InnerCharset, charset);
+ Strfputs(tmp, f);
+ if (Strlastchar(tmp) != '\n' && !(cont && l->next && l->next->bpos))
+ putc('\n', f);
+ }
+ if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) {
+ l = getNextPage(buf, PagerMax);
+#ifdef USE_M17N
+ if (set_charset)
+ charset = buf->document_charset;
+#endif
+ goto pager_next;
+ }
+}
+
+void
+saveBuffer(Buffer *buf, FILE * f, int cont)
+{
+ _saveBuffer(buf, buf->firstLine, f, cont);
+}
+
+void
+saveBufferBody(Buffer *buf, FILE * f, int cont)
+{
+ Line *l = buf->firstLine;
+
+ while (l != NULL && l->real_linenumber == 0)
+ l = l->next;
+ _saveBuffer(buf, l, f, cont);
+}
+
+static Buffer *
+loadcmdout(char *cmd,
+ Buffer *(*loadproc) (URLFile *, Buffer *), Buffer *defaultbuf)
+{
+ FILE *f, *popen(const char *, const char *);
+ Buffer *buf;
+ URLFile uf;
+
+ if (cmd == NULL || *cmd == '\0')
+ return NULL;
+ f = popen(cmd, "r");
+ if (f == NULL)
+ return NULL;
+ init_stream(&uf, SCM_UNKNOWN, newFileStream(f, (void (*)())pclose));
+ buf = loadproc(&uf, defaultbuf);
+ UFclose(&uf);
+ return buf;
+}
+
+/*
+ * getshell: execute shell command and get the result into a buffer
+ */
+Buffer *
+getshell(char *cmd)
+{
+ Buffer *buf;
+
+ buf = loadcmdout(cmd, loadBuffer, NULL);
+ if (buf == NULL)
+ return NULL;
+ buf->filename = cmd;
+ buf->buffername = Sprintf("%s %s", SHELLBUFFERNAME,
+ conv_from_system(cmd))->ptr;
+ return buf;
+}
+
+/*
+ * getpipe: execute shell command and connect pipe to the buffer
+ */
+Buffer *
+getpipe(char *cmd)
+{
+ FILE *f, *popen(const char *, const char *);
+ Buffer *buf;
+
+ if (cmd == NULL || *cmd == '\0')
+ return NULL;
+ f = popen(cmd, "r");
+ if (f == NULL)
+ return NULL;
+ buf = newBuffer(INIT_BUFFER_WIDTH);
+ buf->pagerSource = newFileStream(f, (void (*)())pclose);
+ buf->filename = cmd;
+ buf->buffername = Sprintf("%s %s", PIPEBUFFERNAME,
+ conv_from_system(cmd))->ptr;
+ buf->bufferprop |= BP_PIPE;
+#ifdef USE_M17N
+ buf->document_charset = WC_CES_US_ASCII;
+#endif
+ return buf;
+}
+
+/*
+ * Open pager buffer
+ */
+Buffer *
+openPagerBuffer(InputStream stream, Buffer *buf)
+{
+
+ if (buf == NULL)
+ buf = newBuffer(INIT_BUFFER_WIDTH);
+ buf->pagerSource = stream;
+ buf->buffername = getenv("MAN_PN");
+ if (buf->buffername == NULL)
+ buf->buffername = PIPEBUFFERNAME;
+ else
+ buf->buffername = conv_from_system(buf->buffername);
+ buf->bufferprop |= BP_PIPE;
+#ifdef USE_M17N
+ if (content_charset && UseContentCharset)
+ buf->document_charset = content_charset;
+ else
+ buf->document_charset = WC_CES_US_ASCII;
+#endif
+ buf->currentLine = buf->firstLine;
+
+ return buf;
+}
+
+Buffer *
+openGeneralPagerBuffer(InputStream stream)
+{
+ Buffer *buf;
+ char *t = "text/plain";
+ Buffer *t_buf = NULL;
+ URLFile uf;
+
+ init_stream(&uf, SCM_UNKNOWN, stream);
+
+#ifdef USE_M17N
+ content_charset = 0;
+#endif
+ if (SearchHeader) {
+ t_buf = newBuffer(INIT_BUFFER_WIDTH);
+ readHeader(&uf, t_buf, TRUE, NULL);
+ t = checkContentType(t_buf);
+ if (t == NULL)
+ t = "text/plain";
+ if (t_buf) {
+ t_buf->topLine = t_buf->firstLine;
+ t_buf->currentLine = t_buf->lastLine;
+ }
+ SearchHeader = FALSE;
+ }
+ else if (DefaultType) {
+ t = DefaultType;
+ DefaultType = NULL;
+ }
+ if (!strcasecmp(t, "text/html")) {
+ buf = loadHTMLBuffer(&uf, t_buf);
+ buf->type = "text/html";
+ }
+ else if (is_plain_text_type(t)) {
+ if (IStype(stream) != IST_ENCODED)
+ stream = newEncodedStream(stream, uf.encoding);
+ buf = openPagerBuffer(stream, t_buf);
+ buf->type = "text/plain";
+ }
+#ifdef USE_IMAGE
+ else if (activeImage && displayImage && !useExtImageViewer &&
+ !(w3m_dump & ~DUMP_FRAME) && !strncasecmp(t, "image/", 6)) {
+ cur_baseURL = New(ParsedURL);
+ parseURL("-", cur_baseURL, NULL);
+ buf = loadImageBuffer(&uf, t_buf);
+ buf->type = "text/html";
+ }
+#endif
+ else {
+ if (doExternal(uf, "-", t, &buf, t_buf)) {
+ UFclose(&uf);
+ if (buf == NULL || buf == NO_BUFFER)
+ return buf;
+ }
+ else { /* unknown type is regarded as text/plain */
+ if (IStype(stream) != IST_ENCODED)
+ stream = newEncodedStream(stream, uf.encoding);
+ buf = openPagerBuffer(stream, t_buf);
+ buf->type = "text/plain";
+ }
+ }
+ buf->real_type = t;
+ buf->currentURL.scheme = SCM_LOCAL;
+ buf->currentURL.file = "-";
+ return buf;
+}
+
+Line *
+getNextPage(Buffer *buf, int plen)
+{
+ Line *volatile top = buf->topLine, *volatile last = buf->lastLine,
+ *volatile cur = buf->currentLine;
+ int i;
+ int volatile nlines = 0;
+ clen_t linelen = 0, trbyte = buf->trbyte;
+ Str lineBuf2;
+ char volatile pre_lbuf = '\0';
+ URLFile uf;
+#ifdef USE_M17N
+ wc_ces charset;
+ wc_ces volatile doc_charset = DocumentCharset;
+ wc_uint8 old_auto_detect = WcOption.auto_detect;
+#endif
+ int volatile squeeze_flag = FALSE;
+ Lineprop *propBuffer = NULL;
+
+#ifdef USE_ANSI_COLOR
+ Linecolor *colorBuffer = NULL;
+#endif
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+
+ if (buf->pagerSource == NULL)
+ return NULL;
+
+ if (last != NULL) {
+ nlines = last->real_linenumber;
+ pre_lbuf = *(last->lineBuf);
+ if (pre_lbuf == '\0')
+ pre_lbuf = '\n';
+ buf->currentLine = last;
+ }
+
+#ifdef USE_M17N
+ charset = buf->document_charset;
+ if (buf->document_charset != WC_CES_US_ASCII)
+ doc_charset = buf->document_charset;
+ else if (UseContentCharset) {
+ content_charset = 0;
+ checkContentType(buf);
+ if (content_charset)
+ doc_charset = content_charset;
+ }
+ WcOption.auto_detect = buf->auto_detect;
+#endif
+
+ if (SETJMP(AbortLoading) != 0) {
+ goto pager_end;
+ }
+ TRAP_ON;
+
+ init_stream(&uf, SCM_UNKNOWN, NULL);
+ for (i = 0; i < plen; i++) {
+ lineBuf2 = StrmyISgets(buf->pagerSource);
+ if (lineBuf2->length == 0) {
+ /* Assume that `cmd == buf->filename' */
+ if (buf->filename)
+ buf->buffername = Sprintf("%s %s",
+ CPIPEBUFFERNAME,
+ conv_from_system(buf->filename))->
+ ptr;
+ else if (getenv("MAN_PN") == NULL)
+ buf->buffername = CPIPEBUFFERNAME;
+ buf->bufferprop |= BP_CLOSE;
+ break;
+ }
+ linelen += lineBuf2->length;
+ showProgress(&linelen, &trbyte);
+ lineBuf2 =
+ convertLine(&uf, lineBuf2, PAGER_MODE, &charset, doc_charset);
+ if (squeezeBlankLine) {
+ squeeze_flag = FALSE;
+ if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') {
+ ++nlines;
+ --i;
+ squeeze_flag = TRUE;
+ continue;
+ }
+ pre_lbuf = lineBuf2->ptr[0];
+ }
+ ++nlines;
+ Strchop(lineBuf2);
+ lineBuf2 = checkType(lineBuf2, &propBuffer, &colorBuffer);
+ addnewline(buf, lineBuf2->ptr, propBuffer, colorBuffer,
+ lineBuf2->length, FOLD_BUFFER_WIDTH, nlines);
+ if (!top) {
+ top = buf->firstLine;
+ cur = top;
+ }
+ if (buf->lastLine->real_linenumber - buf->firstLine->real_linenumber
+ >= PagerMax) {
+ Line *l = buf->firstLine;
+ do {
+ if (top == l)
+ top = l->next;
+ if (cur == l)
+ cur = l->next;
+ if (last == l)
+ last = NULL;
+ l = l->next;
+ } while (l && l->bpos);
+ buf->firstLine = l;
+ buf->firstLine->prev = NULL;
+ }
+ }
+ pager_end:
+ TRAP_OFF;
+
+ buf->trbyte = trbyte + linelen;
+#ifdef USE_M17N
+ buf->document_charset = charset;
+ WcOption.auto_detect = old_auto_detect;
+#endif
+ buf->topLine = top;
+ buf->currentLine = cur;
+ if (!last)
+ last = buf->firstLine;
+ else if (last && (last->next || !squeeze_flag))
+ last = last->next;
+ return last;
+}
+
+int
+save2tmp(URLFile uf, char *tmpf)
+{
+ FILE *ff;
+ int check;
+ clen_t linelen = 0, trbyte = 0;
+ MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
+ static JMP_BUF env_bak;
+
+ ff = fopen(tmpf, "wb");
+ if (ff == NULL) {
+ /* fclose(f); */
+ return -1;
+ }
+ bcopy(AbortLoading, env_bak, sizeof(JMP_BUF));
+ if (SETJMP(AbortLoading) != 0) {
+ goto _end;
+ }
+ TRAP_ON;
+ check = 0;
+#ifdef USE_NNTP
+ if (uf.scheme == SCM_NEWS) {
+ char c;
+ while (c = UFgetc(&uf), !iseos(uf.stream)) {
+ if (c == '\n') {
+ if (check == 0)
+ check++;
+ else if (check == 3)
+ break;
+ }
+ else if (c == '.' && check == 1)
+ check++;
+ else if (c == '\r' && check == 2)
+ check++;
+ else
+ check = 0;
+ putc(c, ff);
+ linelen += sizeof(c);
+ showProgress(&linelen, &trbyte);
+ }
+ }
+ else
+#endif /* USE_NNTP */
+ {
+ Str buf = Strnew_size(SAVE_BUF_SIZE);
+ while (UFread(&uf, buf, SAVE_BUF_SIZE)) {
+ Strfputs(buf, ff);
+ linelen += buf->length;
+ showProgress(&linelen, &trbyte);
+ }
+ }
+ _end:
+ bcopy(env_bak, AbortLoading, sizeof(JMP_BUF));
+ TRAP_OFF;
+ fclose(ff);
+ current_content_length = 0;
+ return 0;
+}
+
+int
+doExternal(URLFile uf, char *path, char *type, Buffer **bufp,
+ Buffer *defaultbuf)
+{
+ Str tmpf, command;
+ struct mailcap *mcap;
+ int mc_stat;
+ Buffer *buf = NULL;
+ char *header, *src = NULL, *ext = uf.ext;
+
+ if (!(mcap = searchExtViewer(type)))
+ return 0;
+
+ if (mcap->nametemplate) {
+ tmpf = unquote_mailcap(mcap->nametemplate, NULL, "", NULL, NULL);
+ if (tmpf->ptr[0] == '.')
+ ext = tmpf->ptr;
+ }
+ tmpf = tmpfname(TMPF_DFL, (ext && *ext) ? ext : NULL);
+
+ if (IStype(uf.stream) != IST_ENCODED)
+ uf.stream = newEncodedStream(uf.stream, uf.encoding);
+ header = checkHeader(defaultbuf, "Content-Type:");
+ if (header)
+ header = conv_to_system(header);
+ command = unquote_mailcap(mcap->viewer, type, tmpf->ptr, header, &mc_stat);
+#ifndef __EMX__
+ if (!(mc_stat & MCSTAT_REPNAME)) {
+ Str tmp = Sprintf("(%s) < %s", command->ptr, shell_quote(tmpf->ptr));
+ command = tmp;
+ }
+#endif
+
+#ifdef HAVE_SETPGRP
+ if (!(mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)) &&
+ !(mcap->flags & MAILCAP_NEEDSTERMINAL) && BackgroundExtViewer) {
+ flush_tty();
+ if (!fork()) {
+ setup_child(FALSE, 0, UFfileno(&uf));
+ if (save2tmp(uf, tmpf->ptr) < 0)
+ exit(1);
+ UFclose(&uf);
+ myExec(command->ptr);
+ }
+ *bufp = NO_BUFFER;
+ return 1;
+ }
+ else
+#endif
+ {
+ if (save2tmp(uf, tmpf->ptr) < 0) {
+ *bufp = NULL;
+ return 1;
+ }
+ }
+ if (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)) {
+ if (defaultbuf == NULL)
+ defaultbuf = newBuffer(INIT_BUFFER_WIDTH);
+ if (defaultbuf->sourcefile)
+ src = defaultbuf->sourcefile;
+ else
+ src = tmpf->ptr;
+ defaultbuf->sourcefile = NULL;
+ defaultbuf->mailcap = mcap;
+ }
+ if (mcap->flags & MAILCAP_HTMLOUTPUT) {
+ buf = loadcmdout(command->ptr, loadHTMLBuffer, defaultbuf);
+ if (buf && buf != NO_BUFFER) {
+ buf->type = "text/html";
+ buf->mailcap_source = buf->sourcefile;
+ buf->sourcefile = src;
+ }
+ }
+ else if (mcap->flags & MAILCAP_COPIOUSOUTPUT) {
+ buf = loadcmdout(command->ptr, loadBuffer, defaultbuf);
+ if (buf && buf != NO_BUFFER) {
+ buf->type = "text/plain";
+ buf->mailcap_source = buf->sourcefile;
+ buf->sourcefile = src;
+ }
+ }
+ else {
+ if (mcap->flags & MAILCAP_NEEDSTERMINAL || !BackgroundExtViewer) {
+ fmTerm();
+ mySystem(command->ptr, 0);
+ fmInit();
+ if (CurrentTab && Currentbuf)
+ displayBuffer(Currentbuf, B_FORCE_REDRAW);
+ }
+ else {
+ mySystem(command->ptr, 1);
+ }
+ buf = NO_BUFFER;
+ }
+ if (buf && buf != NO_BUFFER) {
+ buf->filename = path;
+ if (buf->buffername == NULL || buf->buffername[0] == '\0')
+ buf->buffername = conv_from_system(lastFileName(path));
+ buf->edit = mcap->edit;
+ buf->mailcap = mcap;
+ }
+ *bufp = buf;
+ return 1;
+}
+
+static int
+_MoveFile(char *path1, char *path2)
+{
+ InputStream f1;
+ FILE *f2;
+ int is_pipe;
+ clen_t linelen = 0, trbyte = 0;
+ Str buf;
+
+ f1 = openIS(path1);
+ if (f1 == NULL)
+ return -1;
+ if (*path2 == '|' && PermitSaveToPipe) {
+ is_pipe = TRUE;
+ f2 = popen(path2 + 1, "w");
+ }
+ else {
+ is_pipe = FALSE;
+ f2 = fopen(path2, "wb");
+ }
+ if (f2 == NULL) {
+ ISclose(f1);
+ return -1;
+ }
+ current_content_length = 0;
+ buf = Strnew_size(SAVE_BUF_SIZE);
+ while (ISread(f1, buf, SAVE_BUF_SIZE)) {
+ Strfputs(buf, f2);
+ linelen += buf->length;
+ showProgress(&linelen, &trbyte);
+ }
+ ISclose(f1);
+ if (is_pipe)
+ pclose(f2);
+ else
+ fclose(f2);
+ return 0;
+}
+
+int
+_doFileCopy(char *tmpf, char *defstr, int download)
+{
+ Str msg;
+ Str filen;
+ char *p, *q = NULL;
+ pid_t pid;
+ char *lock;
+#if !(defined(HAVE_SYMLINK) && defined(HAVE_LSTAT))
+ FILE *f;
+#endif
+ struct stat st;
+ clen_t size = 0;
+ int is_pipe = FALSE;
+
+ if (fmInitialized) {
+ p = searchKeyData();
+ if (p == NULL || *p == '\0') {
+ /* FIXME: gettextize? */
+ q = inputLineHist("(Download)Save file to: ",
+ defstr, IN_COMMAND, SaveHist);
+ if (q == NULL || *q == '\0')
+ return FALSE;
+ p = conv_to_system(q);
+ }
+ if (*p == '|' && PermitSaveToPipe)
+ is_pipe = TRUE;
+ else {
+ if (q) {
+ p = unescape_spaces(Strnew_charp(q))->ptr;
+ p = conv_to_system(q);
+ }
+ p = expandPath(p);
+ if (checkOverWrite(p) < 0)
+ return -1;
+ }
+ if (checkCopyFile(tmpf, p) < 0) {
+ /* FIXME: gettextize? */
+ msg = Sprintf("Can't copy. %s and %s are identical.",
+ conv_from_system(tmpf), conv_from_system(p));
+ disp_err_message(msg->ptr, FALSE);
+ return -1;
+ }
+ if (!download) {
+ if (_MoveFile(tmpf, p) < 0) {
+ /* FIXME: gettextize? */
+ msg = Sprintf("Can't save to %s", conv_from_system(p));
+ disp_err_message(msg->ptr, FALSE);
+ }
+ return -1;
+ }
+ lock = tmpfname(TMPF_DFL, ".lock")->ptr;
+#if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT)
+ symlink(p, lock);
+#else
+ f = fopen(lock, "w");
+ if (f)
+ fclose(f);
+#endif
+ flush_tty();
+ pid = fork();
+ if (!pid) {
+ setup_child(FALSE, 0, -1);
+ if (!_MoveFile(tmpf, p) && PreserveTimestamp && !is_pipe &&
+ !stat(tmpf, &st))
+ setModtime(p, st.st_mtime);
+ unlink(lock);
+ exit(0);
+ }
+ if (!stat(tmpf, &st))
+ size = st.st_size;
+ addDownloadList(pid, conv_from_system(tmpf), p, lock, size);
+ }
+ else {
+ q = searchKeyData();
+ if (q == NULL || *q == '\0') {
+ /* FIXME: gettextize? */
+ printf("(Download)Save file to: ");
+ fflush(stdout);
+ filen = Strfgets(stdin);
+ if (filen->length == 0)
+ return -1;
+ q = filen->ptr;
+ }
+ for (p = q + strlen(q) - 1; IS_SPACE(*p); p--) ;
+ *(p + 1) = '\0';
+ if (*q == '\0')
+ return -1;
+ p = q;
+ if (*p == '|' && PermitSaveToPipe)
+ is_pipe = TRUE;
+ else {
+ p = expandPath(p);
+ if (checkOverWrite(p) < 0)
+ return -1;
+ }
+ if (checkCopyFile(tmpf, p) < 0) {
+ /* FIXME: gettextize? */
+ printf("Can't copy. %s and %s are identical.", tmpf, p);
+ return -1;
+ }
+ if (_MoveFile(tmpf, p) < 0) {
+ /* FIXME: gettextize? */
+ printf("Can't save to %s\n", p);
+ return -1;
+ }
+ if (PreserveTimestamp && !is_pipe && !stat(tmpf, &st))
+ setModtime(p, st.st_mtime);
+ }
+ return 0;
+}
+
+int
+doFileMove(char *tmpf, char *defstr)
+{
+ int ret = doFileCopy(tmpf, defstr);
+ unlink(tmpf);
+ return ret;
+}
+
+int
+doFileSave(URLFile uf, char *defstr)
+{
+ Str msg;
+ Str filen;
+ char *p, *q;
+ pid_t pid;
+ char *lock;
+#if !(defined(HAVE_SYMLINK) && defined(HAVE_LSTAT))
+ FILE *f;
+#endif
+
+ if (fmInitialized) {
+ p = searchKeyData();
+ if (p == NULL || *p == '\0') {
+ /* FIXME: gettextize? */
+ p = inputLineHist("(Download)Save file to: ",
+ defstr, IN_FILENAME, SaveHist);
+ if (p == NULL || *p == '\0')
+ return -1;
+ p = conv_to_system(p);
+ }
+ if (checkOverWrite(p) < 0)
+ return -1;
+ if (checkSaveFile(uf.stream, p) < 0) {
+ /* FIXME: gettextize? */
+ msg = Sprintf("Can't save. Load file and %s are identical.",
+ conv_from_system(p));
+ disp_err_message(msg->ptr, FALSE);
+ return -1;
+ }
+ /*
+ * if (save2tmp(uf, p) < 0) {
+ * msg = Sprintf("Can't save to %s", conv_from_system(p));
+ * disp_err_message(msg->ptr, FALSE);
+ * }
+ */
+ lock = tmpfname(TMPF_DFL, ".lock")->ptr;
+#if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT)
+ symlink(p, lock);
+#else
+ f = fopen(lock, "w");
+ if (f)
+ fclose(f);
+#endif
+ flush_tty();
+ pid = fork();
+ if (!pid) {
+ setup_child(FALSE, 0, UFfileno(&uf));
+ if (!save2tmp(uf, p) && PreserveTimestamp && uf.modtime != -1)
+ setModtime(p, uf.modtime);
+ UFclose(&uf);
+ unlink(lock);
+ exit(0);
+ }
+ addDownloadList(pid, uf.url, p, lock, current_content_length);
+ }
+ else {
+ q = searchKeyData();
+ if (q == NULL || *q == '\0') {
+ /* FIXME: gettextize? */
+ printf("(Download)Save file to: ");
+ fflush(stdout);
+ filen = Strfgets(stdin);
+ if (filen->length == 0)
+ return -1;
+ q = filen->ptr;
+ }
+ for (p = q + strlen(q) - 1; IS_SPACE(*p); p--) ;
+ *(p + 1) = '\0';
+ if (*q == '\0')
+ return -1;
+ p = expandPath(q);
+ if (checkOverWrite(p) < 0)
+ return -1;
+ if (checkSaveFile(uf.stream, p) < 0) {
+ /* FIXME: gettextize? */
+ printf("Can't save. Load file and %s are identical.", p);
+ return -1;
+ }
+ if (save2tmp(uf, p) < 0) {
+ /* FIXME: gettextize? */
+ printf("Can't save to %s\n", p);
+ return -1;
+ }
+ if (PreserveTimestamp && uf.modtime != -1)
+ setModtime(p, uf.modtime);
+ }
+ return 0;
+}
+
+int
+checkCopyFile(char *path1, char *path2)
+{
+ struct stat st1, st2;
+
+ if (*path2 == '|' && PermitSaveToPipe)
+ return 0;
+ if ((stat(path1, &st1) == 0) && (stat(path2, &st2) == 0))
+ if (st1.st_ino == st2.st_ino)
+ return -1;
+ return 0;
+}
+
+int
+checkSaveFile(InputStream stream, char *path2)
+{
+ struct stat st1, st2;
+ int des = ISfileno(stream);
+
+ if (des < 0)
+ return 0;
+ if (*path2 == '|' && PermitSaveToPipe)
+ return 0;
+ if ((fstat(des, &st1) == 0) && (stat(path2, &st2) == 0))
+ if (st1.st_ino == st2.st_ino)
+ return -1;
+ return 0;
+}
+
+int
+checkOverWrite(char *path)
+{
+ struct stat st;
+ char *ans;
+
+ if (stat(path, &st) < 0)
+ return 0;
+ /* FIXME: gettextize? */
+ ans = inputAnswer("File exists. Overwrite? (y/n)");
+ if (ans && TOLOWER(*ans) == 'y')
+ return 0;
+ else
+ return -1;
+}
+
+char *
+inputAnswer(char *prompt)
+{
+ char *ans;
+
+ if (QuietMessage)
+ return "n";
+ if (fmInitialized) {
+ term_raw();
+ ans = inputChar(prompt);
+ }
+ else {
+ printf(prompt);
+ fflush(stdout);
+ ans = Strfgets(stdin)->ptr;
+ }
+ return ans;
+}
+
+static void
+uncompress_stream(URLFile *uf, char **src)
+{
+ pid_t pid1;
+ FILE *f1;
+ char *expand_cmd = GUNZIP_CMDNAME;
+ char *expand_name = GUNZIP_NAME;
+ char *tmpf = NULL;
+ char *ext = NULL;
+ struct compression_decoder *d;
+
+ if (IStype(uf->stream) != IST_ENCODED) {
+ uf->stream = newEncodedStream(uf->stream, uf->encoding);
+ uf->encoding = ENC_7BIT;
+ }
+ for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
+ if (uf->compression == d->type) {
+ if (d->auxbin_p)
+ expand_cmd = auxbinFile(d->cmd);
+ else
+ expand_cmd = d->cmd;
+ expand_name = d->name;
+ ext = d->ext;
+ break;
+ }
+ }
+ uf->compression = CMP_NOCOMPRESS;
+
+ if (uf->scheme != SCM_LOCAL
+#ifdef USE_IMAGE
+ && !image_source
+#endif
+ ) {
+ tmpf = tmpfname(TMPF_DFL, ext)->ptr;
+ }
+
+ /* child1 -- stdout|f1=uf -> parent */
+ pid1 = open_pipe_rw(&f1, NULL);
+ if (pid1 < 0) {
+ UFclose(uf);
+ return;
+ }
+ if (pid1 == 0) {
+ /* child */
+ pid_t pid2;
+ FILE *f2 = stdin;
+
+ /* uf -> child2 -- stdout|stdin -> child1 */
+ pid2 = open_pipe_rw(&f2, NULL);
+ if (pid2 < 0) {
+ UFclose(uf);
+ exit(1);
+ }
+ if (pid2 == 0) {
+ /* child2 */
+ Str buf = Strnew_size(SAVE_BUF_SIZE);
+ FILE *f = NULL;
+
+ setup_child(TRUE, 2, UFfileno(uf));
+ if (tmpf)
+ f = fopen(tmpf, "wb");
+ while (UFread(uf, buf, SAVE_BUF_SIZE)) {
+ if (Strfputs(buf, stdout) < 0)
+ break;
+ if (f)
+ Strfputs(buf, f);
+ }
+ UFclose(uf);
+ if (f)
+ fclose(f);
+ exit(0);
+ }
+ /* child1 */
+ dup2(1, 2); /* stderr>&stdout */
+ setup_child(TRUE, -1, -1);
+ execlp(expand_cmd, expand_name, NULL);
+ exit(1);
+ }
+ if (tmpf) {
+ if (src)
+ *src = tmpf;
+ else
+ uf->scheme = SCM_LOCAL;
+ }
+ UFhalfclose(uf);
+ uf->stream = newFileStream(f1, (void (*)())pclose);
+}
+
+static FILE *
+lessopen_stream(char *path)
+{
+ char *lessopen;
+ FILE *fp;
+
+ lessopen = getenv("LESSOPEN");
+ if (lessopen == NULL) {
+ return NULL;
+ }
+ if (lessopen[0] == '\0') {
+ return NULL;
+ }
+
+ if (lessopen[0] == '|') {
+ /* pipe mode */
+ Str tmpf;
+ int c;
+
+ ++lessopen;
+ tmpf = Sprintf(lessopen, shell_quote(path));
+ fp = popen(tmpf->ptr, "r");
+ if (fp == NULL) {
+ return NULL;
+ }
+ c = getc(fp);
+ if (c == EOF) {
+ fclose(fp);
+ return NULL;
+ }
+ ungetc(c, fp);
+ }
+ else {
+ /* filename mode */
+ /* not supported m(__)m */
+ fp = NULL;
+ }
+ return fp;
+}
+
+#if 0
+void
+reloadBuffer(Buffer *buf)
+{
+ URLFile uf;
+
+ if (buf->sourcefile == NULL || buf->pagerSource != NULL)
+ return;
+ init_stream(&uf, SCM_UNKNOWN, NULL);
+ examineFile(buf->mailcap_source ? buf->mailcap_source : buf->sourcefile,
+ &uf);
+ if (uf.stream == NULL)
+ return;
+ is_redisplay = TRUE;
+ buf->allLine = 0;
+ buf->href = NULL;
+ buf->name = NULL;
+ buf->img = NULL;
+ buf->formitem = NULL;
+ buf->linklist = NULL;
+ buf->maplist = NULL;
+ if (buf->hmarklist)
+ buf->hmarklist->nmark = 0;
+ if (buf->imarklist)
+ buf->imarklist->nmark = 0;
+ if (!strcasecmp(buf->type, "text/html"))
+ loadHTMLBuffer(&uf, buf);
+ else
+ loadBuffer(&uf, buf);
+ UFclose(&uf);
+ is_redisplay = FALSE;
+}
+#endif
+
+static char *
+guess_filename(char *file)
+{
+ char *p = NULL, *s;
+
+ if (file != NULL)
+ p = mybasename(file);
+ if (p == NULL || *p == '\0')
+ return DEF_SAVE_FILE;
+ s = p;
+ if (*p == '#')
+ p++;
+ while (*p != '\0') {
+ if ((*p == '#' && *(p + 1) != '\0') || *p == '?') {
+ *p = '\0';
+ break;
+ }
+ p++;
+ }
+ return s;
+}
+
+char *
+guess_save_name(Buffer *buf, char *path)
+{
+ if (buf && buf->document_header) {
+ Str name = NULL;
+ char *p, *q;
+ if ((p = checkHeader(buf, "Content-Disposition:")) != NULL &&
+ (q = strcasestr(p, "filename")) != NULL &&
+ (q == p || IS_SPACE(*(q - 1)) || *(q - 1) == ';') &&
+ matchattr(q, "filename", 8, &name))
+ path = name->ptr;
+ else if ((p = checkHeader(buf, "Content-Type:")) != NULL &&
+ (q = strcasestr(p, "name")) != NULL &&
+ (q == p || IS_SPACE(*(q - 1)) || *(q - 1) == ';') &&
+ matchattr(q, "name", 4, &name))
+ path = name->ptr;
+ }
+ return guess_filename(path);
+}
+
+/* Local Variables: */
+/* c-basic-offset: 4 */
+/* tab-width: 8 */
+/* End: */